network supply chain
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
WHAT IS IT?
Inventory management is a critical problem in the supply chain management. Lots of analysis regarding the inventory dynamics in the supply chain system can be found in the literature of the operations research community. In this model, we explore a simplified network supply chain. There is one supplier, which has unlimited supply. There can be multiple distributors and retailers. Players order from upstream nodes and ship to downstream nodes. By selling goods, the players receive revenues. If players are not able to satisfy the demand, back-orders are created, the penalty costs occur. Also holding inventory incurs utility and maitenance costs. Players are striving to maximize their profit by wisely manage their ordering strategy and inventory policy.
HOW IT WORKS
Every day, a daily demand is imposed to each retailer. Retailers order from distributors, and distributors order from the supplier. We assume that all distributors and retailers are following the base-stock policy, that is: once the inventory position drops below the base-stock level, the player order the difference between the base-stock level and current inventory position; otherwise order nothing. The retailers will choose which distributor to order from according to the back-orders. The distributors need to allocate the available on-hand inventory to retailers, according to their respective quota. Once all the order, replenish, and ship activities are complished, we conclude the day and summarize the cost and revenue for each player. Then a new day starts.
HOW TO USE IT
Press "setup" button to establish the supply chain. Press "go" button to carry on the simulation.
"number-of-distributors" and "number-of-retailers" sliders adjust the number of distributors and retailers in the supply chain system.
"lead-time-supplier-distributor" indicates the number of days of supply delay between the supplier and distributors. Similarly, "lead-time-distributor-retailer" indicates the number of days of supply delay between distributors and retailers.
"initial-stock-distributor" and "initial-stock-retailer" are the initial inventory at the begining of the simulation for distributors and retailers, respectively.
"record-length" indicates how many recent day's demand history will be kept in record.
If ticks > "days-of-simulation", the program stops.
There are a chooser and several sliders for adjusting the generation mechanism of the daily demand. The monitor indicates today's demand.
The "total profit" and "on-hand inventory" plot the profit and on-hand stock level, respectively, at the current day of simulation for all players.
THINGS TO NOTICE
The fluctuation of the on-hand inventory level at the distributors and retailers. It is said the fluctuation would propogate from downstream to upstream, so-called bull-whip effect.
THINGS TO TRY
Users can adjust the lead times to see how this will affect the supply chain.
Also, will the safety factors have significant influence on the supply chain?
How will different demand distributions matter?
EXTENDING THE MODEL
In the current model, we assume that all the lead times are the same. Actually they can be different. This would cause desyncronization, which may lead to interesting results.
In the current model, we assume full connection. However, a retailer may not have connections with all the distributors. Will this create bias?
In the current model, we only consider 3 echelons. It may be interesting to extend to more echelons and more complicated supply chain configuration.
RELATED MODELS
Wilensky, U. and Stroup, W. (2003). NetLogo HubNet Root Beer Game model. http://ccl.northwestern.edu/netlogo/models/HubNetRootBeerGame. Center for Connected Learning and Computer-Based Modeling, Northwestern Institute on Complex Systems, Northwestern University, Evanston, IL.
Comments and Questions
globals [ demand-today ;; the demand occurs at all retailers everyday colors ;; colors for plot ] breed [players player] ;; There are 2 types of directed links in the model ;; demand links for order placement, and supply links for shipment pipeline directed-link-breed [supply-links supply-link] supply-links-own [orders-filled pair-demand-link] directed-link-breed [demand-links demand-link] demand-links-own [orders-placed back-orders] players-own [ role ;; 3 roles in the model: supplier, distributor, and retailer base-stock ;; we assume players are operating under base-stock policy on-hand backlog inventory-position ;; inventory equals to on-hand inventory + pipeline inventory - back-orders last-received pen-color cost id-number ;; id-number is used to distinguish players with the same role demand-history ;; a list consisting of the demands in a few past days revenue ;; revenue from selling the products safety-factor ;; parameter determining to what extent the player want to keep safety inventory against demand uncertainty current-supplier ] to setup ca set colors [5 15 25 35 45 55 65 75 85 95 105 115 125 135 67 117 28 18 37] ;; a list of 20 colors set colors shuffle colors layout initialize resize-shape reset-plots reset-ticks end to go if ticks >= days-of-simulation [stop] set demand-today daily-demand ;; generate today's demand place-order-to-up receive-order-from-up process-order-from-down summarize update-policy resize-shape tick end to update-policy ;; the players can update their inventory policy according to their demand record ask players with [role = "distributor"][ set base-stock cal-base-stock-level demand-history lead-time-supplier-distributor ] ask players with [role = "retailer"][ set base-stock cal-base-stock-level demand-history lead-time-distributor-retailer ] end ;; Inventory operations ;; ************************** to place-order-to-up ask players with [role = "retailer" or role = "distributor"][ ;; in this model, we assume all players are operating under base-stock policy let amount-to-order max list (base-stock - inventory-position) 0 ;; that is once the inventory position is below the base stock level, ;; we order the quantity equal to the difference between inventory position and base stock level ;; otherwise, don't place any order ask my-out-demand-links [set orders-placed 0] ;; since in a network supply chain, a player can order from multiple upstream nodes ask who-to-order [set orders-placed amount-to-order] ;; choose one node each time ] end to receive-order-from-up ask players [ if role = "distributor" or role = "retailer" [ set last-received sum [first orders-filled] of my-in-supply-links ;; take out the first item in the supply-link pipeline ask my-in-supply-links [set orders-filled but-first orders-filled] ;; remove it from the pipeline set on-hand on-hand + last-received ;; add it to the current on-hand inventory ] if role = "supplier" [set on-hand 10000] ;; we assume the supplier has unlimited supply ] end to process-order-from-down ask players [ let new-orders 0 ;; for distributors and suppliers, new orders equal to the sum of the orders-placed of all in-demand-links if role = "distributor" or role = "supplier" [set new-orders sum [orders-placed] of my-in-demand-links] if role = "retailer" [set new-orders demand-today] ;; for retailers, new orders simply equal to today's demand set demand-history lput new-orders demand-history ;; record the new-order in the demand history set demand-history but-first demand-history ;; delete the earliest demand history on the record, in order to keep the record length the same let orders-requested new-orders + backlog ;; besides new orders, back-orders also need to be satisfied let orders-to-ship min list orders-requested on-hand ;; if there is sufficient inventory, ship the requested amount ;; if not sufficient inventory, ship whatever on-hand if role = "distributor" [set revenue revenue + 2 * orders-to-ship] ;; revenue for distributors is 2 for each unit shipped if role = "retailer" [set revenue revenue + 3 * orders-to-ship] ;; revenue for is 3 for each unit shipped set backlog max list 0 (backlog - on-hand + new-orders) ;; the unsatisfied demand is counted as backlog (or back-orders) let rest-amount orders-to-ship ;; allocate total shipping amount to each downstream node foreach sort my-out-supply-links [ ask ? [ ;; quota to each supply link is proportional the sum of back-orders and new orders of the pair demand link let quota sum [back-orders] of pair-demand-link + sum [orders-placed] of pair-demand-link let ship-to-this-link 0 ;; if no order, ship nothing, and put 0 in the supply link if orders-requested > 0 [ ;; if positive order, ship according to the quota set ship-to-this-link min list ceiling (quota * orders-to-ship / orders-requested) rest-amount ] ;; note that we use ceiling to guarantee the integrity of the shipping quantity set rest-amount rest-amount - ship-to-this-link set orders-filled lput ship-to-this-link orders-filled ;; put the ship quantity at the last place of the supply pipeline ask pair-demand-link [set back-orders max list 0 (quota - ship-to-this-link)] ;; update the back-orders in the pair demand link ] ] set on-hand on-hand - orders-to-ship ;; reduce the shipped quantity from the on-hand inventory ] end to summarize ask players [ let pipeline sum [sum orders-filled] of my-in-supply-links ;; calculate the pipeline inventory (inventory in-transit) for each player set inventory-position on-hand + pipeline - backlog ;; recalculate the inventory position let cost-add (0.5 * on-hand + 2 * backlog) ;; calculate inventory holding cost and backlog penalty set cost cost + cost-add ;; update the cost ] ask players with [role = "distributor" or role = "retailer"] [ ;; plots plot-on-hand-inventory plot-profit ] end ;; **************************** to-report y-locations [number] ;; report a list of y-coordinates that would evenly distribute the "number" players on y-axis let y-list [] let interval round ((2 * (max-pycor - 3) + 1) / (number + 1)) let current-pos (- max-pycor + 3 + interval) repeat number [ set y-list lput current-pos y-list set current-pos current-pos + interval ] report y-list end to layout set-default-shape players "circle" set-default-shape links "arc" create-players 1 [ setxy -10 0 set color red set role "supplier" set size 5 ;; the size of the supplier won't be updated in the simulation ] ask patches with [pxcor = 0 and (member? pycor y-locations num-of-distributors)] [ ;; evenly layout the distributors in the middle sprout-players 1 [ set color blue set role "distributor" ] ] ask patches with [pxcor = 10 and (member? pycor y-locations num-of-retailers)] [ ;; evenly layout the retailers on the right sprout-players 1 [ set color green set role "retailer" ] ] let d-number 1 foreach sort players with [role = "distributor"][ ;; assign each distributor an id-number, and label them with the id-number ask ?[ set label word "D-" d-number set id-number d-number set d-number d-number + 1 ] ] let r-number 1 foreach sort players with [role = "retailer"][ ;; assign each retailer an id-number, and label them with the id-number ask ?[ set label word "R-" r-number set id-number r-number set r-number r-number + 1 ] ] let index 0 foreach sort players with [role = "distributor" or role = "retailer"][ ask ?[ set pen-color item index colors ;; assign each distributor and retailer a different plot pen color set index index + 1 ] ] ask players with [role = "retailer"] [ create-demand-links-to players with [role = "distributor"] ;; create demand and supply links between distributors and retailers create-supply-links-from players with [role = "distributor"] ] ask players with [role = "distributor"] [ create-demand-links-to players with [role = "supplier"] ;; create demand and supply links between supplier and distributors create-supply-links-from players with [role = "supplier"] ] ask supply-links [ ;; define the pair demand link of each supply link, the link with the same ends set pair-demand-link demand-links with [end1 = [end2] of myself and end2 = [end1] of myself] ] end to initialize ask players [ if role = "distributor" [ set base-stock initial-stock-distributor ;; set the initial base-stock level and on-hand inventory to "initial-stock-distributor" set on-hand initial-stock-distributor ask my-out-demand-links [ set orders-placed 0 set back-orders 0 ] ;; create a list with all elements equal to 0, with the length equals to "lead-time-supplier-distributor" ;; representing the supply pipeline between the supplier and the distributor ask my-in-supply-links [set orders-filled n-values lead-time-supplier-distributor [0]] ] if role = "retailer" [ set base-stock initial-stock-retailer set on-hand initial-stock-retailer ask my-out-demand-links [ set orders-placed 0 set back-orders random 0 ] ;; create a list with all elements equal to 0, with the length equals to "lead-time-distributor-retailer" ;; representing the supply pipeline between the distributor and the retailer ask my-in-supply-links [set orders-filled n-values lead-time-distributor-retailer [0]] ] if role = "supplier"[ set on-hand 10000 ] set backlog 0 set inventory-position on-hand - backlog ] ask players [ ;; randomly assign the safety-factor to players set cost 0 ;; the higher safety factor means that the player is willing to keep higher safety inventory against the demand uncertainty set revenue 0 set safety-factor 1.5 + random-float 1 set demand-history n-values record-length [""] ;; set the demand history as a list with empty elements, with the length equals to "record-length" ] end to resize-shape ;; visualize the on-hand stock via size of the turtle ask players with [role = "distributor" or role = "retailer"][ set size 0.5 * (sqrt on-hand) ] end to reset-plots ;; clear all plots and create plot pens for each player clear-all-plots ask players with [role = "distributor" or role = "retailer"][ create-plot-pens ] end to create-plot-pen [my-plot] set-current-plot my-plot create-temporary-plot-pen label ;; name the plot pen with the player's label set-plot-pen-color pen-color end to create-plot-pens create-plot-pen "total profit" ;; one plot for total profit create-plot-pen "on-hand inventory" ;; one plot for on-hand inventory level end to plot-profit set-current-plot "total profit" set-current-plot-pen label plot revenue - cost end to plot-on-hand-inventory set-current-plot "on-hand inventory" set-current-plot-pen label plot on-hand end ;; Demand distribution generation ;; ************************************** to-report daily-demand ;; we design three mechanisms for generating the daily demand, which can be chosen in the chooser if distribution = "deterministic" [report deterministic-demand] ;; deterministic demand means the demand is constant, there is no uncertainty if distribution = "poisson" ;; poisson demand means that the daily demand follows Poisson distribution [report random-poisson mean-for-poisson] if distribution = "normal" ;; normal demand means that the daily demand follows truncated normal distribution (modified in this model) [report truncated-normal mean-for-normal std-for-normal lower-bound-for-normal upper-bound-for-normal] end to-report truncated-normal [mean-value std-value min-value max-value] ;; there are 4 parameters for the truncated normal distribution let random-num random-normal mean-value std-value ;; we first generate a random-normal number according to the mean value and standard-deviation value ifelse random-num > max-value or random-num < min-value [report round (min-value + random-float (max-value - min-value))] ;; if the value is beyond the min-value and max-value, report a random number within the range [report round random-num] ;; if the value is within the min-value and max-value, report the rounding of this number end ;; *************************************************************** to-report cal-base-stock-level [demand-list delay] ;; calculate base-stock based on demand-history let numbers filter is-number? demand-list ;; during the first few days, not all the elements in the demand history are numbers, but "" let mean-value mean numbers ;; calculate mean value let std 0 if length numbers >= 2[ ;; calculate the standard deviation of the demand history set std standard-deviation numbers ] ;; according to inventory theories, the base-stock level is usually calculate according to mean and std and supply delays report round (mean-value * (delay + 1) + safety-factor * std * (sqrt (delay + 1))) ;; "+1" because of the order processing delay end to-report who-to-order ;; report the demand link that has the lowest back-orders, so that the player will choose to order from this one let min-back-order min [back-orders] of my-out-demand-links ;; find out the minimum back-order let sorted-links [] ;; prepare an empty list foreach sort my-out-demand-links [ ;; if the back-orders of the demand links equals to the minimum back-order ask ? [ ;; add the demand link to sorted-links list if back-orders = min-back-order [set sorted-links lput self sorted-links] ] ] ifelse member? current-supplier sorted-links [ ;; if the current-supplier (actually the corresponding demand link) is among the demand links with the minimum back-order report current-supplier ;; choose the current supplier due to customer loyalty ][ let chosen-one one-of sorted-links ;; if not, choose one from the demand links with the minimum back-order set current-supplier chosen-one ;; then transfer the supplier to this one report chosen-one ] end
There are 5 versions of this model.
This model does not have any ancestors.
This model does not have any descendants.