MODEL:
! Supply Chain design model with Multiple:      (LINDO_SCM_Planner.lng)
     plants, products, DC's, mode of transport, customers,
!  This model helps you decide:
    which plants produce which products,
    which distribution centers(DC) should be used,
    which mode of transportation is used, Plant to DC,
    which mode of transportation is used, DC to Cust,
    which DC serves which customer,
  so as to minimize total of 
    Production cost + Shipping cost inbound to DC's + Fixed cost of DC's +
    Variable cost at DC's + Shipping cost outbound
   and not exceeding capacities at Plants and DC's;

! Ref: based on original Hunt-Wesson Foods 3-level distribution
  model of Geoffrion & Graves, Man. Sci., Jan., 1974;
         
! Keywords: DC location, Distribution, Multi-echelon, 
            Plant location, Single sourcing, Supply chain design;
SETS:
! There are products or SKUs;
   SKU: MNSELS, ACTS;
! produced in plants;
   PLANT: TOTCAP;
! Each DC has an associated fixed cost, F,
  aggregate CAPacity, and an "open" indicator, Z,
  and cost per unit CDU.;
   DISTCTR : F, CAP, CDU, Z;
! Customers, number of suppliers allowed;
   CUSTOMER: NSUP, MNSELC, ACTC;
! Modes of transport;
   MODE;
! D = Demand for a product by a customer;
   CXS( CUSTOMER, SKU): DEM, ACTCS;
! S = Capacity for a product at a plant.;
   SUPLINK( PLANT, SKU ): S, COSTPU;
! If customer L is served by a DC K, 
  then Y(I,L) = 1.;
   YLINK( DISTCTR, CUSTOMER): Y;
! C(j, i, k, m) = Cost/ton of a SKU i from plant j to DC k via mode m,
  X(j, i, k, m) = tons shipped;
   PXSXDXM( PLANT, SKU, DISTCTR, MODE): C, X;
! CG(J,K,M) = product cost per ton from J to K via M
    independent of product;
   PXDXM(PLANT, DISTCTR, MODE): CG;
! G = Cost/ton of a product from a DC to a customer,
  W = tons shipped;
   CXSXDXM( CUSTOMER, SKU, DISTCTR, MODE): G, W;
! CGSHIP( L, K, M) = ship cost DC to Cust, independent
        of product;
   CXDXM( CUSTOMER, DISTCTR, MODE): CGSHIP;
ENDSETS
DATA: ! You can get these data from a spreadsheet using @OLE(), a database using @ODBC( ); SKU = Vege Oils; ! The products; MODE = Truck RailR; ! Transportation modes; PLANT = Fresno Dayton Camden; ! Plant capacities over all products; TOTCAP= 99999 99999 99999; ! Plant Capacities by product; S = 80, 40, 75, ! Vege; 20, 60, 75; ! Oils; ! Production cost/unit by plant, product; COSTPU= 1.80, 2.40, 1.75, ! Vege; 2.20, 1.60, 1.05; ! Oils; DISTCTR = LAX STL ATL PHL; ! The distn centers; F = 120, 130, 160, 139; ! DC fixed costs; CDU = .55 .50 .42 .53; ! DC variable costs; CAP = 300, 300, 300, 300; ! Aggregate capacity; ! Shipping costs, by Plant, SKU, DC, Mode. Use this if shipping costs are product specific, else set to 0; C = 0; ! Shipping costs, by plant, DC, Mode; ! Truck RailR; CG = .22 .25 !Fresno LAX; .41 .29 ! STL; .48 9.99 ! ATL; .57 .47 ! PHL; .66 .41 !Dayton LAX; .39 .36 ! STL; .38 9.99 ! ATL; .47 .37 ! PHL; .68 .59 !Camden LAX ; .55 .51 ! STL; .33 9.99 ! ATL; .27 .36 ! PHL; ; CUSTOMER= CA CO MO PA NY; ! Number DCs allowed to serve each customer; NSUP= 1 2 1 1 2; ! Demands by Customer, Product; DEM= 25, 30, 50, 15, 35, ! Vege; 25, 8, 0, 30, 30; ! Oils; ! Minimum we would like to sell to each customer; MNSELC = 0 0 0 0 0; ! Minimum we would like to sell of each product; MNSELS = 0 0; ! Minimum we would like to sell in total; MNSELT = 0; ! Shipping costs, DC to customer ! by CUSTOMER, Product, DC, Mode; ! Use this if shipping costs are product specific, else set to 0; G = 0; ! Shipping costs, customer, DC, mode; ! Truck RailR; CGSHIP= 2 3 ! CA LAX; 5 6 ! STL; 7 7 ! ATL; 8 6 ! Phl; 4 5 ! CO LAX; 6 5 ! STL; 8 6 ! ATL; 8 7 ! Phl; 5 4 ! MO LAX; 3 4 ! STL; 5 4 ! ATL; 6 5 ! Phl; 8 7 ! PA LAX; 4 4 ! STL; 6 5 ! ATL; 6 9 ! Phl; 9 8 ! NY LAX; 5 6 ! STL; 6 5 ! ATL; 4 4 ! Phl; ; MXDC = 2; ! Max DC's allowed; ENDDATA SUBMODEL SCMOPT: !--------------------------------------------------; ! Objective function minimizes costs based on product i, plant J, DC k, and mode m.; [OBJ] MIN = TOTCOST; TOTCOST= MFGCOST + SHIPDC + FXCOST + DCVAR + SHIPCUST ; ! Manufacturing costs at the plants; MFGCOST= @SUM(PXSXDXM( j, i, k, m): COSTPU(j,i)* X(j,i,k,m)); ! Fixed costs of the distribution centers used; FXCOST = @SUM( DISTCTR: F * Z); ! Shipping costs from plant to DC; SHIPDC= @SUM( PXSXDXM( j, i, k, m): (CG(j,k,m)+ C(j, i, k, m)) * X(j, i, k, m)); ! DC variable costs; DCVAR = @SUM( PXSXDXM( j, i, k, m): CDU(k) * X(j, i, k, m)); ! Shipping costs, DC to customer; SHIPCUST= @SUM( CXSXDXM( L, i, k, m): (CGSHIP(L, k, m) + G( L, i, k, m)) * W( L, i, k, m)); ! Supply Constraints at Plant j, SKU i; @FOR( SKU( i): @FOR( PLANT( j): @SUM( DISTCTR( k):@SUM(MODE(m): X( j, i, k, m))) <= S( j, i)) ); ! Supply constraints over all SKU's at plant j; @FOR(PLANT(j): @SUM(PXSXDXM( j, i, k, m): X(j, i, k, m)) <= TOTCAP(j); ); ! DC balance (inbound = outbound)constraints for SKU i at DC k; @FOR( SKU( i): @FOR( DISTCTR( k): @SUM( PLANT( j): @SUM( MODE(m): X( j, i, k, m))) = @SUM( CUSTOMER( L):@SUM( MODE(m): W(L, i, k, m))) )); ! Aggregate capacities at each DC k. Presumes all products in same units; @FOR( DISTCTR( k): @SUM( SKU( i): @SUM( PLANT( j):@SUM(MODE(m): X(j, i,k,m)))) <= CAP(k)*Z(k); @BIN( Z( k)); ! It's either open or not; ); ! Upper limit on DC's open; @SUM( DISTCTR( k): Z( k)) <= MXDC; ! Demand constraints; ! Each customer's demand for each product must be satisfied; @FOR( SKU(i): @FOR( CUSTOMER(L): ACTCS(L,i)= @SUM( DISTCTR(k): @SUM(MODE(m): W(L, i, k, m))); ACTCS(L,i) >= DEM(L,i); ! Force Y(k,L) = 1 if DC k serves customer L; @FOR( DISTCTR(k): @SUM(MODE(m): W(L, i, k, m)) <= @SMAX(DEM(L,i),MNSELS(i),MNSELC(L),MNSELT)*Y(k,L); ) ) ); ! We ship as much of each product as targeted; @FOR( SKU(i): ACTS(i) = @SUM( PXSXDXM( j, i, k, m): X(j, i, k, m)); ACTS(i) >= MNSELS(i); ); ! We ship as much to each customer as targeted; @FOR( CUSTOMER(L): ACTC(L) = @SUM( CXSXDXM( L, i, k, m): W); ACTC(L) >= MNSELC(L); ); ! Ship total target; ACTT = @SUM( PXSXDXM( j, i, k, m): X(j, i, k, m)); ACTT >= MNSELT; ! Demand: each customer assigned to most NSUP DC's; @FOR( CUSTOMER( L): @SUM( DISTCTR( k): Y( k, L)) <= NSUP(L); ); ! Force DC k open if it serves customer L; @FOR( CUSTOMER( L): @FOR( DISTCTR( k): Y( k, L) <= Z( k);) ); ! Y binary ( Single sourcing variable), Y( k, L)= 1 if customer L served solely from DC k; @FOR( DISTCTR( k): @FOR( CUSTOMER( L): @BIN( Y( k,L))) ); ENDSUBMODEL
! Export the results; CALC: @SET( 'TERSEO',2); ! Output level (0:verb, 1:terse, 2:only errors, 3:none); @SET( 'IPTOLR', .02); ! Set ending relative optimality tolerance; @SET( 'TIM2RL', 30); ! Time in seconds to apply optimality tolerance; @SOLVE( SCMOPT); @WRITE(@NEWLINE(1)); @WRITE('Solution to 3-level Supply Chain Design Problem.' , @NEWLINE(1)) ; @WRITE(" Manufacturing Cost= ", @FORMAT( MFGCOST, '12.2f') , @NEWLINE(1)); @WRITE(" Shipping cost, Inbound = ", @FORMAT( SHIPDC, '12.2f'), @NEWLINE(1)); @WRITE(" Fixed cost of DC's= ", @FORMAT( FXCOST, '12.2f'), @NEWLINE(1)); @WRITE(" Variable cost at DC's= ", @FORMAT( DCVAR, '12.2f'), @NEWLINE(1)); @WRITE(" Shipping cost, Outbound= ", @FORMAT( SHIPCUST, '12.2f'), @NEWLINE(1)); @WRITE(" ----------", @NEWLINE(1)); @WRITE(" Total Cost= ", @FORMAT( TOTCOST, '12.2f'), @NEWLINE(1)); @WRITE(' ', @NEWLINE(1)); @WRITE(" Shipments: Plant to DC ", @NEWLINE(1)); @WRITE(" Plant Product DC Mode Amount", @NEWLINE(1)); @FOR(PXSXDXM( j, i, k, m)| X( j, i, k, m) #GT# 0: @WRITE(' ', Plant(j),' ',SKU(I),' ',DISTCTR(k),' ',Mode(m),' ', @FORMAT( X(j,i,k,m), '6.0f'),@NEWLINE(1)); ); @WRITE( @NEWLINE(1),' Shipments: DC to Customer ',@NEWLINE(1)); @WRITE(' DC Product Customer Mode Amount', @NEWLINE(1)); @FOR( CXSXDXM( L, i, k, m)| W( L, i, k, m) #GT# 0.000001: @WRITE(' ', DISTCTR(k),' ',SKU(i),' ',CUSTOMER(L),' ',Mode(m),' ', @FORMAT( W( L, i, k, m), '6.0f'),@NEWLINE(1))); ENDCALC END