!!!!!!!Created by Rebekka Resell, spring 2017 model MaritimePickupDelivery uses "mmxprs";!gain access to the Xpress-Optimizer solver options explterm options noimplicit uses "mmxprs", "mmodbc","mmsystem"; parameters Datafile = "Case2.txt"; SolutionTime = 10800; end-parameters ! Enable message printing by the Optimizer setparam("xprs_verbose", true); ! Turn off the automatic cut generation setparam("xprs_cutstrategy", 0); ! Turn off the automatic heuristics setparam("xprs_heurstrategy", 0); !**************************************************************************** ! Declaring sets !**************************************************************************** declarations nCargoes: integer; !number of nodes/cargoes nTanks: integer; !number of tanks on the vessel Nodes: set of integer; PickupNodes: set of integer; DeliveryNodes: set of integer; Suppliers: set of integer; ![1 2 3 4] hypothetical CargoConditions: set of integer; ![clean, dirty], [1,2] CargoNodes: set of integer; solutionTime1: real; end-declarations initializations from Datafile nCargoes; nTanks; Nodes; PickupNodes; DeliveryNodes; Suppliers; CargoConditions; CargoNodes; end-initializations finalize(Nodes); finalize(PickupNodes); finalize(DeliveryNodes); finalize(Suppliers); finalize(CargoConditions); finalize(CargoNodes); !**************************************************************************** ! Declaring parameters !**************************************************************************** declarations VesselCapacity: real; TankCapacity: real; !Assuming equally sized tanks TotalDeliveryLoad: dynamic array(Suppliers) of real; TotalPickupLoad: dynamic array(Suppliers) of real; CargoQuantityDel: dynamic array(DeliveryNodes, Suppliers) of real; CargoQuantityPick: dynamic array(PickupNodes, Suppliers) of real; CQPick: dynamic array(PickupNodes) of real; CQDel: dynamic array(DeliveryNodes) of real; VesselSpeedkmh: real; SailingDistanceskm: dynamic array(Nodes, Nodes) of real; SailingTime: dynamic array(Nodes, Nodes) of real; DemandTime: dynamic array(CargoNodes) of real; LoadingRate: real; LoadingTimeDel: dynamic array(DeliveryNodes) of real; LoadingTimePick: dynamic array(PickupNodes) of real; A: dynamic array(Nodes, Nodes) of boolean; BigM: integer;! of real; BigB1: real; BigB2: real; teller: integer; index: integer; !a: real; !Acts as temporary variable !b: real; !Acts as a temporary variable end-declarations initializations from Datafile TankCapacity; CargoQuantityDel; CargoQuantityPick; VesselSpeedkmh; SailingDistanceskm; DemandTime; LoadingRate; BigM; A; end-initializations !*************************************************************************** !Preprocessing of Parameters !*************************************************************************** !Vessel Capacity VesselCapacity := TankCapacity*nTanks; !Total Delivery Load forall(ss in Suppliers) do TotalDeliveryLoad(ss) := sum(ii in DeliveryNodes) CargoQuantityDel(ii,ss); end-do !Total Pickup Load forall(ss in Suppliers) do TotalPickupLoad(ss) := sum(ii in PickupNodes) CargoQuantityPick(ii,ss); end-do !Big B1 and Big B2 BigB1 := sum(ss in Suppliers) TotalDeliveryLoad(ss); BigB2 := sum(ss in Suppliers) TotalPickupLoad(ss); !Time of unloading delivery cargo i forall(ii in DeliveryNodes) do CQDel(ii) := sum(ss in Suppliers) CargoQuantityDel(ii,ss); !Bound in the assumption of only ONE supplier of cargo to an installation LoadingTimeDel(ii):= CQDel(ii)/LoadingRate; end-do !Time of loading pickup cargo i forall(ii in PickupNodes) do CQPick(ii) := sum(ss in Suppliers) CargoQuantityPick(ii,ss); LoadingTimePick(ii) := CQPick(ii)/LoadingRate; end-do !************************************************ !Calculating sailing times !************************************************ !Calculate sailing time forall(ii in Nodes, jj in Nodes | ii<>nCargoes+1 and jj<>0) do SailingTime(ii,jj) := SailingDistanceskm(ii,jj)/VesselSpeedkmh; end-do !**************************************************************************** ! Create variables !**************************************************************************** declarations x: dynamic array(Nodes, Nodes) of mpvar; t: dynamic array(Nodes) of mpvar; l: dynamic array(Nodes, Suppliers, CargoConditions) of mpvar; h: dynamic array(Nodes, Suppliers, CargoConditions) of mpvar; y: dynamic array(CargoNodes) of mpvar; w: dynamic array(Nodes) of mpvar; !of mpvar; !!*** end-declarations !x-variable, binary - 1 if vessel v sails directly from node i to node j. !Except when nodes are equal, from end-base, and to start-base forall(ii in Nodes, jj in Nodes | ii<>nCargoes+1 and jj<>0) do if (A(ii,jj)) then create(x(ii,jj)); x(ii,jj) is_binary; end-if end-do !time-variable, continuous forall(ii in Nodes) do create(t(ii)); end-do !load-variable, continuous forall(ii in Nodes, ss in Suppliers, cc in CargoConditions | ii<>nCargoes+1) do create(l(ii,ss,cc)); end-do !occupied tanks-variable, integer forall(ii in Nodes, ss in Suppliers, cc in CargoConditions) do create(h(ii,ss,cc)); h(ii,ss,cc) is_integer; end-do !gap-variable, continuous forall(ii in CargoNodes) do create(y(ii)); end-do !available tanks-variable, integer forall(ii in CargoNodes) do create(w(ii)); w(ii) is_integer; end-do !**************************************************************************** ! Declare Constraints !**************************************************************************** declarations Gap: linctr; AllNodesVisited: dynamic array(Nodes) of linctr; FlowFromOrigin: linctr; FlowConservation1: dynamic array(Nodes) of linctr; FlowConservation2: dynamic array(Nodes) of linctr; FlowToDestination: linctr; TimeConstraint1: dynamic array(DeliveryNodes, Nodes) of linctr; TimeConstraint2: dynamic array(PickupNodes, Nodes) of linctr; StartNodeFirst: dynamic array(Nodes) of linctr; EndNodeLast: dynamic array(Nodes) of linctr; TimeWindowMin: dynamic array(Nodes) of linctr; TimeWindowMax: dynamic array(Nodes) of linctr; LoadConstraintDel: dynamic array(Nodes, DeliveryNodes, Suppliers) of linctr; LoadConstraintDel1: dynamic array(Nodes, DeliveryNodes, Suppliers) of linctr; LoadConstraintDel2: dynamic array(Nodes, DeliveryNodes, Suppliers) of linctr; LoadConstraintPick: dynamic array(Nodes, PickupNodes, Suppliers) of linctr; LoadConstraintPick1: dynamic array(Nodes, PickupNodes, Suppliers) of linctr; LoadConstraintPick2: dynamic array(Nodes, PickupNodes, Suppliers) of linctr; LoadOrigin: dynamic array(Suppliers, CargoConditions) of linctr; OccTanks1: dynamic array(Nodes, Suppliers, CargoConditions) of linctr; NoTanks: dynamic array(Nodes) of linctr;!linctr; !!*** LimOccupiedTanks: dynamic array(Nodes) of linctr; GapConstraint: dynamic array(CargoNodes) of linctr; end-declarations !**************************************************************************** ! Objective Function !**************************************************************************** Gap := sum(ii in CargoNodes)y(ii) - sum(ii in CargoNodes)w(ii) ; !**************************************************************************** ! Flow Constraints !**************************************************************************** !All nodes/cargoes are visited/handled only once forall (ii in Nodes | ii<>0 and ii<>(nCargoes+1)) do AllNodesVisited(ii) := sum(jj in Nodes) x(ii,jj)= 1; end-do !Only one arc from origin FlowFromOrigin := sum(jj in Nodes) x(0,jj) =1; !Only one visit per node, has to be an arc out from node i forall (ii in Nodes | ii<>0 and ii <>(nCargoes+1)) do FlowConservation1(ii) := sum(jj in Nodes) x(ii,jj) = 1; end-do !Only one visit per node, has to be an arc to node j forall (jj in Nodes | jj<>0 and jj <>(nCargoes+1)) do FlowConservation2(jj) := sum(ii in Nodes) x(ii,jj) = 1; end-do !Only one arc to destination FlowToDestination := sum(ii in Nodes) x(ii,(nCargoes+1))=1; !**************************************************************************** ! Time constraints !**************************************************************************** !Visits start node (node 0) before all other nodes forall (ii in Nodes | ii<>0) do StartNodeFirst(ii) := t(ii) - t(0) >= 0; end-do !Time for arrival in j is to be bigger than the time for arrival in i + time spent in i forall (ii in DeliveryNodes, jj in Nodes | ii<>jj and ii<>nCargoes+1 and jj<>0) do TimeConstraint1(ii,jj) := t(ii) + LoadingTimeDel(ii) + SailingTime(ii,jj) - t(jj) - BigM*(1-x(ii,jj)) <= 0; end-do !Time for arrival in j is to be bigger than the time for arrival in i + time spent in i forall (ii in PickupNodes, jj in Nodes | ii<>jj and ii<>nCargoes+1 and jj<>0) do TimeConstraint2(ii,jj) := t(ii) + LoadingTimePick(ii) + SailingTime(ii,jj) - t(jj) - BigM*(1-x(ii,jj)) <= 0; end-do !Visits end node (node nCargoes+1) after all other nodes forall (ii in Nodes | ii<>(nCargoes+1)) do EndNodeLast(ii) := t(nCargoes+1) - t(ii) >= 0; end-do !**************************************************************************** ! Load constraints !**************************************************************************** !forall(ii in Nodes, ss in Suppliers | ii=0) do forall(ss in Suppliers) do LoadOrigin(ss,1) := l(0,ss,1) = sum(jj in DeliveryNodes) CargoQuantityDel(jj,ss); end-do forall(ii in Nodes, jj in DeliveryNodes, ss in Suppliers | ii<>jj and ii<>nCargoes+1) do LoadConstraintDel(ii,jj,ss) := l(ii,ss,1) - CargoQuantityDel(jj,ss) - l(jj,ss,1) - BigB1*(1-x(ii,jj)) <= 0; LoadConstraintDel1(ii,jj,ss) := l(ii,ss,2) - l(jj,ss,2) + VesselCapacity*x(ii,jj) <= VesselCapacity; LoadConstraintDel2(ii,jj,ss) := l(ii,ss,2) - l(jj,ss,2) - VesselCapacity*x(ii,jj) >= -VesselCapacity; end-do forall(ii in Nodes, jj in PickupNodes, ss in Suppliers | ii<>jj and ii<>nCargoes+1) do LoadConstraintPick(ii,jj,ss) := l(ii,ss,2) + CargoQuantityPick(jj,ss) - l(jj,ss,2) - BigB2*(1-x(ii,jj)) <= 0; LoadConstraintPick1(ii,jj,ss) := l(ii,ss,1) - l(jj,ss,1) + VesselCapacity*x(ii,jj) <= VesselCapacity; LoadConstraintPick2(ii,jj,ss) := l(ii,ss,1) - l(jj,ss,1) - VesselCapacity*x(ii,jj) >= -VesselCapacity; end-do !**************************************************************************** !Tank constraints !**************************************************************************** !Finding number of occupied tanks forall(ii in Nodes, ss in Suppliers, cc in CargoConditions) do OccTanks1(ii,ss,cc) := h(ii,ss,cc) - (l(ii,ss,cc)/TankCapacity) >= 0; end-do !No more occupied tanks than there are tanks on the vessel forall(ii in Nodes) do LimOccupiedTanks(ii) := sum(ss in Suppliers, cc in CargoConditions) h(ii,ss,cc) <= nTanks; end-do !Ensure correct no. of tanks are in use forall(ii in Nodes) do NoTanks(ii) := w(ii) + sum(ss in Suppliers, cc in CargoConditions) h(ii,ss,cc) = nTanks; !!*** end-do !**************************************************************************** !Sequence constraints !**************************************************************************** !Forcing the vessel to service the pickup cargo before the delivery cargo at the same installation forall(ii in PickupNodes, jj in DeliveryNodes | SailingTime(ii,jj) = 0) do x(ii,jj) = 1; end-do forall(ii in DeliveryNodes, jj in PickupNodes | SailingTime(ii,jj) = 0) do x(ii,jj) = 0; end-do !**************************************************************************** !Gap constraint !**************************************************************************** forall(ii in CargoNodes) do GapConstraint(ii) := t(ii) - DemandTime(ii) = y(ii); end-do !**************************************************************************** setparam('xprs_maxtime', SolutionTime); solutionTime1:=gettime; minimize(Gap); !solutionTime2:=gettime; declarations FileName: string; end-declarations FileName := 'Output_' + Datafile + '.txt'; fopen(FileName, F_OUTPUT); writeln("------------------------------------------------------------------------------"); if(TankCapacity=360) then writeln("Total delay is ",getsol(Gap), " hours for Far Scotsman"); else writeln("Total delay is ",getsol(Gap), " hours for Far Solitaire"); end-if writeln("------------------------------------------------------------------------------"); index:=0; teller:=1; while (teller < nCargoes+1) do forall(jj in Nodes) do if(getsol(x(index,jj)) > 0.5) then if (index < nCargoes+1 and jj<>nCargoes+1) then write("The ship sails directly from ",index, " to ",jj); index:=jj; if(getsol(y(index)) > 0.5) then writeln(" The vessel starts service ", getsol(y(index)), " hours after the demand occurs in node ",index); teller:=teller+1; else writeln(" The vessel services node ",index," on time"); teller:=teller+1; end-if else writeln("The ship sails directly from ",index, " to ",jj); teller:=teller+1; writeln("------------------------------------------------------------------------------"); end-if end-if end-do end-do teller:=0; index:=0; while (teller < nCargoes) do forall(jj in CargoNodes) do if(getsol(x(index,jj)) > 0.5) then writeln("The vessel has ", getsol(w(jj)), " available tanks in node ", jj); index:=jj; teller:=teller+1; end-if end-do end-do writeln("------------------------------------------------------------------------------"); fclose(F_OUTPUT); end-model