# Supply Chain

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)

## WHAT IS IT?

This model is an artificial market with four types of participants. The first are the costumers who have a daily demand and according to their strategy can purchase daily or periodically if their stock is below some specific level. The second are the retailers who sell products to costumers and update their demand forecast by considering the sales and the stock rupture (lost sales). The third are the distributors (who follow a similar procedure) to send products to retailers. Finally, there are the factories who start producing once their inventory level is lower than some reorder point.

The model can help students and professionals to understand better the supply chain with a single product, and how simple changes as the promotions, can affect the stocks levels and the demand calculation with a considerable amplitude, which is know as the bullwhip effect.

## HOW IT WORKS

The customers demand is normally distributed with a given standard deviation. Both the mean and the variability are user parameters. The inventory values (product cost, holding costs and order costs), are also parameters from the model. The user can also modify the number of agents. Finally, the clients� strategy and the retailers and distributors strategy are also parameters. At every day, the costumers can score the purchase experience (if there are some), so the next period the customers will choose the best supplier. At the beginning, the score is given by taking into account only the distance from retailers (the nearest retailer will be the supplier), but with the time, the agents could change this perspective by punishing the supplier if the sale is incomplete.

As to suppliers (retailers and distributors), they use linear regression for update their forecast and calculate the reorder point. If the stock is lower than this point, they place an order to their own supplier. If their strategy is (s,Q), they will only ask for the difference between the actual stock and the Economic Order Quantity (EOQ). If the strategy is (s,S), they will also consider the daily demand during the lead time. The last option is to repeat this last strategy but periodically.

The factories does the same estimation but for starting the production in a fix daily rate calculated at the beginning of the simulation.

## HOW TO USE IT

The user should fix some values and play the model (I recommend at least 720 periods for having some stable results), then collect statistics and play again. Different values will result in different costs and stock levels which can be compared in the analysis and conclusions phase.

## THINGS TO NOTICE

See how the stock levels for each type of participant are so different but at the same time they follow the same patron?, this is because the inventory theory, no matter what strategy the agents, it will always happen.

## THINGS TO TRY

Try to create promotions at some moment. See how they affect the stock levels and the inventory costs. See also how some retailer can increase the clients� number and hence the sales with these activities.

## EXTENDING THE MODEL

It would be nice to improve the model with:

1. More sophisticated forecasting models

2. Add some operational costs to the suppliers, so the user could evaluate the profit of every business.

3. Add more products to the models. This will require some elasticity concept because the products could or could not be substitutes among them, so the availability and/or the price will affect the demand.

4. Finally, we can think in smarter suppliers, who update their strategy and also improve it, to compete and to increase the earnings.

## CREDITS AND REFERENCES

Developped by Alvaro Gil at the Polytechnic School of Motreal alvaro.gil@polymtl.ca

If you mention this model in an academic publication, we ask that you include these citations for the model itself:

- Gil, Alvaro (2012). Artificial supply chain. �cole Polytechnique de Montr�al.

alvaro.gil@polymtl.ca

About the NetLogo software

- Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.

## COPYRIGHT NOTICE

Copyright 2012 Alvaro Gil. All rights reserved.

Permission to use, modify or redistribute this model is hereby granted, provided that both of the following requirements are followed:

a) this copyright notice is included.

b) this model will not be redistributed for profit without permission from Alvaro Gil. Contact the author for appropriate licenses for redistribution for profit.

## Comments and Questions

extensions [ matrix table] globals [ safety_values watching promotion stocks_h costs_h ret_list] breed [factories factory] breed [distributors distributor] breed [retailers retailer] breed [customers customer] turtles-own [demand stock strategy] Factories-own [ production_rate reorder_point orders available_stock clients daily_sales sales lost_sales forecast holding_cost order_cost total_cost ] distributors-own [ EOQ next_review reorder_point orders available_stock suppliers supplier_score supplier0 clients daily_sales sales lost_sales forecast placed_orders holding_cost order_cost total_cost ] retailers-own [ EOQ next_review reorder_point suppliers supplier_score supplier0 clients daily_sales sales lost_sales forecast placed_orders holding_cost order_cost total_cost ] customers-own [ next_review daily suppliers supplier_score supplier0 ] to setup ;; (for this model to work with NetLogo's new plotting features, ;; __clear-all-and-reset-ticks should be replaced with clear-all at ;; the beginning of your setup procedure and reset-ticks at the end ;; of the procedure.) __clear-all-and-reset-ticks ask patches [set pcolor white] set promotion [0 0 0] ;Retailer 1, Impact 2, Until 3 set stocks_h [] ;Customer, Retailer, Distributor, Factory set costs_h [] ;Retailer, Distributor, Factory set safety_values table:make table:put safety_values 0.50 0 table:put safety_values 0.55 0.125661347 table:put safety_values 0.60 0.253347103 table:put safety_values 0.65 0.385320466 table:put safety_values 0.70 0.524400513 table:put safety_values 0.75 0.67448975 table:put safety_values 0.80 0.841621234 table:put safety_values 0.85 1.036433389 table:put safety_values 0.90 1.281551566 table:put safety_values 0.95 1.644853627 create-Factories Fact [ set size 6 set color red set label (word "Factory " [who] of self " ") set orders [] let s read-from-string first(Inventory_Policy) ifelse s = 4 [set strategy (random 3) + 1] [set strategy s] ] create-distributors Distr1 [ set size 5 set color blue set suppliers [] set supplier_score [] set orders [] set placed_orders [] set label (word "Distr." [who] of self " ") let s read-from-string first(Inventory_Policy) ifelse s = 4 [set strategy (random 3) + 1] [set strategy s] ] create-retailers Distr2 [ set size 4 set color green set suppliers [] set supplier_score [] set placed_orders [] set label (word "Ret. " [who] of self " ") let s read-from-string first(Inventory_Policy) ifelse s = 4 [set strategy (random 3) + 1] [set strategy s] ] ask turtles with [breed != customers][ set daily_sales [] set clients [] set sales [] set lost_sales [] set forecast [] set holding_cost [] set order_cost [] set total_cost []] create-customers Clients_N [ set size 1 set color 3 set suppliers [] set supplier_score [] set demand round(random-normal Demand_W DS_D) set daily round(demand / 7) let s read-from-string first(Customers_Strategy) ifelse s = 3 [set strategy (random 2) + 1] [set strategy s] ] set-default-shape Factories "dist0" set-default-shape distributors "dist1" set-default-shape retailers "dist2" set-default-shape customers "person" ask turtles [find_patch] find_nearest update_clients 0 update_market update_clients 0 setup_parameters create_network update_plots end to go send_products buy_products main_sequence update_clients 1 create_network update_plots purge evaluate_results print_watch tick ;Next Day end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; SETUP SUBROUTINES ;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to find_patch setxy random-xcor random-ycor while [any? other turtles-here] [find_patch] ; keeps running until each patron is alone on patch end to find_nearest ask turtles with [breed != factories] [let d [] if breed = customers [set d sort([who] of retailers)] if breed = retailers [set d sort([who] of distributors) ] if breed = distributors [set d sort([who] of factories) ] foreach d [let temp2 [] set temp2 lput(?) temp2 set temp2 lput(distance turtle ?) temp2 set suppliers lput temp2 suppliers] set suppliers sort-by [last ?1 < last ?2] suppliers set supplier_score map [int(last ?) + int(((last ?) - int(last ?)) * 10) / 10] suppliers] end to update_clients [flag] ifelse flag = 0 [ask turtles with [breed != factories] [ let m min(supplier_score) let p position m supplier_score set supplier0 first(item p suppliers)] ask turtles with [breed != customers] [ let n [who] of self set clients sort([who] of turtles with [(breed = retailers or breed = distributors or breed = customers) and supplier0 = n])] ask turtles with [breed = distributors or breed = factories] [ foreach clients [set orders lput [0 0] orders]]] [ask customers [ let m min(supplier_score) let p position m supplier_score set supplier0 first(item p suppliers)] ask retailers [ let n [who] of self set clients sort([who] of turtles with [(breed = retailers or breed = distributors or breed = customers) and supplier0 = n])]] end to create_promotion ;Simple method: Increase de demand in some specific retailer choose for the user let list1 read-from-string user-input "Create a promotion [a b c] (retailer a, impact b (1 to 10), during c periods" ifelse is-list? list1 and length(list1) = 3 [let p item 0 list1 let i item 1 list1 let c (item 2 list1) + ticks let l [] set l lput(p) l set l lput(i) l set l lput(c) l set promotion l user-message (word "Today a promotion will occur at store " p) if Score_Retailers? = true [ask customers [let list2 map [first ?] suppliers let m position p list2 set supplier_score (replace-item m supplier_score (item m supplier_score - (random-float item 1 list1)))]] ] [user-message (word "The array doen't have a valid format, pleas try again")] end to create_network ask links [die] ifelse Show_Network = true [ ask customers [ if supplier0 != nobody [create-link-to retailer supplier0 [set color gray + 3]]] ask retailers [ create-link-to distributor supplier0 [set color green]] ask distributors [ create-link-to factory supplier0 [set color blue]] set ret_list sort([who] of retailers) let dd [] ;let ddd sort(retailers) foreach ret_list [set dd lput(count(links with [end2 = retailer ?])) dd] set-current-plot "Clients per Retailer" clear-plot foreach dd [plot ?]] [ask links [die] set-current-plot "Clients per Retailer" clear-plot] end to setup_parameters ask customers [ set stock random demand ] ask retailers [ set stock round(sum([demand] of customers) / count(retailers)) * 5 ;All agents of the same type starts with the same stock set demand mean([daily] of customers) * length(clients) * 1 ] ask distributors [ set stock round(sum([stock] of retailers)) * .5 ;All agents of the same type starts with the same stock set demand mean([demand] of retailers) * length(clients) * 1 ] ask Factories [ set stock round(sum([stock] of distributors)) set production_rate round(sum([demand] of customers) * 10) ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;; GO SUBROUTINES ;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to update_market ask turtles with [breed != customers and clients = []] [die] end to send_products ask turtles with [breed = distributors or breed = factories] [let list1 map [last ?] orders let list2 filter [? = ticks] list1 if length(list2) > 0 and max(list2) > 0 [let attending filter [last ? = ticks] orders set list2 [] let list3 [] foreach attending [ set list2 lput(item (position ? orders) clients) list2 set list3 lput(first(item(position ? orders) orders)) list3] let i 0 while [i < length(list2)] [ ask turtle (item i list2) [ set stock (stock + item i list3)] set i i + 1] set i 0 while [i < length(orders)] [if last(item i orders) = ticks [set orders replace-item i orders [0 0]] set i i + 1]] ] end to buy_products ;Customers go shopping according to their demand and their stock let list1 [] ask turtles with [breed = retailers or breed = distributors or breed = factories ][ set daily_sales [] set lost_sales []] ask customers [ let dem 0 ifelse strategy = 1 [set dem daily] [set dem round(daily * 4)] if promotion != [0 0 0] and member? who [clients] of retailer supplier0 [set dem round(dem * random-float (item 1 promotion))] ifelse stock < dem and next_review = ticks [ let agent [who] of self let d (dem + (dem - stock)) ifelse [stock] of retailer (supplier0) >= d [ask retailer (supplier0) [ set stock stock - d set daily_sales lput d daily_sales set lost_sales lput 0 lost_sales] let dd [] set dd lput agent dd set dd lput d dd set list1 lput dd list1 set stock stock - daily + d if Score_Retailers? = true [score_supplier who -0.01]] [ask retailer (supplier0) [set lost_sales lput dem lost_sales] if Score_Retailers? = true [score_supplier who 2 ]] ifelse strategy = 2 [set next_review ticks + 3] [set next_review ticks + 1]] [ifelse stock - dem >= 0 [set stock stock - dem] [set stock 0] set next_review ticks + 1 ]] ask retailers [ update_sales if strategy != 3 [set next_review ticks + 1]] end to update_sales let es sum(daily_sales) let ls sum(lost_sales) let l [] set l lput es l set l lput ls l set sales lput l sales end to main_sequence ask retailers [ update_forecast place_orders update_costs] ask distributors [ update_sales update_forecast place_orders update_costs] ask factories [ update_sales if stock < reorder_point [set stock stock + production_rate] update_forecast update_costs] ask customers [update_demand] end to update_forecast ;Retailers, Distributors and Factories update their expectations let forecasting [] set forecast [] let temp_demand 0 if length(sales) > 0 [set temp_demand map [sum(?)] sales] let ds 0 ifelse (length(sales) > 2) and (max(temp_demand) != 0) [set forecast matrix:forecast-linear-growth (temp_demand) set ds standard-deviation temp_demand] [set forecast lput(round(demand / 7)) forecast set forecast lput(round(demand / 7)) forecast set forecast lput(0) forecast set forecast lput(0) forecast] let b item 1 forecast let a item 2 forecast let t length(sales) let i 1 while [i <= 7] [ set forecasting lput(t * a + b) forecasting set i i + 1 set t t + 1] set demand round(sum(forecasting)) if demand < 0 [set demand 0] let dailyd demand / 7 let Lead_Time Lt0 if breed = retailers [set Lead_Time Lt1] let z table:get safety_values SS_% if breed != factories [set EOQ round(sqrt(2 * demand * 52 * K / (HC * Product_cost)))] set reorder_point round(dailyd * Lead_Time + z * ds) end to print_watch if watching != 0 [ show (word "At the period " ticks " the agent " watching " update its expectations :") if ([breed] of turtle watching != customers) [ show (word "Sales " [sales] of turtle watching) show (word "Forecast " [forecast] of turtle watching)] show (word "Demand " [demand] of turtle watching) if ([breed] of turtle watching != customers and [breed] of turtle watching != factories) [ show (word "EOQ " [EOQ] of turtle watching) show (word "Reorder Point " [reorder_point] of turtle watching)] show (word "Stock " [stock] of turtle watching) ] end to follow_someone ifelse watching = 0 [let l read-from-string user-input "What agent do you want to inspect?" set watching l watch turtle watching inspect turtle watching] [set watching 0 reset-perspective] end to place_orders ;Retailers and Distributors place orders according to their stock and forecasting if stock <= reorder_point [ let p position [who] of self ([clients] of turtle supplier0) let actual_order first(item p ([orders] of turtle supplier0)) if actual_order = 0 [ let comande 0 let lead_time Lt0 if breed = retailers [set lead_time Lt1] ifelse strategy = 1 [set comande round(EOQ - stock)] [set comande round(EOQ + (demand / 7) * lead_time)] let disp 0 ask turtle supplier0 [ let delivery ticks + lead_time let g [] let ll 0 ifelse stock > comande [set disp comande] [set disp stock set ll comande - disp] set g lput disp g set g lput delivery g set orders replace-item p orders g set stock stock - disp set daily_sales lput(disp) daily_sales set lost_sales lput(ll) lost_sales ] set placed_orders lput(disp) placed_orders] ] end to update_demand ifelse promotion = [0 0 0] [set demand round(random-normal Demand_W DS_D) set daily round(demand / 7)] [let p item 2 promotion if ticks = p [set promotion [0 0 0]] ] end to update_costs set holding_cost lput (HC * stock * Product_cost) holding_cost ifelse breed != factories [if (length(placed_orders) = 0) OR (length(placed_orders) != length(holding_cost)) [set placed_orders lput 0 placed_orders] ifelse last(placed_orders) = 0 [set order_cost lput 0 order_cost] [set order_cost lput K order_cost] set total_cost lput (last(order_cost) + last(holding_cost)) total_cost] [set total_cost lput (last(holding_cost)) total_cost] end to evaluate_results ;Collect statistics at the end of each period let l [] ifelse first(promotion) = 0 [set l lput (word ticks "-Reg") l] [set l lput (word ticks "-P-" item 0 promotion "-" item 1 promotion) l] set l lput(sum([stock] of customers)) l set l lput(sum([stock] of retailers)) l set l lput(sum([stock] of distributors)) l set l lput(sum([stock] of factories)) l set stocks_h l set l [] let s 0 foreach ([total_cost] of retailers) [set s s + (last(?))] set l lput(s) l set s 0 foreach ([total_cost] of distributors) [set s s + (last(?))] set l lput(s) l set s 0 foreach ([total_cost] of factories) [set s s + (last(?))] set l lput(s) l set costs_h l end to purge ask turtles with [breed != customers] [if length(sales) > 100 [let l length(sales) set sales sublist sales (l - 100) l ]] end to score_supplier [a b] ;agent A, score B ask turtle a [ let list1 map [first ?] suppliers let p position supplier0 list1 if item p supplier_score + b >= 0 [set supplier_score replace-item p supplier_score (item p supplier_score + b)] ] end to update_plots set-current-plot "Daily Stock" let s [] ;Customers set-current-plot-pen "Customers" plot sum([stock] of Customers) ;Retailers set-current-plot-pen "Retailers" plot sum([stock] of retailers) set s lput(sum([stock] of retailers)) s ;Distributors set-current-plot-pen "Distributors" plot sum([stock] of distributors) set s lput(sum([stock] of distributors)) s ;Factories set-current-plot-pen "Factories" plot sum([stock] of Factories) set s lput(sum([stock] of Factories)) s ;set-plot-y-range 0 max(s) end

There are 2 versions of this model.

## Attached files

File | Type | Description | Last updated | |
---|---|---|---|---|

Jama-1.0.2.jar | extension | jama | over 4 years ago, by Alvaro Gil | Download |

matrix.jar | extension | Matrix_jar | over 4 years ago, by Alvaro Gil | Download |

Supply Chain.png | preview | Preview | over 4 years ago, by Alvaro Gil | Download |

table.jar | extension | table extention | over 4 years ago, by Alvaro Gil | Download |

This model does not have any ancestors.

This model does not have any descendants.

Ichsan Ramadhani

## Visit

http://aquaponicscenter.blogspot.com/

## Posted almost 3 years ago