diff --git a/contribs/freight/README.md b/contribs/freight/README.md index afdcbcd4abc..746cdba1bc1 100644 --- a/contribs/freight/README.md +++ b/contribs/freight/README.md @@ -1,10 +1,25 @@ # Freight -Package that plugs freight algorithms (programmed in external package jsprit) into matsim. +This contrib contains the following packages: + +## Carriers +(This is formally knows as 'freight contrib') + +Package that plugs vehicle routing problem algorithms (programmed in external package jsprit) into MATSim. A good starting point for jsprit is [ https://github.com/graphhopper/jsprit](https://github.com/graphhopper/jsprit). -For runnable code see, e.g., the packages org.matsim.contrib.freight.usecases.* above . +For runnable code see, e.g., the packages org.matsim.contrib.freight.carriers.usecases.* above . + +## Logistics +(This code comes from [https://github.com/matsim-vsp/logistics/](https://github.com/matsim-vsp/logistics/) ) + +This code deals with creating logistics chains for freight transport. + +Here the decision agent is the logistics service provider (LSP) who decides on the logistics chain to be used for a given freight transport request. +Therefore, it can use carriers (see above) and hubs. + +This package bases on work in the dfg-freight project. \ No newline at end of file diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/ForwardLogisticChainSchedulerImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/ForwardLogisticChainSchedulerImpl.java new file mode 100644 index 00000000000..71d76c307ce --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/ForwardLogisticChainSchedulerImpl.java @@ -0,0 +1,189 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * .... Macht 3 Schritte: 1.) the LSPShipments are handed over to the first {@link + * LogisticChainElement} of their {@link LogisticChain} 2.) the neighbors, i.e. the predecessors and + * successors of all {@link LSPResource}s are determined 3.) the Resources are brought into the + * right sequence according to the algorithm. + * + *

When traversing this list of {@link LSPResource}s, the operations in each {@link LSPResource} + * are scheduled individually by calling their {@link LSPResourceScheduler}. + */ +/* package-private */ class ForwardLogisticChainSchedulerImpl implements LogisticChainScheduler { + + /** + * The Resources are brought into the right sequence according to the algorithm. The result of + * this algorithm is a list of Resources that is later traversed from the front to the back, i.e. + * starting with the entry at index 0. In the algorithm, this list is called sortedResourceList. + */ + private final ArrayList sortedResourceList; + + /** + * The determination of the neighborhood structure among the Resources resulted in the + * neighborList. + */ + private final ArrayList neighbourList; + + private LSP lsp; + private int bufferTime; + + ForwardLogisticChainSchedulerImpl() { + this.sortedResourceList = new ArrayList<>(); + this.neighbourList = new ArrayList<>(); + } + + @Override + public void scheduleLogisticChain() { + insertShipmentsAtBeginning(); + setResourceNeighbours(); + sortResources(); + for (LSPResource resource : sortedResourceList) { + resource.schedule(bufferTime, lsp.getSelectedPlan()); + } + } + + @Override + public void setEmbeddingContainer(LSP lsp) { + this.lsp = lsp; + } + + private void setResourceNeighbours() { + // internal data structure, try to ignore when looking from outside. kai/kai, jan'22 + neighbourList.clear(); + for (LSPResource resource : lsp.getResources()) { + ResourceNeighbours neighbours = new ResourceNeighbours(resource); + for (LogisticChainElement element : resource.getClientElements()) { + LogisticChainElement predecessor = element.getPreviousElement(); + LSPResource previousResource = predecessor.getResource(); + neighbours.addPredecessor(previousResource); + LogisticChainElement successor = element.getNextElement(); + LSPResource nextResource = successor.getResource(); + neighbours.addSuccessor(nextResource); + } + neighbourList.add(neighbours); + } + } + + private void sortResources() { + sortedResourceList.clear(); + while (!neighbourList.isEmpty()) { + for (ResourceNeighbours neighbours : neighbourList) { + if (allPredecessorsAlreadyScheduled(neighbours) + && noSuccessorAlreadyScheduled(neighbours)) { + sortedResourceList.add(neighbours.resource); + neighbourList.remove(neighbours); + } + } + } + } + + private boolean allPredecessorsAlreadyScheduled(ResourceNeighbours neighbours) { + if (neighbours.predecessors.isEmpty()) { + return true; + } + + for (LSPResource predecessor : neighbours.predecessors) { + if (!sortedResourceList.contains(predecessor)) { + return true; + } + } + return false; + } + + private boolean noSuccessorAlreadyScheduled(ResourceNeighbours neighbours) { + if (neighbours.successors.isEmpty()) { + return true; + } + + for (LSPResource successor : neighbours.successors) { + if (!sortedResourceList.contains(successor)) { + return true; + } + } + return false; + } + + private void insertShipmentsAtBeginning() { + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + LogisticChainElement firstElement = getFirstElement(solution); + assert firstElement != null; + for (Id lspShipmentId : solution.getLspShipmentIds()) { + var shipment = LSPUtils.findLspShipment(lsp, lspShipmentId); + assert shipment != null; + firstElement + .getIncomingShipments() + .addShipment(shipment.getPickupTimeWindow().getStart(), shipment); + } + } + } + + private LogisticChainElement getFirstElement(LogisticChain solution) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (element.getPreviousElement() == null) { + return element; + } + } + return null; + } + + @Override + public void setBufferTime(int bufferTime) { + this.bufferTime = bufferTime; + } + + /** + * The relationship between different {@link LSPResource}s allows to handle various supply + * structures that the {@link LSP} might decide to maintain. Thus, a {@link LSPResource} can have + * several successors or predecessors or can be used by several different {@link LogisticChain}s. + * The neighborhood structure among the {@link LSPResource}s is stored in instances of the class + * {@link ResourceNeighbours} which contain references on the considered {@link LSPResource} and + * on the set of immediate successors respective predecessors. As the result of this step, a + * collection of {@link ResourceNeighbours} called neighborList is created that contains the + * neighbors of all {@link LSPResource}s in the plan of the considered {@link LSP}. + */ + private static class ResourceNeighbours { + // internal data structure, try to ignore when looking from outside. kai/kai, jan'22 + + private final ArrayList predecessors; + private final ArrayList successors; + private final LSPResource resource; + + private ResourceNeighbours(LSPResource resource) { + this.resource = resource; + this.predecessors = new ArrayList<>(); + this.successors = new ArrayList<>(); + } + + private void addPredecessor(LSPResource resource) { + this.predecessors.add(resource); + } + + private void addSuccessor(LSPResource resource) { + this.successors.add(resource); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/FreightLogisticsConfigGroup.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/FreightLogisticsConfigGroup.java new file mode 100644 index 00000000000..b346cd92a38 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/FreightLogisticsConfigGroup.java @@ -0,0 +1,143 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.net.URL; +import java.util.Arrays; +import java.util.Map; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.config.ReflectiveConfigGroup; + +public class FreightLogisticsConfigGroup extends ReflectiveConfigGroup { + + public static final String GROUPNAME="freightLogistics" ; + + private String lspsFile; + static final String LSPS_FILE = "lspsFile"; + private static final String LSPS_FILE_DESC = "Freight LogisticsServiceProviders (LSP)s File, according to MATSim logistics extension as part of MATSim's freight contrib."; + + public FreightLogisticsConfigGroup() { + super(GROUPNAME); + } + + //### CarriersFile ### + /** + * @return -- {@value #LSPS_FILE_DESC} + */ + @StringGetter(LSPS_FILE) + public String getLspsFile() { + return lspsFile; + } + + URL getLspsFileUrl(URL context) { + return ConfigGroup.getInputFileURL(context, this.lspsFile); + } + + /** + * @param -- {@value #LSPS_FILE_DESC} + */ + @StringSetter(LSPS_FILE) + public void setLspsFile(String lspsFile) { + this.lspsFile = lspsFile; + } + + + + //--- + // Commenting this out, because in a frist step I think it is better/ more streight forward to have the VRP logic in the carriers as an attribute. + // please see {@link CarrierSchedulerUtils#setVrpLogic(carrier, VRPLogic)} and {@link CarrierSchedulerUtils#getVrpLogic(carrier)} + //--- + +// static final String VRP_LOGIC_OF_DISTRIBUTION_CARRIER = "vrpLogicOfDistributionCarrier"; +// private LSPUtils.LogicOfVrp vrpLogicOfDistributionCarrier = LSPUtils.LogicOfVrp.serviceBased; +// private static final String VRP_LOGIC_OF_DISTRIBUTION_CARRIER_DESC = "Define, on which type of jobs the VRP of the **distribution** carrier will base on:" + Arrays.toString(LSPUtils.LogicOfVrp.values()); +// +// static final String VRP_LOGIC_OF_MAINRUN_CARRIER = "vrpLogicOfMainRunCarrier"; +// private LSPUtils.LogicOfVrp vrpLogicOfMainRunCarrier = LSPUtils.LogicOfVrp.serviceBased; +// private static final String VRP_LOGIC_OF_MAINRUN_CARRIER_DESC = "Define, on which type of jobs the VRP of the **MainRun** carrier will base on:" + Arrays.toString(LSPUtils.LogicOfVrp.values()); +// +// static final String VRP_LOGIC_OF_COLLECTION_CARRIER = "vrpLogicOfCollectionCarrier"; +// private LSPUtils.LogicOfVrp vrpLogicOfCollectionCarrier = LSPUtils.LogicOfVrp.serviceBased; +// private static final String VRP_LOGIC_OF_COLLECTION_CARRIER_DESC = "Define, on which type of jobs the VRP of the **Collection** carrier will base on:" + Arrays.toString(LSPUtils.LogicOfVrp.values()); +// +// /** +// * +// * @return The internal type of jobs, on which the VRPs of the distribution carrier bases on. +// */ +// @StringGetter(VRP_LOGIC_OF_DISTRIBUTION_CARRIER) +// public LSPUtils.LogicOfVrp getVrpLogicOfDistributionCarrier() { +// return vrpLogicOfDistributionCarrier; +// } +// +// /** +// * @param vrpLogicOfDistributionCarrier {@value #VRP_LOGIC_OF_DISTRIBUTION_CARRIER} +// */ +// @StringSetter(VRP_LOGIC_OF_DISTRIBUTION_CARRIER) +// public void setVrpLogicOfDistributionCarrier(LSPUtils.LogicOfVrp vrpLogicOfDistributionCarrier) { +// this.vrpLogicOfDistributionCarrier = vrpLogicOfDistributionCarrier; +// } +// +// /** +// * @return The internal type of jobs, on which the VRPs of the main run carrier bases on. +// */ +// @StringGetter(FreightLogisticsConfigGroup.VRP_LOGIC_OF_MAINRUN_CARRIER) +// public LSPUtils.LogicOfVrp getVrpLogicOfMainRunCarrier() { +// return vrpLogicOfMainRunCarrier; +// } +// +// /** +// * @param vrpLogicOfMainRunCarrier {@value #VRP_LOGIC_OF_MAINRUN_CARRIER} +// */ +// @StringSetter(FreightLogisticsConfigGroup.VRP_LOGIC_OF_MAINRUN_CARRIER) +// public void setVrpLogicOfMainRunCarrier(LSPUtils.LogicOfVrp vrpLogicOfMainRunCarrier) { +// this.vrpLogicOfMainRunCarrier = vrpLogicOfMainRunCarrier; +// } +// +// /** +// * @return The internal type of jobs, on which the VRPs of the collection carrier bases on. +// */ +// @StringGetter(FreightLogisticsConfigGroup.VRP_LOGIC_OF_COLLECTION_CARRIER) +// public LSPUtils.LogicOfVrp getVrpLogicOfCollectionCarrier() { +// return vrpLogicOfCollectionCarrier; +// } +// +// /** +// * @param vrpLogicOfCollectionCarrier {@value #VRP_LOGIC_OF_COLLECTION_CARRIER} +// */ +// @StringSetter(FreightLogisticsConfigGroup.VRP_LOGIC_OF_COLLECTION_CARRIER) +// public void setVrpLogicOfCollectionCarrier(LSPUtils.LogicOfVrp vrpLogicOfCollectionCarrier) { +// this.vrpLogicOfCollectionCarrier = vrpLogicOfCollectionCarrier; +// } + + //--- + //--- + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(LSPS_FILE, LSPS_FILE_DESC); +// map.put(VRP_LOGIC_OF_DISTRIBUTION_CARRIER, VRP_LOGIC_OF_DISTRIBUTION_CARRIER_DESC); +// map.put(VRP_LOGIC_OF_MAINRUN_CARRIER, VRP_LOGIC_OF_MAINRUN_CARRIER_DESC); +// map.put(VRP_LOGIC_OF_COLLECTION_CARRIER, VRP_LOGIC_OF_COLLECTION_CARRIER_DESC); + return map; + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/HasBackpointer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasBackpointer.java new file mode 100644 index 00000000000..73f97386951 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasBackpointer.java @@ -0,0 +1,12 @@ +package org.matsim.freight.logistics; + +@SuppressWarnings("InterfaceMayBeAnnotatedFunctional") +public interface HasBackpointer { + // In general, we set backpointers when we add to the container. + + // yy maybe also have interface HasSettableBackpointer? + void setEmbeddingContainer(T pointer); + + // T getEmbeddingContainer(); + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/HasLspShipmentId.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasLspShipmentId.java new file mode 100644 index 00000000000..e3ddd1fc2f5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasLspShipmentId.java @@ -0,0 +1,32 @@ +/* *********************************************************************** * + * project: org.matsim.* * + * * + * *********************************************************************** * + * * + * copyright : (C) 2008 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ +package org.matsim.freight.logistics; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * @author Kai Martins-Turner (kturner) + */ +public interface HasLspShipmentId { + + String ATTRIBUTE_LSP_SHIPMENT_ID = "lspShipmentId"; + + Id getLspShipmentId(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/HasSimulationTrackers.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasSimulationTrackers.java new file mode 100644 index 00000000000..33ba50074ed --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/HasSimulationTrackers.java @@ -0,0 +1,14 @@ +package org.matsim.freight.logistics; + +import java.util.Collection; + +// One could say that the simulation trackers are the decorators that convert the data objects into +// behavioral objects. In core matsim, we instead +// create behavioral objects, which contain the data objects. E.g. MobsimAgent, DriverAgent, +// CarrierAgent, etc. kai, may'22 +public interface HasSimulationTrackers { + + void addSimulationTracker(LSPSimulationTracker tracker); + + Collection> getSimulationTrackers(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/InitialShipmentAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/InitialShipmentAssigner.java new file mode 100644 index 00000000000..eb6ff6287e7 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/InitialShipmentAssigner.java @@ -0,0 +1,43 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * Takes an {@link LspShipment} and normally assigns it to something that belongs to an {@link LSP}. + *
+ * After changes in fall 2023 (see master thesis of nrichter), the assingment is + * there to be done one time initially. + *
+ * If there are several {@link LogisticChain}s in a {@link LSPPlan}, the {@link LSP} has to assign each {@link + * LspShipment} to the suitable {@link LogisticChain}. For this purpose, each {@link LSPPlan} + * (or only the LSP? - kmt'jan'24), contains a pluggable strategy + * that is contained in classes implementing the interface {@link InitialShipmentAssigner}.
+ *
+ * During iterations, it can happen that the {@link LspShipment} should be moved to another + * {@link LogisticChain} of the same {@link LSPPlan}. This is now (since fall 2023; see master + * thesis of nrichter) part of the (innovative) **Replanning** strategies. + */ +public interface InitialShipmentAssigner { + + void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/KnowsLSP.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/KnowsLSP.java new file mode 100644 index 00000000000..60a9c8ea190 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/KnowsLSP.java @@ -0,0 +1,7 @@ +package org.matsim.freight.logistics; + +interface KnowsLSP { + LSP getLSP(); + + void setLSP(LSP lsp); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSP.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSP.java new file mode 100644 index 00000000000..0486cd0f958 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSP.java @@ -0,0 +1,53 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import org.matsim.api.core.v01.population.HasPlansAndId; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * In the class library, the interface LSP has the following tasks: 1. Maintain one or several + * transport chains through which {@link LspShipment}s are routed. 2. Assign {@link LspShipment}s to + * the suitable transport chain. --> {@link InitialShipmentAssigner}. 3. Interact with the agents that + * embody the demand side of the freight transport market, if they are specified in the setting. 4. + * Coordinate carriers that are in charge of the physical transport. + */ +public interface LSP extends HasPlansAndId, HasSimulationTrackers { + + /** yyyy does this have to be exposed? */ + Collection getLspShipments(); + + /** ok (behavioral method) */ + void scheduleLogisticChains(); + + /** yyyy does this have to be exposed? */ + Collection getResources(); + + /** ok (behavioral method) */ + void scoreSelectedPlan(); + + /** + * @param lspShipment ok (LSP needs to be told that it is responsible for lspShipment) + */ + void assignShipmentToLSP(LspShipment lspShipment); + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPCarrierResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPCarrierResource.java new file mode 100644 index 00000000000..1a26be79a61 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPCarrierResource.java @@ -0,0 +1,28 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.freight.carriers.Carrier; + +public interface LSPCarrierResource extends LSPResource { + + Carrier getCarrier(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPConstants.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPConstants.java new file mode 100644 index 00000000000..44df1603232 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPConstants.java @@ -0,0 +1,29 @@ +package org.matsim.freight.logistics; + +import org.matsim.freight.carriers.CarrierConstants; + +public abstract class LSPConstants extends CarrierConstants { + + public static final String CAPACITY_NEED_FIXED = "capacityNeedFixed"; + public static final String CAPACITY_NEED_LINEAR = "capacityNeedLinear"; + public static final String CHAIN_ID = "chainId"; + public static final String ELEMENT = "element"; + public static final String END_TIME = "endTime"; + public static final String FIXED_COST = "fixedCost"; + public static final String HUB = "hub"; + public static final String LOCATION = "location"; + public static final String LOGISTIC_CHAIN = "logisticChain"; + public static final String LOGISTIC_CHAINS = "logisticChains"; + public static final String LOGISTIC_CHAIN_ELEMENT = "logisticChainElement"; + public static final String LSP = "lsp"; + public static final String LSPS = "lsps"; + public static final String LSP_PLAN = "LspPlan"; + public static final String LSP_PLANS = "LspPlans"; + public static final String RESOURCES = "resources"; + public static final String RESOURCE_ID = "resourceId"; + public static final String SCHEDULER = "scheduler"; + public static final String SHIPMENT_PLAN = "shipmentPlan"; + public static final String SHIPMENT_PLANS = "shipmentPlans"; + public static final String START_TIME = "startTime"; + public static final String TYPE = "type"; +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPControlerListener.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPControlerListener.java new file mode 100644 index 00000000000..e3c864be9bb --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPControlerListener.java @@ -0,0 +1,254 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import jakarta.inject.Inject; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.controler.MatsimServices; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.events.*; +import org.matsim.core.controler.listener.*; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.Gbl; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierPlanWriter; +import org.matsim.freight.carriers.Carriers; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.controler.CarrierAgentTracker; +import org.matsim.freight.logistics.io.LSPPlanXmlWriter; +import org.matsim.freight.logistics.shipment.LspShipment; + +class LSPControlerListener + implements StartupListener, + BeforeMobsimListener, + AfterMobsimListener, + ScoringListener, + ReplanningListener, + IterationStartsListener, + IterationEndsListener, + ShutdownListener { + private static final Logger log = LogManager.getLogger(LSPControlerListener.class); + private final Scenario scenario; + private final List registeredHandlers = new ArrayList<>(); + + private static int addListenerCnt = 0; + private static final int maxAddListenerCnt = 1; + + @Inject private EventsManager eventsManager; + @Inject private MatsimServices matsimServices; + @Inject private LSPScorerFactory lspScoringFunctionFactory; + @Inject @Nullable private LSPStrategyManager strategyManager; + @Inject private OutputDirectoryHierarchy controlerIO; + @Inject private CarrierAgentTracker carrierAgentTracker; + + + @Inject + LSPControlerListener(Scenario scenario) { + this.scenario = scenario; + } + + @Override + public void notifyStartup(StartupEvent event) { + //Ensure that all ressource Ids are only there once. + + checkForUniqueResourceIds(); + + } + +/** +* For later steps, e.g. scoring the Ids of the {@link LSPResource} ids must be unique. + * Otherwise, there are scored several times. + *

+ * For the future we may reduce it to unique {@link LSPResource} ids PER {@link LSP}. + * This means, that the events (also from the carriers) need to have an information obout the LSP it belongs to and that + * in scoring and analysis this must be taken into account. What itself is another source for errors... + * KMT jul'24 +*/ + private void checkForUniqueResourceIds() { + List duplicates = new ArrayList<>(); + Set set = new HashSet<>(); + + LSPs lsps = LSPUtils.getLSPs(scenario); + for (LSP lsp : lsps.getLSPs().values()) { + for (LSPResource lspResource : lsp.getResources()) { + String idString = lspResource.getId().toString(); + if (set.contains(idString)) { + duplicates.add(idString); + } else { + set.add(idString); + } + } + } + + if (!duplicates.isEmpty()) { + log.error("There are non-unique ressource Ids. This must not be! The duplicate ids are: {}.", duplicates.toString()); + log.error("You may also use output_lsp.xml to check were the duplicates are located"); + log.error("Aborting now ..."); + throw new RuntimeException(); + } + } + + @Override + public void notifyBeforeMobsim(BeforeMobsimEvent event) { + LSPs lsps = LSPUtils.getLSPs(scenario); + + // TODO: Why do we add all simTrackers in every iteration beforeMobsim starts? + // Doing so results in a lot of "not adding eventsHandler since already added" warnings. + // @KN: Would it be possible to do it in (simulation) startup and therefor only oce? + for (LSP lsp : lsps.getLSPs().values()) { + ((LSPImpl) lsp).setScorer(lspScoringFunctionFactory.createScoringFunction()); + + // simulation trackers of lsp: + registerSimulationTrackers(lsp); + + // simulation trackers of resources: + for (LSPResource resource : lsp.getResources()) { + registerSimulationTrackers(resource); + } + + // simulation trackers of shipments: + for (LspShipment lspShipment : lsp.getLspShipments()) { + registerSimulationTrackers(lspShipment); + } + + // simulation trackers of solutions: + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + registerSimulationTrackers(solution); + + // simulation trackers of solution elements: + for (LogisticChainElement element : solution.getLogisticChainElements()) { + registerSimulationTrackers(element); + + // simulation trackers of resources: + registerSimulationTrackers(element.getResource()); + } + } + } + } + + private void registerSimulationTrackers(HasSimulationTrackers hasSimulationTrackers) { + // get all simulation trackers ... + for (LSPSimulationTracker simulationTracker : + hasSimulationTrackers.getSimulationTrackers()) { + // ... register them ... + if (!registeredHandlers.contains(simulationTracker)) { + log.info("adding eventsHandler: {}", simulationTracker); + eventsManager.addHandler(simulationTracker); + registeredHandlers.add(simulationTracker); + matsimServices.addControlerListener(simulationTracker); + simulationTracker.setEventsManager(eventsManager); + } else if ( addListenerCnt < maxAddListenerCnt ){ + log.warn("not adding eventsHandler since already added: {}", simulationTracker); + addListenerCnt++; + if (addListenerCnt == maxAddListenerCnt) { + log.warn(Gbl.FUTURE_SUPPRESSED); + } + } + } + + } + + @Override + public void notifyReplanning(ReplanningEvent event) { + if (strategyManager == null) { + throw new RuntimeException( + "You need to set LSPStrategyManager to something meaningful to run iterations."); + } + + LSPs lsps = LSPUtils.getLSPs(scenario); + strategyManager.run( + lsps.getLSPs().values(), event.getIteration(), event.getReplanningContext()); + + for (LSP lsp : lsps.getLSPs().values()) { + lsp.getSelectedPlan() + .getShipmentPlans() + .clear(); // clear ShipmentPlans to start with clear(n) state. Otherwise, some of the times were + // accumulating over the time. :( + lsp.scheduleLogisticChains(); + } + + // Update carriers in scenario and CarrierAgentTracker + carrierAgentTracker.getCarriers().getCarriers().clear(); + for (Carrier carrier : getCarriersFromLSP().getCarriers().values()) { + CarriersUtils.getCarriers(scenario).addCarrier(carrier); + carrierAgentTracker.getCarriers().addCarrier(carrier); + } + } + + @Override + public void notifyScoring(ScoringEvent scoringEvent) { + for (LSP lsp : LSPUtils.getLSPs(scenario).getLSPs().values()) { + lsp.scoreSelectedPlan(); + } + // yyyyyy might make more sense to register the lsps directly as scoring controler listener (??) + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) {} + + Carriers getCarriersFromLSP() { + LSPs lsps = LSPUtils.getLSPs(scenario); + assert !lsps.getLSPs().isEmpty(); + + Carriers carriers = new Carriers(); + for (LSP lsp : lsps.getLSPs().values()) { + LSPPlan selectedPlan = lsp.getSelectedPlan(); + for (LogisticChain solution : selectedPlan.getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (element.getResource() instanceof LSPCarrierResource carrierResource) { + Carrier carrier = carrierResource.getCarrier(); + if (!carriers.getCarriers().containsKey(carrier.getId())) { + carriers.addCarrier(carrier); + } + } + } + } + } + return carriers; + } + + @Override + public void notifyIterationStarts(IterationStartsEvent event) {} + + @Override + public void notifyIterationEnds(IterationEndsEvent event) { + new LSPPlanXmlWriter(LSPUtils.getLSPs(scenario)) + .write(controlerIO.getIterationFilename(event.getIteration(), "lsps.xml")); + } + + @Override + public void notifyShutdown(ShutdownEvent event) { + new LSPPlanXmlWriter(LSPUtils.getLSPs(scenario)) + .write(controlerIO.getOutputPath() + "/output_lsps.xml.gz"); + new CarrierPlanWriter(CarriersUtils.getCarriers(scenario)) + .write(controlerIO.getOutputPath() + "/output_carriers.xml.gz"); + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPDataObject.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPDataObject.java new file mode 100644 index 00000000000..ff150a79d88 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPDataObject.java @@ -0,0 +1,45 @@ +package org.matsim.freight.logistics; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Identifiable; +import org.matsim.utils.objectattributes.attributable.Attributable; +import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; + +public class LSPDataObject implements HasSimulationTrackers, Attributable, Identifiable { + + private final Collection> trackers = new LinkedList<>(); + private final Attributes attributes = new AttributesImpl(); + private final Id id; + + public LSPDataObject(Id id) { + this.id = id; + } + + @Override + public final void addSimulationTracker(LSPSimulationTracker tracker) { + this.trackers.add(tracker); + tracker.setEmbeddingContainer((T) this); + // It may not be possible to do this without this cast. Since "this" only knows that it is at + // least an LSPDataObject, and only we + // know that it is truly of type T. kai, jun'22 + } + + @Override + public final Collection> getSimulationTrackers() { + return Collections.unmodifiableCollection(this.trackers); + } + + @Override + public final Attributes getAttributes() { + return attributes; + } + + @Override + public final Id getId() { + return id; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPImpl.java new file mode 100644 index 00000000000..54840359388 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPImpl.java @@ -0,0 +1,163 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.freight.logistics.shipment.LspShipment; + +/* package-private */ class LSPImpl extends LSPDataObject implements LSP { + private static final Logger log = LogManager.getLogger(LSPImpl.class); + + private final Collection lspShipments; + private final ArrayList lspPlans; + private final LogisticChainScheduler logisticChainScheduler; + private final Collection resources; + private LSPPlan selectedPlan; + private LSPScorer scorer; + + // private LSPReplanner replanner; + + LSPImpl(LSPUtils.LSPBuilder builder) { + super(builder.id); + this.lspShipments = new ArrayList<>(); + this.lspPlans = new ArrayList<>(); + this.logisticChainScheduler = builder.logisticChainScheduler; + this.logisticChainScheduler.setEmbeddingContainer(this); + this.selectedPlan = builder.initialPlan; + this.selectedPlan.setLSP(this); + this.lspPlans.add(builder.initialPlan); + this.resources = builder.resources; + } + + public static LSPPlan copyPlan(LSPPlan plan2copy) { + List newPlanChains = new ArrayList<>(); + for (LogisticChain initialPlanChain : plan2copy.getLogisticChains()) { + LogisticChain newPlanChain = + LSPUtils.LogisticChainBuilder.newInstance(initialPlanChain.getId()).build(); + newPlanChain.getLogisticChainElements().addAll(initialPlanChain.getLogisticChainElements()); + newPlanChain.getLspShipmentIds().addAll(initialPlanChain.getLspShipmentIds()); + newPlanChains.add(newPlanChain); + } + + LSPPlan copiedPlan = LSPUtils.createLSPPlan(); + copiedPlan.setInitialShipmentAssigner(plan2copy.getInitialShipmentAssigner()); + copiedPlan.setLSP(plan2copy.getLSP()); + copiedPlan.setScore(plan2copy.getScore()); + copiedPlan.setType(plan2copy.getType()); + copiedPlan.getLogisticChains().addAll(newPlanChains); + return copiedPlan; + } + + /** + * This is used from {@link LSPControlerListener} and not meant to be used from user code. Users + * should bind {@link LSPScorerFactory}. + */ + /* package-private */ void setScorer(LSPScorer scorer) { + this.scorer = scorer; + scorer.setEmbeddingContainer(this); + this.addSimulationTracker(scorer); + } + + @Override + public void scheduleLogisticChains() { + logisticChainScheduler.scheduleLogisticChain(); + } + + @Override + public boolean addPlan(LSPPlan plan) { + for (LogisticChain solution : plan.getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (!resources.contains(element.getResource())) { + resources.add(element.getResource()); + } + } + } + plan.setLSP(this); + return lspPlans.add(plan); + } + + @Override + public LSPPlan createCopyOfSelectedPlanAndMakeSelected() { + LSPPlan newPlan = LSPImpl.copyPlan(this.selectedPlan); + this.setSelectedPlan(newPlan); + return newPlan; + } + + @Override + public ArrayList getPlans() { + return lspPlans; + } + + @Override + public LSPPlan getSelectedPlan() { + return selectedPlan; + } + + @Override + public void setSelectedPlan(LSPPlan selectedPlan) { + if (!lspPlans.contains(selectedPlan)) { + lspPlans.add(selectedPlan); + } + this.selectedPlan = selectedPlan; + } + + @Override + public boolean removePlan(LSPPlan lspPlan) { + if (lspPlans.contains(lspPlan)) { + lspPlans.remove(lspPlan); + return true; + } else { + return false; + } + } + + @Override + public Collection getResources() { + return resources; + } + + public void scoreSelectedPlan() { + if (this.scorer != null) { + this.selectedPlan.setScore(scorer.getScoreForCurrentPlan()); + } else { + throw new RuntimeException("trying to score the current LSP plan, but scorer is not set."); + } + } + + @Override + public void assignShipmentToLSP(LspShipment lspShipment) { + // shipment.setLspId(this.getId()); // und rückweg dann auch darüber und dann + // lsp.getselectedPlan.getShipment... + lspShipments.add(lspShipment); + for (LSPPlan lspPlan : lspPlans) { + lspPlan.getInitialShipmentAssigner().assignToPlan(lspPlan, lspShipment); + } + } + + @Override + public Collection getLspShipments() { + return this.lspShipments; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPModule.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPModule.java new file mode 100644 index 00000000000..2eb4085ec56 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPModule.java @@ -0,0 +1,184 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.HasPlansAndId; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.events.BeforeMobsimEvent; +import org.matsim.core.controler.listener.BeforeMobsimListener; +import org.matsim.core.mobsim.qsim.AbstractQSimModule; +import org.matsim.core.mobsim.qsim.components.QSimComponentsConfigGroup; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.selectors.PlanSelector; +import org.matsim.freight.carriers.FreightCarriersConfigGroup; +import org.matsim.freight.carriers.controler.*; +import org.matsim.freight.logistics.analysis.LspScoreStatsModule; + +public class LSPModule extends AbstractModule { + private static final Logger log = LogManager.getLogger(LSPModule.class); + + @Override + public void install() { + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(getConfig(), FreightCarriersConfigGroup.class); + + bind(LSPControlerListener.class).in(Singleton.class); + addControlerListenerBinding().to(LSPControlerListener.class); + + install(new CarrierModule()); + install(new LspScoreStatsModule()); + + // this switches on certain qsim components: + QSimComponentsConfigGroup qsimComponents = + ConfigUtils.addOrGetModule(getConfig(), QSimComponentsConfigGroup.class); + List abc = qsimComponents.getActiveComponents(); + abc.add(FreightAgentSource.COMPONENT_NAME); + switch (freightConfig.getTimeWindowHandling()) { + case ignore: + break; + case enforceBeginnings: + //// abc.add( WithinDayActivityReScheduling.COMPONENT_NAME ); + log.warn( + "LSP has never hedged against time window openings; this is probably wrong; but I don't know what to do ..."); + // break; + default: + throw new IllegalStateException( + "Unexpected value: " + freightConfig.getTimeWindowHandling()); + } + qsimComponents.setActiveComponents(abc); + + // this installs qsim components, which are switched on (or not) via the above syntax: + this.installQSimModule( + new AbstractQSimModule() { + @Override + protected void configureQSim() { + this.bind(FreightAgentSource.class).in(Singleton.class); + this.addQSimComponentBinding(FreightAgentSource.COMPONENT_NAME) + .to(FreightAgentSource.class); + switch (freightConfig.getTimeWindowHandling()) { + case ignore: + break; + case enforceBeginnings: + //// + // this.addQSimComponentBinding(WithinDayActivityReScheduling.COMPONENT_NAME).to( + // WithinDayActivityReScheduling.class ); + log.warn( + "LSP has never hedged against time window openings; this is probably wrong; but I don't know what to do ..."); + // break; + default: + throw new IllegalStateException( + "Unexpected value: " + freightConfig.getTimeWindowHandling()); + } + } + }); + + // the scorers are necessary to run a zeroth iteration to the end: + bind(LSPScorerFactory.class).to(LSPScoringFunctionFactoryDummyImpl.class); + + // for iterations, one needs to replace the following with something meaningful. If nothing + // else, there are "empty implementations" that do nothing. kai, jul'22 + bind(LSPStrategyManager.class).toProvider(() -> null); + + this.addControlerListenerBinding().to(DumpLSPPlans.class); + } + + private static class LSPScoringFunctionFactoryDummyImpl implements LSPScorerFactory { + @Override + public LSPScorer createScoringFunction() { + return new LSPScorer() { + @Override + public double getScoreForCurrentPlan() { + return Double.NEGATIVE_INFINITY; + } + + @Override + public void setEmbeddingContainer(LSP pointer) {} + }; + } + } + + public static final class LSPStrategyManagerEmptyImpl implements LSPStrategyManager { + + @Override + public void addStrategy( + GenericPlanStrategy strategy, String subpopulation, double weight) { + throw new RuntimeException("not implemented"); + } + + @Override + public void run( + Iterable> persons, + int iteration, + ReplanningContext replanningContext) { + log.warn("Running iterations without a strategy may lead to unclear results."); // "run" is + // possible, but will not do anything. kai, jul'22 + } + + @Override + public void setMaxPlansPerAgent(int maxPlansPerAgent) { + throw new RuntimeException("not implemented"); + } + + @Override + public void addChangeRequest(int iteration, GenericPlanStrategy strategy, String subpopulation, double newWeight) { + throw new RuntimeException("not implemented"); + } + + @Override + public void setPlanSelectorForRemoval(PlanSelector planSelector) { + throw new RuntimeException("not implemented"); + } + + @Override + public List> getStrategies(String subpopulation) { + throw new RuntimeException("not implemented"); + } + + @Override + public List getWeights(String subpopulation) { + throw new RuntimeException("not implemented"); + } + } + + public static final class DumpLSPPlans implements BeforeMobsimListener { + @Inject Scenario scenario; + + @Override + public void notifyBeforeMobsim(BeforeMobsimEvent event) { + LSPs lsps = LSPUtils.getLSPs(scenario); + for (LSP lsp : lsps.getLSPs().values()) { + log.info("Dumping plan(s) of [LSP={}] ; [No of plans={}]", lsp.getId(), lsp.getPlans().size()); + for (LSPPlan plan : lsp.getPlans()) { + log.info("[LSPPlan: {}]", plan.toString()); + } + log.info("Plan(s) of [LSP={}] dumped.", lsp.getId()); + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlan.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlan.java new file mode 100644 index 00000000000..c6c3d48d4f2 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlan.java @@ -0,0 +1,59 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import org.matsim.api.core.v01.population.BasicPlan; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; + +/** + * This interface has the following properties: + * + *
    + *
  • As a {@link BasicPlan} it has a score, so it can be used for evolutionary learning. kai, + * may'22 + *
  • An {@link LspShipment} is added via lspPlan#getAssigner().assignToSolution(shipment). The + * {@link InitialShipmentAssigner} assigns it deterministically to a {@link LogisticChain}. + *
+ */ +public interface LSPPlan extends BasicPlan, KnowsLSP { + + LSPPlan addLogisticChain(LogisticChain solution); + + Collection getLogisticChains(); + + /** + * yy My intuition would be to replace lspPlan#getAssigner().assignToSolution( shipment ) by + * lspPlan.addShipment( shipment ). kai, may'22 + */ + InitialShipmentAssigner getInitialShipmentAssigner(); + + LSPPlan setInitialShipmentAssigner(InitialShipmentAssigner assigner); + + Collection getShipmentPlans(); + + LSPPlan addShipmentPlan(LspShipmentPlan lspShipmentPlan); + + String getType(); + + void setType(final String type); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlanImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlanImpl.java new file mode 100644 index 00000000000..a1bfe4e25cc --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlanImpl.java @@ -0,0 +1,127 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Collection; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; + +public class LSPPlanImpl implements LSPPlan { + + private final Collection logisticChains; + private final Collection lspShipmentPlans; + private LSP lsp; + private Double score = null; + private InitialShipmentAssigner assigner; + private String type = null; + + public LSPPlanImpl() { + this.logisticChains = new ArrayList<>(); + this.lspShipmentPlans = new ArrayList<>(); + } + + @Override + public LSPPlan addLogisticChain(LogisticChain solution) { + this.logisticChains.add(solution); + solution.setLSP(this.lsp); + return this; + } + + @Override + public Collection getLogisticChains() { + return logisticChains; + } + + @Override + public InitialShipmentAssigner getInitialShipmentAssigner() { + return assigner; + } + + @Override + public LSPPlan setInitialShipmentAssigner(InitialShipmentAssigner assigner) { + this.assigner = assigner; + return this; + } + + @Override + public Collection getShipmentPlans() { + return this.lspShipmentPlans; + } + + @Override + public LSPPlan addShipmentPlan(LspShipmentPlan lspShipmentPlan) { + this.lspShipmentPlans.add(lspShipmentPlan); + return null; + } + + @Override + public Double getScore() { + return score; + } + + @Override + public void setScore(Double score) { + this.score = score; + } + + @Override + public String getType() { + return this.type; + } + + @Override + public void setType(final String type) { + this.type = type; + } + + @Override + public LSP getLSP() { + return lsp; + } + + @Override + public void setLSP(LSP lsp) { + this.lsp = lsp; + for (LogisticChain solution : logisticChains) { + solution.setLSP(lsp); + } + } + + @Override + public String toString() { + StringBuilder strb = new StringBuilder(); + strb.append("[score=").append(this.score).append("]"); + strb.append(", [type=").append(this.type).append("]"); + for (LogisticChain logisticChain : this.logisticChains) { + strb.append(", [LogisticChainId=") + .append(logisticChain.getId()) + .append("], [No of LogisticChainElements=") + .append(logisticChain.getLogisticChainElements().size()) + .append("] \n"); + if (!logisticChain.getLogisticChainElements().isEmpty()) { + for (LogisticChainElement solutionElement : logisticChain.getLogisticChainElements()) { + strb.append("\t \t").append(solutionElement.toString()).append("\n"); + } + } + } + return strb.toString(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResource.java new file mode 100644 index 00000000000..4f1e595ebe0 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResource.java @@ -0,0 +1,40 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Identifiable; +import org.matsim.api.core.v01.network.Link; +import org.matsim.utils.objectattributes.attributable.Attributable; + +/** */ +public interface LSPResource + extends Identifiable, HasSimulationTrackers, Attributable { + + Id getStartLinkId(); + + Id getEndLinkId(); + + Collection getClientElements(); + + void schedule(int bufferTime, LSPPlan lspPlan); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResourceScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResourceScheduler.java new file mode 100644 index 00000000000..c63d9258742 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPResourceScheduler.java @@ -0,0 +1,106 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Comparator; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/** + * Resources are scheduled separately by calling their individual scheduling algorithm. + * + *

Within this algorithm, some methods are abstract, whereas others have a default implementation + * for forward scheduling. The former ones are specified in a suitable way by the corresponding + * Resource whereas the latter are only specified in the abstract parent class in order to + * coordinate the way in which the LSPShipments are handed over between subsequent Resources. The + * abstract methods deal with aspects that are specific to the Resource which contains the + * implementation of the ResourceScheduler. + * + *

Forwarding of LSPShipments is done by the two methods presortIncomingShipments() and + * switchHandledShipments(int bufferTime). + */ +public abstract class LSPResourceScheduler { + + protected LSPResource resource; + protected ArrayList lspShipmentsToSchedule; + + protected LSPPlan lspPlan; + + public final void scheduleShipments(LSPPlan lspPlan, LSPResource resource, int bufferTime) { + this.lspPlan = lspPlan; + this.resource = resource; + this.lspShipmentsToSchedule = new ArrayList<>(); + initializeValues(resource); + presortIncomingShipments(); + scheduleResource(); + updateShipments(); + switchHandledShipments(bufferTime); + lspShipmentsToSchedule.clear(); + } + + /** + * Is in charge of the initialization of the actual scheduling process for the concerned Resource. + * Depending on the concrete shape of this process, there are mainly values to be deleted that are + * still stored from the previous iteration or the infrastructure for the used algorithm has to be + * set up. + * + * @param resource The LSPRessource + */ + protected abstract void initializeValues(LSPResource resource); + + /** Controls the actual scheduling process that depends on the shape and task of the Resource. */ + protected abstract void scheduleResource(); + + /** + * Endows the involved {@link LspShipment}s with information that resulted from the scheduling in + * a narrow sense in scheduleResource(). The information can be divided into two main components. + * 1.) the schedule of the {@link LspShipment}s is updated if necessary 2.) the information for a + * later logging of the is added. + */ + protected abstract void updateShipments(); + + private void presortIncomingShipments() { + this.lspShipmentsToSchedule = new ArrayList<>(); + for (LogisticChainElement element : resource.getClientElements()) { + lspShipmentsToSchedule.addAll(element.getIncomingShipments().getLspShipmentsWTime()); + } + lspShipmentsToSchedule.sort(Comparator.comparingDouble(LspShipmentUtils::getTimeOfLspShipment)); + } + + private void switchHandledShipments(int bufferTime) { + for (LspShipment lspShipmentWithTime : lspShipmentsToSchedule) { + var shipmentPlan = LspShipmentUtils.getOrCreateShipmentPlan(lspPlan, lspShipmentWithTime.getId()); + double endOfTransportTime = shipmentPlan.getMostRecentEntry().getEndTime() + bufferTime; + LspShipmentUtils.setTimeOfLspShipment(lspShipmentWithTime, endOfTransportTime); + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipmentWithTime)) { + element.getIncomingShipments().getLspShipmentsWTime().remove(lspShipmentWithTime); + element.getOutgoingShipments().getLspShipmentsWTime().add(lspShipmentWithTime); + if (element.getNextElement() != null) { + element.getNextElement().getIncomingShipments().getLspShipmentsWTime().add(lspShipmentWithTime); + element.getOutgoingShipments().getLspShipmentsWTime().remove(lspShipmentWithTime); + } + } + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorer.java new file mode 100644 index 00000000000..4f4916c0510 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorer.java @@ -0,0 +1,43 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.api.core.v01.population.Activity; +import org.matsim.core.controler.listener.ControlerListener; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.scoring.ScoringFunction; +import org.matsim.freight.carriers.Carrier; + +/** + * This is somewhat similar to the MATSim core {@link ScoringFunction}, which is also used for + * {@link Carrier}s. A difference, however, is that it does not implement the separate methods + * {@link ScoringFunction#handleActivity(Activity)} etc., but is just an {@link EventHandler} and a + * {@link ControlerListener}. (This is, in some sense, the old design for {@link ScoringFunction}, + * and one, where I am still not sure if the new design is truly better.) In any case, here there is + * not a question: LSP scoring is not so much about activities and legs, since those are handled + * through the carrier scoring, and need to be pulled in by the lsp scoring if the company is + * vertically integrated (i.e. if the LSP owns its carriers). + * + *

also @see {@link LSPScorerFactory} + */ +public interface LSPScorer extends LSPSimulationTracker { + double getScoreForCurrentPlan(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorerFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorerFactory.java new file mode 100644 index 00000000000..e5a5d7ea78f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPScorerFactory.java @@ -0,0 +1,7 @@ +package org.matsim.freight.logistics; + +import org.matsim.core.api.internal.MatsimFactory; + +public interface LSPScorerFactory extends MatsimFactory { + LSPScorer createScoringFunction(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPSimulationTracker.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPSimulationTracker.java new file mode 100644 index 00000000000..55d967c293b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPSimulationTracker.java @@ -0,0 +1,32 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.controler.listener.ControlerListener; +import org.matsim.core.events.handler.EventHandler; + +public interface LSPSimulationTracker + extends ControlerListener, EventHandler, HasBackpointer { + // In general, we set backpointers when we add to the container. So specifically, we set the + // backpointer to which the tracker points when the tracker is added. + default void setEventsManager(EventsManager eventsManager) {} +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManager.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManager.java new file mode 100644 index 00000000000..79d7c5a64bc --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManager.java @@ -0,0 +1,44 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + * + */ + +package org.matsim.freight.logistics; + +import jakarta.inject.Provider; +import org.matsim.core.replanning.GenericStrategyManager; + +/** + * The current (jul'22) logic of this is: + * + *

    + *
  • There is a null binding of this interface in {@link LSPModule}. If one wants to use + * strategies, this needs to be overwritten. + *
  • Normally, the strategy manager is fixed infrastructure, and should just be configured. + * However, since it is not yet there before injection, it also cannot be configured before + * injection. Core matsim solves that by writing the corresponding configuration into the + * config. We could, in principle, do the same here. Don't want to do this yet. + *
  • So way to configure this "in code" is to bind {@link LSPStrategyManager} to a {@link + * Provider } and then configure it in the provider. + *
+ */ +public interface LSPStrategyManager extends GenericStrategyManager { + // (this is mostly there so that it can be guice-bound. kai, jul'22) + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManagerImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManagerImpl.java new file mode 100644 index 00000000000..f628d4f2ab4 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPStrategyManagerImpl.java @@ -0,0 +1,71 @@ +package org.matsim.freight.logistics; + +import java.util.List; +import org.matsim.api.core.v01.population.HasPlansAndId; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericStrategyManager; +import org.matsim.core.replanning.GenericStrategyManagerImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.selectors.PlanSelector; + +/** + * Normally, this would be infrastructure that is configurable via the config. Since we ain't there + * yet, the way to configure this is something like: + * + *
+ *         bind( LSPStrategyManager.class ).to( new Provider() {
+ *                 public LSPStrategyManager.get() {
+ *                         LSPStrategyManager manager = new LSPStrategyManagerImpl();
+ *                         manager.addStrategy(...)
+ *                         ...
+ *                         return manager;
+ *                 }
+ *         }
+ * 
+ */ +public class LSPStrategyManagerImpl implements LSPStrategyManager { + final GenericStrategyManager delegate = new GenericStrategyManagerImpl<>(); + + @Override + public void addStrategy( + GenericPlanStrategy strategy, String subpopulation, double weight) { + delegate.addStrategy(strategy, subpopulation, weight); + } + + @Override + public void run( + Iterable> persons, + int iteration, + ReplanningContext replanningContext) { + delegate.run(persons, iteration, replanningContext); + } + + @Override + public void setMaxPlansPerAgent(int maxPlansPerAgent) { + delegate.setMaxPlansPerAgent(maxPlansPerAgent); + } + + @Override + public void addChangeRequest( + int iteration, + GenericPlanStrategy strategy, + String subpopulation, + double newWeight) { + delegate.addChangeRequest(iteration, strategy, subpopulation, newWeight); + } + + @Override + public void setPlanSelectorForRemoval(PlanSelector planSelector) { + delegate.setPlanSelectorForRemoval(planSelector); + } + + @Override + public List> getStrategies(String subpopulation) { + return delegate.getStrategies(subpopulation); + } + + @Override + public List getWeights(String subpopulation) { + return delegate.getWeights(subpopulation); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPUtils.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPUtils.java new file mode 100644 index 00000000000..e40c44e95b6 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPUtils.java @@ -0,0 +1,271 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.freight.carriers.Carriers; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; +import org.matsim.utils.objectattributes.attributable.Attributable; + +public final class LSPUtils { + private static final String lspsString = "lsps"; + + private LSPUtils() {} // do not instantiate + + public static LSPPlan createLSPPlan() { + return new LSPPlanImpl(); + } + + + /** + * Checks, is the plan the selcted plan. + * (This is adapted copy from PersonUtils.isSelected(plan) ) + * @param lspPlan the plan to check + * @return true if the plan is the selected plan. false, if not. + */ + public static boolean isPlanTheSelectedPlan(LSPPlan lspPlan) { + return lspPlan.getLSP().getSelectedPlan() == lspPlan; + } + + public static LogisticChainScheduler createForwardLogisiticChainScheduler() { + return new ForwardLogisticChainSchedulerImpl(); + } + + public static WaitingShipments createWaitingShipments() { + return new WaitingShipmentsImpl(); + } + + public static void addLSPs(Scenario scenario, LSPs lsps) { + Carriers carriers = CarriersUtils.addOrGetCarriers(scenario); + // Register carriers from all lsps + for (LSP lsp : lsps.getLSPs().values()) { + for (LSPResource lspResource : lsp.getResources()) { + if (lspResource instanceof LSPCarrierResource lspCarrierResource) { + carriers.addCarrier(lspCarrierResource.getCarrier()); + } + } + } + scenario.addScenarioElement(lspsString, lsps); + } + + public static LSPs getLSPs(Scenario scenario) { + Object result = scenario.getScenarioElement(lspsString); + if (result == null) { + throw new RuntimeException( + "there is no scenario element of type " + + lspsString + + ". You will need something like LSPUtils.addLSPs( scenario, lsps) somewhere."); + } + return (LSPs) result; + } + + public static Double getVariableCost(Attributable attributable) { + return (Double) attributable.getAttributes().getAttribute("variableCost"); + } + + public static void setVariableCost(Attributable attributable, Double variableCost) { + attributable.getAttributes().putAttribute("variableCost", variableCost); + } + + public static Double getFixedCost(Attributable attributable) { + return (Double) attributable.getAttributes().getAttribute("fixedCost"); + } + + // The following would be closer to how we have done it elsewhere (scenario containers are + // mutable). kai, may'22' + // public static LSPs createOrGetLPSs( Scenario scenario ){ + // Object result = scenario.getScenarioElement( lspsString ); + // LSPs lsps; + // if ( result != null ) { + // lsps = (LSPs) result; + // } else { + // lsps = new LSPs( ); + // scenario.addScenarioElement( lspsString, lsps ); + // } + // return lsps; + // } + + public static void setFixedCost(Attributable attributable, Double fixedCost) { + attributable.getAttributes().putAttribute("fixedCost", fixedCost); + } + + /** + * Gives back the {@link LspShipment} object of the {@link LSP}, which matches to the shipmentId + * + * @param lsp In this LSP this method tries to find the shipment. + * @param shipmentId Id of the shipment that should be found. + * @return the lspShipment object or null, if it is not found. + */ + public static LspShipment findLspShipment(LSP lsp, Id shipmentId) { + for (LspShipment lspShipment : lsp.getLspShipments()) { + if (lspShipment.getId().equals(shipmentId)) { + return lspShipment; + } + } + return null; + } + + /** + * Returns the {@link LspShipmentPlan} of an {@link LspShipment}. + * + * @param lspPlan the lspPlan: It contains the information of its shipmentPlans + * @param shipmentId Id of the shipment that should be found. + * @return the shipmentPlan object or null, if it is not found. + */ + public static LspShipmentPlan findLspShipmentPlan(LSPPlan lspPlan, Id shipmentId) { + for (LspShipmentPlan lspShipmentPlan : lspPlan.getShipmentPlans()) { + if (lspShipmentPlan.getLspShipmentId().equals(shipmentId)) { + return lspShipmentPlan; + } + } + return null; + } + + public enum LogicOfVrp {serviceBased, shipmentBased} + + public static final class LSPBuilder { + final Collection resources; + final Id id; + LogisticChainScheduler logisticChainScheduler; + LSPPlan initialPlan; + + private LSPBuilder(Id id) { + this.id = id; // this line was not there until today. kai, may'22 + this.resources = new ArrayList<>(); + } + + public static LSPBuilder getInstance(Id id) { + return new LSPBuilder(id); + } + + public LSPBuilder setLogisticChainScheduler(LogisticChainScheduler logisticChainScheduler) { + this.logisticChainScheduler = logisticChainScheduler; + return this; + } + + // /** + // * @deprecated -- It feels attractive to attach this to the "agent". A big disadvantage + // with this approach, however, is that + // * we cannot use injection ... since we cannot inject as many scorers as we have agents. + // (At least this is what I think.) Which means + // * that the approach in matsim core and in carriers to have XxxScoringFunctionFactory is + // better for what we are doing here. yyyyyy So + // * this needs to be changed. kai, jul'22 + // */ + // public LSPBuilder setSolutionScorer(LSPScorer scorer) { + // this.scorer = scorer; + // return this; + // } + + // /** + // * @deprecated -- It feels attractive to attach this to the "agent". A big disadvantage + // with this approach, however, is that + // * we cannot use injection ... since we cannot inject as many replanners as we have + // agents. (At least this is what I think.) yyyyyy So + // * this needs to be changed. kai, jul'22 + // */ + // public LSPBuilder setReplanner(LSPReplanner replanner) { + // this.replanner = replanner; + // return this; + // } + // never used. Thus disabling it. kai, jul'22 + + public LSPBuilder setInitialPlan(LSPPlan plan) { + this.initialPlan = plan; + for (LogisticChain solution : plan.getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (!resources.contains(element.getResource())) { + resources.add(element.getResource()); + } + } + } + return this; + } + + public LSP build() { + return new LSPImpl(this); + } + } + + public static final class LogisticChainBuilder { + final Id id; + final Collection elements; + // final Collection eventHandlers; + final Collection> trackers; + + private LogisticChainBuilder(Id id) { + this.elements = new ArrayList<>(); + this.trackers = new ArrayList<>(); + this.id = id; + } + + public static LogisticChainBuilder newInstance(Id id) { + return new LogisticChainBuilder(id); + } + + public LogisticChainBuilder addLogisticChainElement(LogisticChainElement element) { + elements.add(element); + return this; + } + + public LogisticChainBuilder addTracker(LSPSimulationTracker tracker) { + trackers.add(tracker); + return this; + } + + public LogisticChain build() { + //TODO: Prüfe of das alle Elemente Verbunden sind (in irgendeiner Art). Plus Hinweis auf die Änderung. + + return new LogisticChainImpl(this); + } + } + + public static final class LogisticChainElementBuilder { + final Id id; + final WaitingShipments incomingShipments; + final WaitingShipments outgoingShipments; + LSPResource resource; + + private LogisticChainElementBuilder(Id id) { + this.id = id; + this.incomingShipments = createWaitingShipments(); + this.outgoingShipments = createWaitingShipments(); + } + + public static LogisticChainElementBuilder newInstance(Id id) { + return new LogisticChainElementBuilder(id); + } + + public LogisticChainElementBuilder setResource(LSPResource resource) { + this.resource = resource; + return this; + } + + public LogisticChainElement build() { + return new LogisticChainElementImpl(this); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPs.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPs.java new file mode 100644 index 00000000000..7adfc6d430e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPs.java @@ -0,0 +1,45 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import org.matsim.api.core.v01.Id; + +public class LSPs { + + private final Map, LSP> lsps = new LinkedHashMap<>(); + + public LSPs(Collection lsps) { + makeMap(lsps); + } + + private void makeMap(Collection lsps) { + for (LSP c : lsps) { + this.lsps.put(c.getId(), c); + } + } + + public Map, LSP> getLSPs() { + return lsps; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChain.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChain.java new file mode 100644 index 00000000000..f1b19be6c8f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChain.java @@ -0,0 +1,48 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Identifiable; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.utils.objectattributes.attributable.Attributable; + +/** + * A LogisticsSolution can be seen as a representative of a transport chain. It consists of several + * chain links that implement the interface {@link LogisticChainElement}. The latter is more a + * logical than a physical entity. Physical entities, in turn, are housed inside classes that + * implement the interface {@link LSPResource}. This introduction of an intermediate layer allows + * physical Resources to be used by several {@link LogisticChain}s and thus transport chains. + */ +@SuppressWarnings("GrazieInspection") +public interface LogisticChain + extends Identifiable, + KnowsLSP, + HasSimulationTrackers, + Attributable { + + Collection getLogisticChainElements(); + + Collection> getLspShipmentIds(); + + void addShipmentToChain(LspShipment lspShipment); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElement.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElement.java new file mode 100644 index 00000000000..67a16b43462 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElement.java @@ -0,0 +1,55 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.api.core.v01.Identifiable; +import org.matsim.utils.objectattributes.attributable.Attributable; + +public interface LogisticChainElement + extends Identifiable, + HasBackpointer, + HasSimulationTrackers, + Attributable { + + void connectWithNextElement(LogisticChainElement element); + + /** + * The logistics solution element wraps around a resource. Don't know why we need this wrapping. + * + * @return the resource + */ + LSPResource getResource(); + + LogisticChainElement getPreviousElement(); + + LogisticChainElement getNextElement(); + + /** + * This collection stores LSPShipments that are waiting for their treatment in this element or + * more precisely the Resource that is in charge of the actual physical handling. + * + * @return WaitingShipments + */ + WaitingShipments getIncomingShipments(); + + /** Shipments that have already been treated. */ + WaitingShipments getOutgoingShipments(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElementImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElementImpl.java new file mode 100644 index 00000000000..757c7714e5b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainElementImpl.java @@ -0,0 +1,103 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +/* package-private */ class LogisticChainElementImpl extends LSPDataObject + implements LogisticChainElement { + + private final LSPResource resource; + private final WaitingShipments incomingShipments; + private final WaitingShipments outgoingShipments; + // die beiden nicht im Builder. Die können erst in der Solution als ganzes gesetzt werden + private LogisticChainElement previousElement; + private LogisticChainElement nextElement; + + LogisticChainElementImpl(LSPUtils.LogisticChainElementBuilder builder) { + super(builder.id); + this.resource = builder.resource; + this.incomingShipments = builder.incomingShipments; + this.outgoingShipments = builder.outgoingShipments; + resource.getClientElements().add(this); + } + + @Override + public void connectWithNextElement(LogisticChainElement element) { + this.nextElement = element; + ((LogisticChainElementImpl) element).previousElement = this; + } + + @Override + public LSPResource getResource() { + return resource; + } + + @Override + public WaitingShipments getIncomingShipments() { + return incomingShipments; + } + + @Override + public WaitingShipments getOutgoingShipments() { + return outgoingShipments; + } + + @Override + public void setEmbeddingContainer(LogisticChain logisticChain) { + /* not */ + } + + @Override + public LogisticChainElement getPreviousElement() { + return previousElement; + } + + @Override + public LogisticChainElement getNextElement() { + return nextElement; + } + + @Override + public String toString() { + StringBuilder strb = new StringBuilder(); + strb.append("LogisticsSolutionElementImpl{") + .append("resourceId=") + .append(resource.getId()) + .append(", incomingShipments=") + .append(incomingShipments) + .append(", outgoingShipments=") + .append(outgoingShipments); + + if (previousElement != null) { + strb.append(", previousElementId=").append(previousElement.getId()); + } else { + strb.append(", previousElementId=").append("null"); + } + + if (nextElement != null) { + strb.append(", nextElementId=").append(nextElement.getId()); + } else { + strb.append(", nextElementId=").append("null"); + } + + strb.append('}'); + return strb.toString(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainImpl.java new file mode 100644 index 00000000000..a8d50917504 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainImpl.java @@ -0,0 +1,97 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Collection; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.shipment.LspShipment; + +/* package-private */ class LogisticChainImpl extends LSPDataObject + implements LogisticChain { + private static final Logger log = LogManager.getLogger(LogisticChainImpl.class); + + private final Collection logisticChainElements; + private final Collection> lspShipmentIds; + private LSP lsp; + + LogisticChainImpl(LSPUtils.LogisticChainBuilder builder) { + super(builder.id); + this.logisticChainElements = builder.elements; + for (LogisticChainElement element : this.logisticChainElements) { + element.setEmbeddingContainer(this); + } + this.lspShipmentIds = new ArrayList<>(); + } + + @Override + public LSP getLSP() { + return lsp; + } + + @Override + public void setLSP(LSP lsp) { + this.lsp = lsp; + } + + @Override + public Collection getLogisticChainElements() { + return logisticChainElements; + } + + @Override + public Collection> getLspShipmentIds() { + return lspShipmentIds; + } + + @Override + public void addShipmentToChain(LspShipment lspShipment) { + lspShipmentIds.add(lspShipment.getId()); + } + + @Override + public String toString() { + StringBuilder strb = new StringBuilder(); + strb.append("LogisticsSolutionImpl{") + .append("[No of SolutionsElements=") + .append(logisticChainElements.size()) + .append("] \n"); + if (!logisticChainElements.isEmpty()) { + strb.append("{SolutionElements="); + for (LogisticChainElement solutionElement : logisticChainElements) { + strb.append("\n [").append(solutionElement.toString()).append("]"); + } + strb.append("}"); + } + strb.append("[No of Shipments=").append(lspShipmentIds.size()).append("] \n"); + if (!lspShipmentIds.isEmpty()) { + strb.append("{ShipmentIds="); + for (Id lspShipmentId : lspShipmentIds) { + strb.append("[").append(lspShipmentId.toString()).append("]"); + } + strb.append("}"); + } + strb.append('}'); + return strb.toString(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainScheduler.java new file mode 100644 index 00000000000..e950405e979 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LogisticChainScheduler.java @@ -0,0 +1,47 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * Serve the purpose of routing a set of {@link LspShipment}s + * through a set of {@link LogisticChain}s, which, in turn, consist of several {@link + * LogisticChainElement}s and the corresponding {@link LSPResource}s. + */ +public interface LogisticChainScheduler extends HasBackpointer { + + void scheduleLogisticChain(); + + /** + * The buffer time is only taken into account in planning / scheduling. The idea is to + * ensure that the goods are available for the next ressource "in time", because the scheduling + * does not take into account any congestion during the simulation. E.g. if multiple vehicle are + * leaving the depot at the same time and thus influence each other.
+ * It is not intended to be available as buffer in the simulation itself -> It does not + * influence the events and shipmentLogs. As a consequence, the transportation (in simulation, + * events, ...) is in many cases earlier than scheduled. (Information from TM after asking; KMT + * 17.11.23) + * + * @param bufferTime for scheduling [in sec] + */ + void setBufferTime(int bufferTime); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipments.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipments.java new file mode 100644 index 00000000000..55e72fa3e5d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipments.java @@ -0,0 +1,51 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.Collection; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * Each LogisticsSolutionElement maintains two collections of WaitingShipments. Instances of the + * latter class contain tuples of LSPShipments and time stamps. + * + *

The first of these collections stores LSPShipments that are waiting for their treatment in + * this element or more precisely the Resource that is in charge of the actual physical handling. + * + *

The second one stores shipments that have already been treated. + * + *

At the beginning of the scheduling process, all LSPShipments are added to the collection of + * incoming shipments of the first LogisticsSolutionElement of the LogisticsSolution to which they + * were assigned before. The tuples in the collection of WaitingShipments thus consist of the + * shipments themselves and a time stamp that states when they arrived there (see 3.9). In the case + * of the first LogisticsSolutionElement, this time stamp corresponds to the start time window of + * the LSPShipment + */ +public interface WaitingShipments { + + void addShipment(double time, LspShipment lspShipment); + + Collection getSortedLspShipments(); + + Collection getLspShipmentsWTime(); + + void clear(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipmentsImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipmentsImpl.java new file mode 100644 index 00000000000..6404d32a802 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/WaitingShipmentsImpl.java @@ -0,0 +1,73 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/* package-private */ class WaitingShipmentsImpl implements WaitingShipments { + + private final List shipments; + + WaitingShipmentsImpl() { + this.shipments = new ArrayList<>(); + } + + @Override + public void addShipment(double time, LspShipment lspShipment) { + LspShipmentUtils.setTimeOfLspShipment(lspShipment, time); + this.shipments.add(lspShipment); + shipments.sort(Comparator.comparingDouble(LspShipmentUtils::getTimeOfLspShipment)); + } + + @Override + public Collection getSortedLspShipments() { + shipments.sort(Comparator.comparingDouble(LspShipmentUtils::getTimeOfLspShipment)); + return shipments; + } + + public void clear() { + shipments.clear(); + } + + @Override + public Collection getLspShipmentsWTime() { + return shipments; + } + + @Override + public String toString() { + StringBuilder strb = new StringBuilder(); + strb.append("WaitingShipmentsImpl{").append("No of Shipments= ").append(shipments.size()); + if (!shipments.isEmpty()) { + strb.append("; ShipmentIds="); + for (LspShipment shipment : getSortedLspShipments()) { + strb.append("[").append(shipment.getId()).append("]"); + } + } + strb.append('}'); + return strb.toString(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Driver2VehicleEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Driver2VehicleEventHandler.java new file mode 100644 index 00000000000..5cfde304930 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Driver2VehicleEventHandler.java @@ -0,0 +1,72 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.analysis; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; +import org.matsim.api.core.v01.events.handler.VehicleEntersTrafficEventHandler; +import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; +import org.matsim.api.core.v01.population.Person; +import org.matsim.vehicles.Vehicle; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Basic event handler that collects the relation between vehicles and drivers. + * Necessary since link enter and leave events do not contain the driver anymore. + *

+ * This is the vice-versa implementation of {@link org.matsim.core.events.algorithms.Vehicle2DriverEventHandler}. + *

+ * In a first step only used internally. When needed more often, I have nothing against putting it more central. -> matsim-libs + * + * @author kturner + */ +public class Driver2VehicleEventHandler implements VehicleEntersTrafficEventHandler, VehicleLeavesTrafficEventHandler { + + private final Map, Id> driversVehicles = new ConcurrentHashMap<>(); + + @Override + public void reset(int iteration) { + driversVehicles.clear(); + } + + @Override + public void handleEvent(VehicleEntersTrafficEvent event) { + driversVehicles.put(event.getPersonId(), event.getVehicleId()); + } + + @Override + public void handleEvent(VehicleLeavesTrafficEvent event) { + driversVehicles.remove(event.getPersonId()); + } + + /** + * @param personId the unique driver identifier. + * @return vehicle id of the driver's vehicle + */ + public Id getVehicleOfDriver(Id personId) { + return driversVehicles.get(personId); + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStats.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStats.java new file mode 100644 index 00000000000..297e99fc5b7 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStats.java @@ -0,0 +1,35 @@ + +/* + * *********************************************************************** * + * * project: org.matsim.* + * * ScoreStats.java + * * * + * * *********************************************************************** * + * * * + * * copyright : (C) 2014 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.analysis; + +import java.util.Map; + +public interface LspScoreStats { + + /** + * @return the history of scores in last iterations + */ + Map> getScoreHistory(); + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsControlerListener.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsControlerListener.java new file mode 100644 index 00000000000..2a687b82f0f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsControlerListener.java @@ -0,0 +1,286 @@ +/* *********************************************************************** * + * project: org.matsim.* + * ScoreStats.java + * * + * *********************************************************************** * + * * + * copyright : (C) 2007 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + +package org.matsim.freight.logistics.analysis; + +import jakarta.inject.Inject; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.*; +import java.util.stream.Collectors; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.config.groups.ControllerConfigGroup; +import org.matsim.core.config.groups.GlobalConfigGroup; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.events.IterationEndsEvent; +import org.matsim.core.controler.events.ShutdownEvent; +import org.matsim.core.controler.events.StartupEvent; +import org.matsim.core.controler.listener.IterationEndsListener; +import org.matsim.core.controler.listener.ShutdownListener; +import org.matsim.core.controler.listener.StartupListener; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.utils.charts.XYLineChart; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LSPs; + +/** + * Calculates at the end of each iteration the following statistics: + *

    + *
  • average score of the selected plan
  • + *
  • average of the score of the worst plan of each agent
  • + *
  • average of the score of the best plan of each agent
  • + *
  • average of the average score of all plans of each agent
  • + *
+ * Plans with undefined scores + * are not included in the statistics. The calculated values are written to a file, each iteration on + * a separate line. + * + * @author mrieser + */ +public class LspScoreStatsControlerListener implements StartupListener, IterationEndsListener, ShutdownListener, LspScoreStats { + + private static final String LSP_SCORESTATS = "lsp_scorestats"; + + public enum ScoreItem { worst, best, average, executed } + + private final LSPs lsps; + private final OutputDirectoryHierarchy controllerIO; + private final String delimiter; + private final BufferedWriter out; + + private final ControllerConfigGroup controllerConfigGroup; + + private final Map> scoreHistory = new HashMap<>(); + + private final Map perLsp = new HashMap<>(); + + private int minIteration = 0; + + private final static Logger log = LogManager.getLogger(LspScoreStatsControlerListener.class); + + @Inject + LspScoreStatsControlerListener(ControllerConfigGroup controllerConfigGroup, Scenario scenario, OutputDirectoryHierarchy controllerIO, + GlobalConfigGroup globalConfig ) { + this.controllerConfigGroup = controllerConfigGroup; + this.lsps = LSPUtils.getLSPs(scenario); + this.controllerIO = controllerIO; + this.delimiter = globalConfig.getDefaultDelimiter(); + this.out = IOUtils.getBufferedWriter(controllerIO.getOutputFilename(LSP_SCORESTATS + ".csv")); + + //TODO: Das hier dann mal ansehen, weil es ja nun nicht mehr via Subpobulations ist.. Vermutlich brauche ich nur die LSPIds... + Set lspIds = lsps.getLSPs().values().stream() + .map(PopulationUtils::getSubpopulation) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + for (String lspId : lspIds) { + this.perLsp.put(lspId, new ScoreHist(new HashMap<>(), IOUtils.getBufferedWriter(controllerIO.getOutputFilename(LSP_SCORESTATS + "_" + lspId + ".csv")))); + } + + try { + this.out.write("iteration" + this.delimiter + "avg_executed" + this.delimiter + + "avg_worst" + this.delimiter + "avg_average" + this.delimiter + "avg_best\n"); + for (Map.Entry e : this.perLsp.entrySet()) { + e.getValue().out.write("iteration" + this.delimiter + "avg_executed" + this.delimiter + + "avg_worst" + this.delimiter + "avg_average" + this.delimiter + "avg_best\n"); + } + + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public void notifyStartup(final StartupEvent event) { + this.minIteration = this.controllerConfigGroup.getFirstIteration(); + // int maxIter = controlerConfigGroup.getLastIteration(); + // int iterations = maxIter - this.minIteration; + // if (iterations > 5000) iterations = 5000; // limit the history size + for ( ScoreItem item : ScoreItem.values() ) { + this.scoreHistory.put( item, new TreeMap<>() ) ; + this.perLsp.forEach((s, data) -> data.hist.put(item, new TreeMap<>())); + } + } + + @Override + public void notifyIterationEnds(final IterationEndsEvent event) { + collectScoreInfo(event); + if (isWriteGraph(event)) { + writePng(); + } + } + + private boolean isWriteGraph(IterationEndsEvent event) { + // create chart when data of more than one iteration is available. + return this.controllerConfigGroup.getCreateGraphsInterval() > 0 && + event.getIteration() % this.controllerConfigGroup.getCreateGraphsInterval() == 0 && + event.getIteration() > this.minIteration; + } + + private void collectScoreInfo(final IterationEndsEvent event) { + ScoreInfo info = new ScoreInfo(); + + Map perLsp = new HashMap<>(); + this.perLsp.forEach((subpop, d) -> perLsp.put(subpop, new ScoreInfo())); + + for (LSP lsp : this.lsps.getLSPs().values()) { + info.update(lsp); + String subpop = PopulationUtils.getSubpopulation(lsp); + if (subpop != null) + perLsp.get(subpop).update(lsp); + } + + + log.info("-- avg. score of the executed plan of each agent: " + (info.sumExecutedScores / info.nofExecutedScores)); + log.info("-- avg. score of the worst plan of each agent: " + (info.sumScoreWorst / info.nofScoreWorst)); + log.info("-- avg. of the avg. plan score per agent: " + (info.sumAvgScores / info.nofAvgScores)); + log.info("-- avg. score of the best plan of each agent: " + (info.sumScoreBest / info.nofScoreBest)); + + try { + info.write(event.getIteration(), this.out, this.delimiter); + for (Map.Entry e : this.perLsp.entrySet()) { + perLsp.get(e.getKey()).write(event.getIteration(), e.getValue().out, this.delimiter); + } + + } catch (IOException e) { + e.printStackTrace(); + } + +// int index = event.getIteration() - this.minIteration; + + this.scoreHistory.get( ScoreItem.worst ).put( event.getIteration(), info.sumScoreWorst / info.nofScoreWorst ) ; + this.scoreHistory.get( ScoreItem.best ).put( event.getIteration(), info.sumScoreBest / info.nofScoreBest ) ; + this.scoreHistory.get( ScoreItem.average ).put( event.getIteration(), info.sumAvgScores / info.nofAvgScores ) ; + this.scoreHistory.get( ScoreItem.executed ).put( event.getIteration(), info.sumExecutedScores / info.nofExecutedScores ) ; + } + + private void writePng() { + XYLineChart chart = new XYLineChart("Score Statistics", "iteration", "score"); + chart.addSeries("avg. worst score", this.scoreHistory.get( ScoreItem.worst ) ) ; + chart.addSeries("avg. best score", this.scoreHistory.get( ScoreItem.best) ); + chart.addSeries("avg. of plans' average score", this.scoreHistory.get( ScoreItem.average) ); + chart.addSeries("avg. executed score", this.scoreHistory.get( ScoreItem.executed ) ); + chart.addMatsimLogo(); + chart.saveAsPng(this.controllerIO.getOutputFilename(LSP_SCORESTATS + ".png"), 800, 600); + } + + @Override + public void notifyShutdown(final ShutdownEvent controlerShudownEvent) { + try { + this.out.close(); + for (ScoreHist data : this.perLsp.values()) { + data.out.close(); + } + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + + @Override + public Map> getScoreHistory() { + return Collections.unmodifiableMap( this.scoreHistory ) ; + } + + private record ScoreHist(Map> hist, BufferedWriter out) {} + + private static final class ScoreInfo { + double sumScoreWorst = 0.0; + double sumScoreBest = 0.0; + double sumAvgScores = 0.0; + double sumExecutedScores = 0.0; + int nofScoreWorst = 0; + int nofScoreBest = 0; + int nofAvgScores = 0; + int nofExecutedScores = 0; + + private void update(LSP lsp) { + LSPPlan worstPlan = null; + LSPPlan bestPlan = null; + double worstScore = Double.POSITIVE_INFINITY; + double bestScore = Double.NEGATIVE_INFINITY; + double sumScores = 0.0; + double cntScores = 0; + for (LSPPlan plan : lsp.getPlans()) { + + if (plan.getScore() == null) { + continue; + } + double score = plan.getScore(); + + // worst plan + if (worstPlan == null) { + worstPlan = plan; + worstScore = score; + } else if (score < worstScore) { + worstPlan = plan; + worstScore = score; + } + + // best plan + if (bestPlan == null) { + bestPlan = plan; + bestScore = score; + } else if (score > bestScore) { + bestPlan = plan; + bestScore = score; + } + + // avg. score + sumScores += score; + cntScores++; + + // executed plan? + if (LSPUtils.isPlanTheSelectedPlan(plan)) { + this.sumExecutedScores += score; + this.nofExecutedScores++; + } + } + + if (worstPlan != null) { + this.nofScoreWorst++; + this.sumScoreWorst += worstScore; + } + if (bestPlan != null) { + this.nofScoreBest++; + this.sumScoreBest += bestScore; + } + if (cntScores > 0) { + this.sumAvgScores += (sumScores / cntScores); + this.nofAvgScores++; + } + } + + private void write(int iteration, BufferedWriter out, String delimiter) throws IOException { + out.write(iteration + delimiter + + (this.sumExecutedScores / this.nofExecutedScores) + delimiter + + (this.sumScoreWorst / this.nofScoreWorst) + delimiter + + (this.sumAvgScores / this.nofAvgScores) + delimiter + + (this.sumScoreBest / this.nofScoreBest) + "\n"); + out.flush(); + } + + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsModule.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsModule.java new file mode 100644 index 00000000000..948b206388d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/LspScoreStatsModule.java @@ -0,0 +1,35 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * ScoreStatsModule.java + * * * + * * *********************************************************************** * + * * * + * * copyright : (C) 2014 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.analysis; + +import com.google.inject.Singleton; +import org.matsim.core.controler.AbstractModule; + +public class LspScoreStatsModule extends AbstractModule { + @Override + public void install() { + bind(LspScoreStatsControlerListener.class).in(Singleton.class); + addControlerListenerBinding().to(LspScoreStatsControlerListener.class); + bind(LspScoreStats.class).to(LspScoreStatsControlerListener.class); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Vehicle2CarrierEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Vehicle2CarrierEventHandler.java new file mode 100644 index 00000000000..d7230ab3d41 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Vehicle2CarrierEventHandler.java @@ -0,0 +1,71 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.analysis; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourEndEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourStartEventHandler; +import org.matsim.vehicles.Vehicle; + +/** + * Basic event handler that collects the relation between vehicles and carrier. + * Necessary since there is no event having all this information together. + *

+ * This is a modified implementation of {@link org.matsim.core.events.algorithms.Vehicle2DriverEventHandler}. + *

+ * In a first step only used internally. When needed more often, I have nothing against putting it more central. -> matsim-libs + * + * @author kturner + */ +public class Vehicle2CarrierEventHandler implements CarrierTourStartEventHandler, CarrierTourEndEventHandler { + + private final Map, Id> vehicle2carrier = new ConcurrentHashMap<>(); + + @Override + public void reset(int iteration) { + vehicle2carrier.clear(); + } + + @Override + public void handleEvent(CarrierTourStartEvent event) { + vehicle2carrier.put(event.getVehicleId(), event.getCarrierId()); + } + + @Override + public void handleEvent(CarrierTourEndEvent event) { + vehicle2carrier.remove(event.getVehicleId()); + } + + /** + * @param vehicleId the unique vehicle Id + * @return id of the vehicle's carrier + */ + public Id getCarrierOfVehicle(Id vehicleId) { + return vehicle2carrier.get(vehicleId); + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/AbstractLogisticEvent.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/AbstractLogisticEvent.java new file mode 100644 index 00000000000..fd9791a6831 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/AbstractLogisticEvent.java @@ -0,0 +1,55 @@ +package org.matsim.freight.logistics.events; + +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.Event; +import org.matsim.api.core.v01.events.HasLinkId; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.logistics.HasLspShipmentId; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * A general logistic event contains the information (= {@link Id}) of the - the location (= {@link + * Link}) - the lspShipment (= {@link LspShipment}) belonging to it. + * + *

Please note, that general _freight_ events can be found in the freight contrib. + * + * @author Kai Martins-Turner (kturner) + */ +public abstract class AbstractLogisticEvent extends Event implements HasLinkId, HasLspShipmentId { + + private final Id linkId; + private final Id lspShipmentId; + + public AbstractLogisticEvent(double time, Id linkId, Id lspShipmentId) { + super(time); + this.linkId = linkId; + this.lspShipmentId = lspShipmentId; + } + + /** + * @return id of the {@link LspShipment} + */ + @Override + public final Id getLspShipmentId() { + return lspShipmentId; + } + + @Override + public final Id getLinkId() { + return linkId; + } + + /** + * Adds the {@link Id< LspShipment >} to the list of attributes. {@link Id} is handled by + * superclass {@link Event} + * + * @return The map of attributes + */ + @Override + public Map getAttributes() { + Map attr = super.getAttributes(); + attr.put(ATTRIBUTE_LSP_SHIPMENT_ID, lspShipmentId.toString()); + return attr; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartedEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartedEventHandler.java new file mode 100644 index 00000000000..b8b9c6e900e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartedEventHandler.java @@ -0,0 +1,11 @@ +package org.matsim.freight.logistics.events; + +import org.matsim.core.events.handler.EventHandler; + +/** + * @author Kai Martins-Turner (kturner) + */ +public interface HandlingInHubStartedEventHandler extends EventHandler { + + void handleEvent(HandlingInHubStartsEvent event); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartsEvent.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartsEvent.java new file mode 100644 index 00000000000..c7e9f4a754d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/HandlingInHubStartsEvent.java @@ -0,0 +1,88 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + * + */ + +package org.matsim.freight.logistics.events; + +import static org.matsim.freight.logistics.events.LspEventAttributes.ATTRIBUTE_EXP_HANDLING_DURATION; +import static org.matsim.freight.logistics.events.LspEventAttributes.ATTRIBUTE_HUB_ID; + +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.GenericEvent; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * An event, that informs that the handling of a {@link LspShipment} in a hub has started. + * + * @author Kai Martins-Turner (kturner) + */ +public final class HandlingInHubStartsEvent extends AbstractLogisticEvent { + + public static final String EVENT_TYPE = "Handling_started"; + private final Id hubId; + private final double expHandlingDuration; + + public HandlingInHubStartsEvent( + double time, + Id linkId, + Id lspShipmentId, + Id hubId, + double expHandlingDuration) { + super(time, linkId, lspShipmentId); + this.hubId = hubId; + this.expHandlingDuration = expHandlingDuration; + } + + public static HandlingInHubStartsEvent convert(GenericEvent event) { + Map attributes = event.getAttributes(); + double time = Double.parseDouble(attributes.get(ATTRIBUTE_TIME)); + Id linkId = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); + Id lspSipmentId = + Id.create(attributes.get(ATTRIBUTE_LSP_SHIPMENT_ID), LspShipment.class); + var hubId = Id.create(attributes.get(ATTRIBUTE_HUB_ID), LSPResource.class); + double expHandlingDuration = + Double.parseDouble(attributes.get(ATTRIBUTE_EXP_HANDLING_DURATION)); + return new HandlingInHubStartsEvent(time, linkId, lspSipmentId, hubId, expHandlingDuration); + } + + @Override + public String getEventType() { + return EVENT_TYPE; + } + + public Id getHubId() { + return hubId; + } + + public double getExpHandlingDuration() { + return expHandlingDuration; + } + + @Override + public Map getAttributes() { + Map attr = super.getAttributes(); + attr.put(ATTRIBUTE_HUB_ID, hubId.toString()); + attr.put(ATTRIBUTE_EXP_HANDLING_DURATION, String.valueOf(expHandlingDuration)); + return attr; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventAttributes.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventAttributes.java new file mode 100644 index 00000000000..830862b6f5b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventAttributes.java @@ -0,0 +1,32 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + * + */ + +package org.matsim.freight.logistics.events; + +/** + * Some constants, that are used for the Attributes of different logistic events. + * + * @author Kai Martins-Turner (kturner) + */ +public class LspEventAttributes { + public static final String ATTRIBUTE_HUB_ID = "hubId"; + public static final String ATTRIBUTE_EXP_HANDLING_DURATION = "expHandlingDuration"; +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java new file mode 100644 index 00000000000..b5a0933fa7c --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java @@ -0,0 +1,36 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + * + */ + +package org.matsim.freight.logistics.events; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.Event; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * @author Kai Martins-Turner (kturner) + */ +public interface LspEventCreator { + + // I am unsure, if I need the activity or not. kmt 'dec22 + Event createEvent(Event event, Id lspShipmentId, Activity activity); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java new file mode 100644 index 00000000000..1380da69044 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java @@ -0,0 +1,54 @@ +/* + * *********************************************************************** * + * project: org.matsim.* + * *********************************************************************** * + * * + * copyright : (C) by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + * + */ + +package org.matsim.freight.logistics.events; + +import java.util.Map; +import java.util.TreeMap; + +import org.matsim.freight.logistics.LSP; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.events.MatsimEventsReader; +import org.matsim.freight.carriers.events.CarrierEventsReaders; + +/** + * Creates an {@link MatsimEventsReader} that also handles the {@link + * LSP} specific events. + * + * @author kturner (Kai Martins-Turner) + */ +public class LspEventsReader { + + public static Map createCustomEventMappers() { + Map map = + new TreeMap<>( + CarrierEventsReaders + .createCustomEventMappers()); // also get all the Carrier-related EventMapper + map.put(HandlingInHubStartsEvent.EVENT_TYPE, HandlingInHubStartsEvent::convert); + return map; + } + + public static MatsimEventsReader createEventsReader(EventsManager eventsManager) { + MatsimEventsReader reader = new MatsimEventsReader(eventsManager); + createCustomEventMappers().forEach(reader::addCustomEventMapper); + return reader; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/ExampleConstants.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/ExampleConstants.java new file mode 100644 index 00000000000..02939778990 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/ExampleConstants.java @@ -0,0 +1,83 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples; + +import java.util.Arrays; +import java.util.List; + +public class ExampleConstants { + //Both, the ingoing and outgoing links are tolled. -> Please be aware of it. + public static final List TOLLED_LINK_LIST_BERLIN_BOTH_DIRECTIONS = + Arrays.asList( + "70831", "14691", "49319", "70830", "17284", "65008", "65007", "62413", "17283", "144164", + "144165", "4606", "118311", "4607", "15423", "53820", "15422", "138286", "69167", + "138287", "17057", "74648", "74647", "113641", "10307", "10306", "51775", "155051", + "51776", "150042", "150043", "150164", "90583", "96329", "19320", "132511", "19321", + "64851", "144180", "34042", "124770", "34041", "74891", "144184", "124769", "35018", + "35017", "77379", "35256", "108717", "113640", "157261", "142799", "157262", "52995", + "934", "52996", "935", "95587", "95588", "17150", "147460", "147461", "54024", "54023", + "152801", "144506", "145715", "144505", "156464", "17125", "17126", "114545", "114546", + "140792", "17127", "17248", "17128", "17249", "156458", "35463", "159609", "35462", + "159608", "22046", "154715", "22047", "144373", "154716", "155927", "155926", "144372", + "96330", "61139", "98190", "144126", "144127", "61011", "61010", "156463", "63682", + "47555", "73006", "94867", "138930", "94866", "133488", "138931", "47554", "73005", + "58893", "116395", "116394", "144136", "1158", "1157", "58894", "61269", "79237", + "144137", "732", "149702", "733", "77854", "4785", "55946", "77855", "4786", "55945", + "90018", "61264", "61263", "86201", "77738", "120646", "77739", "26507", "108414", + "108415", "17115", "66841", "26506", "78255", "78254", "118561", "35447", "147535", + "17116", "118560", "61270", "102480", "51917", "62494", "72973", "51918", "72972", + "72050", "72051", "147027", "33258", "61169", "18419", "102479", "20863", "61170", + "43048", "43049", "69459", "73037", "18420", "69458", "3255", "3254", "73036", "27017", + "76094", "41429", "74241", "76095", "149583", "74240", "35426", "81688", "81689", "12686", + "25848", "25849", "64459", "115416", "149592", "74374", "115417", "81474", "81475", + "36983", "36984", "36985", "36986", "52917", "52918", "64460", "40311", "108695", "40310", + "79385", "119212", "155909", "119213", "119334", "119335", "112023", "48277", "48278", + "106946", "91853", "91854", "102288", "69129", "102287", "13607", "2985", "64482", + "156612", "8983", "156613", "67517", "28548", "28549", "83543", "145734", "83542", + "149536", "149537", "151175", "151174", "18159", "8994", "93250", "147370", "53001", + "5918", "24153", "79875", "147369", "36147", "53002", "138543", "138542", "104212", + "137699", "137698", "41960", "104211", "18160", "41723", "41724", "3505", "123744", + "81389", "104205", "104206", "112065", "49320", "84772", "37107", "142803"); + public static final List TOLLED_LINK_LIST_GRID = Arrays.asList( + "i(3,4)", "i(3,6)", "i(7,5)R", "i(7,7)R", "j(4,8)R", "j(6,8)R", "j(3,4)", "j(5,4)"); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfInitialPlan.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfInitialPlan.java new file mode 100644 index 00000000000..29afe8dbb14 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfInitialPlan.java @@ -0,0 +1,211 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/*package-private*/ class ExampleSchedulingOfInitialPlan { + + private static LSP createInitialLSP(Scenario scenario) { + + // The Carrier for the resource of the sole LogisticsSolutionElement of the LSP is created + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = + CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities capabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(carrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + // The Resource i.e. the Resource is created + LSPResource collectionResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + carrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the only LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement collectionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + // The LogisticsSolutionElement is now inserted into the only LogisticsSolution of the LSP + LogisticChain collectionSolution = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("CollectionSolution", LogisticChain.class)) + .addLogisticChainElement(collectionElement) + .build(); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + InitialShipmentAssigner assigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + LogisticChainScheduler simpleScheduler = + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + + return LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)) + .setInitialPlan(collectionPlan) + .setLogisticChainScheduler(simpleScheduler) + .build(); + } + + private static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + // Create five LSPShipments that are located in the left half of the network. + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(Id.createLinkId("(4 2) (4 3)")); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public static void main(String[] args) { + + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + // Create LSP and lspShipments + LSP lsp = createInitialLSP(scenario); + Collection lspShipments = createInitialLSPShipments(network); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the lspShipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // print the schedules for the assigned LSPShipments + for (LspShipment lspShipment : lspShipments) { + System.out.println("Shipment: " + lspShipment.getId()); + ArrayList scheduleElements = + new ArrayList<>( + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = + new ArrayList<>(lspShipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement element : + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .values()) { + System.out.println( + // "Solution Id: " + element.getSolutionElement().getEmbeddingContainer().getId() + + " SolutionElement Id: " + + element.getLogisticChainElement().getId() + + " Resource Id: " + + element.getResourceId() + + " Type: " + + element.getElementType() + + " Start Time: " + + element.getStartTime() + + " End Time: " + + element.getEndTime()); + } + System.out.println(); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChain.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChain.java new file mode 100644 index 00000000000..fc3ea48678f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChain.java @@ -0,0 +1,390 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.DistributionCarrierResourceBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/*A transport chain with five elements (collection-> reloading -> main run -> reloading -> delivery) is created and scheduled + * + */ + +/*package-private*/ class ExampleSchedulingOfTransportChain { + + private static LSP createInitialLSP(Scenario scenario) { + + Network network = scenario.getNetwork(); + + // The Carrier for collection is created + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = + CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(capabilities); + + // The collection adapter i.e. the Resource is created + LSPResource collectionResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + collectionCarrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement collectionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + // The first reloading adapter i.e. the Resource is created + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + TransshipmentHubBuilder firstTransshipmentHubBuilder = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + + // The scheduler for the first reloading point is created + final LSPResourceScheduler firstHubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + // The scheduler is added to the Resource and the Resource is created + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstHubScheduler); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + // The SolutionElement for the first reloading point is created + Id firstHubElementId = + Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + // The Carrier for the main run Resource is created + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + final VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + mainRunVehType.setNetworkMode(TransportMode.car); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = + CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities mainRunCapabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(mainRunCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + // The adapter i.e. the main run resource is created + LSPResource mainRunResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .build(); + + // The LogisticsSolutionElement for the main run Resource is created + LogisticChainElement mainRunElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + // The second reloading adapter i.e. the Resource is created + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + // The scheduler for the second reloading point is created + LSPResourceScheduler secondHubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource secondTransshipmentHubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario) + .setTransshipmentHubScheduler(secondHubScheduler) + .build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + Id secondHubElementId = + Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTransshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + // The Carrier for distribution is created + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + final VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + distributionVehType.setNetworkMode(TransportMode.car); + + + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = + CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder distributionCapabilitiesBuilder = + CarrierCapabilities.Builder.newInstance(); + distributionCapabilitiesBuilder.addVehicle(distributionCarrierVehicle); + distributionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = distributionCapabilitiesBuilder.build(); + Carrier distributionCarrier = CarriersUtils.createCarrier(distributionCarrierId); + distributionCarrier.setCarrierCapabilities(distributionCapabilities); + + // The distribution adapter i.e. the Resource is created + DistributionCarrierResourceBuilder distributionResourceBuilder = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier); + distributionResourceBuilder.setLocationLinkId(distributionLinkId); + + // The scheduler for the Resource is created and added. This is where jsprit comes into play. + distributionResourceBuilder.setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)); + LSPResource distributionResource = distributionResourceBuilder.build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + Id distributionElementId = + Id.create("DistributionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder distributionBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId); + distributionBuilder.setResource(distributionResource); + LogisticChainElement distributionElement = distributionBuilder.build(); + + // The Order of the logisticsSolutionElements is now specified + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + // The SolutionElements are now inserted into the only LogisticsSolution of the LSP + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = + LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + completeSolutionBuilder.addLogisticChainElement(distributionElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan completePlan = LSPUtils.createLSPPlan(); + InitialShipmentAssigner assigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = + LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTransshipmentHubResource); + resourcesList.add(distributionResource); + + // SolutionScheduler forwardSolutionScheduler = LSPUtils.createForwardSolutionScheduler(); + // //Ist der "nicht einfache" Scheduler. TODO braucht der keine RessourcenListe oder ähnliches? + // --> Offenbar ja, weil Null Pointer. argh! + // completeLSPBuilder.setSolutionScheduler(forwardSolutionScheduler); + + LogisticChainScheduler simpleScheduler = + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + + return completeLSPBuilder.build(); + } + + private static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 + && pendingToLink.getFromNode().getCoord().getY() <= 4000 + && pendingToLink.getFromNode().getCoord().getX() >= 14000 + && pendingToLink.getToNode().getCoord().getX() <= 18000 + && pendingToLink.getToNode().getCoord().getY() <= 4000 + && pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + } + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public static void main(String[] args) { + + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + // Create LSP and shipments + LSP lsp = createInitialLSP(scenario); + Collection lspShipments = createInitialLSPShipments(scenario.getNetwork()); + + // assign the shipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the shipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // print the schedules for the assigned LSPShipments + for (LspShipment lspShipment : lsp.getLspShipments()) { + ArrayList elementList = + new ArrayList<>( + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + System.out.println("Shipment: " + lspShipment.getId()); + for (LspShipmentPlanElement element : elementList) { + System.out.println( + element.getLogisticChainElement().getId() + + "\t\t" + + element.getResourceId() + + "\t\t" + + element.getElementType() + + "\t\t" + + element.getStartTime() + + "\t\t" + + element.getEndTime()); + } + System.out.println(); + } + + // for (LSPResource lspResource : lsp.getResources()) { + // if (lspResource instanceof Carrier ) { + // ((Carrier) lspResource).getShipments().toString(); + // } + // } + // the above cast keeps complaining when I refactor; in consequence, I am becoming doubtful if + // this condition can ever be satisfied. + // also not sure what the code stub might be doing: It is converting to string, but not doing + // anything with it. kai, may'22 + + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirect.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirect.java new file mode 100644 index 00000000000..d2062b18450 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirect.java @@ -0,0 +1,624 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.CommandLine; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.carriers.events.CarrierServiceEndEvent; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceEndEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourEndEventHandler; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * The LSP have to possibilities to send the goods from the first depot to the recipients: A) via + * another hub and then distributed or B) directly from the depot + * + *

This examples bases on the Example ExampleSchedulingOfTransportChain.class -- the collection + * Part is removed, Chain is now starting at the CollectionHub + * + *

Scheduler = Macht die Pläne für die Fahrzeuge für die nächste MATSim-Iteration. Er plant es + * für jede Ressource. --> jede Ressource hat einen eigenen Scheduler: 1.) Simple: Nimm die + * mitgegebene Reihenfolge. 2.) + */ +/*package-private*/ final class ExampleSchedulingOfTransportChainHubsVsDirect { + + private static final Logger log = + LogManager.getLogger(ExampleSchedulingOfTransportChainHubsVsDirect.class); + + private ExampleSchedulingOfTransportChainHubsVsDirect() {} // so it cannot be instantiated + + public static void main(String[] args) { + + final SolutionType solutionType; + + for (String arg : args) { + log.warn(arg); + } + + // Set up required MATSim classes + + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + + CommandLine cmd = ConfigUtils.getCommandLine(args); + solutionType = SolutionType.valueOf(cmd.getOption("solutionType").orElseThrow()); + + } else { + solutionType = SolutionType.onePlan_direct; + log.warn("SolutionType was set in code to: {}", solutionType); + config.controller().setOutputDirectory("output/ChainVsDirect/" + solutionType); + config.controller().setLastIteration(2); + } + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + config.vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + log.warn("solutionType= {}", solutionType); + + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + log.info("Starting ..."); + log.info("Set up required MATSim classes"); + + Scenario scenario = ScenarioUtils.loadScenario(config); + + // ######## + + log.info("create LSP"); + LSP lsp = createInitialLSP(scenario, solutionType); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments(scenario.getNetwork())) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + log.info("Set up simulation controler and LSPModule"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(lsp))); + + // @KMT: LSPModule ist vom Design her nur im Zusammenhang mit dem Controler sinnvoll. Damit kann + // man dann auch vollständig auf + // Injection setzen. + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + + // bind( LSPStrategyManager.class ).toInstance( new + // LSPModule.LSPStrategyManagerEmptyImpl() ); + // The above means there will be no replanning. The below needs at least one strategy + // to be happy. kai, jul'22 + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + }); + + log.info("Run MATSim"); + + controler.run(); + + // print the schedules for the assigned LSPShipments + log.info("print the schedules for the assigned LSPShipments"); + ResourceImplementationUtils.printResults_shipmentPlan( + config.controller().getOutputDirectory(), lsp); + + log.info("Done."); + } + + private static LSP createInitialLSP(Scenario scenario, SolutionType solutionType) { + + Network network = scenario.getNetwork(); + + LSPUtils.LSPBuilder lspBuilder = + switch (solutionType) { + case onePlan_withHub -> LSPUtils.LSPBuilder.getInstance( + Id.create("LSPwithReloading", LSP.class)); + case onePlan_direct, twoPlans_directAndHub -> LSPUtils.LSPBuilder.getInstance(Id.create("LSPdirect", LSP.class)); + }; + + // lspBuilder.setSolutionScorer(new MyLSPScorer()); + + final Id depotLinkId = + Id.createLinkId("(4 2) (4 3)"); // TODO: Hochziehen aber non-static. + final Id hubLinkId = Id.createLinkId("(14 2) (14 3)"); + + LogisticChainElement depotElement; + { + // The SolutionElement for the first reloading point is created + + log.info(""); + log.info("Create depot"); + + // The scheduler for the first reloading point is created --> this will be the depot in this + // use case + LSPResourceScheduler depotScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) // Time needed, fixed (for Scheduler) + .setCapacityNeedLinear(1) // additional time needed per shipmentSize (for Scheduler) + .build(); + + // The scheduler is added to the Resource and the Resource is created + LSPResource depotResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Depot", LSPResource.class), depotLinkId, scenario) + .setTransshipmentHubScheduler(depotScheduler) + .build(); + + depotElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("DepotElement", LogisticChainElement.class)) + .setResource(depotResource) + .build(); // Nicht unbedingt nötig, aber nehme den alten Hub nun als Depot. Waren + // werden dann dort "Zusammengestellt". + // Maybe TODO: Depot als LogisticSolutionElement raus nehmen.(?) + } + + // The LogisticsSolutionElement for the main run Resource is created + LogisticChainElement mainRunElement; + { + log.info(""); + log.info("The Carrier for the main run is created"); + Carrier mainRunCarrier = + CarriersUtils.createCarrier(Id.create("MainRunCarrier", Carrier.class)); + + Id mainRunCarrierVehicleType = Id.create("MainRunCarrierVehicleType", VehicleType.class); + VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunCarrierVehicleType, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + mainRunVehType.setNetworkMode(TransportMode.car); + + CarrierVehicle mainRunCarrierVehicle = + CarrierVehicle.Builder.newInstance( + Id.createVehicleId("MainRunVehicle"), depotLinkId, mainRunVehType) + .build(); + + mainRunCarrier.setCarrierCapabilities( + CarrierCapabilities.Builder.newInstance() + .addVehicle(mainRunCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build()); + + // The scheduler for the main run Resource is created and added to the Resource + LSPResource mainRunResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setFromLinkId(depotLinkId) + .setToLinkId(hubLinkId) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .build(); + + mainRunElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + } + + LogisticChainElement hubElement; + { + log.info(""); + log.info("The second reloading adapter (hub) i.e. the Resource is created"); + // The scheduler for the second reloading point is created + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + // The scheduler is added to the Resource and the Resource is created + // The second reloading adapter i.e. the Resource is created + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + secondTransshipmentHubId, hubLinkId, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + hubElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("SecondHubElement", LogisticChainElement.class)) + .setResource(hubResource) + .build(); + } + + LogisticChainElement distributionElement; + { + // The Carrier for distribution from reloading Point is created + VehicleType distributionVehType = + createCarrierVehicleType("DistributionCarrierVehicleType"); + + CarrierVehicle distributionCarrierVehicle = + CarrierVehicle.Builder.newInstance( + Id.createVehicleId("DistributionVehicle"), hubLinkId, distributionVehType) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("DistributionCarrier", Carrier.class)); + distributionCarrier.setCarrierCapabilities( + CarrierCapabilities.Builder.newInstance() + .addVehicle(distributionCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build()); + + // The distribution adapter i.e. the Resource is created + LSPResource distributionResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setLocationLinkId(hubLinkId) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + // (The scheduler is where jsprit comes into play.) + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + + distributionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("DistributionElement", LogisticChainElement.class)) + .setResource(distributionResource) + .build(); + } + + // ### New (KMT): Carrier for direct distribution from Depot (without 2nd reloading Point) + LogisticChainElement directDistributionElement; + { + // The Carrier for distribution from reloading Point is created + VehicleType directdistributionVehType = + createCarrierVehicleType("DirectDistributionCarrierVehicleType"); + + CarrierVehicle directDistributionCarrierVehicle = + CarrierVehicle.Builder.newInstance( + Id.createVehicleId("DirectDistributionVehicle"), + depotLinkId, + directdistributionVehType) + .build(); + + CarrierCapabilities directDistributionCarrierCapabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(directDistributionCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier directDistributionCarrier = + CarriersUtils.createCarrier(Id.create("DirectDistributionCarrier", Carrier.class)); + directDistributionCarrier.setCarrierCapabilities(directDistributionCarrierCapabilities); + + // The distribution adapter i.e. the Resource is created + LSPResource directDistributionResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + directDistributionCarrier) + .setLocationLinkId(depotLinkId) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + // (The scheduler is where jsprit comes into play.) + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + directDistributionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("DirectDistributionElement", LogisticChainElement.class)) + .setResource(directDistributionResource) + .build(); + } + // ### end new + + // TODO: Beide Lösungen anbieten und "bessere" oder zunächst "eine" auswählen" + + // TODO: Für die Auswahl "CostInfo an die Solutions dran heften. + + // The SolutionElements are now inserted into the only LogisticsSolution of the LSP. + // Die Reihenfolge des Hinzufügens ist egal, da weiter oben die jeweils direkten + // Vorgänger/Nachfolger bestimmt wurden. + + switch (solutionType) { + case onePlan_withHub -> { + // ### This is the original solution with mainRun - TranshipmentHub - distributionRun + log.info("Creating LSP with one plan: reloading at hub"); + + LSPPlan lspPlan_Reloading = + createLSPPlan_reloading(depotElement, mainRunElement, hubElement, distributionElement); + + return lspBuilder + .setInitialPlan(lspPlan_Reloading) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlan(lspPlan_Reloading))) + .build(); + } + case onePlan_direct -> { + // ### This is the new solution with directDistribution from the Depot. + log.info("Creating LSP with one plan: direct distribution from the depot"); + + LSPPlan lspPlan_direct = createLSPPlan_direct(depotElement, directDistributionElement); + + return lspBuilder + .setInitialPlan(lspPlan_direct) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlan(lspPlan_direct))) + .build(); + } + case twoPlans_directAndHub -> { + log.info( + "Creating LSP with two plans: i) direct distribution from the depot ii) reloading at hub"); + + log.error( + "This is totally untested. I can neither say if it will work nor if it will do anything useful - kmt feb22"); + + // TODO: Habe das vorziehen vor das switch statement rückgängig gemacht, weil es sideeffekte + // hatte -> Die dürften hier auch sein!!!! (KMT may22) + // Die createLSPPlan_reloading(..) Methoden sind nicht unabhängig voneinander. + // Das liegt wohl am statischen und das dann dort wieder Verknüpfungen gesetzt werden --> + // Hier auch aufpassen + LSPPlan lspPlan_Reloading = + createLSPPlan_reloading(depotElement, mainRunElement, hubElement, distributionElement); + LSPPlan lspPlan_direct = createLSPPlan_direct(depotElement, directDistributionElement); + + // TODO: Müsste nicht eigentlich der SolutionScheduler dann auf Ebene der einzelnen Pläne + // (mit ihren Solutions) sein?? kmt Feb22 + // So muss ich erst die Ressourcen aus beiden hinzuzufügenden Plänen aufsammeln, damit die + // dann schon in den Builder können. Irgendwie unschön. + List resourcesList = createResourcesListFromLSPPlan(lspPlan_direct); + resourcesList.addAll(createResourcesListFromLSPPlan(lspPlan_Reloading)); + + final LSP lsp = + lspBuilder + .setInitialPlan(lspPlan_direct) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + resourcesList)) + .build(); + + lsp.addPlan(lspPlan_Reloading); // adding the second plan + + return lsp; + } + default -> throw new IllegalStateException("Unexpected value: " + solutionType); + } + } + + private static List createResourcesListFromLSPPlan(LSPPlan lspPlanWithReloading) { + log.info("Collecting all LSPResources from the LSPPlan"); + List resourcesList = + new ArrayList<>(); // TODO: Mahe daraus ein Set, damit jede Resource nur einmal drin ist? + // kmt Feb22 + for (LogisticChain solution : lspPlanWithReloading.getLogisticChains()) { + for (LogisticChainElement solutionElement : solution.getLogisticChainElements()) { + resourcesList.add(solutionElement.getResource()); + } + } + return resourcesList; + } + + private static LSPPlan createLSPPlan_direct( + LogisticChainElement depotElement, LogisticChainElement directDistributionElement) { + log.info(""); + log.info("The order of the logisticsSolutionElements is now specified"); + depotElement.connectWithNextElement(directDistributionElement); + + log.info(""); + log.info("set up logistic Solution - direct distribution from the depot is created"); + + LogisticChain completeSolutionDirect = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("SolutionDirectId", LogisticChain.class)) + .addLogisticChainElement(depotElement) + .addLogisticChainElement(directDistributionElement) + .build(); + + log.info(""); + log.info( + "The initial plan of the lsp is generated and the assigner and the solution from above are added"); + + return LSPUtils.createLSPPlan() + .setInitialShipmentAssigner(ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner()) + .addLogisticChain(completeSolutionDirect); + } + + private static LSPPlan createLSPPlan_reloading( + LogisticChainElement depotElement, + LogisticChainElement mainRunElement, + LogisticChainElement hubElement, + LogisticChainElement distributionElement) { + log.info(""); + log.info("set up logistic Solution - original with hub usage solution is created"); + + // Das ist wichtig, damit er die Kette zur Verfügung hat. + depotElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(hubElement); + hubElement.connectWithNextElement(distributionElement); + + LogisticChain completeSolutionWithReloading = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("SolutionWithTransshipmentHubId", LogisticChain.class)) + .addLogisticChainElement(depotElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(hubElement) + .addLogisticChainElement(distributionElement) + .build(); + + log.info(""); + log.info( + "The initial plan of the lsp is generated and the assigner and the solution from above are added"); + + return LSPUtils.createLSPPlan() + .setInitialShipmentAssigner(ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner()) + .addLogisticChain(completeSolutionWithReloading); + } + + private static VehicleType createCarrierVehicleType(String vehicleTypeId) { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create(vehicleTypeId, VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(10); + vehicleType.getCostInformation().setCostsPerMeter(0.0004); + vehicleType.getCostInformation().setCostsPerSecond(0.38); + vehicleType.getCostInformation().setFixedCost(49.); + vehicleType.setMaximumVelocity(50 / 3.6); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 + && pendingToLink.getFromNode().getCoord().getY() <= 4000 + && pendingToLink.getFromNode().getCoord().getX() >= 14000 + && pendingToLink.getToNode().getCoord().getX() <= 18000 + && pendingToLink.getToNode().getCoord().getY() <= 4000 + && pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + } + + builder.setFromLinkId( + Id.createLinkId( + "(4 2) (4 3)")); // Here was the "first" reloading Point, now called depot. + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment lspShipment = builder.build(); + shipmentList.add(lspShipment); + } + return shipmentList; + } + + enum SolutionType { + onePlan_withHub, + onePlan_direct, + twoPlans_directAndHub + } + + private static class MyLSPScorer + implements LSPScorer, CarrierTourEndEventHandler, CarrierServiceEndEventHandler { + private double score = 0.; + + @Override + public double getScoreForCurrentPlan() { + return score; + } + + @Override + public void setEmbeddingContainer(LSP pointer) {} + + @Override + public void handleEvent(CarrierTourEndEvent event) { + score++; + // use event handlers to compute score. In this case, score is incremented by one every time + // a CarrierService and a tour ends. + } + + @Override + public void reset(int iteration) { + score = 0.; + } + + @Override + public void handleEvent(CarrierServiceEndEvent event) { + score++; + // use event handlers to compute score. In this case, score is incremented by one every time + // a CarrierService and a tour ends. + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTestOutput.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTestOutput.java new file mode 100644 index 00000000000..8a0fbd8ce12 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTestOutput.java @@ -0,0 +1,60 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; + +class ExampleTestOutput { + + public static void main(String[] args) { + + Config config = + ConfigUtils.loadConfig( + IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("equil"), "config.xml")); + + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setLastIteration(1); + + Scenario scenario = ScenarioUtils.loadScenario(config); + + Controler controler = new Controler(scenario); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid.java new file mode 100644 index 00000000000..a776131e925 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid.java @@ -0,0 +1,537 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.CommandLine; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * This is an academic example for the 2-echelon problem. It uses the 9x9-grid network from the + * matsim-examples. + * + *

The depot is located at the outer border of the network, while the jobs are located in the + * middle area. The {@link LSP} has two different {@link LSPPlan}s: 1) direct delivery from the + * depot 2) Using a TransshipmentHubResource: All goods were brought from the depot to the hub, + * reloaded and then brought from the hub to the customers + * + *

The decision which of these plans is chosen should be made via the Score of the plans. We will + * modify the costs of the vehicles and/or for using(having) the Transshipment hub. Depending on + * this setting, the plan selection should be done accordingly. + * + *

Please note: This example is in part on existing examples, but I start from the scratch for a) + * see, if this works and b) have a "clean" class :) + * + * @author Kai Martins-Turner (kturner) + */ +final class ExampleTwoEchelonGrid { + + // Run Settings + static final double HUBCOSTS_FIX = 100; + private static final DemandSetting demandSetting = DemandSetting.oneCustomer; + private static final CarrierCostSetting costSetting = CarrierCostSetting.lowerCost4LastMile; + private static final double TOLL_VALUE = 1000; + + private static final Logger log = LogManager.getLogger(ExampleTwoEchelonGrid.class); + + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final Id HUB_LINK_ID = Id.createLinkId("j(5,3)"); + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + + private ExampleTwoEchelonGrid() {} // so it cannot be instantiated + + public static void main(String[] args) { + log.info("Prepare Config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare Controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + // bind( CarrierScoringFunctionFactory.class ).toInstance( new MyCarrierScorer()); + final MyEventBasedCarrierScorer carrierScorer = new MyEventBasedCarrierScorer(); + carrierScorer.setToll(TOLL_VALUE); + + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + } + }); + + log.info("Run MATSim"); + log.warn("Runs settings were: Demand: {}\n CarrierCosts: {}\n HubCosts: " + HUBCOSTS_FIX + "\n tollValue: " + TOLL_VALUE, demandSetting, costSetting); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Some results ...."); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printScores(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printShipmentsOfLSP( + controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentPlan( + controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog( + controler.getControlerIO().getOutputPath(), lsp); + } + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + + CommandLine cmd = ConfigUtils.getCommandLine(args); + } else { + config + .controller() + .setOutputDirectory( + "output/2echelon_" + + demandSetting + + "_" + + costSetting + + "_" + + HUBCOSTS_FIX + + "_" + + TOLL_VALUE); + config.controller().setLastIteration(2); + } + + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + // Change speed on all links to 30 km/h (8.33333 m/s) for easier computation --> Freeflow TT per + // link is 2min + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + LSPPlan lspPlan_direct; + { + log.info("Create lspPlan for direct delivery"); + + Carrier directCarrier = + CarriersUtils.createCarrier(Id.create("directCarrier", Carrier.class)); + directCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + directCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("directTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource directCarrierRessource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + directCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement directCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("directCarrierLSE", LogisticChainElement.class)) + .setResource(directCarrierRessource) + .build(); + + LogisticChain solution_direct = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("directSolution", LogisticChain.class)) + .addLogisticChainElement(directCarrierElement) + .build(); + + final InitialShipmentAssigner singleSolutionShipmentAssigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + lspPlan_direct = + LSPUtils.createLSPPlan() + .addLogisticChain(solution_direct) + .setInitialShipmentAssigner(singleSolutionShipmentAssigner); + } + + LSPPlan lspPlan_withHub; + { + log.info("Create lspPlan with Hub"); + + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierRessource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainCarrier) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierLSE = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierLSE", LogisticChainElement.class)) + .setResource(mainCarrierRessource) + .build(); + + // The scheduler for the first reloading point is created --> this will be the depot in this + // use case + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) // Time needed, fixed (for Scheduler) + .setCapacityNeedLinear(1) // additional time needed per shipmentSize (for Scheduler) + .build(); + + // The scheduler is added to the Resource and the Resource is created + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Hub", LSPResource.class), HUB_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + LSPUtils.setFixedCost( + hubResource, HUBCOSTS_FIX); // Set fixed costs (per day) for the availability of the hub. + + LogisticChainElement hubLSE = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubLSE", LogisticChainElement.class)) + .setResource(hubResource) + .build(); // Nicht unbedingt nötig, aber nehme den alten Hub nun als Depot. Waren + // werden dann dort "Zusammengestellt". + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + final VehicleType vehType; + switch (costSetting) { + case sameCost -> vehType = VEH_TYPE_LARGE_50; + case lowerCost4LastMile -> vehType = VEH_TYPE_SMALL_05; + default -> throw new IllegalStateException("Unexpected value: " + costSetting); + } + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_LINK_ID, vehType)); + LSPResource distributionCarrierRessource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierLSE", LogisticChainElement.class)) + .setResource(distributionCarrierRessource) + .build(); + + // Kettenbildung per hand, damit dann klar ist, wie das Scheduling ablaufen soll. TODO: + // Vielleicht bekommt man das noch eleganter hin. + // z.B. in der Reihenfolge in der die solutionsElements der LogisticsSolution zugeordnet + // werden: ".addSolutionElement(..)" + mainCarrierLSE.connectWithNextElement(hubLSE); + hubLSE.connectWithNextElement(distributionCarrierElement); + + LogisticChain solution_withHub = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubSolution", LogisticChain.class)) + .addLogisticChainElement(mainCarrierLSE) + .addLogisticChainElement(hubLSE) + .addLogisticChainElement(distributionCarrierElement) + .build(); + + lspPlan_withHub = + LSPUtils.createLSPPlan() + .addLogisticChain(solution_withHub) + .setInitialShipmentAssigner(ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner()); + } + + // Todo: Auch das ist wirr: Muss hier alle sammeln, damit man die dann im LSPBuilder dem + // SolutionScheduler mitgeben kann. Im Nachgang packt man dann aber erst den zweiten Plan dazu + // ... urgs KMT'Jul22 + List lspPlans = new ArrayList<>(); + lspPlans.add(lspPlan_withHub); + lspPlans.add(lspPlan_direct); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(lspPlan_direct) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + lsp.addPlan(lspPlan_withHub); // add the second plan to the lsp + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments(network)) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments(Network network) { + List shipmentList = new ArrayList<>(); + + switch (demandSetting) { + case oneCustomer -> { + Id id = Id.create("Shipment_" + 1, LspShipment.class); + int capacityDemand = 1; + + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + builder.setToLinkId(Id.createLinkId("i(5,5)R")); + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + + return shipmentList; + } + case tenCustomers -> { + Random rand1 = MatsimRandom.getLocalInstance(); + Random rand2 = MatsimRandom.getLocalInstance(); + + List zoneLinkList = + Arrays.asList( + "i(4,4)", "i(5,4)", "i(6,4)", "i(4,6)", "i(5,6)", "i(6,6)", "j(3,5)", "j(3,6)", + "j(3,7)", "j(5,5)", "j(5,6)", "j(5,7)", "i(4,5)R", "i(5,5)R", "i(6,5)R", "i(4,7)R", + "i(5,7)R", "i(6,7)R", "j(4,5)R", "j(4,6)R", "j(4,7)R", "j(6,5)R", "j(6,6)R", + "j(6,7)R"); + for (String linkIdString : zoneLinkList) { + if (!network.getLinks().containsKey(Id.createLinkId(linkIdString))) { + throw new RuntimeException("Link is not in Network!"); + } + } + + for (int i = 1; i <= 10; i++) { + Id id = Id.create("Shipment_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = + LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + int capacityDemand = + rand1.nextInt(5) + 1; // Random is drawn from 0 (incl) to bound (excl) -> adding 1. + builder.setCapacityDemand(capacityDemand); + + builder.setFromLinkId(DEPOT_LINK_ID); + final Id toLinkId = + Id.createLinkId(zoneLinkList.get(rand2.nextInt(zoneLinkList.size() - 1))); + builder.setToLinkId(toLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + return shipmentList; + } + default -> throw new IllegalStateException("Unexpected value: " + demandSetting); + } + } + + // TODO: This is maybe something that can go into a utils class ... KMT jul22 + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourcesList = + new ArrayList<>(); // TODO: Mache daraus ein Set, damit jede Resource nur einmal drin ist? + // kmt Feb22 + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain solution : lspPlan.getLogisticChains()) { + for (LogisticChainElement solutionElement : solution.getLogisticChainElements()) { + resourcesList.add(solutionElement.getResource()); + } + } + } + return resourcesList; + } + + enum DemandSetting { + oneCustomer, + tenCustomers + } + + enum CarrierCostSetting { + sameCost, + lowerCost4LastMile + } + + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + // @Override public ScoringFunction createScoringFunction(Carrier carrier ){ + // + // return new ScoringFunction(){ + // + // private double score; + // + // @Override public void handleActivity( Activity activity ){ + // score--; + // } + // @Override public void handleLeg( Leg leg ){ + // score = score - 10; + // } + // @Override public void agentStuck( double time ){ + // } + // @Override public void addMoney( double amount ){ + // } + // @Override public void addScore( double amount ){ + // } + // @Override public void finish(){ + // } + // @Override public double getScore(){ + // return score; + // } + // @Override public void handleEvent( Event event ){ + // score = score - 0.01; + // } + // }; + // } + // } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid_NR.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid_NR.java new file mode 100644 index 00000000000..18525885ce7 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid_NR.java @@ -0,0 +1,546 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.CommandLine; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.io.LSPPlanXmlReader; +import org.matsim.freight.logistics.io.LSPPlanXmlWriter; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * This is an academic example for the 2-echelon problem. It uses the 9x9-grid network from the + * matsim-examples. + * + *

The depot is located at the outer border of the network, while the jobs are located in the + * middle area. The {@link LSP} has two different {@link LSPPlan}s: 1) direct delivery from the + * depot 2) Using a TransshipmentHubResource: All goods were brought from the depot to the hub, + * reloaded and then brought from the hub to the customers + * + *

The decision which of these plans is chosen should be made via the Score of the plans. We will + * modify the costs of the vehicles and/or for using(having) the Transshipment hub. Depending on + * this setting, the plan selection should be done accordingly. + * + *

Please note: This example is in part on existing examples, but I start from the scratch for a) + * see, if this works and b) have a "clean" class :) + * + * @author Kai Martins-Turner (kturner) + */ +final class ExampleTwoEchelonGrid_NR { + + // Run Settings + static final double HUBCOSTS_FIX = 100; + private static final DemandSetting demandSetting = DemandSetting.tenCustomers; + private static final CarrierCostSetting costSetting = CarrierCostSetting.lowerCost4LastMile; + private static final double TOLL_VALUE = 1000; + + private static final Logger log = LogManager.getLogger(ExampleTwoEchelonGrid_NR.class); + + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final Id HUB_LINK_ID = Id.createLinkId("j(5,3)"); + + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private ExampleTwoEchelonGrid_NR() {} // so it cannot be instantiated + + public static void main(String[] args) { + log.info("Prepare Config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare Controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + // bind( CarrierScoringFunctionFactory.class ).toInstance( new MyCarrierScorer()); + final MyEventBasedCarrierScorer carrierScorer = new MyEventBasedCarrierScorer(); + carrierScorer.setToll(TOLL_VALUE); + + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + } + }); + + log.info("Run MATSim"); + log.warn("Runs settings were: Demand: {}\n CarrierCosts: {}\n HubCosts: " + HUBCOSTS_FIX + "\n tollValue: " + TOLL_VALUE, demandSetting, costSetting); + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + // Ggf. muss der Ordner noch erstellt werden (?) + new LSPPlanXmlWriter(LSPUtils.getLSPs(controler.getScenario())) + .write(controler.getConfig().controller().getOutputDirectory() + "/lsps.xml"); + new LSPPlanXmlReader( + LSPUtils.getLSPs(controler.getScenario()), + CarriersUtils.getCarriers(controler.getScenario())); + new CarrierPlanWriter(CarriersUtils.getCarriers(controler.getScenario())) + .write(controler.getConfig().controller().getOutputDirectory() + "/carriers.xml"); + + log.info("Some results ...."); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printScores(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printShipmentsOfLSP( + controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentPlan( + controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog( + controler.getControlerIO().getOutputPath(), lsp); + } + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + + CommandLine cmd = ConfigUtils.getCommandLine(args); + } else { + config + .controller() + .setOutputDirectory( + "output/2echelon_" + + demandSetting + + "_" + + costSetting + + "_" + + HUBCOSTS_FIX + + "_" + + TOLL_VALUE); + config.controller().setLastIteration(2); + } + + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.overwriteExistingFiles); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + // Change speed on all links to 30 km/h (8.33333 m/s) for easier computation --> Freeflow TT per + // link is 2min + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + LSPPlan lspPlan_direct; + { + log.info("Create lspPlan for direct delivery"); + + Carrier directCarrier = + CarriersUtils.createCarrier(Id.create("directCarrier", Carrier.class)); + directCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + directCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("directTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource directCarrierRessource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + directCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement directCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("directCarrierLSE", LogisticChainElement.class)) + .setResource(directCarrierRessource) + .build(); + + LogisticChain solution_direct = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("directSolution", LogisticChain.class)) + .addLogisticChainElement(directCarrierElement) + .build(); + + final InitialShipmentAssigner singleSolutionShipmentAssigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + lspPlan_direct = + LSPUtils.createLSPPlan() + .addLogisticChain(solution_direct) + .setInitialShipmentAssigner(singleSolutionShipmentAssigner); + } + + LSPPlan lspPlan_withHub; + { + log.info("Create lspPlan with Hub"); + + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierRessource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainCarrier) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierLSE = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierLSE", LogisticChainElement.class)) + .setResource(mainCarrierRessource) + .build(); + + // The scheduler for the first reloading point is created --> this will be the depot in this + // use case + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) // Time needed, fixed (for Scheduler) + .setCapacityNeedLinear(1) // additional time needed per shipmentSize (for Scheduler) + .build(); + + // The scheduler is added to the Resource and the Resource is created + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Hub", LSPResource.class), HUB_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + LSPUtils.setFixedCost( + hubResource, HUBCOSTS_FIX); // Set fixed costs (per day) for the availability of the hub. + + LogisticChainElement hubLSE = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubLSE", LogisticChainElement.class)) + .setResource(hubResource) + .build(); // Nicht unbedingt nötig, aber nehme den alten Hub nun als Depot. Waren + // werden dann dort "Zusammengestellt". + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + final VehicleType vehType; + switch (costSetting) { + case sameCost -> vehType = VEH_TYPE_LARGE_50; + case lowerCost4LastMile -> vehType = VEH_TYPE_SMALL_05; + default -> throw new IllegalStateException("Unexpected value: " + costSetting); + } + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_LINK_ID, vehType)); + LSPResource distributionCarrierRessource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierLSE", LogisticChainElement.class)) + .setResource(distributionCarrierRessource) + .build(); + + // Kettenbildung per hand, damit dann klar ist, wie das Scheduling ablaufen soll. TODO: + // Vielleicht bekommt man das noch eleganter hin. + // z.B. in der Reihenfolge in der die solutionsElements der LogisticsSolution zugeordnet + // werden: ".addSolutionElement(..)" + mainCarrierLSE.connectWithNextElement(hubLSE); + hubLSE.connectWithNextElement(distributionCarrierElement); + + LogisticChain solution_withHub = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubSolution", LogisticChain.class)) + .addLogisticChainElement(mainCarrierLSE) + .addLogisticChainElement(hubLSE) + .addLogisticChainElement(distributionCarrierElement) + .build(); + + lspPlan_withHub = + LSPUtils.createLSPPlan() + .addLogisticChain(solution_withHub) + .setInitialShipmentAssigner(ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner()); + } + + // Todo: Auch das ist wirr: Muss hier alle sammeln, damit man die dann im LSPBuilder dem + // SolutionScheduler mitgeben kann. Im Nachgang packt man dann aber erst den zweiten Plan dazu + // ... urgs KMT'Jul22 + List lspPlans = new ArrayList<>(); + lspPlans.add(lspPlan_withHub); + lspPlans.add(lspPlan_direct); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(lspPlan_direct) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + lsp.addPlan(lspPlan_withHub); // add the second plan to the lsp + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments(network)) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments(Network network) { + List shipmentList = new ArrayList<>(); + + switch (demandSetting) { + case oneCustomer -> { + Id id = Id.create("Shipment_" + 1, LspShipment.class); + int capacityDemand = 1; + + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + builder.setToLinkId(Id.createLinkId("i(5,5)R")); + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + + return shipmentList; + } + case tenCustomers -> { + Random rand1 = MatsimRandom.getLocalInstance(); + Random rand2 = MatsimRandom.getLocalInstance(); + + List zoneLinkList = + Arrays.asList( + "i(4,4)", "i(5,4)", "i(6,4)", "i(4,6)", "i(5,6)", "i(6,6)", "j(3,5)", "j(3,6)", + "j(3,7)", "j(5,5)", "j(5,6)", "j(5,7)", "i(4,5)R", "i(5,5)R", "i(6,5)R", "i(4,7)R", + "i(5,7)R", "i(6,7)R", "j(4,5)R", "j(4,6)R", "j(4,7)R", "j(6,5)R", "j(6,6)R", + "j(6,7)R"); + for (String linkIdString : zoneLinkList) { + if (!network.getLinks().containsKey(Id.createLinkId(linkIdString))) { + throw new RuntimeException("Link is not in Network!"); + } + } + + for (int i = 1; i <= 10; i++) { + Id id = Id.create("Shipment_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = + LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + int capacityDemand = + rand1.nextInt(5) + 1; // Random is drawn from 0 (incl) to bound (excl) -> adding 1. + builder.setCapacityDemand(capacityDemand); + + builder.setFromLinkId(DEPOT_LINK_ID); + final Id toLinkId = + Id.createLinkId(zoneLinkList.get(rand2.nextInt(zoneLinkList.size() - 1))); + builder.setToLinkId(toLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + return shipmentList; + } + default -> throw new IllegalStateException("Unexpected value: " + demandSetting); + } + } + + // TODO: This is maybe something that can go into a utils class ... KMT jul22 + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourcesList = + new ArrayList<>(); // TODO: Mache daraus ein Set, damit jede Resource nur einmal drin ist? + // kmt Feb22 + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain solution : lspPlan.getLogisticChains()) { + for (LogisticChainElement solutionElement : solution.getLogisticChainElements()) { + resourcesList.add(solutionElement.getResource()); + } + } + } + return resourcesList; + } + + enum DemandSetting { + oneCustomer, + tenCustomers + } + + enum CarrierCostSetting { + sameCost, + lowerCost4LastMile + } + + // @Override public ScoringFunction createScoringFunction(Carrier carrier ){ + // + // return new ScoringFunction(){ + // + // private double score; + // + // @Override public void handleActivity( Activity activity ){ + // score--; + // } + // @Override public void handleLeg( Leg leg ){ + // score = score - 10; + // } + // @Override public void agentStuck( double time ){ + // } + // @Override public void addMoney( double amount ){ + // } + // @Override public void addScore( double amount ){ + // } + // @Override public void finish(){ + // } + // @Override public double getScore(){ + // return score; + // } + // @Override public void handleEvent( Event event ){ + // score = score - 0.01; + // } + // }; + // } + // } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyCarrierScorer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyCarrierScorer.java new file mode 100644 index 00000000000..7ee4a9f4d74 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyCarrierScorer.java @@ -0,0 +1,61 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import org.matsim.core.scoring.ScoringFunction; +import org.matsim.core.scoring.SumScoringFunction; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; + +/** + * @author Kai Martins-Turner (kturner) + */ +class MyCarrierScorer implements CarrierScoringFunctionFactory { + + public ScoringFunction createScoringFunction(Carrier carrier) { + SumScoringFunction sf = new SumScoringFunction(); + TakeJspritScore takeJspritScore = new TakeJspritScore(carrier); + sf.addScoringFunction(takeJspritScore); + return sf; + } + + private class TakeJspritScore implements SumScoringFunction.BasicScoring { + + private final Carrier carrier; + + public TakeJspritScore(Carrier carrier) { + super(); + this.carrier = carrier; + } + + @Override + public void finish() {} + + @Override + public double getScore() { + if (carrier.getSelectedPlan().getScore() != null) { + return carrier.getSelectedPlan().getScore(); + } + return Double.NEGATIVE_INFINITY; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyEventBasedCarrierScorer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyEventBasedCarrierScorer.java new file mode 100644 index 00000000000..da264c45ca1 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyEventBasedCarrierScorer.java @@ -0,0 +1,219 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import jakarta.inject.Inject; +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.events.Event; +import org.matsim.api.core.v01.events.LinkEnterEvent; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.scoring.ScoringFunction; +import org.matsim.core.scoring.SumScoringFunction; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.Tour; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.logistics.examples.ExampleConstants; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * @author Kai Martins-Turner (kturner) + */ +class MyEventBasedCarrierScorer implements CarrierScoringFunctionFactory { + + @Inject private Network network; + + @Inject private Scenario scenario; + + private double toll; + + public ScoringFunction createScoringFunction(Carrier carrier) { + SumScoringFunction sf = new SumScoringFunction(); + sf.addScoringFunction(new EventBasedScoring()); + sf.addScoringFunction(new LinkBasedTollScoring(toll, List.of("large50"))); + return sf; + } + + void setToll(double toll) { + this.toll = toll; + } + + /** + * Calculate the carrier's score based on Events. Currently, it includes: - fixed costs (using + * CarrierTourEndEvent) - time-dependent costs (using FreightTourStart- and -EndEvent) - + * distance-dependent costs (using LinkEnterEvent) + */ + private class EventBasedScoring implements SumScoringFunction.ArbitraryEventScoring { + + final Logger log = LogManager.getLogger(EventBasedScoring.class); + private final double MAX_SHIFT_DURATION = 8 * 3600; + private final Map vehicleType2TourDuration = new LinkedHashMap<>(); + private final Map vehicleType2ScoredFixCosts = new LinkedHashMap<>(); + private final Map, Double> tourStartTime = new LinkedHashMap<>(); + private double score; + + public EventBasedScoring() { + super(); + } + + @Override + public void finish() {} + + @Override + public double getScore() { + return score; + } + + @Override + public void handleEvent(Event event) { + log.debug(event.toString()); + switch (event) { + case CarrierTourStartEvent freightTourStartEvent -> handleEvent(freightTourStartEvent); + case CarrierTourEndEvent freightTourEndEvent -> handleEvent(freightTourEndEvent); + case LinkEnterEvent linkEnterEvent -> handleEvent(linkEnterEvent); + default -> { + } + } + } + + private void handleEvent(CarrierTourStartEvent event) { + // Save time of freight tour start + tourStartTime.put(event.getTourId(), event.getTime()); + } + + // Fix costs for vehicle usage + private void handleEvent(CarrierTourEndEvent event) { + // Fix costs for vehicle usage + final VehicleType vehicleType = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)).getType(); + + double tourDuration = event.getTime() - tourStartTime.get(event.getTourId()); + { // limit fixed costs of vehicles if vehicles could be reused during shift + if (tourDuration > MAX_SHIFT_DURATION) { + throw new RuntimeException( + "Duration of tour is longer than max shift defined in scoring fct, caused by event:" + + event + + " tourDuration: " + + tourDuration + + " max shift duration: " + + MAX_SHIFT_DURATION); + } + + // sum up tour durations + if (vehicleType2TourDuration.containsKey(vehicleType)) { + vehicleType2TourDuration.put( + vehicleType, vehicleType2TourDuration.get(vehicleType) + tourDuration); + } else { + vehicleType2TourDuration.put(vehicleType, tourDuration); + } + + // scoring needed? + final double currentNuOfVehiclesNeeded = + Math.ceil(vehicleType2TourDuration.get(vehicleType) / MAX_SHIFT_DURATION); + final Integer nuAlreadyScored = vehicleType2ScoredFixCosts.get(vehicleType); + if (nuAlreadyScored == null) { + log.info("Score fixed costs for vehicle type: {}", vehicleType.getId().toString()); + score = score - vehicleType.getCostInformation().getFixedCosts(); + vehicleType2ScoredFixCosts.put(vehicleType, 1); + } else if (currentNuOfVehiclesNeeded > nuAlreadyScored) { + log.info("Score fixed costs for vehicle type: {}", vehicleType.getId().toString()); + score = score - vehicleType.getCostInformation().getFixedCosts(); + vehicleType2ScoredFixCosts.put( + vehicleType, vehicleType2ScoredFixCosts.get(vehicleType) + 1); + } + } + + // variable costs per time + score = score - (tourDuration * vehicleType.getCostInformation().getCostsPerSecond()); + } + + private void handleEvent(LinkEnterEvent event) { + final double distance = network.getLinks().get(event.getLinkId()).getLength(); + final double costPerMeter = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)) + .getType() + .getCostInformation() + .getCostsPerMeter(); + // variable costs per distance + score = score - (distance * costPerMeter); + } + } + + /** + * Calculate some toll for driving on a link This a lazy implementation of a cordon toll. A + * vehicle is only tolled once. + */ + class LinkBasedTollScoring implements SumScoringFunction.ArbitraryEventScoring { + + final Logger log = LogManager.getLogger(EventBasedScoring.class); + + private final double toll; + private final List vehicleTypesToBeTolled; + private final List> tolledVehicles = new ArrayList<>(); + private double score; + + public LinkBasedTollScoring(double toll, List vehicleTypesToBeTolled) { + super(); + this.toll = toll; + this.vehicleTypesToBeTolled = vehicleTypesToBeTolled; + } + + @Override + public void finish() {} + + @Override + public double getScore() { + return score; + } + + @Override + public void handleEvent(Event event) { + if (event instanceof LinkEnterEvent linkEnterEvent) { + handleEvent(linkEnterEvent); + } + } + + private void handleEvent(LinkEnterEvent event) { + List tolledLinkList = ExampleConstants.TOLLED_LINK_LIST_GRID; + + final Id vehicleTypeId = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)).getType().getId(); + + // toll a vehicle only once. + if (!tolledVehicles.contains(event.getVehicleId())) + if (vehicleTypesToBeTolled.contains(vehicleTypeId.toString())) { + if (tolledLinkList.contains(event.getLinkId().toString())) { + log.info("Tolling caused by event: {}", event); + tolledVehicles.add(event.getVehicleId()); + score = score - toll; + } + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyLSPScorer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyLSPScorer.java new file mode 100644 index 00000000000..3a70e72d252 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/MyLSPScorer.java @@ -0,0 +1,103 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.initialPlans; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.TransshipmentHubResource; + +/** + * A scorer for the LSP. It uses the scores of the - carriers: Take the carrier's score and add it + * to the LSP's score - hubs: currently a very simple fixed costs scoring (see below {@link + * #scoreHub()}) + * + * @author Kai Martins-Turner (kturner) + */ +/*package-private*/ class MyLSPScorer implements LSPScorer { + final Logger logger = LogManager.getLogger(MyLSPScorer.class); + private double score = 0; + private LSP lsp; + + @Override + public void reset(int iteration) { + score = 0.; + } + + @Override + public double getScoreForCurrentPlan() { + scoreLspCarriers(); + scoreHub(); + scoreMissingShipments(); + return score; + } + + private void scoreLspCarriers() { + var lspPlan = lsp.getSelectedPlan(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + if (logisticChainElement.getResource() instanceof LSPCarrierResource carrierResource) { + var carriersScore = carrierResource.getCarrier().getSelectedPlan().getScore(); + if (carriersScore != null) { + score = score + carriersScore; + } + } + } + } + } + + /** + * If a hub resource is in the selected plan of the LSP, it will get scored. + * + *

This is somehow a quickfix, because the hubs do **not** have any own events yet. This needs + * to be implemented later KMT oct'22 + */ + private void scoreHub() { + var lspPlan = lsp.getSelectedPlan(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + if (logisticChainElement.getResource() instanceof TransshipmentHubResource hub) { + score = score - LSPUtils.getFixedCost(hub); + } + } + } + } + + private void scoreMissingShipments() { + LSPPlan lspPlan = lsp.getSelectedPlan(); + int lspPlanShipmentCount = + lspPlan.getLogisticChains().stream() + .mapToInt(logisticChain -> logisticChain.getLspShipmentIds().size()) + .sum(); + if (lspPlanShipmentCount != lsp.getLspShipments().size()) { + logger.error( + "LspPlan doesn't contain the same number of shipments as LSP, " + + "shipments probably lost during replanning."); + score -= 10000; + } + } + + @Override + public void setEmbeddingContainer(LSP pointer) { + this.lsp = pointer; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/AssignmentStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/AssignmentStrategyFactory.java new file mode 100644 index 00000000000..cf2056d9bbc --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/AssignmentStrategyFactory.java @@ -0,0 +1,88 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspReplanning; + +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/** + * @deprecated This class is a work-around. Please do not use this method for any new runs! + *

The plan-handling below was previously done in the LSPControlerListener during replanning. + * Since we (nrichter, kturner) are now running with one replanning strategies, which will allow + * to move shipments within the same (LSP) plan to a different logisticChain. As a consequence, + * the code below is not needed for us (starting from now). More than that, it is in part + * working against the new workflow, because the (re) assignment should **not** be done during + * replanning anymore. + *

The code here is used so that the old stuff from (tm). It keeps this old behaviour (and + * tests passing) with its own strategy, instead running it for everyone. + *

nrichter, kturner Jul'23 + */ +@Deprecated +public class AssignmentStrategyFactory { + + public AssignmentStrategyFactory() {} + + public GenericPlanStrategy createStrategy() { + + GenericPlanStrategyImpl strategy = + new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()); + GenericPlanStrategyModule assignmentModule = + new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + for (LogisticChain solution : lspPlan.getLogisticChains()) { + solution.getLspShipmentIds().clear(); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + element.getIncomingShipments().clear(); + element.getOutgoingShipments().clear(); + } + } + + for (LspShipment lspShipment : lspPlan.getLSP().getLspShipments()) { + LspShipmentUtils.getOrCreateShipmentPlan(lspPlan, lspShipment.getId()).clear(); + lspShipment.getShipmentLog().clear(); + lspPlan.getInitialShipmentAssigner().assignToPlan(lspPlan, lspShipment); + } + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(assignmentModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/ExampleLSPReplanning.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/ExampleLSPReplanning.java new file mode 100644 index 00000000000..20bde8fb6a5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/ExampleLSPReplanning.java @@ -0,0 +1,31 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspReplanning; + +/** +* Please refer to the + * - org.matsim.freight.logistics.example.lsp.multipleChains.ExampleMultipleOneEchelonChainsReplanning for an example with Replanning + *

+ * - CollectionLSPReplanningTest for an idea, how replanning works (old way -- will be removed in the future). +*/ +@Deprecated +/*package-private*/ class ExampleLSPReplanning {} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/MaybeTodayAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/MaybeTodayAssigner.java new file mode 100644 index 00000000000..15850ba29de --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/MaybeTodayAssigner.java @@ -0,0 +1,56 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspReplanning; + +import java.util.Random; +import org.matsim.core.gbl.Gbl; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** +* This class is deprecated and will be removed in the future. + * It follows the old and no longer wanted approach. + * Now, an Assigner is used to assign all LSPShipments to one LogisticChain of the LSPPlan. + *

+ * This class here is in contrast used as a Replanning strategy. This behavior is not wanted anymore. + * KMT, Jul'24 +*/ +@Deprecated +/*package-private*/ class MaybeTodayAssigner implements InitialShipmentAssigner { + + private final Random random; + + public MaybeTodayAssigner() { + this.random = new Random(1); + } + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + boolean assignToday = random.nextBoolean(); + if (assignToday) { + Gbl.assertIf(lspPlan.getLogisticChains().size() == 1); + lspPlan.getLogisticChains().iterator().next().addShipmentToChain(lspShipment); + } + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/TomorrowShipmentAssignerStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/TomorrowShipmentAssignerStrategyFactory.java new file mode 100644 index 00000000000..2c96a7910b9 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/TomorrowShipmentAssignerStrategyFactory.java @@ -0,0 +1,92 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspReplanning; + +import java.util.Collection; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +@Deprecated +/*package-private*/ class TomorrowShipmentAssignerStrategyFactory { + + private final InitialShipmentAssigner assigner; + + /*package-private*/ TomorrowShipmentAssignerStrategyFactory(InitialShipmentAssigner assigner) { + this.assigner = assigner; + } + + /*package-private*/ GenericPlanStrategy createStrategy() { + GenericPlanStrategyImpl strategy = + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()); + + GenericPlanStrategyModule tomorrowModule = + new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) { + // TODO Auto-generated method stub + + } + + @Override + public void handlePlan(LSPPlan plan) { + plan.getLogisticChains().iterator().next().getLspShipmentIds().clear(); + plan.setInitialShipmentAssigner(assigner); + // LSP lsp = assigner.getLSP(); + LSP lsp = plan.getLSP(); + Collection lspShipments = lsp.getLspShipments(); + for (LspShipment lspShipment : lspShipments) { + assigner.assignToPlan(plan, lspShipment); + } + + for (LogisticChain solution : plan.getLogisticChains()) { + solution.getLspShipmentIds().clear(); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + element.getIncomingShipments().clear(); + element.getOutgoingShipments().clear(); + } + } + + for (LspShipment lspShipment : plan.getLSP().getLspShipments()) { + LspShipmentUtils.getOrCreateShipmentPlan(plan, lspShipment.getId()).clear(); + lspShipment.getShipmentLog().clear(); + plan.getInitialShipmentAssigner().assignToPlan(plan, lspShipment); + } + } + + @Override + public void finishReplanning() { + // TODO Auto-generated method stub + + } + }; + + strategy.addStrategyModule(tomorrowModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/package-info.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/package-info.java new file mode 100644 index 00000000000..3a42f344ada --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspReplanning/package-info.java @@ -0,0 +1,36 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/** + * @deprecated This package is deprecated and will be removed in the future. + * It follows the old and no longer wanted approach. + * Now, an Assigner is used to assign all LSPShipments to one LogisticChain of the LSPPlan. + *

+ * This class here is in contrast used as a Replanning strategy. This behavior is not wanted anymore. + *

+ * Please use the new approach as shown in + * {@link org.matsim.freight.logistics.example.lsp.multipleChains} ExampleMultipleOneEchelonChainsReplanning instead. + * ((The old approach is still available in CollectionLSPReplanningTest but will get removed earlier or later)). + *

+ * KMT, Jul'24 + * */ +@Deprecated +package org.matsim.freight.logistics.examples.lspReplanning; diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoring.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoring.java new file mode 100644 index 00000000000..917c60a2567 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoring.java @@ -0,0 +1,266 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspScoring; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.events.CarrierServiceEndEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceEndEventHandler; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/* Example for customized scoring. Each customer that is visited will give a random tip between zero and five + * + * + */ + +/*package-private*/ final class ExampleLSPScoring { + + private ExampleLSPScoring() {} + + private static LSP createLSPWithScorer(Scenario scenario) { + + // The Carrier for the resource of the sole LogisticsSolutionElement of the LSP is created + final VehicleType carrierVehType = VehicleUtils.createVehicleType( Id.create("CollectionCarrierVehicleType", VehicleType.class), TransportMode.car); + carrierVehType.getCapacity().setOther(10); + carrierVehType.getCostInformation().setCostsPerMeter(0.0004); + carrierVehType.getCostInformation().setCostsPerSecond(0.38); + carrierVehType.getCostInformation().setFixedCost(49.); + carrierVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + + CarrierCapabilities capabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, carrierVehType)) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier carrier = CarriersUtils.createCarrier(Id.create("CollectionCarrier", Carrier.class)); + carrier.setCarrierCapabilities(capabilities); + + // The Resource i.e. the Resource is created + // The scheduler for the Resource is created and added. This is where jsprit comes into play. + LSPResource lspResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + carrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the only LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement logisticChainElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(lspResource) + .build(); + + // The LogisticsSolutionElement is now inserted into the only LogisticsSolution of the LSP + LogisticChain logisticChain = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("CollectionSolution", LogisticChain.class)) + .addLogisticChainElement(logisticChainElement) + .build(); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan lspPlan = + LSPUtils.createLSPPlan() + .setInitialShipmentAssigner(ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner()) + .addLogisticChain(logisticChain); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + + return LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)) + .setInitialPlan(lspPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + Collections.singletonList(lspResource))) + // .setSolutionScorer(new TipScorer()) + .build(); + } + + private static Collection createInitialLSPShipments(Network network) { + List shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + // Create five LSPShipments that are located in the left half of the network. + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(Id.createLinkId("(4 2) (4 3)")); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public static void main(String[] args) { + + Config config = prepareConfig(); + + Scenario scenario = prepareScenario(config); + + Controler controler = prepareControler(scenario); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp2 : LSPUtils.getLSPs(scenario).getLSPs().values()) { + System.out.println("The tip of all customers was: " + lsp2.getSelectedPlan().getScore()); + } + } + + static Controler prepareControler(Scenario scenario) { + // Start the Mobsim one iteration is sufficient for scoring + Controler controler = new Controler(scenario); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + bind(LSPScorerFactory.class).toInstance(TipScorer::new); + } + }); + return controler; + } + + static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + // Create LSP and lspShipments + LSP lsp = createLSPWithScorer(scenario); + Collection lspShipments = createInitialLSPShipments(scenario.getNetwork()); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the lspShipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // Prepare LSPModule and add the LSP + LSPs lsps = new LSPs(Collections.singletonList(lsp)); + LSPUtils.addLSPs(scenario, lsps); + return scenario; + } + + static Config prepareConfig() { + // Set up required MATSim classes + Config config = ConfigUtils.createConfig(); + + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + return config; + } + + /*package-private*/ static class TipScorer + implements LSPScorer, LSPSimulationTracker, CarrierServiceEndEventHandler { + + private static final Logger log = LogManager.getLogger(TipScorer.class); + + private final Random tipRandom; + private double tipSum; + + /*package-private*/ TipScorer() { + tipRandom = new Random(1); + tipSum = 0; + } + + @Override + public double getScoreForCurrentPlan() { + return tipSum; + } + + @Override + public void setEmbeddingContainer(LSP pointer) { + // backpointer not needed here, therefor not memorizing it. kai, jun'22 + } + + @Override + public void handleEvent(CarrierServiceEndEvent event) { + double tip = tipRandom.nextDouble() * 5; + log.warn("tipSum={}; tip={}", tipSum, tip); + tipSum += tip; + } + + @Override + public void reset(int iteration) { + tipSum = 0.; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSP.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSP.java new file mode 100644 index 00000000000..dbcf83690e8 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSP.java @@ -0,0 +1,265 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.mobsimExamples; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/*package-private*/ class ExampleMobsimOfSimpleLSP { + + public static void main(String[] args) { + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + + if (args.length != 0) { + ConfigUtils.applyCommandline(config, args); + } + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + Scenario scenario = ScenarioUtils.createScenario(config); + + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + // Create LSP and lspShipments + LSP lsp = createInitialLSP(scenario); + Collection lspShipments = createInitialLSPShipments(scenario.getNetwork()); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the lspShipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // set up simulation controler and LSPModule + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + LSPUtils.addLSPs(scenario, lsps); + + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.overwriteExistingFiles); + + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LspShipment lspShipment : lsp.getLspShipments()) { + System.out.println("LspShipment: " + lspShipment.getId()); + ArrayList scheduleElements = + new ArrayList<>( + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = + new ArrayList<>(lspShipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (int i = 0; + i + < LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .size(); + i++) { + System.out.println( + "Scheduled: " + + scheduleElements.get(i).getLogisticChainElement().getId() + + " " + + scheduleElements.get(i).getResourceId() + + " " + + scheduleElements.get(i).getElementType() + + " Start: " + + scheduleElements.get(i).getStartTime() + + " End: " + + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + for (int i = 0; i < lspShipment.getShipmentLog().getPlanElements().size(); i++) { + System.out.println( + "Logged: " + + logElements.get(i).getLogisticChainElement().getId() + + " " + + logElements.get(i).getResourceId() + + " " + + logElements.get(i).getElementType() + + " Start: " + + logElements.get(i).getStartTime() + + " End: " + + logElements.get(i).getEndTime()); + } + System.out.println(); + } + } + + private static LSP createInitialLSP(Scenario scenario) { + + // The Carrier for the resource of the sole LogisticsSolutionElement of the LSP is created + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = + CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities capabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(carrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + // The Resource i.e. the Resource is created + LSPResource collectionResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the only LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement collectionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + // The LogisticsSolutionElement is now inserted into the only LogisticsSolution of the LSP + LogisticChain collectionSolution = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("CollectionSolution", LogisticChain.class)) + .addLogisticChainElement(collectionElement) + .build(); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + InitialShipmentAssigner assigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = + LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + LogisticChainScheduler simpleScheduler = + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + + return collectionLSPBuilder.build(); + } + + private static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + // Create five LSPShipments that are located in the left half of the network. + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(Id.createLinkId("(4 2) (4 3)")); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfTransportChain.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfTransportChain.java new file mode 100644 index 00000000000..b65592ed3bc --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfTransportChain.java @@ -0,0 +1,421 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.mobsimExamples; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/*package-private*/ class ExampleMobsimOfTransportChain { + + private static LSP createInitialLSP(Scenario scenario) { + + Network network = scenario.getNetwork(); + + // The Carrier for collection is created + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = + CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities capabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(carrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(capabilities); + + // The collection adapter i.e. the Resource is created + LSPResource collectionResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + collectionCarrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement collectionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + // The first reloading adapter i.e. the Resource is created + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + TransshipmentHubBuilder firstTransshipmentHubBuilder = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + + // The scheduler for the first reloading point is created + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + // The scheduler is added to the Resource and the Resource is created + firstTransshipmentHubBuilder.setTransshipmentHubScheduler( + firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + // The SolutionElement for the first reloading point is created + Id firstHubElementId = + Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + // The Carrier for the main run Resource is created + final Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + final Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + final VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + mainRunVehType.setNetworkMode(TransportMode.car); + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities mainRunCapabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(mainRunCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + // The adapter i.e. the main run resource is created + LSPResource mainRunResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .build(); + + // The LogisticsSolutionElement for the main run Resource is created + Id mainRunElementId = + Id.create("MainRunElement", LogisticChainElement.class); + LogisticChainElement mainRunElement = + LSPUtils.LogisticChainElementBuilder.newInstance(mainRunElementId) + .setResource(mainRunResource) + .build(); + + // The second reloading adapter i.e. the Resource is created + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + TransshipmentHubBuilder secondTransshipmentHubBuilder = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + + // The scheduler for the second reloading point is created + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + // The scheduler is added to the Resource and the Resource is created + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + Id secondHubElementId = + Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + // The Carrier for distribution is created + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = + Id.create("DistributionCarrierVehicleType", VehicleType.class); + VehicleType distributionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = + CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities distributionCapabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(distributionCarrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier distributionCarrier = CarriersUtils.createCarrier(distributionCarrierId); + distributionCarrier.setCarrierCapabilities(distributionCapabilities); + + // The distribution adapter i.e. the Resource is created + LSPResource distributionResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setLocationLinkId(distributionLinkId) + // The scheduler for the Resource is created and added. This is where jsprit comes into + // play. + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + // The adapter is now inserted into the corresponding LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + Id distributionElementId = + Id.create("DistributionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder distributionBuilder = + LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId); + distributionBuilder.setResource(distributionResource); + LogisticChainElement distributionElement = distributionBuilder.build(); + + // The Order of the logisticsSolutionElements is now specified + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + // The SolutionElements are now inserted into the only LogisticsSolution of the LSP + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = + LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + completeSolutionBuilder.addLogisticChainElement(distributionElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan completePlan = LSPUtils.createLSPPlan(); + InitialShipmentAssigner assigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = + LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + LogisticChainScheduler simpleScheduler = + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + + return completeLSPBuilder.build(); + } + + private static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 + && pendingToLink.getFromNode().getCoord().getY() <= 4000 + && pendingToLink.getFromNode().getCoord().getX() >= 14000 + && pendingToLink.getToNode().getCoord().getX() <= 18000 + && pendingToLink.getToNode().getCoord().getY() <= 4000 + && pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + } + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public static void main(String[] args) { + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + // Create LSP and lspShipments + LSP lsp = createInitialLSP(scenario); + Collection lspShipments = createInitialLSPShipments(scenario.getNetwork()); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the lspShipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // set up simulation controler and LSPModule + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install( + new LSPModule()); // this is the better syntax, having everything in one module. + // kai, may'22 + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.overwriteExistingFiles); + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LspShipment lspShipment : lsp.getLspShipments()) { + System.out.println("Shipment: " + lspShipment.getId()); + ArrayList scheduleElements = + new ArrayList<>( + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = + new ArrayList<>(lspShipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (int i = 0; + i + < LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), lspShipment.getId()) + .getPlanElements() + .size(); + i++) { + System.out.println( + "Scheduled: " + + scheduleElements.get(i).getLogisticChainElement().getId() + + " " + + scheduleElements.get(i).getResourceId() + + " " + + scheduleElements.get(i).getElementType() + + " Start: " + + scheduleElements.get(i).getStartTime() + + " End: " + + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + for (int i = 0; i < lspShipment.getShipmentLog().getPlanElements().size(); i++) { + System.out.println( + "Logged: " + + logElements.get(i).getLogisticChainElement().getId() + + " " + + logElements.get(i).getResourceId() + + " " + + logElements.get(i).getElementType() + + " Start: " + + logElements.get(i).getStartTime() + + " End: " + + logElements.get(i).getEndTime()); + } + System.out.println(); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChains.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChains.java new file mode 100644 index 00000000000..d0932dc1753 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChains.java @@ -0,0 +1,201 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import com.google.inject.Inject; +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.events.*; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.scoring.ScoringFunction; +import org.matsim.core.scoring.SumScoringFunction; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.Tour; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.logistics.analysis.Vehicle2CarrierEventHandler; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * @author Kai Martins-Turner (kturner) + */ +class EventBasedCarrierScorer4MultipleChains implements CarrierScoringFunctionFactory { + + @Inject private Network network; + @Inject private Scenario scenario; + + private Id carrierId; + + private double toll; + private List tolledVehicleTypes = new ArrayList<>(); + private List tolledLinks = new ArrayList<>(); + + public ScoringFunction createScoringFunction(Carrier carrier) { + this.carrierId = carrier.getId(); + SumScoringFunction sf = new SumScoringFunction(); + sf.addScoringFunction(new EventBasedScoring()); + sf.addScoringFunction(new LinkBasedTollScoring(toll, tolledVehicleTypes, tolledLinks)); + return sf; + } + + void setToll(double toll) { + this.toll = toll; + } + + void setTolledVehicleTypes(List tolledVehicleTypes) { + this.tolledVehicleTypes = tolledVehicleTypes; + } + + void setTolledLinks(List tolledLinks) { + this.tolledLinks = tolledLinks; + } + + /** + * Calculate the carrier's score based on Events. Currently, it includes: - fixed costs (using + * CarrierTourEndEvent) - time-dependent costs (using FreightTourStart- and -EndEvent) - + * distance-dependent costs (using LinkEnterEvent) + */ + private class EventBasedScoring implements SumScoringFunction.ArbitraryEventScoring { + + final Logger log = LogManager.getLogger(EventBasedScoring.class); + private final Map, Double> tourStartTime = new LinkedHashMap<>(); + private double score; + + public EventBasedScoring() { + super(); + } + + @Override + public void finish() {} + + @Override + public double getScore() { + return score; + } + + @Override + public void handleEvent(Event event) { + log.debug(event.toString()); + switch (event) { + case CarrierTourStartEvent carrierTourStartEvent -> handleEvent(carrierTourStartEvent); + case CarrierTourEndEvent carrierTourEndEvent -> handleEvent(carrierTourEndEvent); + case LinkEnterEvent linkEnterEvent -> handleEvent(linkEnterEvent); + default -> {} + } + } + + private void handleEvent(CarrierTourStartEvent event) { + // Save time of freight tour start + tourStartTime.put(event.getTourId(), event.getTime()); + } + + // scores fix costs for vehicle usage and variable costs per time + private void handleEvent(CarrierTourEndEvent event) { + // Fix costs for vehicle usage + final VehicleType vehicleType = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)).getType(); + + double tourDuration = event.getTime() - tourStartTime.get(event.getTourId()); + + log.info("Score fixed costs for vehicle type: {}", vehicleType.getId().toString()); + score = score - vehicleType.getCostInformation().getFixedCosts(); + + // variable costs per time + score = score - (tourDuration * vehicleType.getCostInformation().getCostsPerSecond()); + } + + // scores variable costs per distance + private void handleEvent(LinkEnterEvent event) { + final double distance = network.getLinks().get(event.getLinkId()).getLength(); + final double costPerMeter = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)) + .getType() + .getCostInformation() + .getCostsPerMeter(); + // variable costs per distance + score = score - (distance * costPerMeter); + } + } + + /** + * Calculate some toll for driving on a link This a lazy implementation of a cordon toll. A + * vehicle is only tolled once. + */ + class LinkBasedTollScoring implements SumScoringFunction.ArbitraryEventScoring { + + final Logger log = LogManager.getLogger(EventBasedScoring.class); + + private final double toll; + private final List vehicleTypesToBeTolled; + private double score; + private List tolledLinkList; + private final Vehicle2CarrierEventHandler v2c = new Vehicle2CarrierEventHandler(); + + public LinkBasedTollScoring(double toll, List vehicleTypeToBeTolled, List tolledLinkListBerlin) { + super(); + this.vehicleTypesToBeTolled = vehicleTypeToBeTolled; + this.tolledLinkList = tolledLinkListBerlin; + this.toll = toll; + } + + @Override + public void finish() {} + + @Override + public double getScore() { + return score; + } + + @Override + public void handleEvent(Event event) { + + switch (event) { + case LinkEnterEvent linkEnterEvent -> handleEvent(linkEnterEvent); + case CarrierTourStartEvent carrierTourStartEvent -> v2c.handleEvent(carrierTourStartEvent); + case CarrierTourEndEvent carrierTourEndEvent -> v2c.handleEvent(carrierTourEndEvent); + default -> {} + } + + } + + private void handleEvent(LinkEnterEvent event) { + final Id vehicleTypeId = (VehicleUtils.findVehicle(event.getVehicleId(), scenario)).getType().getId(); + + Id vehicleId = event.getVehicleId(); + if (vehicleTypesToBeTolled.contains(vehicleTypeId.toString())) { + if (tolledLinkList.contains(event.getLinkId().toString())) { + Id carrierIdOfVehicle = v2c.getCarrierOfVehicle(vehicleId); + if (carrierId.equals(carrierIdOfVehicle)) { + log.info("Tolling caused by event: {}, tollvalue {}", event, toll); + score = score - toll; + } + } + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChainsInclToll.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChainsInclToll.java new file mode 100644 index 00000000000..91e60ea2b8e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/EventBasedCarrierScorer4MultipleChainsInclToll.java @@ -0,0 +1,159 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import com.google.inject.Inject; +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.events.*; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.population.Person; +import org.matsim.core.scoring.ScoringFunction; +import org.matsim.core.scoring.SumScoringFunction; +import org.matsim.core.scoring.SumScoringFunction.ArbitraryEventScoring; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.Tour; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.logistics.analysis.Driver2VehicleEventHandler; +import org.matsim.freight.logistics.analysis.Vehicle2CarrierEventHandler; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * @author Kai Martins-Turner (kturner) + */ +class EventBasedCarrierScorer4MultipleChainsInclToll implements CarrierScoringFunctionFactory { + + @Inject private Network network; + @Inject private Scenario scenario; + + private Id carrierId; + + public ScoringFunction createScoringFunction(Carrier carrier) { + this.carrierId = carrier.getId(); + SumScoringFunction sf = new SumScoringFunction(); + sf.addScoringFunction(new EventBasedScoring()); + return sf; + } + + + /** + * Calculate the carrier's score based on Events. Currently, it includes: - fixed costs (using + * CarrierTourEndEvent) - time-dependent costs (using FreightTourStart- and -EndEvent) - + * distance-dependent costs (using LinkEnterEvent) + * tolls (using PersonMoneyEvent) + */ + private class EventBasedScoring implements ArbitraryEventScoring { + + final Logger log = LogManager.getLogger(EventBasedScoring.class); + private final Map, Double> tourStartTime = new LinkedHashMap<>(); + private final Driver2VehicleEventHandler d2v = new Driver2VehicleEventHandler(); + private final Vehicle2CarrierEventHandler v2c = new Vehicle2CarrierEventHandler(); + private double score; + + public EventBasedScoring() { + super(); + } + + @Override + public void finish() {} + + @Override + public double getScore() { + return score; + } + + @Override + public void handleEvent(Event event) { + log.debug(event.toString()); + switch (event) { + case CarrierTourStartEvent carrierTourStartEvent -> handleEvent(carrierTourStartEvent); + case CarrierTourEndEvent carrierTourEndEvent -> handleEvent(carrierTourEndEvent); + case LinkEnterEvent linkEnterEvent -> handleEvent(linkEnterEvent); + case PersonMoneyEvent personMoneyEvent -> handleEvent(personMoneyEvent); + case VehicleEntersTrafficEvent vehicleEntersTrafficEvent -> d2v.handleEvent(vehicleEntersTrafficEvent); + case VehicleLeavesTrafficEvent vehicleLeavesTrafficEvent -> d2v.handleEvent(vehicleLeavesTrafficEvent); + default -> {} + } + } + + private void handleEvent(CarrierTourStartEvent event) { + v2c.handleEvent(event); + // Save time of freight tour start + tourStartTime.put(event.getTourId(), event.getTime()); + } + + // scores fix costs for vehicle usage and variable costs per time + private void handleEvent(CarrierTourEndEvent event) { + v2c.handleEvent(event); + // Fix costs for vehicle usage + final VehicleType vehicleType = (VehicleUtils.findVehicle(event.getVehicleId(), scenario)).getType(); + + double tourDuration = event.getTime() - tourStartTime.get(event.getTourId()); + + log.info("Score fixed costs for vehicle type: {}", vehicleType.getId().toString()); + score = score - vehicleType.getCostInformation().getFixedCosts(); + + // variable costs per time + score = score - (tourDuration * vehicleType.getCostInformation().getCostsPerSecond()); + } + + // scores variable costs per distance + private void handleEvent(LinkEnterEvent event) { + final double distance = network.getLinks().get(event.getLinkId()).getLength(); + final double costPerMeter = + (VehicleUtils.findVehicle(event.getVehicleId(), scenario)) + .getType() + .getCostInformation() + .getCostsPerMeter(); + // variable costs per distance + score = score - (distance * costPerMeter); + } + + private final List> tolledPersons = new ArrayList<>(); + + // scores tolls for vehicles driving on tolled links + private void handleEvent(PersonMoneyEvent event) { + double tollValue = 0; + + if (event.getPurpose().equals("toll")) { + Id vehicleId = d2v.getVehicleOfDriver(event.getPersonId()); + if (vehicleId != null) { + Id carrierIdOfVehicle = v2c.getCarrierOfVehicle(vehicleId); + if (carrierId.equals(carrierIdOfVehicle)) { + tollValue = event.getAmount(); + log.info("Tolling caused by event: {}, tollvalue {}", event, tollValue); + score = score + tollValue; + } + + } + } + } + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleGroceryDeliveryMultipleChains.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleGroceryDeliveryMultipleChains.java new file mode 100644 index 00000000000..b4dee499b34 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleGroceryDeliveryMultipleChains.java @@ -0,0 +1,345 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import static org.matsim.freight.logistics.examples.multipleChains.MultipleChainsUtils.createLSPShipmentsFromCarrierShipments; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.ExampleConstants; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.vehicles.VehicleType; + +final class ExampleGroceryDeliveryMultipleChains { + + private static final Logger log = + LogManager.getLogger(ExampleGroceryDeliveryMultipleChains.class); + private static final Id HUB_LINK_ID = Id.createLinkId("91085"); + private static final double TOLL_VALUE = 1000; + static final double HUBCOSTS_FIX = 100; + private static final List TOLLED_LINKS = ExampleConstants.TOLLED_LINK_LIST_BERLIN_BOTH_DIRECTIONS; + + private ExampleGroceryDeliveryMultipleChains() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = + new EventBasedCarrierScorer4MultipleChains(); + carrierScorer.setToll(TOLL_VALUE); + carrierScorer.setTolledVehicleTypes( List.of("heavy40t")); + carrierScorer.setTolledLinks(TOLLED_LINKS); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())), null, 1); + strategyManager.addStrategy(RandomShiftingStrategyFactory.createStrategy(), null, 1); + strategyManager.setMaxPlansPerAgent(5); + strategyManager.setPlanSelectorForRemoval(new GenericWorstPlanForRemovalSelector<>()); + return strategyManager; + }); + } + }); + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory("output/groceryDelivery_kmt"); + config.controller().setLastIteration(20); + } + + config.network().setInputFile( + "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-v5.5-network.xml.gz"); + config.controller().setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + String carrierPlanFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/CarrierLEH_v2_withFleet_Shipment_OneTW_PickupTime_ICEVandBEV.xml"; + String vehicleTypeFile = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/vehicleTypesBVWP100_DC_noTax.xml"; + + CarrierVehicleTypes vehicleTypes = new CarrierVehicleTypes(); + CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(vehicleTypes); + vehicleTypeReader.readFile(vehicleTypeFile); + + Carriers carriers = new Carriers(); + CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, vehicleTypes); + carrierReader.readFile(carrierPlanFile); + + Carrier carrier = carriers.getCarriers() + .get(Id.create("kaufland_VERBRAUCHERMARKT_TROCKEN", CarrierImpl.class)); + Id depotLinkFromVehicles = carrier + .getCarrierCapabilities() + .getCarrierVehicles() + .values() + .iterator() + .next() + .getLinkId(); + + log.info("create LSP"); + + LSPPlan multipleMixedEchelonChainsPlan; + { + LogisticChain directChain; + { + Carrier singleCarrier = CarriersUtils.createCarrier(Id.create("singleCarrier", Carrier.class)); + singleCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(singleCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("singleCarrier"), + depotLinkFromVehicles, + vehicleTypes.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + singleCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("directCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + directChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("directChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + } + + LogisticChain hubChain; + { + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), + depotLinkFromVehicles, + vehicleTypes.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource mainCarrierResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance( + mainCarrier) + .setFromLinkId(depotLinkFromVehicles) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource) + .build(); + + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Hub", LSPResource.class), HUB_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + + LSPUtils.setFixedCost(hubResource, HUBCOSTS_FIX); + + LogisticChainElement hubElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResource) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), + HUB_LINK_ID, + vehicleTypes + .getVehicleTypes() + .get(Id.create("heavy40t_electro", VehicleType.class)))); + LSPResource distributionCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource) + .build(); + + mainCarrierElement.connectWithNextElement(hubElement); + hubElement.connectWithNextElement(distributionCarrierElement); + + hubChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubChain", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement) + .addLogisticChainElement(hubElement) + .addLogisticChainElement(distributionCarrierElement) + .build(); + } + + multipleMixedEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(directChain) + .addLogisticChain(hubChain) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(multipleMixedEchelonChainsPlan); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(multipleMixedEchelonChainsPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createLSPShipmentsFromCarrierShipments(carrier)) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleMixedEchelonChains.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleMixedEchelonChains.java new file mode 100644 index 00000000000..5a1a0090fbd --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleMixedEchelonChains.java @@ -0,0 +1,500 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.ExampleConstants; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +final class ExampleMultipleMixedEchelonChains { + + static final double HUBCOSTS_FIX = 100; + private static final Logger log = LogManager.getLogger(ExampleMultipleMixedEchelonChains.class); + private static final double TOLL_VALUE = 1000; + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final Id HUB_LINK_ID = Id.createLinkId("j(5,3)"); + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private ExampleMultipleMixedEchelonChains() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = + new EventBasedCarrierScorer4MultipleChains(); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + carrierScorer.setToll(TOLL_VALUE); + carrierScorer.setTolledVehicleTypes( List.of("heavy40t")); + carrierScorer.setTolledLinks(ExampleConstants.TOLLED_LINK_LIST_BERLIN_BOTH_DIRECTIONS); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + } + }); + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory("output/multipleMixedEchelonChains_twoPlans"); + config.controller().setLastIteration(2); + } + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + LSPPlan singleTwoEchelonChainPlan; + { + LogisticChain hubChain1; + { + Carrier mainCarrier1 = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier1.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier1, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierResource1 = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance( + mainCarrier1) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement1 = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource1) + .build(); + + LSPResourceScheduler hubScheduler1 = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResource1 = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Hub", LSPResource.class), HUB_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler1) + .build(); + LSPUtils.setFixedCost(hubResource1, HUBCOSTS_FIX); + + LogisticChainElement hubElement1 = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResource1) + .build(); + + Carrier distributionCarrier1 = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier1 + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrier1, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource distributionCarrierResource1 = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier1) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement1 = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource1) + .build(); + + mainCarrierElement1.connectWithNextElement(hubElement1); + hubElement1.connectWithNextElement(distributionCarrierElement1); + + hubChain1 = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubChain", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement1) + .addLogisticChainElement(hubElement1) + .addLogisticChainElement(distributionCarrierElement1) + .build(); + } + + singleTwoEchelonChainPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(hubChain1) + .setInitialShipmentAssigner( + MultipleChainsUtils.createPrimaryLogisticChainShipmentAssigner()); + } + + // A plan with a direct chain and a hub chain is created + LSPPlan multipleMixedEchelonChainsPlan; + { + LogisticChain directChain; + { + Carrier singleCarrier = + CarriersUtils.createCarrier(Id.create("singleCarrier", Carrier.class)); + singleCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + singleCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("singleCarrier"), DEPOT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + singleCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("directCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + directChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("directChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + } + + LogisticChain hubChain; + { + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance( + mainCarrier) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource) + .build(); + + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("Hub", LSPResource.class), HUB_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + LSPUtils.setFixedCost(hubResource, HUBCOSTS_FIX); + + LogisticChainElement hubElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResource) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource distributionCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource) + .build(); + + mainCarrierElement.connectWithNextElement(hubElement); + hubElement.connectWithNextElement(distributionCarrierElement); + + hubChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubChain", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement) + .addLogisticChainElement(hubElement) + .addLogisticChainElement(distributionCarrierElement) + .build(); + } + + multipleMixedEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(hubChain) + .addLogisticChain(directChain) + .setInitialShipmentAssigner( + MultipleChainsUtils.createRoundRobinLogisticChainShipmentAssigner()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(singleTwoEchelonChainPlan); + lspPlans.add(multipleMixedEchelonChainsPlan); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(singleTwoEchelonChainPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments(network)) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments(Network network) { + List shipmentList = new ArrayList<>(); + + Random rand = MatsimRandom.getLocalInstance(); + + int capacityDemand = 1; + + List zoneLinkList = + Arrays.asList( + "i(4,4)", "i(5,4)", "i(6,4)", "i(4,6)", "i(5,6)", "i(6,6)", "j(3,5)", "j(3,6)", + "j(3,7)", "j(5,5)", "j(5,6)", "j(5,7)", "i(4,5)R", "i(5,5)R", "i(6,5)R", "i(4,7)R", + "i(5,7)R", "i(6,7)R", "j(4,5)R", "j(4,6)R", "j(4,7)R", "j(6,5)R", "j(6,6)R", "j(6,7)R"); + for (String linkIdString : zoneLinkList) { + if (!network.getLinks().containsKey(Id.createLinkId(linkIdString))) { + throw new RuntimeException("Link is not in Network!"); + } + } + + for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) { + Id id = Id.create("ShipmentInside_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id toLinkId = + Id.createLinkId(zoneLinkList.get(rand.nextInt(zoneLinkList.size() - 1))); + builder.setToLinkId(toLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } else { + Id id = Id.create("ShipmentOutside_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id toLinkId = Id.createLinkId("i(9,0)"); + builder.setToLinkId(toLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + } + return shipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } + + enum AssignerSetting { + primary, + roundRobin + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChains.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChains.java new file mode 100644 index 00000000000..2e107c961db --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChains.java @@ -0,0 +1,392 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +final class ExampleMultipleOneEchelonChains { + + private static final Logger log = LogManager.getLogger(ExampleMultipleOneEchelonChains.class); + + private static final DemandSetting demandSetting = DemandSetting.fiveUnits; + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + + private ExampleMultipleOneEchelonChains() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = + new EventBasedCarrierScorer4MultipleChains(); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + } + }); + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory("output/multipleOneEchelonChains_" + demandSetting); + config.controller().setLastIteration(2); + } + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + // A plan with one logistic chain, containing a single carrier is created + LSPPlan singleOneEchelonChainPlan; + { + Carrier singleCarrier = + CarriersUtils.createCarrier(Id.create("singleCarrier", Carrier.class)); + singleCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + singleCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_large"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + singleCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("singleCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + LogisticChain singleChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("singleChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + + final InitialShipmentAssigner singleSolutionShipmentAssigner = + MultipleChainsUtils.createPrimaryLogisticChainShipmentAssigner(); + singleOneEchelonChainPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(singleChain) + .setInitialShipmentAssigner(singleSolutionShipmentAssigner); + } + + // A plan with two different logistic chains on the left and right, with respective carriers is + // created + LSPPlan multipleOneEchelonChainsPlan; + { + LogisticChainElement leftCarrierElement; + { + Carrier carrierLeft = CarriersUtils.createCarrier(Id.create("carrierLeft", Carrier.class)); + carrierLeft.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + carrierLeft, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource carrierLeftResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + carrierLeft) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + leftCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("leftCarrierElement", LogisticChainElement.class)) + .setResource(carrierLeftResource) + .build(); + } + + LogisticChainElement rightCarrierElement; + { + Carrier carrierRight = + CarriersUtils.createCarrier(Id.create("carrierRight", Carrier.class)); + carrierRight.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + carrierRight, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource carrierRightResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + carrierRight) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + rightCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("rightCarrierElement", LogisticChainElement.class)) + .setResource(carrierRightResource) + .build(); + } + + LogisticChain leftChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("leftChain", LogisticChain.class)) + .addLogisticChainElement(leftCarrierElement) + .build(); + + LogisticChain rightChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("rightChain", LogisticChain.class)) + .addLogisticChainElement(rightCarrierElement) + .build(); + + final InitialShipmentAssigner shipmentAssigner = + MultipleChainsUtils.createRoundRobinLogisticChainShipmentAssigner(); + multipleOneEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(leftChain) + .addLogisticChain(rightChain) + .setInitialShipmentAssigner(shipmentAssigner); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(singleOneEchelonChainPlan); + lspPlans.add(multipleOneEchelonChainsPlan); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(singleOneEchelonChainPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + lsp.addPlan(multipleOneEchelonChainsPlan); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments()) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments() { + List lspShipmentList = new ArrayList<>(); + int capacityDemand; + + switch (demandSetting) { + case oneUnit -> capacityDemand = 1; + case fiveUnits -> capacityDemand = 5; + default -> throw new IllegalStateException("Unexpected value: " + demandSetting); + } + + for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) { + Id id = Id.create("ShipmentLeft_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentLeftLinkId = Id.createLinkId("i(1,9)R"); + builder.setToLinkId(shipmentLeftLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + lspShipmentList.add(builder.build()); + } else { + Id id = Id.create("ShipmentRight_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentRightLinkId = Id.createLinkId("j(9,9)"); + builder.setToLinkId(shipmentRightLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + lspShipmentList.add(builder.build()); + } + } + return lspShipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } + + enum DemandSetting { + oneUnit, + fiveUnits + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChainsReplanning.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChainsReplanning.java new file mode 100644 index 00000000000..58aa47a74ab --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChainsReplanning.java @@ -0,0 +1,403 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +final class ExampleMultipleOneEchelonChainsReplanning { + + private static final Logger log = + LogManager.getLogger(ExampleMultipleOneEchelonChainsReplanning.class); + + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private ExampleMultipleOneEchelonChainsReplanning() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = + new EventBasedCarrierScorer4MultipleChains(); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>( + new ExpBetaPlanSelector<>(new ScoringConfigGroup())), + null, + 1); + strategyManager.addStrategy( + RandomShiftingStrategyFactory.createStrategy(), null, 1); + // + // strategyManager.addStrategy(ProximityStrategyFactory.createStrategy(scenario.getNetwork()), null, 1); + strategyManager.setMaxPlansPerAgent(5); + strategyManager.setPlanSelectorForRemoval( + new GenericWorstPlanForRemovalSelector<>()); + return strategyManager; + }); + } + }); + + // TODO: Innovation switch not working + config.replanning().setFractionOfIterationsToDisableInnovation(0.8); + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory("output/multipleOneEchelonChainsReplanning"); + config.controller().setLastIteration(10); + } + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + // A plan with one logistic chain, containing a single carrier is created + LSPPlan singleOneEchelonChainPlan; + { + Carrier singleCarrier = + CarriersUtils.createCarrier(Id.create("singleCarrier", Carrier.class)); + singleCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + singleCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_large"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + singleCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("singleCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + LogisticChain singleChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("singleChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + + final InitialShipmentAssigner singleSolutionShipmentAssigner = + MultipleChainsUtils.createPrimaryLogisticChainShipmentAssigner(); + singleOneEchelonChainPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(singleChain) + .setInitialShipmentAssigner(singleSolutionShipmentAssigner); + + singleOneEchelonChainPlan.setType( + MultipleChainsUtils.LspPlanTypes.SINGLE_ONE_ECHELON_CHAIN.toString()); + } + + // A plan with two different logistic chains on the left and right, with respective carriers is + // created + LSPPlan multipleOneEchelonChainsPlan; + { + LogisticChainElement leftCarrierElement; + { + Carrier carrierLeft = CarriersUtils.createCarrier(Id.create("carrierLeft", Carrier.class)); + carrierLeft.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + carrierLeft, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource carrierLeftResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + carrierLeft) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + leftCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("leftCarrierElement", LogisticChainElement.class)) + .setResource(carrierLeftResource) + .build(); + } + + LogisticChainElement rightCarrierElement; + { + Carrier carrierRight = + CarriersUtils.createCarrier(Id.create("carrierRight", Carrier.class)); + carrierRight.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + carrierRight, + CarrierVehicle.newInstance( + Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource carrierRightResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + carrierRight) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + rightCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("rightCarrierElement", LogisticChainElement.class)) + .setResource(carrierRightResource) + .build(); + } + + LogisticChain leftChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("leftChain", LogisticChain.class)) + .addLogisticChainElement(leftCarrierElement) + .build(); + + LogisticChain rightChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("rightChain", LogisticChain.class)) + .addLogisticChainElement(rightCarrierElement) + .build(); + + final InitialShipmentAssigner shipmentAssigner = + MultipleChainsUtils.createRandomLogisticChainShipmentAssigner(); + multipleOneEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(leftChain) + .addLogisticChain(rightChain) + .setInitialShipmentAssigner(shipmentAssigner); + + multipleOneEchelonChainsPlan.setType( + MultipleChainsUtils.LspPlanTypes.MULTIPLE_ONE_ECHELON_CHAINS.toString()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(singleOneEchelonChainPlan); + lspPlans.add(multipleOneEchelonChainsPlan); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(singleOneEchelonChainPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + lsp.addPlan(multipleOneEchelonChainsPlan); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments()) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments() { + List shipmentList = new ArrayList<>(); + int capacityDemand = 1; + + for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) { + Id id = Id.create("ShipmentLeft_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentLeftLinkId = Id.createLinkId("i(1,9)R"); + builder.setToLinkId(shipmentLeftLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } else { + Id id = Id.create("ShipmentRight_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentRightLinkId = Id.createLinkId("j(9,9)"); + builder.setToLinkId(shipmentRightLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + } + return shipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleTwoEchelonChainsReplanning.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleTwoEchelonChainsReplanning.java new file mode 100644 index 00000000000..0b36343790d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleTwoEchelonChainsReplanning.java @@ -0,0 +1,443 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +final class ExampleMultipleTwoEchelonChainsReplanning { + + static final double HUBCOSTS_FIX = 100; + private static final Logger log = + LogManager.getLogger(ExampleMultipleTwoEchelonChainsReplanning.class); + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final Id HUB_LEFT_LINK_ID = Id.createLinkId("i(1,5)R"); + private static final Id HUB_RIGHT_LINK_ID = Id.createLinkId("j(9,5)"); + + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + private static final VehicleType VEH_TYPE_SMALL_05 = createVehTypeSmall05(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private static VehicleType createVehTypeSmall05() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(5); + vehicleType.getCostInformation().setCostsPerMeter(0.001); + vehicleType.getCostInformation().setCostsPerSecond(0.005); + vehicleType.getCostInformation().setFixedCost(25.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + private ExampleMultipleTwoEchelonChainsReplanning() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = prepareScenario(config); + + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + // @formatter:off + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = new EventBasedCarrierScorer4MultipleChains(); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class).toProvider( () -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class).toProvider( () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( new GenericPlanStrategyImpl<>( new ExpBetaPlanSelector<>(new ScoringConfigGroup())), null, 1); + strategyManager.addStrategy( ProximityStrategyFactory.createStrategy(scenario.getNetwork()), null, 1); + strategyManager.setMaxPlansPerAgent(5); + strategyManager.setPlanSelectorForRemoval( new GenericWorstPlanForRemovalSelector<>()); + return strategyManager; + }); + } + }); + // @formatter:on + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory("output/multipleTwoEchelonChainsReplanning"); + config.controller().setLastIteration(8); + } + config + .network() + .setInputFile( + String.valueOf( + IOUtils.extendUrl( + ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config + .controller() + .setOverwriteFileSetting( + OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = + ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + log.info("Add LSP to the scenario"); + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + log.info("create LSP"); + Network network = scenario.getNetwork(); + + // A plan with a two hub chains is created + LSPPlan multipleTwoEchelonChainsPlan; + { + LogisticChain hubChainLeft; + { + Carrier mainCarrierLeft = + CarriersUtils.createCarrier(Id.create("mainCarrierLeft", Carrier.class)); + mainCarrierLeft + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrierLeft, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierResourceLeft = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainCarrierLeft) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_LEFT_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElementLeft = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElementLeft", LogisticChainElement.class)) + .setResource(mainCarrierResourceLeft) + .build(); + + LSPResourceScheduler hubSchedulerLeft = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResourceLeft = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("HubLeft", LSPResource.class), HUB_LEFT_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubSchedulerLeft) + .build(); + LSPUtils.setFixedCost(hubResourceLeft, HUBCOSTS_FIX); + + LogisticChainElement hubElementLeft = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResourceLeft) + .build(); + + Carrier distributionCarrierLeft = + CarriersUtils.createCarrier(Id.create("distributionCarrierLeft", Carrier.class)); + distributionCarrierLeft + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrierLeft, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_LEFT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource distributionCarrierResourceLeft = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrierLeft) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElementLeft = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElementLeft", LogisticChainElement.class)) + .setResource(distributionCarrierResourceLeft) + .build(); + + mainCarrierElementLeft.connectWithNextElement(hubElementLeft); + hubElementLeft.connectWithNextElement(distributionCarrierElementLeft); + + hubChainLeft = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("hubChainLeft", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElementLeft) + .addLogisticChainElement(hubElementLeft) + .addLogisticChainElement(distributionCarrierElementLeft) + .build(); + } + + LogisticChain hubChainRight; + { + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create("mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource mainCarrierResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainCarrier) + .setFromLinkId(DEPOT_LINK_ID) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(HUB_RIGHT_LINK_ID) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource) + .build(); + + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResourceRight = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create("HubRight", LSPResource.class), HUB_RIGHT_LINK_ID, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + LSPUtils.setFixedCost(hubResourceRight, HUBCOSTS_FIX); + + LogisticChainElement hubElementRight = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResourceRight) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create("distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), HUB_RIGHT_LINK_ID, VEH_TYPE_SMALL_05)); + LSPResource distributionCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource) + .build(); + + mainCarrierElement.connectWithNextElement(hubElementRight); + hubElementRight.connectWithNextElement(distributionCarrierElement); + + hubChainRight = + LSPUtils.LogisticChainBuilder.newInstance( + Id.create("hubChainRight", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement) + .addLogisticChainElement(hubElementRight) + .addLogisticChainElement(distributionCarrierElement) + .build(); + } + + multipleTwoEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(hubChainLeft) + .addLogisticChain(hubChainRight) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(multipleTwoEchelonChainsPlan); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(multipleTwoEchelonChainsPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + + log.info("create initial LSPShipments"); + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : createInitialLSPShipments()) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments() { + List shipmentList = new ArrayList<>(); + int capacityDemand = 1; + + for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) { + Id id = Id.create("ShipmentLeft_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentLeftLinkId = Id.createLinkId("i(1,9)R"); + builder.setToLinkId(shipmentLeftLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } else { + Id id = Id.create("ShipmentRight_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentRightLinkId = Id.createLinkId("j(9,9)"); + builder.setToLinkId(shipmentRightLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + } + return shipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChains.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChains.java new file mode 100644 index 00000000000..57231be2dc1 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChains.java @@ -0,0 +1,459 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.io.IOException; +import java.util.*; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.analysis.RunFreightAnalysisEventBased; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.ExampleConstants; +import org.matsim.freight.logistics.resourceImplementations.CarrierSchedulerUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.vehicles.VehicleType; + + +/** + * This bases on {@link ExampleGroceryDeliveryMultipleChains}. + * Now it will include two different LSPs + * + */ +final class ExampleTwoLspsGroceryDeliveryMultipleChains { + + private static final Logger log = LogManager.getLogger(ExampleTwoLspsGroceryDeliveryMultipleChains.class); + + private static final Id HUB_LINK_ID_NEUKOELLN = Id.createLinkId("91085"); + private static final double HUBCOSTS_FIX = 100; + + private static final List TOLLED_LINKS = ExampleConstants.TOLLED_LINK_LIST_BERLIN_BOTH_DIRECTIONS; + private static final List TOLLED_VEHICLE_TYPES = List.of("heavy40t"); // Für welche Fahrzeugtypen soll das MautSchema gelten? + private static final double TOLL_VALUE = 1000; + + private static final String CARRIER_PLAN_FILE = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/CarrierLEH_v2_withFleet_Shipment_OneTW_PickupTime_ICEVandBEV.xml"; + private static final String VEHICLE_TYPE_FILE = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/vehicleTypesBVWP100_DC_noTax.xml"; + private static final String EDEKA_SUPERMARKT_TROCKEN = "edeka_SUPERMARKT_TROCKEN"; + private static final String KAUFLAND_VERBRAUCHERMARKT_TROCKEN = "kaufland_VERBRAUCHERMARKT_TROCKEN"; + + private static final String OUTPUT_DIRECTORY = "output/groceryDelivery_kmt_1000_1LSPb"; + + + private ExampleTwoLspsGroceryDeliveryMultipleChains() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = ScenarioUtils.loadScenario(config); + + CarrierVehicleTypes vehicleTypes = new CarrierVehicleTypes(); + CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(vehicleTypes); + vehicleTypeReader.readFile(VEHICLE_TYPE_FILE); + //The following is needed, because since fall 2024 the vehicle types are not assigned to a network mode by default. + for (VehicleType vehicleType : vehicleTypes.getVehicleTypes().values()) { + vehicleType.setNetworkMode(TransportMode.car); + } + + Carriers carriers = new Carriers(); + CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, vehicleTypes); + carrierReader.readFile(CARRIER_PLAN_FILE); + + Carrier carrierEdeka = carriers.getCarriers().get(Id.create(EDEKA_SUPERMARKT_TROCKEN, CarrierImpl.class)); + Carrier carrierKaufland = carriers.getCarriers().get(Id.create(KAUFLAND_VERBRAUCHERMARKT_TROCKEN, CarrierImpl.class)); + + log.info("Add LSP(s) to the scenario"); + Collection lsps = new LinkedList<>(); + lsps.add(createLspWithTwoChains(scenario, "Edeka", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierEdeka), getDepotLinkFromVehicle(carrierEdeka), HUB_LINK_ID_NEUKOELLN, vehicleTypes, vehicleTypes, vehicleTypes)); + lsps.add(createLspWithTwoChains(scenario, "Kaufland", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierKaufland), getDepotLinkFromVehicle(carrierKaufland), HUB_LINK_ID_NEUKOELLN, vehicleTypes, vehicleTypes, vehicleTypes)); + lsps.add(createLspWithDirectChain(scenario, "Edeka_DIRECT", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierEdeka), getDepotLinkFromVehicle(carrierEdeka), vehicleTypes)); + lsps.add(createLspWithDirectChain(scenario, "Kaufland_DIRECT", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierKaufland), getDepotLinkFromVehicle(carrierKaufland), vehicleTypes)); + LSPUtils.addLSPs(scenario, new LSPs(lsps)); + + Controler controler = prepareControler(scenario); + + log.info("Run MATSim"); + + controler.run(); + + runCarrierAnalysis(controler.getControlerIO().getOutputPath(), config); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory(OUTPUT_DIRECTORY); + config.controller().setLastIteration(1); + } + + config.network().setInputFile("https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-v5.5-network.xml.gz"); + config.global().setCoordinateSystem("EPSG:31468"); + config.global().setRandomSeed(4177); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + config.vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + + FreightCarriersConfigGroup freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Controler prepareControler(Scenario scenario) { + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = + new EventBasedCarrierScorer4MultipleChains(); + carrierScorer.setToll(TOLL_VALUE); + carrierScorer.setTolledVehicleTypes(TOLLED_VEHICLE_TYPES); + carrierScorer.setTolledLinks(TOLLED_LINKS); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())), null, 1); + strategyManager.addStrategy(RandomShiftingStrategyFactory.createStrategy(), null, 4); + strategyManager.setMaxPlansPerAgent(5); + strategyManager.setPlanSelectorForRemoval(new GenericWorstPlanForRemovalSelector<>()); + return strategyManager; + }); + } + }); + return controler; + } + + private static void runCarrierAnalysis(String outputPath, Config config) { + RunFreightAnalysisEventBased freightAnalysis = new RunFreightAnalysisEventBased(outputPath +"/", outputPath +"/Analysis/", config.global().getCoordinateSystem()); + try { + freightAnalysis.runCompleteAnalysis(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Creates an LSP with two chains: + * - direct delivery + * - 2-echelon delivery + *

+ * TODO: Es sollten dann am Besten direkt die zur Verfügung stehenden VehicleTypes übergeben werden und diese dann hier jeweils (alle) hinzugefügt werden. + * Aktuell erfolgt die Auswahl ja noch hier. Das sollte dann aber nicht mehr so sein, sondern bereits weiter upstream definiert werden. + * kmt Jul'24 + * + * @param scenario the scenario, used e.g. for getting the network and register some stuff + * @param lspName String of LSP's Id + * @param lspShipments Collection of LSPShipments to be assigned to the LSP + * @param depotLinkId Id of the depot link + * @param hubLinkId location of the hub + * @param vehicleTypesMainRun vehicle types for the main run (2e-chain) + * @param vehicleTypesDistributionRun vehicle types for the distribution run (2e-chain) + * @param vehicleTypesDirect vehicle types for the direct run (direct chain) + * @return the LSP + */ + private static LSP createLspWithTwoChains(Scenario scenario, String lspName, Collection lspShipments, Id depotLinkId, Id hubLinkId, CarrierVehicleTypes vehicleTypesMainRun, CarrierVehicleTypes vehicleTypesDistributionRun, CarrierVehicleTypes vehicleTypesDirect) { + log.info("create LSP"); + //Chains + LogisticChain directChain = createDirectChain(scenario, lspName, depotLinkId, vehicleTypesDirect); + LogisticChain twoEchelonChain = createTwoEchelonChain(scenario, lspName, hubLinkId, depotLinkId, vehicleTypesMainRun, vehicleTypesDistributionRun); + + LSPPlan multipleMixedEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(directChain) + .addLogisticChain(twoEchelonChain) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + + List lspPlans = List.of(multipleMixedEchelonChainsPlan); + + LSP lsp = LSPUtils.LSPBuilder.getInstance(Id.create(lspName, LSP.class)) + .setInitialPlan(multipleMixedEchelonChainsPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Id getDepotLinkFromVehicle(Carrier carrier) { + return carrier + .getCarrierCapabilities() + .getCarrierVehicles() + .values() + .iterator() + .next() + .getLinkId(); + } + + /* + TODO: Es sollten dann am Besten direkt die zur Verfügung stehenden VehicleTypes übergeben werden und diese dann hier jeweils (alle) hinzugefügt werden. + Aktuell erfolgt die Auswahl ja noch hier. Das sollte dann aber nicht mehr so sein, sondern bereits weiter upstream definiert werden. + kmt Jul'24 + */ + private static LogisticChain createTwoEchelonChain(Scenario scenario, String lspName, Id hubLinkId, Id depotLinkFromVehicles, CarrierVehicleTypes vehicleTypesMainRun, CarrierVehicleTypes vehicleTypesDistributionRun) { + LogisticChain hubChain; + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create(lspName +"_mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), + depotLinkFromVehicles, + vehicleTypesMainRun.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource mainCarrierResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance( + mainCarrier) + .setFromLinkId(depotLinkFromVehicles) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(hubLinkId) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource) + .build(); + + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create(lspName +"_Hub", LSPResource.class), hubLinkId, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + + LSPUtils.setFixedCost(hubResource, HUBCOSTS_FIX); + + LogisticChainElement hubElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResource) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create(lspName +"_distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + //.setNumberOfJspritIterations // TODO Das mal hier einbauen. --> Ist aktuell in CarrierUtils. + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + CarrierSchedulerUtils.setVrpLogic(distributionCarrier, LSPUtils.LogicOfVrp.serviceBased); + + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), + hubLinkId, + vehicleTypesDistributionRun + .getVehicleTypes() + .get(Id.create("heavy40t_electro", VehicleType.class)))); + LSPResource distributionCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource) + .build(); + + mainCarrierElement.connectWithNextElement(hubElement); + hubElement.connectWithNextElement(distributionCarrierElement); + + //TODO: Hier das Verbinden einfügen und in der Reihenfolge ist es. KMT Nov'24 + hubChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubChain", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement) + .addLogisticChainElement(hubElement) + .addLogisticChainElement(distributionCarrierElement) + .build(); + return hubChain; + } + + /** + * Creates an LSP with direct chains: + * + * @param scenario the scenario, used e.g. for getting the network and register some stuff + * @param lspName String of LSP's Id + * @param lspShipments Collection of LSPShipments to be assigned to the LSP + * @param depotLinkId Id of the depot link + * @param vehicleTypesDirect vehicle types for the direct run (direct chain) + * @return the LSP + */ + private static LSP createLspWithDirectChain(Scenario scenario, String lspName, Collection lspShipments, Id depotLinkId, CarrierVehicleTypes vehicleTypesDirect) { + log.info("create LSP"); + + LSPPlan lspPlan = LSPUtils.createLSPPlan() + .addLogisticChain(createDirectChain(scenario, lspName, depotLinkId, vehicleTypesDirect)) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create(lspName, LSP.class)) + .setInitialPlan(lspPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(List.of(lspPlan)))) + .build(); + + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + + private static LogisticChain createDirectChain(Scenario scenario, String lspName, Id depotLinkFromVehicles, CarrierVehicleTypes vehicleTypes) { + LogisticChain directChain; + Carrier directCarrier = CarriersUtils.createCarrier(Id.create(lspName +"_directCarrier", Carrier.class)); + directCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + CarrierSchedulerUtils.setVrpLogic(directCarrier, LSPUtils.LogicOfVrp.serviceBased); + + CarriersUtils.addCarrierVehicle(directCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("directCarrierTruck"), + depotLinkFromVehicles, + vehicleTypes.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(directCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("directCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + directChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("directChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + return directChain; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll.java new file mode 100644 index 00000000000..e27b2e27a4b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll.java @@ -0,0 +1,485 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.io.IOException; +import java.util.*; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.analysis.personMoney.PersonMoneyEventsAnalysisModule; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.roadpricing.*; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.misc.Time; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.analysis.RunFreightAnalysisEventBased; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.ExampleConstants; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/** + * This bases on {@link ExampleTwoLspsGroceryDeliveryMultipleChains}. + * It is extended in a way that it will use the roadpricing contrib... + * This class is here only for development and will be merged into {@link ExampleTwoLspsGroceryDeliveryMultipleChains} + * once the result is satisfying. + * KMT, Jul'24 + */ +final class ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll { + + private static final Logger log = LogManager.getLogger(ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll.class); + + private static final Id HUB_LINK_ID_NEUKOELLN = Id.createLinkId("91085"); + private static final double HUBCOSTS_FIX = 100; + + private static final List TOLLED_LINKS = ExampleConstants.TOLLED_LINK_LIST_BERLIN_BOTH_DIRECTIONS; + private static final List TOLLED_VEHICLE_TYPES = List.of("heavy40t"); // Für welche Fahrzeugtypen soll das MautSchema gelten? + private static final double TOLL_VALUE = 1000; + + private static final String CARRIER_PLAN_FILE = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/CarrierLEH_v2_withFleet_Shipment_OneTW_PickupTime_ICEVandBEV.xml"; + private static final String VEHICLE_TYPE_FILE = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/projects/freight/foodRetailing_wo_rangeConstraint/input/vehicleTypesBVWP100_DC_noTax.xml"; + private static final String EDEKA_SUPERMARKT_TROCKEN = "edeka_SUPERMARKT_TROCKEN"; + private static final String KAUFLAND_VERBRAUCHERMARKT_TROCKEN = "kaufland_VERBRAUCHERMARKT_TROCKEN"; + + private static final String OUTPUT_DIRECTORY = "output/groceryDelivery_kmt_1000_newTollScoring_1it"; + + + private ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll() {} + + public static void main(String[] args) { + log.info("Prepare config"); + Config config = prepareConfig(args); + + log.info("Prepare scenario"); + Scenario scenario = ScenarioUtils.loadScenario(config); + + CarrierVehicleTypes vehicleTypes = new CarrierVehicleTypes(); + CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(vehicleTypes); + vehicleTypeReader.readFile(VEHICLE_TYPE_FILE); + //The following is needed, because since fall 2024 the vehicle types are not assigned to a network mode by default. + for (VehicleType vehicleType : vehicleTypes.getVehicleTypes().values()) { + vehicleType.setNetworkMode(TransportMode.car); + } + + Carriers carriers = new Carriers(); + CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, vehicleTypes); + carrierReader.readFile(CARRIER_PLAN_FILE); + + Carrier carrierEdeka = carriers.getCarriers().get(Id.create(EDEKA_SUPERMARKT_TROCKEN, CarrierImpl.class)); + Carrier carrierKaufland = carriers.getCarriers().get(Id.create(KAUFLAND_VERBRAUCHERMARKT_TROCKEN, CarrierImpl.class)); + + RoadPricingScheme rpScheme = setUpRoadpricing(scenario); + + log.info("Add LSP(s) to the scenario"); + Collection lsps = new LinkedList<>(); + lsps.add(createLspWithTwoChains(scenario, "Edeka", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierEdeka), getDepotLinkFromVehicle(carrierEdeka), HUB_LINK_ID_NEUKOELLN, vehicleTypes, vehicleTypes, vehicleTypes)); + lsps.add(createLspWithTwoChains(scenario, "Kaufland", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierKaufland), getDepotLinkFromVehicle(carrierKaufland), HUB_LINK_ID_NEUKOELLN, vehicleTypes, vehicleTypes, vehicleTypes)); + lsps.add(createLspWithDirectChain(scenario, "Edeka_DIRECT", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierEdeka), getDepotLinkFromVehicle(carrierEdeka), vehicleTypes)); + lsps.add(createLspWithDirectChain(scenario, "Kaufland_DIRECT", MultipleChainsUtils.createLSPShipmentsFromCarrierShipments(carrierKaufland), getDepotLinkFromVehicle(carrierKaufland), vehicleTypes)); + LSPUtils.addLSPs(scenario, new LSPs(lsps)); + + + Controler controler = prepareControler(scenario, rpScheme); + + log.info("Run MATSim"); + + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + runCarrierAnalysis(controler.getControlerIO().getOutputPath(), config); + + log.info("Done."); + } + + private static Config prepareConfig(String[] args) { + Config config = ConfigUtils.createConfig(); + if (args.length != 0) { + for (String arg : args) { + log.warn(arg); + } + ConfigUtils.applyCommandline(config, args); + } else { + config.controller().setOutputDirectory(OUTPUT_DIRECTORY); + config.controller().setLastIteration(1); + } + + config.network().setInputFile("https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/berlin/berlin-v5.5-10pct/input/berlin-v5.5-network.xml.gz"); + config.global().setCoordinateSystem("EPSG:31468"); + config.global().setRandomSeed(4177); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + + FreightCarriersConfigGroup freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + private static Controler prepareControler(Scenario scenario, RoadPricingScheme rpScheme) { + log.info("Prepare controler"); + Controler controler = new Controler(scenario); + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + install(new PersonMoneyEventsAnalysisModule()); + } + }); + + controler.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + bind(CarrierScoringFunctionFactory.class).toInstance(new EventBasedCarrierScorer4MultipleChainsInclToll()); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class) + .toProvider( + () -> { + CarrierStrategyManager strategyManager = + CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class) + .toProvider( + () -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())), null, 1); + strategyManager.addStrategy(RandomShiftingStrategyFactory.createStrategy(), null, 4); + strategyManager.setMaxPlansPerAgent(5); + strategyManager.setPlanSelectorForRemoval(new GenericWorstPlanForRemovalSelector<>()); + return strategyManager; + }); + } + }); + if (!rpScheme.getTolledLinkIds().isEmpty()) { + // RoadPricing.configure(controler); + controler.addOverridingModule( new RoadPricingModule(rpScheme) ); + } + return controler; + } + + /* + * Set up roadpricing --- this is a copy paste from KMT lecture in GVSim --> need some adaptions + * TODO Adapt settings + */ + + private static RoadPricingSchemeUsingTollFactor setUpRoadpricing(Scenario scenario) { + + //Create Rp Scheme from code. + RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme, "MautFromCodeKMT"); + RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme, "Mautdaten erstellt aus Link-Liste."); + + /* Add general toll. */ + for (String linkIdString : TOLLED_LINKS) { + RoadPricingUtils.addLink(scheme, Id.createLinkId(linkIdString)); + } + + RoadPricingUtils.createAndAddGeneralCost(scheme, + Time.parseTime("00:00:00"), + Time.parseTime("72:00:00"), + TOLL_VALUE); + ///___ End creating from Code + + // Wenn FzgTypId in Liste, erfolgt die Bemautung mit dem Kostensatz (Faktor = 1), + // sonst mit 0 (Faktor = 0). ((MATSim seite) + TollFactor tollFactor = + (personId, vehicleId, linkId, time) -> { + var vehTypeId = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId(); + if (TOLLED_VEHICLE_TYPES.contains(vehTypeId.toString())) { + return 1; + } else { + return 0; + } + }; + + return new RoadPricingSchemeUsingTollFactor(scheme, tollFactor); + } + + private static void runCarrierAnalysis(String outputPath, Config config) { + RunFreightAnalysisEventBased freightAnalysis = new RunFreightAnalysisEventBased(outputPath +"/", outputPath +"/Analysis/", config.global().getCoordinateSystem()); + try { + freightAnalysis.runCompleteAnalysis(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Creates an LSP with two chains: + * - direct delivery + * - 2-echelon delivery + *

+ * TODO: Es sollten dann am Besten direkt die zur Verfügung stehenden VehicleTypes übergeben werden und diese dann hier jeweils (alle) hinzugefügt werden. + * Aktuell erfolgt die Auswahl ja noch hier. Das sollte dann aber nicht mehr so sein, sondern bereits weiter upstream definiert werden. + * kmt Jul'24 + * + * @param scenario the scenario, used e.g. for getting the network and register some stuff + * @param lspName String of LSP's Id + * @param lspShipments Collection of LSPShipments to be assigned to the LSP + * @param depotLinkId Id of the depot link + * @param hubLinkId location of the hub + * @param vehicleTypesMainRun vehicle types for the main run (2e-chain) + * @param vehicleTypesDistributionRun vehicle types for the distribution run (2e-chain) + * @param vehicleTypesDirect vehicle types for the direct run (direct chain) + * @return the LSP + */ + private static LSP createLspWithTwoChains(Scenario scenario, String lspName, Collection lspShipments, Id depotLinkId, Id hubLinkId, CarrierVehicleTypes vehicleTypesMainRun, CarrierVehicleTypes vehicleTypesDistributionRun, CarrierVehicleTypes vehicleTypesDirect) { + log.info("create LSP"); + //Chains + LogisticChain directChain = createDirectChain(scenario, lspName, depotLinkId, vehicleTypesDirect); + LogisticChain twoEchelonChain = createTwoEchelonChain(scenario, lspName, hubLinkId, depotLinkId, vehicleTypesMainRun, vehicleTypesDistributionRun); + + LSPPlan multipleMixedEchelonChainsPlan = + LSPUtils.createLSPPlan() + .addLogisticChain(directChain) + .addLogisticChain(twoEchelonChain) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + + List lspPlans = List.of(multipleMixedEchelonChainsPlan); + + LSP lsp = LSPUtils.LSPBuilder.getInstance(Id.create(lspName, LSP.class)) + .setInitialPlan(multipleMixedEchelonChainsPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(lspPlans))) + .build(); + + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Id getDepotLinkFromVehicle(Carrier carrier) { + return carrier + .getCarrierCapabilities() + .getCarrierVehicles() + .values() + .iterator() + .next() + .getLinkId(); + } + + /* + TODO: Es sollten dann am Besten direkt die zur Verfügung stehenden VehicleTypes übergeben werden und diese dann hier jeweils (alle) hinzugefügt werden. + Aktuell erfolgt die Auswahl ja noch hier. Das sollte dann aber nicht mehr so sein, sondern bereits weiter upstream definiert werden. + kmt Jul'24 + */ + private static LogisticChain createTwoEchelonChain(Scenario scenario, String lspName, Id hubLinkId, Id depotLinkFromVehicles, CarrierVehicleTypes vehicleTypesMainRun, CarrierVehicleTypes vehicleTypesDistributionRun) { + LogisticChain hubChain; + Carrier mainCarrier = CarriersUtils.createCarrier(Id.create(lspName +"_mainCarrier", Carrier.class)); + mainCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + mainCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("mainTruck"), + depotLinkFromVehicles, + vehicleTypesMainRun.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource mainCarrierResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance( + mainCarrier) + .setFromLinkId(depotLinkFromVehicles) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setToLinkId(hubLinkId) + .setVehicleReturn(ResourceImplementationUtils.VehicleReturn.returnToFromLink) + .build(); + + LogisticChainElement mainCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("mainCarrierElement", LogisticChainElement.class)) + .setResource(mainCarrierResource) + .build(); + + LSPResourceScheduler hubScheduler = + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed(10) + .setCapacityNeedLinear(1) + .build(); + + LSPResource hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create(lspName +"_Hub", LSPResource.class), hubLinkId, scenario) + .setTransshipmentHubScheduler(hubScheduler) + .build(); + + LSPUtils.setFixedCost(hubResource, HUBCOSTS_FIX); + + LogisticChainElement hubElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("HubElement", LogisticChainElement.class)) + .setResource(hubResource) + .build(); + + Carrier distributionCarrier = + CarriersUtils.createCarrier(Id.create(lspName +"_distributionCarrier", Carrier.class)); + distributionCarrier + .getCarrierCapabilities() + //.setNumberOfJspritIterations // TODO Das mal hier einbauen. --> Ist aktuell in CarrierUtils. + .setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle( + distributionCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("distributionTruck"), + hubLinkId, + vehicleTypesDistributionRun + .getVehicleTypes() + .get(Id.create("heavy40t_electro", VehicleType.class)))); + LSPResource distributionCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + distributionCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement distributionCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("distributionCarrierElement", LogisticChainElement.class)) + .setResource(distributionCarrierResource) + .build(); + + mainCarrierElement.connectWithNextElement(hubElement); + hubElement.connectWithNextElement(distributionCarrierElement); + + hubChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("hubChain", LogisticChain.class)) + .addLogisticChainElement(mainCarrierElement) + .addLogisticChainElement(hubElement) + .addLogisticChainElement(distributionCarrierElement) + .build(); + return hubChain; + } + + /** + * Creates an LSP with direct chains: + * + * @param scenario the scenario, used e.g. for getting the network and register some stuff + * @param lspName String of LSP's Id + * @param lspShipments Collection of LSPShipments to be assigned to the LSP + * @param depotLinkId Id of the depot link + * @param vehicleTypesDirect vehicle types for the direct run (direct chain) + * @return the LSP + */ + private static LSP createLspWithDirectChain(Scenario scenario, String lspName, Collection lspShipments, Id depotLinkId, CarrierVehicleTypes vehicleTypesDirect) { + log.info("create LSP"); + + LSPPlan lspPlan = LSPUtils.createLSPPlan() + .addLogisticChain(createDirectChain(scenario, lspName, depotLinkId, vehicleTypesDirect)) + .setInitialShipmentAssigner(MultipleChainsUtils.createRandomLogisticChainShipmentAssigner()); + + LSP lsp = + LSPUtils.LSPBuilder.getInstance(Id.create(lspName, LSP.class)) + .setInitialPlan(lspPlan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + createResourcesListFromLSPPlans(List.of(lspPlan)))) + .build(); + + log.info("assign the shipments to the LSP"); + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + log.info("schedule the LSP with the shipments and according to the scheduler of the Resource"); + lsp.scheduleLogisticChains(); + + return lsp; + } + + + private static LogisticChain createDirectChain(Scenario scenario, String lspName, Id depotLinkFromVehicles, CarrierVehicleTypes vehicleTypes) { + LogisticChain directChain; + Carrier directCarrier = CarriersUtils.createCarrier(Id.create(lspName +"_directCarrier", Carrier.class)); + directCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(directCarrier, + CarrierVehicle.newInstance( + Id.createVehicleId("directCarrierTruck"), + depotLinkFromVehicles, + vehicleTypes.getVehicleTypes().get(Id.create("heavy40t", VehicleType.class)))); + LSPResource singleCarrierResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(directCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = + LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("directCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + directChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("directChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + return directChain; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + log.info("Collecting all LSPResources from the LSPPlans"); + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsUtils.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsUtils.java new file mode 100644 index 00000000000..30517805da5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsUtils.java @@ -0,0 +1,98 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import static java.util.stream.Collectors.toMap; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierShipment; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +class MultipleChainsUtils { + private MultipleChainsUtils() {} + + public static RandomLogisticChainShipmentAssigner createRandomLogisticChainShipmentAssigner() { + return new RandomLogisticChainShipmentAssigner(); + } + + public static RoundRobinLogisticChainShipmentAssigner + createRoundRobinLogisticChainShipmentAssigner() { + return new RoundRobinLogisticChainShipmentAssigner(); + } + + public static PrimaryLogisticChainShipmentAssigner createPrimaryLogisticChainShipmentAssigner() { + return new PrimaryLogisticChainShipmentAssigner(); + } + + public static Collection createLSPShipmentsFromCarrierShipments(Carrier carrier) { + List shipmentList = new ArrayList<>(); + + List carrierShipments = carrier.getShipments().values().stream().toList(); + + for (CarrierShipment shipment : carrierShipments) { + LspShipmentUtils.LspShipmentBuilder builder = + LspShipmentUtils.LspShipmentBuilder.newInstance( + Id.create(shipment.getId().toString(), LspShipment.class)); + builder.setCapacityDemand(shipment.getSize()); + builder.setFromLinkId(shipment.getFrom()); + builder.setToLinkId(shipment.getTo()); + builder.setStartTimeWindow(shipment.getPickupTimeWindow()); + builder.setEndTimeWindow(shipment.getDeliveryTimeWindow()); + builder.setPickupServiceTime(shipment.getPickupServiceTime()); + builder.setDeliveryServiceTime(shipment.getDeliveryServiceTime()); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public enum LspPlanTypes { + SINGLE_ONE_ECHELON_CHAIN("singleOneEchelonChain"), + SINGLE_TWO_ECHELON_CHAIN("singleTwoEchelonChain"), + MULTIPLE_ONE_ECHELON_CHAINS("multipleOneEchelonChains"), + MULTIPLE_TWO_ECHELON_CHAINS("multipleTwoEchelonChains"), + MULTIPLE_MIXED_ECHELON_CHAINS("multipleMixedEchelonChains"); + + private static final Map stringToEnum = + Stream.of(values()).collect(toMap(Object::toString, e -> e)); + private final String label; + + LspPlanTypes(String label) { + this.label = label; + } + + public static LspPlanTypes fromString(String label) { + return stringToEnum.get(label); + } + + @Override + public String toString() { + return label; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MyLSPScorer.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MyLSPScorer.java new file mode 100644 index 00000000000..e82311ffcbf --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/MyLSPScorer.java @@ -0,0 +1,104 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.TransshipmentHubResource; + +/** + * A scorer for the LSP. It uses the scores of the - carriers: Take the carrier's score and add it + * to the LSP's score - hubs: currently a very simple fixed costs scoring (see below {@link + * #scoreHub()}) + * + * @author Kai Martins-Turner (kturner) + */ +/*package-private*/ class MyLSPScorer implements LSPScorer { + final Logger logger = LogManager.getLogger(MyLSPScorer.class); + private double score = 0; + private LSP lsp; + + @Override + public void reset(int iteration) { + score = 0.; + } + + @Override + public double getScoreForCurrentPlan() { + scoreLspCarriers(); + scoreHub(); + scoreMissingShipments(); + return score; + } + + private void scoreLspCarriers() { + var lspPlan = lsp.getSelectedPlan(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + if (logisticChainElement.getResource() instanceof LSPCarrierResource carrierResource) { + var carriersScore = carrierResource.getCarrier().getSelectedPlan().getScore(); + if (carriersScore != null) { + score = score + carriersScore; + } + } + } + } + } + + /** + * If a hub resource is in the selected plan of the LSP, it will get scored. + * + *

This is somehow a quickfix, because the hubs do **not** have any own events yet. This needs + * to be implemented later KMT oct'22 + */ + private void scoreHub() { + var lspPlan = lsp.getSelectedPlan(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + if (logisticChainElement.getResource() instanceof TransshipmentHubResource hub) { + score = score - LSPUtils.getFixedCost(hub); + } + } + } + } + + private void scoreMissingShipments() { + LSPPlan lspPlan = lsp.getSelectedPlan(); + int lspPlanShipmentCount = + lspPlan.getLogisticChains().stream() + .mapToInt(logisticChain -> logisticChain.getLspShipmentIds().size()) + .sum(); + int shipmentCountDifference = lsp.getLspShipments().size() - lspPlanShipmentCount; + if (shipmentCountDifference > 0) { + logger.error( + "LspPlan contains less shipments than LSP, " + + "shipments probably lost during replanning."); + score -= 10000 * shipmentCountDifference; + } + } + + @Override + public void setEmbeddingContainer(LSP pointer) { + this.lsp = pointer; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/PrimaryLogisticChainShipmentAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/PrimaryLogisticChainShipmentAssigner.java new file mode 100644 index 00000000000..62365040897 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/PrimaryLogisticChainShipmentAssigner.java @@ -0,0 +1,46 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import org.matsim.core.gbl.Gbl; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * The {@link LspShipment} is assigned to the first {@link LogisticChain}. In case of one chain the + * shipment is assigned to that chain. If there are more chains, the shipment is assigned to the + * first of all chains. Requirements: There must be at least one logisticChain in the plan + */ +class PrimaryLogisticChainShipmentAssigner implements InitialShipmentAssigner { + + + public PrimaryLogisticChainShipmentAssigner() {} + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + Gbl.assertIf(!lspPlan.getLogisticChains().isEmpty()); + LogisticChain firstLogisticChain = lspPlan.getLogisticChains().iterator().next(); + firstLogisticChain.addShipmentToChain(lspShipment); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ProximityStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ProximityStrategyFactory.java new file mode 100644 index 00000000000..1e48dec8363 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ProximityStrategyFactory.java @@ -0,0 +1,149 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * This strategy removes **one** randomly selected shipment from logistic chain with the most shipments and reassign it to the chain with the closest chain. + * The distance is measured as the Euclidean distance between the shipment's destination and the resource's start link. + * This strategy allows to slowly change the plans and therefore follow the iterative learning process. + * + * @author nrichter (during his master thesis @VSP) + */ +final class ProximityStrategyFactory { + //This is ok so as long as it is **non-public**. + //Before making it public, it should be configurable either via config or Injection. + //KMT, KN (Jan'24) + + // yyyy This factory class contains a long anonymous class. It seems that it should be the other way round: The anonymous class should be a proper + // class, and the factory method (or maybe just normal constructor) should be contained in the class. At some point, try to exchange. kmt & kai, mar'24 + + // @formatter:off + + private ProximityStrategyFactory() {} // class contains only static methods; do not instantiate + + static GenericPlanStrategy createStrategy(Network network) { + + GenericPlanStrategyImpl strategy = new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())); + GenericPlanStrategyModule randomModule = new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + // Shifting shipments only makes sense for multiple chains + if (lspPlan.getLogisticChains().size() < 2) return; + + LSP lsp = lspPlan.getLSP(); + double minDistance = Double.MAX_VALUE; + LSPResource minDistanceResource = null; + + // get all shipments assigned to the LSP + Map, LspShipment> lspShipmentById = new HashMap<>(); + for (LspShipment lspShipment : lsp.getLspShipments()) { + lspShipmentById.put(lspShipment.getId(), lspShipment); + } + + // Retrieve all shipments in the logistic chains of the plan + // These should be all shipments of the lsp, but not necessarily if shipments got lost + ArrayList shipments = new ArrayList<>(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (Id id : logisticChain.getLspShipmentIds()) { + LspShipment lspShipment = lspShipmentById.get(id); + if (lspShipment != null) { + shipments.add(lspShipment); + } + } + } + + // pick a random lspShipment from the shipments contained in the plan + int shipmentIndex = MatsimRandom.getRandom().nextInt(shipments.size()); + LspShipment lspShipment = shipments.get(shipmentIndex); + + // Collect all resources of the logistic chains of the LSP plan + ArrayList resources = new ArrayList<>(); + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : + logisticChain.getLogisticChainElements()) { + resources.add(logisticChainElement.getResource()); + } + } + + // get the resource with the smallest distance to the lspShipment + for (LSPResource resource : resources) { + Link shipmentLink = network.getLinks().get(lspShipment.getTo()); + Link resourceLink = network.getLinks().get(resource.getStartLinkId()); + double distance = + NetworkUtils.getEuclideanDistance( + shipmentLink.getFromNode().getCoord(), resourceLink.getFromNode().getCoord()); + if (distance < minDistance) { + minDistance = distance; + minDistanceResource = resource; + } + } + + // add randomly picked lspShipment to chain with resource of the smallest distance + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : + logisticChain.getLogisticChainElements()) { + if (logisticChainElement.getResource().equals(minDistanceResource)) { + logisticChain.getLspShipmentIds().add(lspShipment.getId()); + } + } + } + + // remove the lspShipment from the previous logistic chain, can be the same as the new + // logistic chain + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + if (logisticChain.getLspShipmentIds().contains(lspShipment.getId())) { + logisticChain.getLspShipmentIds().remove(lspShipment.getId()); + break; + } + } + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(randomModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomDistributionAllShipmentsStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomDistributionAllShipmentsStrategyFactory.java new file mode 100644 index 00000000000..64371400ab9 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomDistributionAllShipmentsStrategyFactory.java @@ -0,0 +1,90 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.List; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * This strategy removes **all** shipments from the logistic chains and reassigns them randomly. + * It does not seem to be a very useful strategy in terms of going forward towards a (local) optimum, as long as it is the only one. + * But it is i) a good example how to write such a strategy and ii) can be used to reshuffle the current state and find a new starting point when running with different strategies. + * @author nrichter (during his master thesis @VSP) + */ +final class RandomDistributionAllShipmentsStrategyFactory { + //This is ok so as long as it is **non-public**. + //Before making it public, it should be configurable either via config or Injection. + //KMT, KN (Jan'24) + + private + RandomDistributionAllShipmentsStrategyFactory() {} // class contains only static methods; do not + // instantiate + + static GenericPlanStrategy createStrategy() { + + GenericPlanStrategyImpl strategy = + new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())); + GenericPlanStrategyModule randomModule = + new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + // Shifting shipments only makes sense for multiple chains + if (lspPlan.getLogisticChains().size() < 2) return; + + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + logisticChain.getLspShipmentIds().clear(); + } + + LSP lsp = lspPlan.getLSP(); + List logisticChains = + new ArrayList<>(lsp.getSelectedPlan().getLogisticChains()); + + for (LspShipment lspShipment : lsp.getLspShipments()) { + int index = MatsimRandom.getRandom().nextInt(logisticChains.size()); + logisticChains.get(index).addShipmentToChain(lspShipment); + } + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(randomModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomLogisticChainShipmentAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomLogisticChainShipmentAssigner.java new file mode 100644 index 00000000000..7477d0e0ac3 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomLogisticChainShipmentAssigner.java @@ -0,0 +1,56 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.matsim.core.gbl.Gbl; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * The {@link LspShipment} is assigned randomly to a {@link LogisticChain}. The logistic chains of a + * plan are collected in a list. The chain to which the shipment is to be assigned is selected by a + * seeded random index. Requirements: There must be at least one logisticChain in the plan. + */ +class RandomLogisticChainShipmentAssigner implements InitialShipmentAssigner { + + private final Random random; + + RandomLogisticChainShipmentAssigner() { + MatsimRandom.reset(); + this.random = MatsimRandom.getLocalInstance(); + } + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + Gbl.assertIf(!lspPlan.getLogisticChains().isEmpty()); + List logisticChains = new ArrayList<>(lspPlan.getLogisticChains()); + int index = random.nextInt(logisticChains.size()); + LogisticChain logisticChain = logisticChains.get(index); + logisticChain.addShipmentToChain(lspShipment); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomShiftingStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomShiftingStrategyFactory.java new file mode 100644 index 00000000000..ee25acd18e5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomShiftingStrategyFactory.java @@ -0,0 +1,116 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * This strategy removes **one** randomly selected shipment from the logistic chain it was assigned to and reassign it to another chain. + * This strategy allows to slowly change the plans and therefore follow the iterative learning process. + * But it is i) slow, because it needs a lot of iterations and ii) has a high chance to get stuck in a local optimum. + * @author nrichter (during his master thesis @VSP) + */ +class RandomShiftingStrategyFactory { + + private static Random random = null; + + //This is ok so as long as it is **non-public**. + //Before making it public, it should be configurable either via config or Injection. + //KMT, KN (Jan'24) + RandomShiftingStrategyFactory() {} // class contains only static methods; do not instantiate. + + static GenericPlanStrategy createStrategy() { + + MatsimRandom.reset(); + random = MatsimRandom.getLocalInstance(); + + GenericPlanStrategyImpl strategy = new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())); + GenericPlanStrategyModule randomModule = new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + // Shifting lspShipments only makes sense for multiple chains + if (lspPlan.getLogisticChains().size() < 2) return; + + LSP lsp = lspPlan.getLSP(); + + // Make a new list of lspShipments and pick a random lspShipment from it + List lspShipments = new ArrayList<>(lsp.getLspShipments()); + int shipmentIndex = random.nextInt(lsp.getLspShipments().size()); + LspShipment lspShipment = lspShipments.get(shipmentIndex); + + // Find and remove the random lspShipment from its current logistic chain + LogisticChain sourceLogisticChain = null; + for (LogisticChain logisticChain : lsp.getSelectedPlan().getLogisticChains()) { + if (logisticChain.getLspShipmentIds().remove(lspShipment.getId())) { + sourceLogisticChain = logisticChain; + break; + } + } + + // Find a new logistic chain for the lspShipment + // Ensure that the chain selected is not the same as the one it was removed from + int chainIndex; + LogisticChain targetLogisticChain = null; + do { + chainIndex = random.nextInt(lsp.getSelectedPlan().getLogisticChains().size()); + Iterator iterator = lsp.getSelectedPlan().getLogisticChains().iterator(); + for (int i = 0; iterator.hasNext(); i++) { + targetLogisticChain = iterator.next(); + if (i == chainIndex) { + break; + } + } + } while (targetLogisticChain == sourceLogisticChain); + + // Add the lspShipment to the new logistic chain + assert targetLogisticChain != null; + targetLogisticChain.addShipmentToChain(lspShipment); + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(randomModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RebalancingStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RebalancingStrategyFactory.java new file mode 100644 index 00000000000..a9b08f9469c --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RebalancingStrategyFactory.java @@ -0,0 +1,110 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * This strategy removes **one** randomly selected shipment from logistic chain with the most shipments and reassign it to one of the chains with the lowest number of shipments. + * This strategy allows to slowly change the plans and therefore follow the iterative learning process. But is moves towards a solution with all chains having the same number of shipments. + * For me (KMT) the use case is not obvious, when used as only strategy, but it can have its use in a set of strategies. + * @author nrichter (during his master thesis @VSP) + */ +class RebalancingStrategyFactory { + //This is ok so as long as it is **non-public**. + //Before making it public, it should be configurable either via config or Injection. + //KMT, KN (Jan'24) + + private RebalancingStrategyFactory() {} // class contains only static methods; do not instantiate + + static GenericPlanStrategy createStrategy() { + + GenericPlanStrategyImpl strategy = + new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())); + GenericPlanStrategyModule loadBalancingModule = + new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + // Shifting shipments only makes sense for multiple chains + if (lspPlan.getLogisticChains().size() < 2) return; + + LSP lsp = lspPlan.getLSP(); + Map shipmentCountByChain = new HashMap<>(); + LogisticChain minChain; + LogisticChain maxChain; + + // fill the shipmentCountByChain map with each chain's shipment count + for (LogisticChain chain : lsp.getSelectedPlan().getLogisticChains()) { + shipmentCountByChain.put(chain, chain.getLspShipmentIds().size()); + } + + // find the chains with the minimum and maximum shipment counts + minChain = + Collections.min(shipmentCountByChain.entrySet(), Map.Entry.comparingByValue()) + .getKey(); + maxChain = + Collections.max(shipmentCountByChain.entrySet(), Map.Entry.comparingByValue()) + .getKey(); + + // If min and max chains are the same, no need to shift shipments + if (minChain.equals(maxChain)) return; + + // get the first shipment ID from the chain with the maximum shipment count + Id shipmentIdForReplanning = maxChain.getLspShipmentIds().iterator().next(); + + // iterate through the chains and move the shipment from the max chain to the min chain + for (LogisticChain logisticChain : lsp.getSelectedPlan().getLogisticChains()) { + if (logisticChain.equals(maxChain)) { + logisticChain.getLspShipmentIds().remove(shipmentIdForReplanning); + } + if (logisticChain.equals(minChain)) { + logisticChain.getLspShipmentIds().add(shipmentIdForReplanning); + } + } + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(loadBalancingModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinDistributionAllShipmentsStrategyFactory.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinDistributionAllShipmentsStrategyFactory.java new file mode 100644 index 00000000000..74ac28b39a5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinDistributionAllShipmentsStrategyFactory.java @@ -0,0 +1,97 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.replanning.GenericPlanStrategy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.modules.GenericPlanStrategyModule; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * This strategy removes **all** shipments from the logistic chains and reassigns them. + * The reassignment is done in a round-robin fashion, so that in the hand all chains have the same number of shipments. + * It does not seem to be a very useful strategy in terms of going forward towards a (local) optimum, as long as it is the only one. + * + * @author nrichter (during his master thesis @VSP) + */ +/*package-private*/ class RoundRobinDistributionAllShipmentsStrategyFactory { + //This is ok so as long as it is **non-public**. + //Before making it public, it should be configurable either via config or Injection. + //KMT, KN (Jan'24) + + private + RoundRobinDistributionAllShipmentsStrategyFactory() {} // class contains only static methods; do + // not instantiate + + /*package-private*/ static GenericPlanStrategy createStrategy() { + GenericPlanStrategyImpl strategy = + new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())); + GenericPlanStrategyModule roundRobinModule = + new GenericPlanStrategyModule<>() { + + @Override + public void prepareReplanning(ReplanningContext replanningContext) {} + + @Override + public void handlePlan(LSPPlan lspPlan) { + + // Shifting shipments only makes sense for multiple chains + if (lspPlan.getLogisticChains().size() < 2) return; + + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + logisticChain.getLspShipmentIds().clear(); + } + + LSP lsp = lspPlan.getLSP(); + Map shipmentCountByChain = new LinkedHashMap<>(); + + for (LspShipment lspShipment : lsp.getLspShipments()) { + if (shipmentCountByChain.isEmpty()) { + for (LogisticChain chain : lsp.getSelectedPlan().getLogisticChains()) { + shipmentCountByChain.put(chain, 0); + } + } + LogisticChain minChain = + Collections.min(shipmentCountByChain.entrySet(), Map.Entry.comparingByValue()) + .getKey(); + minChain.addShipmentToChain(lspShipment); + shipmentCountByChain.merge(minChain, 1, Integer::sum); + } + } + + @Override + public void finishReplanning() {} + }; + + strategy.addStrategyModule(roundRobinModule); + return strategy; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinLogisticChainShipmentAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinLogisticChainShipmentAssigner.java new file mode 100644 index 00000000000..c7d1dfae611 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RoundRobinLogisticChainShipmentAssigner.java @@ -0,0 +1,64 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import org.matsim.core.gbl.Gbl; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * The {@link LspShipment} is assigned consecutively to a {@link LogisticChain}. In case of one + * chain the shipment is assigned to that chain. If there are more chains, the shipment is assigned + * to the chain which has the least shipments to this point and thus distributes the shipments + * evenly in sequence across the logistics chains. Requirements: There must be at least one + * logisticChain in the plan + */ +class RoundRobinLogisticChainShipmentAssigner implements InitialShipmentAssigner { + + // map of logistic chains and their number of assigned shipments in order of addition + final Map shipmentCountByChain = new LinkedHashMap<>(); + + RoundRobinLogisticChainShipmentAssigner() {} + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + Gbl.assertIf(!lspPlan.getLogisticChains().isEmpty()); + // prepare the map if empty for the first time with each number of assigned shipments being zero + if (shipmentCountByChain.isEmpty()) { + for (LogisticChain chain : lspPlan.getLogisticChains()) { + shipmentCountByChain.put(chain, 0); + } + } + + // assign the shipment to the chain with the least number of assigned shipments so far, increase + // its value by one + LogisticChain minChain = + Collections.min(shipmentCountByChain.entrySet(), Map.Entry.comparingByValue()).getKey(); + minChain.addShipmentToChain(lspShipment); + shipmentCountByChain.merge(minChain, 1, Integer::sum); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/BlueRequirement.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/BlueRequirement.java new file mode 100644 index 00000000000..4137417af9f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/BlueRequirement.java @@ -0,0 +1,58 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.requirementsChecking; + +import static org.matsim.freight.logistics.examples.requirementsChecking.ExampleCheckRequirementsOfAssigner.ATTRIBUTE_COLOR; + +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipmentRequirement; + +/*package-private*/ class BlueRequirement implements LspShipmentRequirement { + + static final String BLUE = "blue"; + + @Override + public boolean checkRequirement(LogisticChain solution) { + return solution.getAttributes().getAttribute(ATTRIBUTE_COLOR).equals(BLUE); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/ExampleCheckRequirementsOfAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/ExampleCheckRequirementsOfAssigner.java new file mode 100644 index 00000000000..ab521a85ec4 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/ExampleCheckRequirementsOfAssigner.java @@ -0,0 +1,264 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.requirementsChecking; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +class ExampleCheckRequirementsOfAssigner { + + static final String ATTRIBUTE_COLOR = "color"; + + private static LSP createLSPWithProperties(Scenario scenario) { + + final Network network = scenario.getNetwork(); + + // Create red LogisticsSolution which has the corresponding info + final Id redCarrierId = Id.create("RedCarrier", Carrier.class); + final Id collectionVehTypeId = Id.create("RedCarrierVehicleType", VehicleType.class); + final VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + collectionVehType.setNetworkMode(TransportMode.car); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id redVehicleId = Id.createVehicleId("RedVehicle"); + CarrierVehicle redVehicle = + CarrierVehicle.newInstance(redVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities redCapabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(redVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier redCarrier = CarriersUtils.createCarrier(redCarrierId); + redCarrier.setCarrierCapabilities(redCapabilities); + + LSPResource redResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(redCarrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id redElementId = Id.create("RedElement", LogisticChainElement.class); + LogisticChainElement redElement = + LSPUtils.LogisticChainElementBuilder.newInstance(redElementId) + .setResource(redResource) + .build(); + + Id redSolutionId = Id.create("RedSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder redSolutionBuilder = + LSPUtils.LogisticChainBuilder.newInstance(redSolutionId); + redSolutionBuilder.addLogisticChainElement(redElement); + LogisticChain redSolution = redSolutionBuilder.build(); + + // Add info that shows the world the color of the solution + redSolution.getAttributes().putAttribute(ATTRIBUTE_COLOR, RedRequirement.RED); + + // Create blue LogisticsSolution which has the corresponding info + Id blueCarrierId = Id.create("BlueCarrier", Carrier.class); + Id blueVehicleId = Id.createVehicleId("BlueVehicle"); + CarrierVehicle blueVehicle = + CarrierVehicle.newInstance(blueVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities blueCapabilities = + CarrierCapabilities.Builder.newInstance() + .addVehicle(blueVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier blueCarrier = CarriersUtils.createCarrier(blueCarrierId); + blueCarrier.setCarrierCapabilities(blueCapabilities); + + LSPResource blueResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(blueCarrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id blueElementId = Id.create("BlueCElement", LogisticChainElement.class); + LogisticChainElement blueElement = + LSPUtils.LogisticChainElementBuilder.newInstance(blueElementId) + .setResource(blueResource) + .build(); + + LogisticChain blueSolution = + LSPUtils.LogisticChainBuilder.newInstance(Id.create("BlueSolution", LogisticChain.class)) + .addLogisticChainElement(blueElement) + .build(); + + // Add info that shows the world the color of the solution + blueSolution.getAttributes().putAttribute(ATTRIBUTE_COLOR, BlueRequirement.BLUE); + + // Create the initial plan, add assigner that checks requirements of the shipments when + // assigning and add both solutions (red and blue) to the + // plan. + LSPPlan plan = + LSPUtils.createLSPPlan() + .setInitialShipmentAssigner(new RequirementsAssigner()) + .addLogisticChain(redSolution) + .addLogisticChain(blueSolution); + + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(redResource); + resourcesList.add(blueResource); + + return LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)) + .setInitialPlan(plan) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + resourcesList)) + .build(); + } + + public static Collection createShipmentsWithRequirements(Network network) { + // Create ten shipments with either a red or blue requirement, i.e. that they only can be + // transported in a solution with the matching color + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + Random rand = new Random(1); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(Id.createLinkId("(4 2) (4 3)")); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + boolean blue = rand.nextBoolean(); + if (blue) { + builder.addRequirement(new BlueRequirement()); + } else { + builder.addRequirement(new RedRequirement()); + } + + shipmentList.add(builder.build()); + } + + return shipmentList; + } + + public static void main(String[] args) { + + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + // Create LSP and lspShipments + LSP lsp = createLSPWithProperties(scenario); + Collection lspShipments = createShipmentsWithRequirements(network); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + for (LogisticChain logisticChain : lsp.getSelectedPlan().getLogisticChains()) { + if (logisticChain.getId().toString().equals("RedSolution")) { + for (Id lspShipmentId : logisticChain.getLspShipmentIds()) { + LspShipment lspShipment = LSPUtils.findLspShipment(lsp, lspShipmentId); + if (lspShipment != null && !(lspShipment.getRequirements().iterator().next() instanceof RedRequirement)) { + break; + } + } + System.out.println("All lspShipments in " + logisticChain.getId() + " are red"); + } + if (logisticChain.getId().toString().equals("BlueSolution")) { + for (Id lspShipmentId : logisticChain.getLspShipmentIds()) { + LspShipment shipment = LSPUtils.findLspShipment(lsp, lspShipmentId); + if (shipment != null && !(shipment.getRequirements().iterator().next() instanceof BlueRequirement)) { + break; + } + } + System.out.println("All lspShipments in " + logisticChain.getId() + " are blue"); + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RedRequirement.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RedRequirement.java new file mode 100644 index 00000000000..ea51cb3a65a --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RedRequirement.java @@ -0,0 +1,60 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.requirementsChecking; + +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipmentRequirement; + + +/*package-private*/ class RedRequirement implements LspShipmentRequirement { + + static final String RED = "red"; + + @Override + public boolean checkRequirement(LogisticChain solution) { + return solution + .getAttributes() + .getAttribute(ExampleCheckRequirementsOfAssigner.ATTRIBUTE_COLOR) + .equals(RED); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RequirementsAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RequirementsAssigner.java new file mode 100644 index 00000000000..e47b3d358e8 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RequirementsAssigner.java @@ -0,0 +1,79 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.requirementsChecking; + +import java.util.ArrayList; +import java.util.Collection; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentRequirement; + +class RequirementsAssigner implements InitialShipmentAssigner { + + private final Collection feasibleLogisticChains; + + public RequirementsAssigner() { + this.feasibleLogisticChains = new ArrayList<>(); + } + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + feasibleLogisticChains.clear(); + + label: + for (LogisticChain solution : lspPlan.getLogisticChains()) { + for (LspShipmentRequirement requirement : lspShipment.getRequirements()) { + if (!requirement.checkRequirement(solution)) { + + continue label; + } + } + feasibleLogisticChains.add(solution); + } + LogisticChain chosenSolution = feasibleLogisticChains.iterator().next(); + chosenSolution.addShipmentToChain(lspShipment); + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionServiceHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionServiceHandler.java new file mode 100644 index 00000000000..1bbc708aa92 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionServiceHandler.java @@ -0,0 +1,111 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.ArrayList; +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.events.CarrierServiceEndEvent; +import org.matsim.freight.carriers.events.CarrierServiceStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceEndEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceStartEventHandler; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleUtils; +import org.matsim.vehicles.Vehicles; + +/*package-private*/ class CollectionServiceHandler + implements CarrierServiceStartEventHandler, CarrierServiceEndEventHandler { + + private final Collection tuples; + private final Vehicles allVehicles; + private double totalLoadingCosts; + private int totalNumberOfShipments; + private int totalWeightOfShipments; + + public CollectionServiceHandler(Scenario scenario) { + this.allVehicles = VehicleUtils.getOrCreateAllvehicles(scenario); + this.tuples = new ArrayList<>(); + } + + @Override + public void reset(int iteration) { + tuples.clear(); + totalNumberOfShipments = 0; + totalWeightOfShipments = 0; + } + + @Override + public void handleEvent(CarrierServiceEndEvent event) { + System.out.println("Service Ends"); + double loadingCosts; + for (ServiceTuple tuple : tuples) { + if (tuple.getServiceId() == event.getServiceId()) { + double serviceDuration = event.getTime() - tuple.getStartTime(); + + final Vehicle vehicle = allVehicles.getVehicles().get(event.getVehicleId()); + loadingCosts = serviceDuration * vehicle.getType().getCostInformation().getCostsPerSecond(); + totalLoadingCosts = totalLoadingCosts + loadingCosts; + tuples.remove(tuple); + break; + } + } + } + + @Override + public void handleEvent(CarrierServiceStartEvent event) { + totalNumberOfShipments++; + totalWeightOfShipments = totalWeightOfShipments + event.getCapacityDemand(); + tuples.add(new ServiceTuple(event.getServiceId(), event.getTime())); + } + + public double getTotalLoadingCosts() { + return totalLoadingCosts; + } + + public int getTotalNumberOfShipments() { + return totalNumberOfShipments; + } + + public int getTotalWeightOfShipments() { + return totalWeightOfShipments; + } + + private static class ServiceTuple { + private final Id serviceId; + private final double startTime; + + public ServiceTuple(Id serviceId, double startTime) { + this.serviceId = serviceId; + this.startTime = startTime; + } + + public Id getServiceId() { + return serviceId; + } + + public double getStartTime() { + return startTime; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/DistanceAndTimeHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/DistanceAndTimeHandler.java new file mode 100644 index 00000000000..5eece04dd0e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/DistanceAndTimeHandler.java @@ -0,0 +1,101 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.events.LinkEnterEvent; +import org.matsim.api.core.v01.events.LinkLeaveEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; +import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler; +import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler; +import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; +import org.matsim.api.core.v01.network.Network; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleUtils; +import org.matsim.vehicles.Vehicles; + +/*package-private*/ class DistanceAndTimeHandler + implements LinkEnterEventHandler, VehicleLeavesTrafficEventHandler, LinkLeaveEventHandler { + private static final Logger log = LogManager.getLogger(DistanceAndTimeHandler.class); + + private final Map, LinkEnterEvent> events; + private final Vehicles allVehicles; + private final Network network; + private double distanceCosts; + private double timeCosts; + + DistanceAndTimeHandler(Scenario scenario) { + this.network = scenario.getNetwork(); + this.events = new LinkedHashMap<>(); + this.allVehicles = VehicleUtils.getOrCreateAllvehicles(scenario); + } + + @Override + public void handleEvent(LinkEnterEvent event) { + events.put(event.getVehicleId(), event); + } + + @Override + public void reset(int iteration) { + events.clear(); + } + + @Override + public void handleEvent(VehicleLeavesTrafficEvent leaveEvent) { + processLeaveEvent(leaveEvent.getVehicleId(), leaveEvent.getTime()); + } + + @Override + public void handleEvent(LinkLeaveEvent leaveEvent) { + processLeaveEvent(leaveEvent.getVehicleId(), leaveEvent.getTime()); + } + + private void processLeaveEvent(Id vehicleId, double time) { + + LinkEnterEvent enterEvent = events.remove(vehicleId); + if (enterEvent != null) { + Vehicle carrierVehicle = this.allVehicles.getVehicles().get(vehicleId); + double linkDuration = time - enterEvent.getTime(); + timeCosts += linkDuration * carrierVehicle.getType().getCostInformation().getCostsPerSecond(); + double linkLength = network.getLinks().get(enterEvent.getLinkId()).getLength(); + distanceCosts += + linkLength * carrierVehicle.getType().getCostInformation().getCostsPerMeter(); + } + // (there might not be a corresponding enter event if vehicle just entered traffic. Could add + // that as well, but then we would need to compensate for fact that this covers little distance. + // kai, jul'22) + + } + + public double getDistanceCosts() { + return distanceCosts; + } + + public double getTimeCosts() { + return timeCosts; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/ExampleSimulationTrackers.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/ExampleSimulationTrackers.java new file mode 100644 index 00000000000..291e275df6a --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/ExampleSimulationTrackers.java @@ -0,0 +1,218 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Random; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +/*package-private*/ class ExampleSimulationTrackers { + + /*package-private*/ + static LSP createLSPWithTracker(Scenario scenario) { + + // The Carrier for the resource of the sole LogisticsSolutionElement of the LSP is created + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = + CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities capabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(carrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + // The Resource i.e. the Resource is created + + LSPResource collectionResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + carrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + // The adapter is now inserted into the only LogisticsSolutionElement of the only + // LogisticsSolution of the LSP + LogisticChainElement collectionElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + // The LogisticsSolutionElement is now inserted into the only LogisticsSolution of the LSP + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LogisticChain collectionSolution = + LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId) + .addLogisticChainElement(collectionElement) + .build(); + + // Create cost tracker and add it to solution + LinearCostTracker tracker = new LinearCostTracker(0.2); + tracker.getEventHandlers().add(new TourStartHandler(scenario)); + tracker.getEventHandlers().add(new CollectionServiceHandler(scenario)); + tracker.getEventHandlers().add(new DistanceAndTimeHandler(scenario)); + collectionSolution.addSimulationTracker(tracker); + + // The initial plan of the lsp is generated and the assigner and the solution from above are + // added + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + InitialShipmentAssigner assigner = + ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = + LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + + // The exogenous list of Resources for the SolutionScheduler is compiled and the Scheduler is + // added to the LSPBuilder + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + LogisticChainScheduler simpleScheduler = + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + + return collectionLSPBuilder.build(); + } + + public static Collection createInitialLSPShipments(Network network) { + ArrayList shipmentList = new ArrayList<>(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + // Create five LSPShipments that are located in the left half of the network. + for (int i = 1; i < 6; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(Id.createLinkId("(4 2) (4 3)")); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipmentList.add(builder.build()); + } + return shipmentList; + } + + public static void main(String[] args) { + + // Set up required MATSim classes + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()) + .readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + // Create LSP and lspShipments + LSP lsp = createLSPWithTracker(scenario); + Collection lspShipments = createInitialLSPShipments(network); + + // assign the lspShipments to the LSP + for (LspShipment lspShipment : lspShipments) { + lsp.assignShipmentToLSP(lspShipment); + } + + // schedule the LSP with the lspShipments and according to the scheduler of the Resource + lsp.scheduleLogisticChains(); + + // Prepare LSPModule and add the LSP + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + LSPUtils.addLSPs(scenario, lsps); + + // Start the Mobsim one iteration is sufficient for tracking + Controler controler = new Controler(config); + controler.addOverridingModule(new LSPModule()); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.overwriteExistingFiles); + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + // The VSP default settings are designed for person transport simulation. After talking to Kai, + // they will be set to WARN here. Kai MT may'23 + controler + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + // Retrieve cost info from lsp + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + System.out.println(solution.getAttributes().getAttribute("cost_function")); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/LinearCostTracker.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/LinearCostTracker.java new file mode 100644 index 00000000000..8a8fbb9f2a2 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/LinearCostTracker.java @@ -0,0 +1,173 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.ArrayList; +import java.util.Collection; +import org.matsim.api.core.v01.events.LinkEnterEvent; +import org.matsim.api.core.v01.events.LinkLeaveEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; +import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler; +import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler; +import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.freight.carriers.events.CarrierServiceEndEvent; +import org.matsim.freight.carriers.events.CarrierServiceStartEvent; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceEndEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceStartEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourStartEventHandler; +import org.matsim.freight.logistics.LSPSimulationTracker; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChain; + +/*package-private*/ class LinearCostTracker + implements AfterMobsimListener, + LSPSimulationTracker, + LinkEnterEventHandler, + VehicleLeavesTrafficEventHandler, + CarrierTourStartEventHandler, + CarrierServiceStartEventHandler, + CarrierServiceEndEventHandler, + LinkLeaveEventHandler { + + private final Collection eventHandlers; + private final double shareOfFixedCosts; + // private final Collection infos; + private double distanceCosts; + private double timeCosts; + private double loadingCosts; + private double vehicleFixedCosts; + private int totalNumberOfShipments; + private int totalWeightOfShipments; + private double fixedUnitCosts; + private double linearUnitCosts; + private LogisticChain logisticChain; + + public LinearCostTracker(double shareOfFixedCosts) { + this.shareOfFixedCosts = shareOfFixedCosts; + this.eventHandlers = new ArrayList<>(); + } + + public final Collection getEventHandlers() { + return eventHandlers; + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) { + for (EventHandler handler : eventHandlers) { + if (handler instanceof TourStartHandler startHandler) { + this.vehicleFixedCosts = startHandler.getVehicleFixedCosts(); + } + if (handler instanceof DistanceAndTimeHandler distanceHandler) { + this.distanceCosts = distanceHandler.getDistanceCosts(); + this.timeCosts = distanceHandler.getTimeCosts(); + } + if (handler instanceof CollectionServiceHandler collectionHandler) { + totalNumberOfShipments = collectionHandler.getTotalNumberOfShipments(); + System.out.println(totalNumberOfShipments); + totalWeightOfShipments = collectionHandler.getTotalWeightOfShipments(); + loadingCosts = collectionHandler.getTotalLoadingCosts(); + } + } + + double totalCosts = distanceCosts + timeCosts + loadingCosts + vehicleFixedCosts; + fixedUnitCosts = (totalCosts * shareOfFixedCosts) / totalNumberOfShipments; + linearUnitCosts = (totalCosts * (1 - shareOfFixedCosts)) / totalWeightOfShipments; + + LSPUtils.setFixedCost(this.logisticChain, fixedUnitCosts); + LSPUtils.setVariableCost(this.logisticChain, linearUnitCosts); + } + + @Override + public void reset(int iteration) { + distanceCosts = 0; + timeCosts = 0; + loadingCosts = 0; + vehicleFixedCosts = 0; + totalNumberOfShipments = 0; + totalWeightOfShipments = 0; + fixedUnitCosts = 0; + linearUnitCosts = 0; + } + + @Override + public void setEmbeddingContainer(LogisticChain pointer) { + this.logisticChain = pointer; + } + + @Override + public void handleEvent(LinkEnterEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof LinkEnterEventHandler) { + ((LinkEnterEventHandler) eventHandler).handleEvent(event); + } + } + } + + @Override + public void handleEvent(VehicleLeavesTrafficEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof VehicleLeavesTrafficEventHandler) { + ((VehicleLeavesTrafficEventHandler) eventHandler).handleEvent(event); + } + } + } + + @Override + public void handleEvent(CarrierTourStartEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof CarrierTourStartEventHandler) { + ((CarrierTourStartEventHandler) eventHandler).handleEvent(event); + } + } + } + + @Override + public void handleEvent(CarrierServiceEndEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof CarrierServiceEndEventHandler) { + ((CarrierServiceEndEventHandler) eventHandler).handleEvent(event); + } + } + } + + @Override + public void handleEvent(CarrierServiceStartEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof CarrierServiceStartEventHandler) { + ((CarrierServiceStartEventHandler) eventHandler).handleEvent(event); + } + } + } + + @Override + public void handleEvent(LinkLeaveEvent event) { + for (EventHandler eventHandler : this.eventHandlers) { + if (eventHandler instanceof LinkLeaveEventHandler) { + ((LinkLeaveEventHandler) eventHandler).handleEvent(event); + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/TourStartHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/TourStartHandler.java new file mode 100644 index 00000000000..79b92965cf1 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/TourStartHandler.java @@ -0,0 +1,83 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.Collection; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourStartEventHandler; + +/*package-private*/ class TourStartHandler implements CarrierTourStartEventHandler { + + private static final Logger log = LogManager.getLogger(TourStartHandler.class); + private final Carriers carriers; + private double vehicleFixedCosts; + + public TourStartHandler(Scenario scenario) { + this.carriers = CarriersUtils.addOrGetCarriers(scenario); + } + + @Override + public void reset(int iteration) { + vehicleFixedCosts = 0; + } + + @Override + public void handleEvent(CarrierTourStartEvent event) { + log.warn("handling tour start event={}", event.toString()); + + CarrierVehicle carrierVehicle = null; + /* + * This somehow a workaround, because the Vehicle can't get received from the (MATSim) allVehicle container. + * At the TourStartEvent stage, the event.getVehicle is still not known ("null"), because it bases on ActivityEndEvent. + * And since it is the first ActEndEvent of the person, it never entered a vehicle before -.- + * + * My preferred approach would have been something like + * final Vehicle vehicle = allVehicles.getVehicles().get(event.getVehicleId()); + * kmt sep'22 + */ + Carrier carrier = carriers.getCarriers().get(event.getCarrierId()); + Collection scheduledTours = carrier.getSelectedPlan().getScheduledTours(); + for (ScheduledTour scheduledTour : scheduledTours) { + if (scheduledTour.getTour().getId() == event.getTourId()) { + carrierVehicle = scheduledTour.getVehicle(); + break; + } + } + assert carrierVehicle != null; + vehicleFixedCosts = + vehicleFixedCosts + carrierVehicle.getType().getCostInformation().getFixedCosts(); + } + + /** + * ATTENTION: Does this really give back the costs of the current vehicle? Or is the value maybe + * overwritten if another event happens before calling the getFixedCosts function? kmt sep'22 + * + * @return the fixedCosts + */ + public double getVehicleFixedCosts() { + return vehicleFixedCosts; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlParserV1.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlParserV1.java new file mode 100644 index 00000000000..e555e9adccf --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlParserV1.java @@ -0,0 +1,437 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2023 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.io; + +import static org.matsim.freight.logistics.LSPConstants.*; +import static org.matsim.utils.objectattributes.attributable.AttributesUtils.ATTRIBUTE; +import static org.matsim.utils.objectattributes.attributable.AttributesUtils.ATTRIBUTES; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.gbl.Gbl; +import org.matsim.core.utils.io.MatsimXmlParser; +import org.matsim.core.utils.misc.Time; +import org.matsim.freight.carriers.*; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.TransshipmentHubResource; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.utils.objectattributes.attributable.AttributesXmlReaderDelegate; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; +import org.xml.sax.Attributes; + +/** + * Reads data out of LSPPlans file and builds the LSPs with their according resources, shipments and + * plans. StartTag mainly for parsing data, endTag for assigning data to according LSP. + * + * @author nrichter (Niclas Richter) + */ +class LSPPlanXmlParserV1 extends MatsimXmlParser { + + public static final Logger logger = LogManager.getLogger(LSPPlanXmlParserV1.class); + private final LSPs lsPs; + private final Carriers carriers; + private final Map elementIdResourceIdMap = new LinkedHashMap<>(); + private final Map planElements = new LinkedHashMap<>(); + private final AttributesXmlReaderDelegate attributesReader = new AttributesXmlReaderDelegate(); + private final List logisticChains = new LinkedList<>(); + private LSP currentLsp = null; + private Carrier currentCarrier = null; + private LspShipment currentShipment = null; + private LSPPlan currentLspPlan = null; + private CarrierCapabilities.Builder capabilityBuilder; + private TransshipmentHubResource hubResource; + private String currentHubId; + private Double currentHubFixedCost; + private String currentHubLocation; + private String chainId; + private Double score; + private String selected; + private String shipmentPlanId; + private String shipmentChainId; + + LSPPlanXmlParserV1(LSPs lsPs, Carriers carriers) { + super(ValidationType.XSD_ONLY); + this.lsPs = lsPs; + this.carriers = carriers; + } + + @Override + public void startTag(String name, Attributes atts, Stack context) { + org.matsim.utils.objectattributes.attributable.Attributes currAttributes; + switch (name) { + case LSP -> { + String lspId = atts.getValue(ID); + Gbl.assertNotNull(lspId); + currentLsp = + LSPUtils.LSPBuilder.getInstance(Id.create(lspId, LSP.class)) + .setLogisticChainScheduler( + ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler( + Collections.emptyList())) + .setInitialPlan(new LSPPlanImpl()) + .build(); + } + case CARRIER -> { + String carrierId = atts.getValue(ID); + Gbl.assertNotNull(carrierId); + currentCarrier = carriers.getCarriers().get(Id.create(carrierId, Carrier.class)); + } + case HUB -> { + currentHubId = atts.getValue(ID); + Gbl.assertNotNull(currentHubId); + currentHubLocation = atts.getValue(LOCATION); + Gbl.assertNotNull(currentHubLocation); + currentHubFixedCost = Double.parseDouble(atts.getValue(FIXED_COST)); + Gbl.assertNotNull(currentHubFixedCost); + } + case CAPABILITIES -> { + String fleetSize = atts.getValue(FLEET_SIZE); + Gbl.assertNotNull(fleetSize); + this.capabilityBuilder = CarrierCapabilities.Builder.newInstance(); + if (fleetSize.toUpperCase().equals(CarrierCapabilities.FleetSize.FINITE.toString())) { + this.capabilityBuilder.setFleetSize(CarrierCapabilities.FleetSize.FINITE); + } else { + this.capabilityBuilder.setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + } + } + case SCHEDULER -> { + double capacityNeedFixed = Double.parseDouble(atts.getValue(CAPACITY_NEED_FIXED)); + double capacityNeedLinear = Double.parseDouble(atts.getValue(CAPACITY_NEED_LINEAR)); + hubResource = + ResourceImplementationUtils.TransshipmentHubBuilder.newInstance( + Id.create(currentHubId, LSPResource.class), + Id.createLinkId(currentHubLocation), + null) + .setTransshipmentHubScheduler( + ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance() + .setCapacityNeedFixed( + capacityNeedFixed) // Time needed, fixed (for Scheduler) + .setCapacityNeedLinear( + capacityNeedLinear) // additional time needed per shipmentSize (for + // Scheduler) + .build()) + .build(); + } + case ATTRIBUTES -> { + switch (context.peek()) { + case SHIPMENT -> currAttributes = currentShipment.getAttributes(); + case LSP -> currAttributes = currentLsp.getAttributes(); + default -> throw new RuntimeException( + "could not derive context for attributes. context=" + context.peek()); + } + attributesReader.startTag(name, atts, context, currAttributes); + } + case ATTRIBUTE -> { + currAttributes = currentCarrier.getAttributes(); + Gbl.assertNotNull(currAttributes); + attributesReader.startTag(name, atts, context, currAttributes); + } + case VEHICLE -> { + String vehicleId = atts.getValue(ID); + Gbl.assertNotNull(vehicleId); + + String depotLinkId = atts.getValue(DEPOT_LINK_ID); + Gbl.assertNotNull(depotLinkId); + + String typeId = atts.getValue(TYPE_ID); + Gbl.assertNotNull(typeId); + VehicleType vehicleType = + VehicleUtils.createVehicleType(Id.create(typeId, VehicleType.class)); + Gbl.assertNotNull(vehicleType); + + CarrierVehicle.Builder vehicleBuilder = + CarrierVehicle.Builder.newInstance( + Id.create(vehicleId, Vehicle.class), + Id.create(depotLinkId, Link.class), + vehicleType); + String startTime = atts.getValue(EARLIEST_START); + if (startTime != null) vehicleBuilder.setEarliestStart(parseTimeToDouble(startTime)); + String endTime = atts.getValue(LATEST_END); + if (endTime != null) vehicleBuilder.setLatestEnd(parseTimeToDouble(endTime)); + + CarrierVehicle vehicle = vehicleBuilder.build(); + capabilityBuilder.addVehicle(vehicle); + } + case SHIPMENT -> { + String shipmentId = atts.getValue(ID); + Gbl.assertNotNull(shipmentId); + Id id = Id.create(shipmentId, LspShipment.class); + + String from = atts.getValue(FROM); + Gbl.assertNotNull(from); + String to = atts.getValue(TO); + Gbl.assertNotNull(to); + String sizeString = atts.getValue(SIZE); + Gbl.assertNotNull(sizeString); + int size = Integer.parseInt(sizeString); + LspShipmentUtils.LspShipmentBuilder shipmentBuilder = + LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + shipmentBuilder.setFromLinkId(Id.createLinkId(from)); + shipmentBuilder.setToLinkId(Id.createLinkId(to)); + shipmentBuilder.setCapacityDemand(size); + + String startPickup = atts.getValue(START_PICKUP); + String endPickup = atts.getValue(END_PICKUP); + String startDelivery = atts.getValue(START_DELIVERY); + String endDelivery = atts.getValue(END_DELIVERY); + String pickupServiceTime = atts.getValue(PICKUP_SERVICE_TIME); + String deliveryServiceTime = atts.getValue(DELIVERY_SERVICE_TIME); + + if (startPickup != null && endPickup != null) + shipmentBuilder.setStartTimeWindow( + TimeWindow.newInstance(parseTimeToDouble(startPickup), parseTimeToDouble(endPickup))); + if (startDelivery != null && endDelivery != null) + shipmentBuilder.setEndTimeWindow( + TimeWindow.newInstance( + parseTimeToDouble(startDelivery), parseTimeToDouble(endDelivery))); + if (pickupServiceTime != null) + shipmentBuilder.setPickupServiceTime(parseTimeToDouble(pickupServiceTime)); + if (deliveryServiceTime != null) + shipmentBuilder.setDeliveryServiceTime(parseTimeToDouble(deliveryServiceTime)); + + currentShipment = shipmentBuilder.build(); + currentLsp.getLspShipments().add(currentShipment); + } + case LSP_PLAN -> { + currentLspPlan = LSPUtils.createLSPPlan(); + score = Double.valueOf(atts.getValue(SCORE)); + Gbl.assertNotNull(score); + selected = atts.getValue(SELECTED); + Gbl.assertNotNull(selected); + } + case LOGISTIC_CHAIN -> { + chainId = atts.getValue(ID); + Gbl.assertNotNull(chainId); + } + case RESOURCES -> {} + case LOGISTIC_CHAIN_ELEMENT -> { + String logisticChainElementId = atts.getValue(ID); + String resourceId = atts.getValue(RESOURCE_ID); + + elementIdResourceIdMap.put(logisticChainElementId, resourceId); + } + case SHIPMENT_PLAN -> { + shipmentPlanId = atts.getValue(SHIPMENT_ID); + Gbl.assertNotNull(shipmentPlanId); + shipmentChainId = atts.getValue(CHAIN_ID); + Gbl.assertNotNull(shipmentChainId); + } + case ELEMENT -> { + String elementId = atts.getValue(ID); + Gbl.assertNotNull(elementId); + + String type = atts.getValue(TYPE); + Gbl.assertNotNull(type); + + String startTime = atts.getValue(START_TIME); + Gbl.assertNotNull(startTime); + + String endTime = atts.getValue(END_TIME); + Gbl.assertNotNull(endTime); + + String resourceId = atts.getValue(RESOURCE_ID); + Gbl.assertNotNull(resourceId); + + LspShipmentPlanElement planElement = null; + + switch (type) { + case "LOAD" -> { + var planElementBuilder = LspShipmentUtils.ScheduledShipmentLoadBuilder.newInstance(); + planElementBuilder.setStartTime(parseTimeToDouble(startTime)); + planElementBuilder.setEndTime(parseTimeToDouble(endTime)); + planElementBuilder.setResourceId(Id.create(resourceId, LSPResource.class)); + planElement = planElementBuilder.build(); + } + case "TRANSPORT" -> { + var planElementBuilder = LspShipmentUtils.ScheduledShipmentTransportBuilder.newInstance(); + planElementBuilder.setStartTime(parseTimeToDouble(startTime)); + planElementBuilder.setEndTime(parseTimeToDouble(endTime)); + planElementBuilder.setResourceId(Id.create(resourceId, LSPResource.class)); + planElement = planElementBuilder.build(); + } + case "UNLOAD" -> { + var planElementBuilder = LspShipmentUtils.ScheduledShipmentUnloadBuilder.newInstance(); + planElementBuilder.setStartTime(parseTimeToDouble(startTime)); + planElementBuilder.setEndTime(parseTimeToDouble(endTime)); + planElementBuilder.setResourceId(Id.create(resourceId, LSPResource.class)); + planElement = planElementBuilder.build(); + } + case "HANDLE" -> { + var planElementBuilder = LspShipmentUtils.ScheduledShipmentHandleBuilder.newInstance(); + planElementBuilder.setStartTime(parseTimeToDouble(startTime)); + planElementBuilder.setEndTime(parseTimeToDouble(endTime)); + planElementBuilder.setResourceId(Id.create(resourceId, LSPResource.class)); + planElement = planElementBuilder.build(); + } + } + planElements.put(elementId, planElement); + } + } + } + + @Override + public void endTag(String name, String content, Stack context) { + switch (name) { + case LSP -> { + Gbl.assertNotNull(currentLsp); + Gbl.assertNotNull(lsPs); + Gbl.assertNotNull(lsPs.getLSPs()); + currentLsp.getPlans().removeFirst(); // empty plan zero was set for initialization of currentLSP + lsPs.getLSPs().put(currentLsp.getId(), currentLsp); + currentLsp = null; + } + case CARRIER -> { + Gbl.assertNotNull(currentCarrier); + Gbl.assertNotNull(carriers); + Gbl.assertNotNull(carriers.getCarriers()); + LSPResource lspResource; + + switch (ResourceImplementationUtils.getCarrierType(currentCarrier)) { + case collectionCarrier -> lspResource = + ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance( + currentCarrier) + .setCollectionScheduler( + ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(null)) + .build(); + case mainRunCarrier -> lspResource = + ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(currentCarrier) + .setMainRunCarrierScheduler( + ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(null)) + .build(); + case distributionCarrier -> lspResource = + ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance( + currentCarrier) + .setDistributionScheduler( + ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(null)) + .build(); + default -> throw new IllegalStateException( + "Unexpected value: " + currentCarrier.getAttributes().toString()); + } + Gbl.assertNotNull(lspResource); + currentLsp.getResources().add(lspResource); + currentCarrier = null; + } + case HUB -> { + currentLsp.getResources().add(hubResource); + LSPUtils.setFixedCost(hubResource, currentHubFixedCost); + hubResource = null; + currentHubFixedCost = null; + currentHubLocation = null; + currentHubId = null; + } + case CAPABILITIES -> currentCarrier.setCarrierCapabilities(capabilityBuilder.build()); + case ATTRIBUTE -> attributesReader.endTag(name, content, context); + case SHIPMENT -> this.currentShipment = null; + case LSP_PLAN -> {} + + case LOGISTIC_CHAINS -> { + currentLspPlan = LSPUtils.createLSPPlan(); + + for (LogisticChain logisticChain : logisticChains) { + currentLspPlan.addLogisticChain(logisticChain); + } + + currentLspPlan.setScore(score); + currentLspPlan.setLSP(currentLsp); + if (selected.equals("true")) { + currentLsp.setSelectedPlan(currentLspPlan); + } else { + currentLsp.addPlan(currentLspPlan); + } + + logisticChains.clear(); + } + + case LOGISTIC_CHAIN -> { + LSPResource resource; + List logisticChainElements = new LinkedList<>(); + + for (Map.Entry entry : elementIdResourceIdMap.entrySet()) { + for (LSPResource currentResource : currentLsp.getResources()) { + if (currentResource.getId().toString().equals(entry.getValue())) { + resource = currentResource; + Gbl.assertNotNull(resource); + LogisticChainElement logisticChainElement = + LSPUtils.LogisticChainElementBuilder.newInstance( + Id.create(entry.getKey(), LogisticChainElement.class)) + .setResource(resource) + .build(); + logisticChainElements.add(logisticChainElement); + } + } + } + + elementIdResourceIdMap.clear(); + + LogisticChain currentLogisticChain = + LSPUtils.LogisticChainBuilder.newInstance(Id.create(chainId, LogisticChain.class)) + .addLogisticChainElement(logisticChainElements.getFirst()) + .build(); + + for (int i = 1; + i < logisticChainElements.size(); + i++) { // element 0 was already added in Builder as first element. + logisticChainElements.get(i - 1).connectWithNextElement(logisticChainElements.get(i)); + currentLogisticChain.getLogisticChainElements().add(logisticChainElements.get(i)); + } + + logisticChains.add(currentLogisticChain); + } + + case SHIPMENT_PLAN -> { + for (LspShipment lspShipment : currentLsp.getLspShipments()) { + if (lspShipment.getId().toString().equals(shipmentPlanId)) { + for (Map.Entry planElement : planElements.entrySet()) { + LspShipmentUtils.getOrCreateShipmentPlan(currentLspPlan, lspShipment.getId()) + .addPlanElement( + Id.create(planElement.getKey(), LspShipmentPlanElement.class), + planElement.getValue()); + } + } + for (LogisticChain logisticChain : currentLspPlan.getLogisticChains()) { + if (logisticChain.getId().toString().equals(shipmentChainId) + && lspShipment.getId().toString().equals(shipmentPlanId)) { + logisticChain.addShipmentToChain(lspShipment); + } + } + } + shipmentPlanId = null; + planElements.clear(); + } + } + } + + private double parseTimeToDouble(String timeString) { + if (timeString.contains(":")) { + return Time.parseTime(timeString); + } else { + return Double.parseDouble(timeString); + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlReader.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlReader.java new file mode 100644 index 00000000000..3f84c85cda2 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlReader.java @@ -0,0 +1,116 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2023 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.io; + +import java.net.URL; +import java.util.Stack; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.core.api.internal.MatsimReader; +import org.matsim.core.utils.io.MatsimXmlParser; +import org.matsim.freight.carriers.Carriers; +import org.matsim.freight.logistics.LSPConstants; +import org.matsim.freight.logistics.LSPs; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * Delegates a LSPPlanXmlParser according to declared schema definition file + * + * @author nrichter (Niclas Richter) + */ +public final class LSPPlanXmlReader implements MatsimReader { + private static final Logger log = LogManager.getLogger(LSPPlanXmlReader.class); + private final LSPsPlanParser parser; + + public LSPPlanXmlReader(final LSPs lsPs, Carriers carriers) { + System.setProperty("matsim.preferLocalDtds", "true"); + this.parser = new LSPsPlanParser(lsPs, carriers); + } + + public void readFile(String filename) { + try { + this.parser.setValidating(true); + this.parser.readFile(filename); + } catch (Exception e) { + log.warn("### Exception found while trying to read LSPPlan: Message: {} ; cause: {} ; class {}", e.getMessage(), e.getCause(), e.getClass()); + throw e; + } + } + + public void readURL(URL url) { + try { + this.parser.readURL(url); + } catch (Exception e) { + log.warn("### Exception found while trying to read LSPPlan: Message: {} ; cause: {} ; class {}", e.getMessage(), e.getCause(), e.getClass()); + if (e.getCause() + .getMessage() + .contains( + "cvc-elt.1")) { // "Cannot find the declaration of element" -> exception comes most + // probably because no validation information was found + log.warn("read with validation = true failed. Try it again without validation... url: {}", url.toString()); + parser.setValidating(true); + parser.readURL(url); + } else { // other problem: e.g. validation does not work, because of missing validation file. + throw e; + } + } + } + + private static final class LSPsPlanParser extends MatsimXmlParser { + private final LSPs lsPs; + private final Carriers carriers; + + private MatsimXmlParser delegate = null; + + LSPsPlanParser(LSPs lsPs, Carriers carriers) { + super(ValidationType.XSD_ONLY); + this.lsPs = lsPs; + this.carriers = carriers; + } + + public void startTag(String name, Attributes attributes, Stack context) { + if (LSPConstants.LSPS.equalsIgnoreCase(name)) { + String str = attributes.getValue("xsi:schemaLocation"); + log.info("Found following schemaLocation in lsPs definition file: {}", str); + if (str.contains("lspsDefinitions_v1.xsd")) { + delegate = new LSPPlanXmlParserV1(lsPs, carriers); + } else { + throw new RuntimeException("no reader found for " + str); + } + } else { + this.delegate.startTag(name, attributes, context); + } + } + + public void endTag(String name, String content, Stack context) { + this.delegate.endTag(name, content, context); + } + + public void endDocument() { + try { + this.delegate.endDocument(); + } catch (SAXException var2) { + throw new RuntimeException(var2); + } + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlWriter.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlWriter.java new file mode 100644 index 00000000000..2c97a9ae99e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/io/LSPPlanXmlWriter.java @@ -0,0 +1,220 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2023 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.io; + +import static org.matsim.freight.logistics.LSPConstants.*; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.core.gbl.Gbl; +import org.matsim.core.utils.collections.Tuple; +import org.matsim.core.utils.io.MatsimXmlWriter; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.resourceImplementations.TransshipmentHubResource; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/** + * Writes out resources, shipments and plans for each LSP in an XML-file including header for + * validating against respective XSD and setting up according writer. Uses variables defined in + * LSPConstants-class for the elements and attributes within the XML. + * + * @author nrichter (Niclas Richter) + */ +public class LSPPlanXmlWriter extends MatsimXmlWriter { + + private static final Logger logger = LogManager.getLogger(LSPPlanXmlWriter.class); + + private final Collection lsPs; + + public LSPPlanXmlWriter(LSPs lsPs) { + super(); + this.lsPs = lsPs.getLSPs().values(); + } + + public void write(String filename) { + logger.info(Gbl.aboutToWrite("lsps", filename)); + try { + this.openFile(filename); + this.writeXmlHead(); + this.writeRootElement(); + for (LSP lsp : lsPs) { + this.startLSP(lsp); + this.writeResources(lsp); + this.writeShipments(lsp); + this.writePlans(lsp, this.writer); + this.writeEndTag(LSP); + } + this.writeEndTag(LSPConstants.LSPS); + this.close(); + logger.info("done"); + } catch (IOException e) { + e.printStackTrace(); + logger.error(e); + System.exit(1); + } + } + + private void writeRootElement() throws IOException { + List> atts = new ArrayList<>(); + atts.add(createTuple(XMLNS, MatsimXmlWriter.MATSIM_NAMESPACE)); + atts.add(createTuple(XMLNS + ":xsi", DEFAULTSCHEMANAMESPACELOCATION)); + atts.add( + createTuple( + "xsi:schemaLocation", + MATSIM_NAMESPACE + " " + DEFAULT_DTD_LOCATION + "lspsDefinitions_v1.xsd")); + this.writeStartTag(LSPConstants.LSPS, atts); + this.writer.write(NL); + } + + private void startLSP(LSP lsp) throws IOException { + this.writeStartTag(LSP, List.of(createTuple(ID, lsp.getId().toString()))); + } + + private void writeResources(LSP lsp) throws IOException { + if (lsp.getResources().isEmpty()) return; + this.writeStartTag(RESOURCES, null); + for (LSPResource resource : lsp.getResources()) { + if (resource instanceof TransshipmentHubResource hub) { + List> tupleList = new ArrayList<>(); + tupleList.add(new Tuple<>(ID, hub.getId().toString())); + tupleList.add(new Tuple<>(LOCATION, hub.getStartLinkId().toString())); + if (hub.getAttributes().getAttribute(FIXED_COST) != null) { + tupleList.add( + new Tuple<>(FIXED_COST, hub.getAttributes().getAttribute(FIXED_COST).toString())); + } + this.writeStartTag(HUB, tupleList); + this.writeStartTag( + SCHEDULER, + List.of( + createTuple(CAPACITY_NEED_FIXED, hub.getCapacityNeedFixed()), + createTuple(CAPACITY_NEED_LINEAR, hub.getCapacityNeedLinear())), + true); + this.writeEndTag(HUB); + } + if (resource instanceof LSPCarrierResource carrierResource) { + this.writeStartTag( + CARRIER, List.of(createTuple(ID, carrierResource.getId().toString())), true); + } + } + this.writeEndTag(RESOURCES); + } + + private void writeShipments(LSP lsp) throws IOException { + if (lsp.getLspShipments().isEmpty()) return; + this.writeStartTag(SHIPMENTS, null); + for (LspShipment lspShipment : lsp.getLspShipments()) { + this.writeStartTag( + SHIPMENT, + List.of( + createTuple(ID, lspShipment.getId().toString()), + createTuple(FROM, lspShipment.getFrom().toString()), + createTuple(TO, lspShipment.getTo().toString()), + createTuple(SIZE, lspShipment.getSize()), + createTuple(START_PICKUP, lspShipment.getPickupTimeWindow().getStart()), + createTuple(END_PICKUP, lspShipment.getPickupTimeWindow().getEnd()), + createTuple(START_DELIVERY, lspShipment.getDeliveryTimeWindow().getStart()), + createTuple(END_DELIVERY, lspShipment.getDeliveryTimeWindow().getEnd()), + createTuple(PICKUP_SERVICE_TIME, lspShipment.getPickupServiceTime()), + createTuple(DELIVERY_SERVICE_TIME, lspShipment.getDeliveryServiceTime())), + true); + } + this.writeEndTag(SHIPMENTS); + } + + private void writePlans(LSP lsp, BufferedWriter writer) throws IOException { + if (lsp.getPlans().isEmpty()) return; + this.writeStartTag(LSP_PLANS, null); + + for (LSPPlan plan : lsp.getPlans()) { + if (plan.getScore() != null && lsp.getSelectedPlan() != null) { + if (plan == lsp.getSelectedPlan()) { + this.writeStartTag( + LSP_PLAN, + List.of(createTuple(SCORE, plan.getScore()), createTuple(SELECTED, "true"))); + } else { + this.writeStartTag( + LSP_PLAN, + List.of(createTuple(SCORE, plan.getScore()), createTuple(SELECTED, "false"))); + } + } else { + this.writeStartTag(LSP_PLAN, List.of(createTuple(SELECTED, "false"))); + } + + this.writeStartTag(LOGISTIC_CHAINS, null); + for (LogisticChain chain : plan.getLogisticChains()) { + writeStartTag(LOGISTIC_CHAIN, List.of(createTuple(ID, chain.getId().toString()))); + for (LogisticChainElement chainElement : chain.getLogisticChainElements()) { + this.writeStartTag( + LOGISTIC_CHAIN_ELEMENT, + List.of( + createTuple(ID, chainElement.getId().toString()), + createTuple(RESOURCE_ID, chainElement.getResource().getId().toString())), + true); + } + writeEndTag(LOGISTIC_CHAIN); + } + writeEndTag(LOGISTIC_CHAINS); + + writeStartTag(SHIPMENT_PLANS, null); + for (LogisticChain chain : plan.getLogisticChains()) { + for (Id shipmentId : chain.getLspShipmentIds()) { + if (chain.getLspShipmentIds().contains(shipmentId)) { + this.writeStartTag( + SHIPMENT_PLAN, + List.of( + createTuple(SHIPMENT_ID, shipmentId.toString()), + createTuple(CHAIN_ID, chain.getId().toString()))); + } + LspShipment lspShipment = LSPUtils.findLspShipment(lsp, shipmentId); + assert lspShipment != null; + final Map, LspShipmentPlanElement> planElements = + LspShipmentUtils.getOrCreateShipmentPlan(plan, lspShipment.getId()).getPlanElements(); + for (Id elementId : planElements.keySet()) { + LspShipmentPlanElement element = planElements.get(elementId); + this.writeStartTag( + ELEMENT, + List.of( + createTuple(ID, elementId.toString()), + createTuple(TYPE, element.getElementType()), + createTuple(START_TIME, element.getStartTime()), + createTuple(END_TIME, element.getEndTime()), + createTuple(RESOURCE_ID, element.getResourceId().toString())), + true); + } + writeEndTag(SHIPMENT_PLAN); + } + } + writeEndTag(SHIPMENT_PLANS); + writeEndTag(LSP_PLAN); + } + this.writeEndTag(LSP_PLANS); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CarrierSchedulerUtils.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CarrierSchedulerUtils.java new file mode 100644 index 00000000000..bbd9235ca64 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CarrierSchedulerUtils.java @@ -0,0 +1,146 @@ +package org.matsim.freight.logistics.resourceImplementations; + +import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; +import com.graphhopper.jsprit.core.algorithm.box.Jsprit; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import com.graphhopper.jsprit.core.util.Solutions; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.roadpricing.RoadPricingScheme; +import org.matsim.contrib.roadpricing.RoadPricingUtils; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierPlan; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; +import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; +import org.matsim.freight.carriers.jsprit.NetworkRouter; +import org.matsim.freight.logistics.LSPUtils; + +/** + * This class contains some code fragments, that are used in the different *CarrierScheduler + * classes. To avoid code duplication these methods are extracted and located here more centralized. + * + * @author Kai Martins-Turner (kturner) + */ +public class CarrierSchedulerUtils { + private static final Logger log = LogManager.getLogger(CarrierSchedulerUtils.class); + private static final String LOGIC_OF_VRP = "logicOfVrp"; + + /** + * Creates a VehicleRoutingProblem from a carrier and a network and solves it with Jsprit. + * If a roadPricingScheme is given, the tolls are considered in the routing costs. + *

+ * This looks for me (KMT) similar to what is done in {@link org.matsim.freight.carriers.CarriersUtils#runJsprit(Scenario)}. + * So, maybe this can be more simplify. + * + * @param carrier Carrier for which the problem should be solved + * @param scenario the scenario + * @return Carrier with the solution of the VehicleRoutingProblem and the routed plan. + */ + public static Carrier solveVrpWithJsprit(Carrier carrier, Scenario scenario) { + // Maybe it make sense to store this object instead of rebuilding it for each carrier (in each iteration) ??? + // pro: save computation time + // con: interdependencies, if something changes in the network (load), the object is not up-to-date & it is not clear, if the object is thread safe + // Decision for the time being: rebuild it for each carrier to have a clear state KMT/KN Aug'24 + NetworkBasedTransportCosts netbasedTransportCosts; + Network network = scenario.getNetwork(); + RoadPricingScheme roadPricingScheme = null; + try { + roadPricingScheme = RoadPricingUtils.getRoadPricingScheme(scenario); + } catch (Exception e) { + log.info("Was not able getting RoadPricingScheme. Tolls cannot be considered.", e); + } + if (roadPricingScheme != null) { + netbasedTransportCosts = NetworkBasedTransportCosts.Builder.newInstance(network, ResourceImplementationUtils.getVehicleTypeCollection(carrier)) + .setRoadPricingScheme(roadPricingScheme) + .build(); + } else { + log.debug("RoadPricingScheme is null. Tolls cannot be considered."); + netbasedTransportCosts = NetworkBasedTransportCosts.Builder.newInstance(network, ResourceImplementationUtils.getVehicleTypeCollection(carrier)) + .build(); + } + + VehicleRoutingProblem vrp = + MatsimJspritFactory.createRoutingProblemBuilder(carrier, network) + .setRoutingCost(netbasedTransportCosts) + .build(); + + //If jspritIterations are not set (get.... returns a negativ value), set it to 1 + int jspritIterations; + if (CarriersUtils.getJspritIterations(carrier) >= 1) { + jspritIterations = CarriersUtils.getJspritIterations(carrier); + } else { + log.info("Jsprit iterations are not set (properly) for carrier {}. Set to 1.", carrier.getId()); + jspritIterations = 1; + } + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + vra.setMaxIterations(jspritIterations); + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + + CarrierPlan plan = MatsimJspritFactory.createPlan(carrier, solution); + NetworkRouter.routePlan(plan, netbasedTransportCosts); + carrier.addPlan(plan); + carrier.setSelectedPlan(plan); + return carrier; + } + + public static Double sumUpScore(List scheduledPlans) { + double score = 0; + for (CarrierPlan scheduledPlan : scheduledPlans) { + if (scheduledPlan.getScore() != null) { + score = score + scheduledPlan.getScore(); + } + } + return score; + } + + /** + * Sum up the jsprit score of the given list of CarrierPlans. + * As a consequence this is not from the one and only jsprit run, but from all jsprit runs af the different auxiliary carriers. + * @param scheduledPlans the scheduled plans with the jsprit results + * @return the summ of the scores coming from jsprit + */ + public static Double sumUpJspritScore(List scheduledPlans) { + double jspritScore = 0; + for (CarrierPlan scheduledPlan : scheduledPlans) { + if (scheduledPlan.getJspritScore() != null) { + jspritScore = jspritScore + scheduledPlan.getJspritScore(); } + } + return jspritScore; + } + + /** + * Setter for the internal solving logic of a VRP. + * This decides later, whether the VRP is build base on {@link org.matsim.freight.carriers.CarrierService}s or {@link org.matsim.freight.carriers.CarrierShipment}s. + * + * @param carrier The carrier for which the setting should be set. + * @param logicOfVrp the logic of the VRP + */ + public static void setVrpLogic(Carrier carrier, LSPUtils.LogicOfVrp logicOfVrp){ + carrier.getAttributes().putAttribute(LOGIC_OF_VRP, logicOfVrp); + } + + /** + * Getter for the internal solving logic of a VRP. + * This decides later, whether the VRP is build base on {@link org.matsim.freight.carriers.CarrierService}s or {@link org.matsim.freight.carriers.CarrierShipment}s. + * + * @param carrier The carrier for which the setting should be got. + * @return the logic of the VRP, returns {@link LSPUtils.LogicOfVrp#serviceBased} if not set. + */ + public static LSPUtils.LogicOfVrp getVrpLogic(Carrier carrier){ + LSPUtils.LogicOfVrp result = (LSPUtils.LogicOfVrp) carrier.getAttributes().getAttribute(LOGIC_OF_VRP); + if (result == null){ + log.error("VRPLogic not found for carrier {}. Will return {}", carrier.getId(), LSPUtils.LogicOfVrp.serviceBased); + return LSPUtils.LogicOfVrp.serviceBased; + } else { + return result ; + } + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierResource.java new file mode 100644 index 00000000000..f54e29ff6d9 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierResource.java @@ -0,0 +1,85 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Collection; +import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierVehicle; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; + +/*package-private*/ class CollectionCarrierResource extends LSPDataObject + implements LSPCarrierResource { + + private final Carrier carrier; + private final List clientElements; + private final CollectionCarrierScheduler collectionScheduler; + + CollectionCarrierResource(CollectionCarrierResourceBuilder builder) { + super(builder.id); + this.collectionScheduler = builder.collectionScheduler; + this.clientElements = builder.clientElements; + this.carrier = builder.carrier; + } + + @Override + public Id getStartLinkId() { + Id depotLinkId = null; + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + if (depotLinkId == null || depotLinkId == vehicle.getLinkId()) { + depotLinkId = vehicle.getLinkId(); + } + } + + return depotLinkId; + } + + @Override + public Id getEndLinkId() { + Id depotLinkId = null; + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + if (depotLinkId == null || depotLinkId == vehicle.getLinkId()) { + depotLinkId = vehicle.getLinkId(); + } + } + + return depotLinkId; + } + + @Override + public Collection getClientElements() { + return clientElements; + } + + @Override + public void schedule(int bufferTime, LSPPlan lspPlan) { + collectionScheduler.scheduleShipments(lspPlan, this, bufferTime); + } + + public Carrier getCarrier() { + return carrier; + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierScheduler.java new file mode 100644 index 00000000000..708f57974e4 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierScheduler.java @@ -0,0 +1,248 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Objects; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.Tour.Leg; +import org.matsim.freight.carriers.Tour.ServiceActivity; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/** + * Schedules the {@link CollectionCarrierResource}. + * + *

Converts the {@link LspShipment}s into {@link CarrierService}s that are needed for the {@link + * Carrier} from the freight contrib of MATSim and then routes the vehicles of this {@link Carrier} + * through the network by calling the corresponding methods of jsprit + */ +/*package-private*/ class CollectionCarrierScheduler extends LSPResourceScheduler { + + Logger log = LogManager.getLogger(CollectionCarrierScheduler.class); + + private Carrier carrier; + private CollectionCarrierResource resource; + private final Scenario scenario; + + /** + * Constructor for the CollectionCarrierScheduler. + * TODO: In the future, the scenario should come via injection(?) This here is only a dirty workaround. KMT'Aug'24 + * + * @param scenario the road pricing scheme + */ + CollectionCarrierScheduler(Scenario scenario) { + this.scenario = scenario; + } + + @Override + public void initializeValues(LSPResource resource) { + if (resource.getClass() == CollectionCarrierResource.class) { + this.resource = (CollectionCarrierResource) resource; + this.carrier = this.resource.getCarrier(); + this.carrier.getServices().clear(); + this.carrier.getShipments().clear(); + this.carrier.getPlans().clear(); + } + } + + @Override + public void scheduleResource() { + for (LspShipment lspShipmentToBeAssigned : lspShipmentsToSchedule) { + CarrierService carrierService = convertToCarrierService(lspShipmentToBeAssigned); + carrier.getServices().put(carrierService.getId(), carrierService); + } + CarrierSchedulerUtils.solveVrpWithJsprit(carrier, scenario); + } + + private CarrierService convertToCarrierService(LspShipment lspShipment) { + Id serviceId = Id.create(lspShipment.getId().toString(), CarrierService.class); + CarrierService carrierService = CarrierService.Builder.newInstance(serviceId, lspShipment.getFrom()) + .setServiceStartTimeWindow(TimeWindow.newInstance(lspShipment.getPickupTimeWindow().getStart(), lspShipment.getPickupTimeWindow().getEnd())) + .setCapacityDemand(lspShipment.getSize()) + .setServiceDuration(lspShipment.getDeliveryServiceTime()) + .build(); + //ensure that the ids of the lspShipment and the carrierService are the same. This is needed for updating the LSPShipmentPlan + if (! Objects.equals(lspShipment.getId().toString(), carrierService.getId().toString())) { + log.error("Id of LspShipment: {} and CarrierService: {} do not match", lspShipment.getId().toString(), carrierService.getId().toString(), + new IllegalStateException("Id of LspShipment and CarrierService do not match")); + } + return carrierService; + } + + @Override + protected void updateShipments() { + for (LspShipment lspShipment : lspShipmentsToSchedule) { + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + Tour tour = scheduledTour.getTour(); + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity serviceActivity) { + if (Objects.equals(lspShipment.getId().toString(), serviceActivity.getService().getId().toString())) { + addShipmentLoadElement(lspShipment, tour, serviceActivity); + addShipmentTransportElement(lspShipment, tour, serviceActivity); + addShipmentUnloadElement(lspShipment, tour); + addCollectionTourEndEventHandler(serviceActivity.getService(), lspShipment, resource, tour); + addCollectionServiceEventHandler(serviceActivity.getService(), lspShipment, resource); + } + } + } + } + } + } + + private void addShipmentLoadElement( + LspShipment lspShipment, Tour tour, ServiceActivity serviceActivity) { + + LspShipmentUtils.ScheduledShipmentLoadBuilder builder = + LspShipmentUtils.ScheduledShipmentLoadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + + int serviceIndex = tour.getTourElements().indexOf(serviceActivity); + Leg legBeforeService = (Leg) tour.getTourElements().get(serviceIndex - 1); + double startTimeOfLoading = + legBeforeService.getExpectedDepartureTime() + legBeforeService.getExpectedTransportTime(); + builder.setStartTime(startTimeOfLoading); + builder.setEndTime(startTimeOfLoading + lspShipment.getDeliveryServiceTime()); + + LspShipmentPlanElement load = builder.build(); + String idString = + load.getResourceId() + "" + load.getLogisticChainElement().getId() + load.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, load); + } + + private void addShipmentTransportElement( + LspShipment lspShipment, Tour tour, Tour.ServiceActivity serviceActivity) { + + LspShipmentUtils.ScheduledShipmentTransportBuilder builder = + LspShipmentUtils.ScheduledShipmentTransportBuilder.newInstance(); + builder.setResourceId(resource.getId()); + + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + + int serviceIndex = tour.getTourElements().indexOf(serviceActivity); + Leg legAfterService = (Leg) tour.getTourElements().get(serviceIndex + 1); + double startTimeOfTransport = legAfterService.getExpectedDepartureTime(); + builder.setStartTime(startTimeOfTransport); + Leg lastLeg = (Leg) tour.getTourElements().getLast(); + double endTimeOfTransport = lastLeg.getExpectedDepartureTime() + lastLeg.getExpectedTransportTime(); + builder.setEndTime(endTimeOfTransport); + builder.setCarrierId(carrier.getId()); + builder.setFromLinkId(serviceActivity.getLocation()); + builder.setToLinkId(tour.getEndLinkId()); + builder.setCarrierService(serviceActivity.getService()); + LspShipmentPlanElement transport = builder.build(); + String idString = + transport.getResourceId() + + "" + + transport.getLogisticChainElement().getId() + + transport.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, transport); + } + + private void addCollectionServiceEventHandler( + CarrierService carrierService, LspShipment lspShipment, LSPCarrierResource resource) { + + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + CollectionServiceEndEventHandler endHandler = + new CollectionServiceEndEventHandler( + carrierService, lspShipment, element, resource); + lspShipment.addSimulationTracker(endHandler); + break; + } + } + } + + private void addCollectionTourEndEventHandler( + CarrierService carrierService, + LspShipment lspShipment, + LSPCarrierResource resource, + Tour tour) { + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + LSPTourEndEventHandler handler = + new LSPTourEndEventHandler( + lspShipment, carrierService, element, resource, tour); + lspShipment.addSimulationTracker(handler); + break; + } + } + } + + private void addShipmentUnloadElement(LspShipment lspShipment, Tour tour) { + + LspShipmentUtils.ScheduledShipmentUnloadBuilder builder = + LspShipmentUtils.ScheduledShipmentUnloadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticsChainElement(element); + } + } + Leg lastLeg = (Leg) tour.getTourElements().getLast(); + double startTime = lastLeg.getExpectedDepartureTime() + lastLeg.getExpectedTransportTime(); + builder.setStartTime(startTime); + builder.setEndTime(startTime + getUnloadEndTime(tour)); + + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId() + + "" + + unload.getLogisticChainElement().getId() + + unload.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, unload); + } + + private double getUnloadEndTime(Tour tour) { + double unloadEndTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity serviceActivity) { + unloadEndTime = unloadEndTime + serviceActivity.getDuration(); + } + } + return unloadEndTime; + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionServiceEndEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionServiceEndEventHandler.java new file mode 100644 index 00000000000..ffd8f53ca59 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionServiceEndEventHandler.java @@ -0,0 +1,135 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import org.matsim.api.core.v01.Id; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.events.CarrierServiceEndEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceEndEventHandler; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPSimulationTracker; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentLeg; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/*package-private*/ class CollectionServiceEndEventHandler + implements AfterMobsimListener, + CarrierServiceEndEventHandler, + LSPSimulationTracker { + + private final CarrierService carrierService; + private final LogisticChainElement logisticChainElement; + private final LSPCarrierResource resource; + private LspShipment lspShipment; + + public CollectionServiceEndEventHandler( + CarrierService carrierService, + LspShipment lspShipment, + LogisticChainElement element, + LSPCarrierResource resource) { + this.carrierService = carrierService; + this.lspShipment = lspShipment; + this.logisticChainElement = element; + this.resource = resource; + } + + @Override + public void reset(int iteration) { + // TODO Auto-generated method stub + + } + + @Override + public void handleEvent(CarrierServiceEndEvent event) { + if (event.getServiceId() == carrierService.getId() + && event.getCarrierId() == resource.getCarrier().getId()) { + logLoad(event); + logTransport(event); + } + } + + private void logLoad(CarrierServiceEndEvent event) { + LspShipmentUtils.LoggedShipmentLoadBuilder builder = + LspShipmentUtils.LoggedShipmentLoadBuilder.newInstance(); + builder.setStartTime(event.getTime() - event.getServiceDuration()); + builder.setEndTime(event.getTime()); + builder.setLogisticsChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setLinkId(event.getLinkId()); + builder.setCarrierId(event.getCarrierId()); + LspShipmentPlanElement loggedShipmentLoad = builder.build(); + String idString = + loggedShipmentLoad.getResourceId() + + "" + + loggedShipmentLoad.getLogisticChainElement().getId() + + loggedShipmentLoad.getElementType(); + Id loadId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(loadId, loggedShipmentLoad); + } + + private void logTransport(CarrierServiceEndEvent event) { + LspShipmentUtils.LoggedShipmentTransportBuilder builder = + LspShipmentUtils.LoggedShipmentTransportBuilder.newInstance(); + builder.setStartTime(event.getTime()); + builder.setLogisticChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setFromLinkId(event.getLinkId()); + builder.setCarrierId(event.getCarrierId()); + LspShipmentLeg transport = builder.build(); + String idString = + transport.getResourceId() + + "" + + transport.getLogisticChainElement().getId() + + transport.getElementType(); + Id transportId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(transportId, transport); + } + + public CarrierService getCarrierService() { + return carrierService; + } + + public LspShipment getLspShipment() { + return lspShipment; + } + + public LogisticChainElement getElement() { + return logisticChainElement; + } + + public Id getResourceId() { + return resource.getId(); + } + + @Override + public void setEmbeddingContainer(LspShipment pointer) { + this.lspShipment = pointer; + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) {} +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierResource.java new file mode 100644 index 00000000000..00ca29acceb --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierResource.java @@ -0,0 +1,83 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierVehicle; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.DistributionCarrierResourceBuilder; + +/*package-private*/ class DistributionCarrierResource extends LSPDataObject + implements LSPCarrierResource { + + private final Carrier carrier; + private final Collection clientElements; + private final DistributionCarrierScheduler distributionHandler; + + DistributionCarrierResource(DistributionCarrierResourceBuilder builder) { + super(builder.id); + this.distributionHandler = builder.distributionHandler; + this.clientElements = builder.clientElements; + this.carrier = builder.carrier; + } + + @Override + public Id getStartLinkId() { + Id depotLinkId = null; + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + if (depotLinkId == null || depotLinkId == vehicle.getLinkId()) { + depotLinkId = vehicle.getLinkId(); + } + } + + return depotLinkId; + } + + @Override + public Id getEndLinkId() { + Id depotLinkId = null; + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + if (depotLinkId == null || depotLinkId == vehicle.getLinkId()) { + depotLinkId = vehicle.getLinkId(); + } + } + + return depotLinkId; + } + + @Override + public Collection getClientElements() { + return clientElements; + } + + @Override + public void schedule(int bufferTime, LSPPlan lspPlan) { + distributionHandler.scheduleShipments(lspPlan, this, bufferTime); + } + + public Carrier getCarrier() { + return carrier; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierScheduler.java new file mode 100644 index 00000000000..249b5a76031 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierScheduler.java @@ -0,0 +1,481 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.*; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.locationtech.jts.util.Assert; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.Tour.Leg; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; + +/** + * Ähnlich zu CollectionCarrierScheduler: Nun werden Sendungen verteilt statt eingesammelt. + * + *

BUT: scheduleResource() is different from the one used in the case of collection. The + * LSPShipments are not simply handed over to jsprit which calculates the vehicle tours, but rather + * loaded into a waiting distribution vehicle in the order of their arrival at the depot. Once this + * vehicle is full, the tour for this single one is planned by jsprit. All vehicles are thus filled + * and scheduled consecutively. + */ +/*package-private*/ class DistributionCarrierScheduler extends LSPResourceScheduler { + + Logger log = LogManager.getLogger(DistributionCarrierScheduler.class); + + private Carrier carrier; + private DistributionCarrierResource resource; + private int carrierCnt = 1; + private final Scenario scenario; + + + /** + * Constructor for the DistributionCarrierScheduler. + * TODO: In the future, the scenario should come via injection(?) This here is only a dirty workaround. KMT'Aug'24 + * + * @param scenario the scenario + */ + DistributionCarrierScheduler(Scenario scenario) { + this.scenario = scenario; + } + + @Override + protected void initializeValues(LSPResource resource) { + if (resource.getClass() == DistributionCarrierResource.class) { + this.resource = (DistributionCarrierResource) resource; + this.carrier = this.resource.getCarrier(); + this.carrier.getServices().clear(); + this.carrier.getShipments().clear(); + this.carrier.getPlans().clear(); + } + } + + @Override + protected void scheduleResource() { + int load = 0; + double cumulatedLoadingTime = 0; + double availabilityTimeOfLastShipment = 0; + ArrayList copyOfAssignedShipments = new ArrayList<>(lspShipmentsToSchedule); + ArrayList shipmentsInCurrentTour = new ArrayList<>(); + List scheduledPlans = new LinkedList<>(); + + for (LspShipment lspShipment : copyOfAssignedShipments) { + // TODO KMT: Verstehe es nur mäßig, was er hier mit den Fahrzeugtypen macht. Er nimmt einfach + // das erste/nächste(?) und schaut ob es da rein passt... Aber was ist, wenn es mehrere + // gibt??? + VehicleType vehicleType = ResourceImplementationUtils.getVehicleTypeCollection(carrier).iterator().next(); + if ((load + lspShipment.getSize()) > vehicleType.getCapacity().getOther().intValue()) { + load = 0; + Carrier auxiliaryCarrier = + CarrierSchedulerUtils.solveVrpWithJsprit( + createAuxiliaryCarrier(shipmentsInCurrentTour, availabilityTimeOfLastShipment + cumulatedLoadingTime), + scenario); + scheduledPlans.add(auxiliaryCarrier.getSelectedPlan()); + var vrpLogic = CarrierSchedulerUtils.getVrpLogic(carrier); + switch (vrpLogic) { + case serviceBased -> { carrier.getServices().putAll(auxiliaryCarrier.getServices()); } + case shipmentBased -> { carrier.getShipments().putAll(auxiliaryCarrier.getShipments()); } + default -> throw new IllegalStateException("Unexpected value: " + vrpLogic); + } + + cumulatedLoadingTime = 0; + shipmentsInCurrentTour.clear(); + } + shipmentsInCurrentTour.add(lspShipment); + load = load + lspShipment.getSize(); + cumulatedLoadingTime = cumulatedLoadingTime + lspShipment.getDeliveryServiceTime(); + availabilityTimeOfLastShipment = LspShipmentUtils.getTimeOfLspShipment(lspShipment); + } + + if (!shipmentsInCurrentTour.isEmpty()) { + Carrier auxiliaryCarrier = + CarrierSchedulerUtils.solveVrpWithJsprit( + createAuxiliaryCarrier(shipmentsInCurrentTour, availabilityTimeOfLastShipment + cumulatedLoadingTime), + scenario); + scheduledPlans.add(auxiliaryCarrier.getSelectedPlan()); + + switch (CarrierSchedulerUtils.getVrpLogic(carrier)) { + case serviceBased -> { carrier.getServices().putAll(auxiliaryCarrier.getServices()); } + case shipmentBased -> { carrier.getShipments().putAll(auxiliaryCarrier.getShipments()); + //TODO: When using shipmentbased, only ONE Vrp should be created and solved. -> No need for the auxiliary carrier(s). KMT'Aug 24 + //Then we can also just pass all the vehicles over :) + //And need the TimeWindows for the Shipments... + } + default -> throw new IllegalStateException("Unexpected value: " + CarrierSchedulerUtils.getVrpLogic(carrier)); + } + shipmentsInCurrentTour.clear(); + } + + CarrierPlan plan = new CarrierPlan(carrier, unifyTourIds(scheduledPlans)); + plan.setScore(CarrierSchedulerUtils.sumUpScore(scheduledPlans)); + plan.setJspritScore(CarrierSchedulerUtils.sumUpJspritScore(scheduledPlans)); + carrier.addPlan(plan); + carrier.setSelectedPlan(plan); + } + + /** + * This method unifies the tourIds of the CollectionCarrier. + * + *

It is done because in the current setup, there is one (auxiliary) Carrier per Tour. ---> in + * each Carrier the Tour has the id 1. In a second step all of that tours were put together in one + * single carrier {@link #scheduleResource()} But now, this carrier can have several tours, all + * with the same id (1). + * + *

In this method all tours copied but with a new (unique) TourId. + * + *

This is a workaround. In my (KMT, sep'22) opinion it would be better to switch so {@link + * CarrierShipment}s instead of {@link CarrierService} and use only on DistributionCarrier with + * only one VRP and only one jsprit-Run. This would avoid this workaround and also improve the + * solution, because than the DistributionCarrier can decide on it one which shipments will go + * into which tours + * + * @param carrierPlans Collection of CarrierPlans + * @return Collection the scheduledTours with unified tour Ids. + */ + // private Collection unifyTourIds(Collection scheduledTours) { + private Collection unifyTourIds(Collection carrierPlans) { + int tourIdIndex = 1; + List scheduledToursUnified = new LinkedList<>(); + + for (CarrierPlan carrierPlan : carrierPlans) { + for (ScheduledTour scheduledTour : carrierPlan.getScheduledTours()) { + var newTour = + scheduledTour + .getTour() + .duplicateWithNewId(Id.create("dist_" + tourIdIndex, Tour.class)); + tourIdIndex++; + var newScheduledTour = + ScheduledTour.newInstance( + newTour, scheduledTour.getVehicle(), scheduledTour.getDeparture()); + scheduledToursUnified.add(newScheduledTour); + } + } + return scheduledToursUnified; + } + + private CarrierService convertToCarrierService(LspShipment lspShipment) { + Id serviceId = Id.create(lspShipment.getId().toString(), CarrierService.class); + CarrierService carrierService = CarrierService.Builder.newInstance(serviceId, lspShipment.getTo()) + //TODO TimeWindows are not set. This seems to be a problem. KMT'Aug'24 + //If added here, we also need to decide what happens, if the vehicles StartTime (plus TT) is > TimeWindowEnd .... + .setCapacityDemand(lspShipment.getSize()) + .setServiceDuration(lspShipment.getDeliveryServiceTime()) + .build(); + //ensure that the ids of the lspShipment and the carrierService are the same. This is needed for updating the LSPShipmentPlan + if (! Objects.equals(lspShipment.getId().toString(), carrierService.getId().toString())) { + log.error("Id of LspShipment: {} and CarrierService: {} do not match", lspShipment.getId().toString(), carrierService.getId().toString(), + new IllegalStateException("Id of LspShipment and CarrierService do not match")); + } + return carrierService; + } + + /** + * This method converts a LspShipment to a CarrierShipment. + * Please note: This method may get removed in the future, in case that the LSPShipment and the CarrierShipment are merged. KMT'Aug'24 + + * @param lspShipment the LspShipment to convert + * @return a CarrierShipment + */ + private CarrierShipment convertToCarrierShipment(LspShipment lspShipment) { + Id serviceId = Id.create(lspShipment.getId().toString(), CarrierShipment.class); + CarrierShipment carrierShipment = CarrierShipment.Builder.newInstance(serviceId, lspShipment.getFrom(), lspShipment.getTo(), lspShipment.getSize()) + //TODO TimeWindows are not set. This seems to be a problem. KMT'Aug'24 + //If added here, we also need to decide what happens, if the vehicles StartTime (plus TT) is > TimeWindowEnd .... + .setDeliveryServiceTime(lspShipment.getDeliveryServiceTime()) + .build(); + //ensure that the ids of the lspShipment and the carrierShipment are the same. This is needed for updating the LSPShipmentPlan + if (! Objects.equals(lspShipment.getId().toString(), carrierShipment.getId().toString())) { + log.error("Id of LspShipment: {} and CarrierService: {} do not match", lspShipment.getId().toString(), carrierShipment.getId().toString(), + new IllegalStateException("Id of LspShipment and CarrierService do not match")); + } + return carrierShipment; + } + + + @Override + protected void updateShipments() { + for (LspShipment lspShipment : lspShipmentsToSchedule) { + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + Tour tour = scheduledTour.getTour(); + + switch (CarrierSchedulerUtils.getVrpLogic(carrier)) { + case serviceBased -> { + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity serviceActivity) { + if (Objects.equals(lspShipment.getId().toString(), serviceActivity.getService().getId().toString())) { + addShipmentLoadElement(lspShipment, tour); + addShipmentTransportElement(lspShipment, tour, serviceActivity); + addShipmentUnloadElement(lspShipment, serviceActivity); + addDistributionTourStartEventHandler(serviceActivity, lspShipment, resource, tour); + addDistributionServiceEventHandler(serviceActivity, lspShipment, resource); + } + } + } + } + case shipmentBased -> { + //TODO needs to get fixed. KMT'Aug'24 + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.Delivery deliveryActivity) { + if (Objects.equals(lspShipment.getId().toString(), deliveryActivity.getShipment().getId().toString())) { + addShipmentLoadElement(lspShipment, tour); + addShipmentTransportElement(lspShipment, tour, deliveryActivity); + addShipmentUnloadElement(lspShipment, deliveryActivity); + addDistributionTourStartEventHandler(deliveryActivity, lspShipment, resource, tour); + addDistributionServiceEventHandler(deliveryActivity, lspShipment, resource); + } + } + } + } + default -> + throw new IllegalStateException( + "Unexpected value: " + CarrierSchedulerUtils.getVrpLogic(carrier)); + } + } + } + } + + private void addShipmentLoadElement(LspShipment lspShipment, Tour tour) { + LspShipmentUtils.ScheduledShipmentLoadBuilder builder = + LspShipmentUtils.ScheduledShipmentLoadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + + int startIndex = tour.getTourElements().indexOf(tour.getTourElements().indexOf(tour.getStart())); + Leg legAfterStart = (Leg) tour.getTourElements().get(startIndex + 1); + double startTimeOfTransport = legAfterStart.getExpectedDepartureTime(); + double cumulatedLoadingTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity activity) { + cumulatedLoadingTime = cumulatedLoadingTime + activity.getDuration(); + } + } + builder.setStartTime(startTimeOfTransport - cumulatedLoadingTime); + builder.setEndTime(startTimeOfTransport); + + LspShipmentPlanElement load = builder.build(); + String idString = + load.getResourceId() + "" + load.getLogisticChainElement().getId() + load.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, load); + } + + private void addShipmentTransportElement( + LspShipment lspShipment, Tour tour, Tour.TourActivity tourActivity) { + + LspShipmentUtils.ScheduledShipmentTransportBuilder builder = + LspShipmentUtils.ScheduledShipmentTransportBuilder.newInstance(); + builder.setResourceId(resource.getId()); + + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + + int startIndex = tour.getTourElements().indexOf(tour.getTourElements().indexOf(tour.getStart())); + final Leg legAfterStart = (Leg) tour.getTourElements().get(startIndex + 1); + final int serviceIndex = tour.getTourElements().indexOf(tourActivity); + final Leg legBeforeService = (Leg) tour.getTourElements().get(serviceIndex - 1); + final double startTimeOfTransport = legAfterStart.getExpectedDepartureTime(); + final double endTimeOfTransport = + legBeforeService.getExpectedTransportTime() + legBeforeService.getExpectedDepartureTime(); + Assert.isTrue( + endTimeOfTransport >= startTimeOfTransport, + "latest End must be later than earliest start. start: " + + startTimeOfTransport + + " ; end: " + + endTimeOfTransport); + + builder.setStartTime(startTimeOfTransport); + builder.setEndTime(endTimeOfTransport); + builder.setCarrierId(carrier.getId()); + builder.setFromLinkId(tour.getStartLinkId()); + builder.setToLinkId(tourActivity.getLocation()); + switch( tourActivity ){ + case Tour.ServiceActivity serviceActivity -> builder.setCarrierService( serviceActivity.getService() ); + case Tour.ShipmentBasedActivity shipment -> builder.setCarrierShipment( shipment.getShipment() ); + default -> throw new IllegalStateException("Unexpected value: " + tourActivity); + // yyyy: At the jsprit level, it makes sense to have these different since services run about 10x faster than shipments. However, + // at the matsim level we could consider to either only have shipments (from depot to xx for what used to be services), or only have + // services. See also MATSim issue #3510 kai/kai, oct'24 + } + LspShipmentPlanElement transport = builder.build(); + String idString = + transport.getResourceId() + + "" + + transport.getLogisticChainElement().getId() + + transport.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, transport); + } + + private void addShipmentUnloadElement(LspShipment tuple, Tour.TourActivity tourActivity) { + + LspShipmentUtils.ScheduledShipmentUnloadBuilder builder = + LspShipmentUtils.ScheduledShipmentUnloadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(tuple)) { + builder.setLogisticsChainElement(element); + } + } + + final double startTime = tourActivity.getExpectedArrival(); + final double endTime = startTime + tourActivity.getDuration(); + //Todo: Check if it also works with shipmentBased activity, or if we in that case need the way with the switch-case and the data from the shipmentBasedActivity. KMT Oct'24 + +// switch( tourActivity ){ +// case Tour.ServiceActivity serviceActivity -> { +// startTime = tourActivity.getExpectedArrival(); +// endTime = startTime + tourActivity.getDuration(); +// +//// startTime = serviceActivity.getExpectedArrival(); //Why is there also a arrivalTime in the Tour.ServiceActivity? Why do not take the date in TourActivity.getExpectedArrivalTime()? KMT Oct'24 +//// endTime = startTime + serviceActivity.getDuration(); +// } +// case Tour.ShipmentBasedActivity shipmentBasedActivity -> { +// //Todo: Not tested ; maybe we need to take the data from the shipment itself (as is was originally done with the service: serviceActivity.getService() ,..... KMT Oct'24 +// startTime = shipmentBasedActivity.getExpectedArrival(); //Why is there also a arrivalTime in the Tour.ServiceActivity? Why do not take the date in TourActivity.getExpectedArrivalTime()? KMT Oct'24 +// endTime = startTime + shipmentBasedActivity.getDuration(); +// +// } +// default -> {} +// } + + Assert.isTrue( + endTime >= startTime, + "latest End must be later than earliest start. start: " + startTime + " ; end: " + endTime); + + builder.setStartTime(startTime); + builder.setEndTime(endTime); + + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId() + + String.valueOf(unload.getLogisticChainElement().getId()) + + unload.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, tuple.getId()) + .addPlanElement(id, unload); + } + + private Carrier createAuxiliaryCarrier(ArrayList shipmentsInCurrentTour, double startTime) { + final Id carrierId = Id.create(carrier.getId().toString() + carrierCnt, Carrier.class); + carrierCnt++; + + CarrierVehicle carrierVehicle = carrier.getCarrierCapabilities().getCarrierVehicles().values().iterator().next(); + CarrierVehicle cv = CarrierVehicle.Builder.newInstance( + carrierVehicle.getId(), carrierVehicle.getLinkId(), carrierVehicle.getType()) + .setEarliestStart(startTime) + .setLatestEnd(24 * 60 * 60) + .build(); + Carrier auxiliaryCarrier = CarriersUtils.createCarrier(carrierId); + auxiliaryCarrier.getCarrierCapabilities().getCarrierVehicles().put(cv.getId(), cv); + auxiliaryCarrier.getCarrierCapabilities().setFleetSize(FleetSize.FINITE); + + switch (CarrierSchedulerUtils.getVrpLogic(carrier)) { + case serviceBased -> { + for (LspShipment lspShipment : shipmentsInCurrentTour) { + CarrierService carrierService = convertToCarrierService(lspShipment); + auxiliaryCarrier.getServices().put(carrierService.getId(), carrierService); + } + } + case shipmentBased -> { + for (LspShipment lspShipment : shipmentsInCurrentTour) { + CarrierShipment carrierShipment = convertToCarrierShipment(lspShipment); + auxiliaryCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); + } + } + default -> throw new IllegalStateException("Unexpected value: " + CarrierSchedulerUtils.getVrpLogic(carrier)); + } + + + return auxiliaryCarrier; + } + + private void addDistributionServiceEventHandler( + Tour.TourActivity tourActivity, + LspShipment lspShipment, + LSPCarrierResource resource) { + + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + DistributionServiceStartEventHandler handler; + switch (tourActivity) { + case Tour.ServiceActivity serviceActivity-> { + handler = new DistributionServiceStartEventHandler(serviceActivity.getService(), lspShipment, element, resource, null); + } + case Tour.ShipmentBasedActivity shipmentBasedActivity-> { + handler = new DistributionServiceStartEventHandler(null, lspShipment, element, resource, shipmentBasedActivity.getShipment()); + } + default -> throw new IllegalStateException("Unexpected value: " + tourActivity); + } + + lspShipment.addSimulationTracker(handler); + break; + } + } + } + + private void addDistributionTourStartEventHandler( + Tour.TourActivity tourActivity, + LspShipment lspShipment, + LSPCarrierResource resource, + Tour tour) { + + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + LSPTourStartEventHandler handler; + switch (tourActivity) { + case Tour.ServiceActivity serviceActivity-> { + handler = new LSPTourStartEventHandler(lspShipment, serviceActivity.getService(), element, resource, tour, null); + } + case Tour.ShipmentBasedActivity shipmentBasedActivity-> { + handler = new LSPTourStartEventHandler(lspShipment, null , element, resource, tour, shipmentBasedActivity.getShipment()); + } + default -> throw new IllegalStateException("Unexpected value: " + tourActivity); + } + + lspShipment.addSimulationTracker(handler); + break; + } + } + } + + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionServiceStartEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionServiceStartEventHandler.java new file mode 100644 index 00000000000..047ade24f65 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionServiceStartEventHandler.java @@ -0,0 +1,175 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import org.matsim.api.core.v01.Id; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.CarrierShipment; +import org.matsim.freight.carriers.events.CarrierServiceStartEvent; +import org.matsim.freight.carriers.events.CarrierShipmentDeliveryStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierServiceStartEventHandler; +import org.matsim.freight.carriers.events.eventhandler.CarrierShipmentDeliveryStartEventHandler; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPSimulationTracker; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentLeg; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/*package-private*/ class DistributionServiceStartEventHandler + implements AfterMobsimListener, + CarrierServiceStartEventHandler, + CarrierShipmentDeliveryStartEventHandler, + LSPSimulationTracker { + + private final CarrierService carrierService; + private final CarrierShipment carrierShipment; + private final LogisticChainElement logisticChainElement; + private final LSPCarrierResource resource; + private LspShipment lspShipment; + + DistributionServiceStartEventHandler( + CarrierService carrierService, + LspShipment lspShipment, + LogisticChainElement element, + LSPCarrierResource resource, + CarrierShipment carrierShipment) { + this.carrierShipment = carrierShipment; + this.carrierService = carrierService; + this.lspShipment = lspShipment; + this.logisticChainElement = element; + this.resource = resource; + } + + @Override + public void reset(int iteration) { + // TODO Auto-generated method stub + + } + + @Override + public void handleEvent(CarrierServiceStartEvent event) { + if (event.getServiceId() == carrierService.getId() + && event.getCarrierId() == resource.getCarrier().getId()) { + logTransport(event); + logUnload(event); + } + } + + @Override + public void handleEvent(CarrierShipmentDeliveryStartEvent event) { + if (event.getShipmentId() == this.carrierShipment.getId() + && event.getCarrierId() == resource.getCarrier().getId()) { + logTransport(event); + logUnload(event); + } + } + + private void logTransport(CarrierServiceStartEvent event) { + String idString = resource.getId() + "" + logisticChainElement.getId() + "TRANSPORT"; + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentPlanElement abstractPlanElement = + lspShipment.getShipmentLog().getPlanElements().get(id); + if (abstractPlanElement instanceof LspShipmentLeg transport) { + transport.setEndTime(event.getTime()); + } + } + + //TODO: Inhaltlich ansehen, was hier passiert. Ist aktuell nur Copy und Paste aus Service-Variante + private void logTransport(CarrierShipmentDeliveryStartEvent event) { + String idString = resource.getId() + "" + logisticChainElement.getId() + "TRANSPORT"; + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentPlanElement abstractPlanElement = + lspShipment.getShipmentLog().getPlanElements().get(id); + if (abstractPlanElement instanceof LspShipmentLeg transport) { + transport.setEndTime(event.getTime()); + } + } + + private void logUnload(CarrierServiceStartEvent event) { + LspShipmentUtils.LoggedShipmentUnloadBuilder builder = + LspShipmentUtils.LoggedShipmentUnloadBuilder.newInstance(); + builder.setCarrierId(event.getCarrierId()); + builder.setLinkId(event.getLinkId()); + builder.setLogisticChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setStartTime(event.getTime()); + builder.setEndTime(event.getTime() + event.getServiceDuration()); + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId() + + "" + + unload.getLogisticChainElement().getId() + + unload.getElementType(); + Id unloadId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(unloadId, unload); + } + + //TODO: Inhaltlich ansehen, was hier passiert. Ist aktuell nur Copy und Paste aus Service-Variante + private void logUnload(CarrierShipmentDeliveryStartEvent event) { + LspShipmentUtils.LoggedShipmentUnloadBuilder builder = + LspShipmentUtils.LoggedShipmentUnloadBuilder.newInstance(); + builder.setCarrierId(event.getCarrierId()); + builder.setLinkId(event.getLinkId()); + builder.setLogisticChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setStartTime(event.getTime()); + builder.setEndTime(event.getTime() + event.getDeliveryDuration()); + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId() + + "" + + unload.getLogisticChainElement().getId() + + unload.getElementType(); + Id unloadId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(unloadId, unload); + } + + //Todo: Wird das auch inhaltlich irgendwo genutzt,oder ist das nur für die Tests da? + //todo ctd. Brauchen wir den CarrierService hier eigentlich wirklich oder kann das zurück gebaut werden? KMT Okt'24 + public CarrierService getCarrierService() { + return carrierService; + } + + public LspShipment getLspShipment() { + return lspShipment; + } + + public LogisticChainElement getLogisticChainElement() { + return logisticChainElement; + } + + public LSPCarrierResource getResource() { + return resource; + } + + @Override + public void setEmbeddingContainer(LspShipment pointer) { + this.lspShipment = pointer; + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) {} +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourEndEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourEndEventHandler.java new file mode 100644 index 00000000000..db316c2e849 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourEndEventHandler.java @@ -0,0 +1,156 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.Tour; +import org.matsim.freight.carriers.Tour.ServiceActivity; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourEndEventHandler; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentLeg; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/*package-private*/ class LSPTourEndEventHandler + implements AfterMobsimListener, CarrierTourEndEventHandler, LSPSimulationTracker { + + private final CarrierService carrierService; + private final LogisticChainElement logisticChainElement; + private final LSPCarrierResource resource; + private final Tour tour; + private LspShipment lspShipment; + + public LSPTourEndEventHandler( + LspShipment lspShipment, + CarrierService carrierService, + LogisticChainElement logisticChainElement, + LSPCarrierResource resource, + Tour tour) { + this.lspShipment = lspShipment; + this.carrierService = carrierService; + this.logisticChainElement = logisticChainElement; + this.resource = resource; + this.tour = tour; + } + + @Override + public void reset(int iteration) { + // TODO Auto-generated method stub + } + + @Override + public void handleEvent(CarrierTourEndEvent event) { + if (event.getTourId().equals(tour.getId())) { + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity serviceActivity) { + if (serviceActivity.getService().getId() == carrierService.getId() + && event.getCarrierId() == resource.getCarrier().getId()) { + if (resource instanceof CollectionCarrierResource) { + logTransport(event.getTime(), tour.getEndLinkId()); + logUnload( + event.getCarrierId(), + event.getTime(), + event.getTime() + getTotalUnloadingTime(tour)); + } else if (resource instanceof MainRunCarrierResource) { + logUnload( + event.getCarrierId(), + event.getTime() - getTotalUnloadingTime(tour), + event.getTime()); + logTransport(event.getTime() - getTotalUnloadingTime(tour), event.getLinkId()); + } + } + } + } + } + } + + private void logUnload(Id carrierId, double startTime, double endTime) { + LspShipmentUtils.LoggedShipmentUnloadBuilder builder = + LspShipmentUtils.LoggedShipmentUnloadBuilder.newInstance(); + builder.setStartTime(startTime); + builder.setEndTime(endTime); + builder.setLogisticChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setCarrierId(carrierId); + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId().toString() + + unload.getLogisticChainElement().getId() + + unload.getElementType(); + Id unloadId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(unloadId, unload); + } + + private void logTransport(double endTime, Id endLinkId) { + String idString = resource.getId().toString() + logisticChainElement.getId() + "TRANSPORT"; + LspShipmentPlanElement abstractPlanElement = + lspShipment + .getShipmentLog() + .getPlanElements() + .get(Id.create(idString, LspShipmentPlanElement.class)); + if (abstractPlanElement instanceof LspShipmentLeg transport) { + transport.setEndTime(endTime); + transport.setToLinkId(endLinkId); + } + } + + private double getTotalUnloadingTime(Tour tour) { + double totalTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity serviceActivity) { + totalTime = totalTime + serviceActivity.getDuration(); + } + } + return totalTime; + } + + public CarrierService getCarrierService() { + return carrierService; + } + + public LspShipment getLspShipment() { + return lspShipment; + } + + public LogisticChainElement getLogisticChainElement() { + return logisticChainElement; + } + + public Id getResourceId() { + return resource.getId(); + } + + @Override + public void setEmbeddingContainer(LspShipment pointer) { + this.lspShipment = pointer; + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) {} +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourStartEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourStartEventHandler.java new file mode 100644 index 00000000000..4b3ff6a8daf --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourStartEventHandler.java @@ -0,0 +1,174 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.CarrierShipment; +import org.matsim.freight.carriers.Tour; +import org.matsim.freight.carriers.Tour.ServiceActivity; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.carriers.events.CarrierTourStartEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourStartEventHandler; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPSimulationTracker; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentLeg; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +import java.util.Objects; + +/*package-private*/ class LSPTourStartEventHandler + implements CarrierTourStartEventHandler, LSPSimulationTracker { + + private final Tour tour; + private final CarrierService carrierService; + private final CarrierShipment carrierShipment; + private final LogisticChainElement logisticChainElement; + private final LSPCarrierResource resource; + private LspShipment lspShipment; + + public LSPTourStartEventHandler( + LspShipment lspShipment, + CarrierService carrierService, + LogisticChainElement logisticChainElement, + LSPCarrierResource resource, + Tour tour, + CarrierShipment carrierShipment) + { + this.lspShipment = lspShipment; + this.carrierService = carrierService; + this.carrierShipment = carrierShipment; + this.logisticChainElement = logisticChainElement; + this.resource = resource; + this.tour = tour; + } + + @Override + public void reset(int iteration) { + // TODO Auto-generated method stub + } + + @Override + public void handleEvent(CarrierTourStartEvent event) { + if (event.getTourId().equals(tour.getId()) && event.getCarrierId() == resource.getCarrier().getId()) { + for (TourElement tourElement : tour.getTourElements()) { + switch (tourElement) { + //This could even be short, if the Id would be available already on the level of Tour.TourActivity. KMT Oct'24 + case ServiceActivity serviceActivity -> { + if (serviceActivity.getService().getId() == carrierService.getId()) { + logLoadAndTransport(event); + } + } + case Tour.ShipmentBasedActivity shipmentBasedActivity -> { + if (Objects.equals(shipmentBasedActivity.getShipment().getId().toString(), carrierService.getId().toString())) { + logLoadAndTransport(event); + } + } + case null, default -> {} + } + } + } + } + + private void logLoadAndTransport(CarrierTourStartEvent event) { + if (resource instanceof DistributionCarrierResource || resource instanceof MainRunCarrierResource) { + logLoad(event.getCarrierId(), event.getLinkId(), event.getTime() - getCumulatedLoadingTime(tour), event.getTime()); + logTransport(event.getCarrierId(), event.getLinkId(), tour.getEndLinkId(), event.getTime()); + } + } + + private void logLoad(Id carrierId, Id linkId, double startTime, double endTime) { + LspShipmentUtils.LoggedShipmentLoadBuilder builder = + LspShipmentUtils.LoggedShipmentLoadBuilder.newInstance(); + builder.setCarrierId(carrierId); + builder.setLinkId(linkId); + builder.setLogisticsChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setStartTime(startTime); + builder.setEndTime(endTime); + LspShipmentPlanElement loggedShipmentLoad = builder.build(); + String idString = + loggedShipmentLoad.getResourceId() + + "" + + loggedShipmentLoad.getLogisticChainElement().getId() + + loggedShipmentLoad.getElementType(); + Id loadId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(loadId, loggedShipmentLoad); + } + + private void logTransport(Id carrierId, Id fromLinkId, + Id toLinkId, double startTime) { + LspShipmentUtils.LoggedShipmentTransportBuilder builder = + LspShipmentUtils.LoggedShipmentTransportBuilder.newInstance(); + builder.setCarrierId(carrierId); + builder.setFromLinkId(fromLinkId); + builder.setToLinkId(toLinkId); + builder.setLogisticChainElement(logisticChainElement); + builder.setResourceId(resource.getId()); + builder.setStartTime(startTime); + LspShipmentLeg transport = builder.build(); + String idString = + transport.getResourceId() + + "" + + transport.getLogisticChainElement().getId() + + transport.getElementType(); + Id transportId = Id.create(idString, LspShipmentPlanElement.class); + lspShipment.getShipmentLog().addPlanElement(transportId, transport); + } + + private double getCumulatedLoadingTime(Tour tour) { + double cumulatedLoadingTime = 0; + for (TourElement tourElement : tour.getTourElements()) { + if (tourElement instanceof ServiceActivity serviceActivity) { + cumulatedLoadingTime = cumulatedLoadingTime + serviceActivity.getDuration(); + } + } + return cumulatedLoadingTime; + } + + public CarrierService getCarrierService() { + return carrierService; + } + + public LspShipment getLspShipment() { + return lspShipment; + } + + public LogisticChainElement getLogisticChainElement() { + return logisticChainElement; + } + + public Id getResourceId() { + return resource.getId(); + } + + @Override + public void setEmbeddingContainer(LspShipment pointer) { + this.lspShipment = pointer; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierResource.java new file mode 100644 index 00000000000..8dd7eb1f0a3 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierResource.java @@ -0,0 +1,88 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Collection; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.MainRunCarrierResourceBuilder; + +/*package-private*/ class MainRunCarrierResource extends LSPDataObject + implements LSPCarrierResource { + + private static final Logger log = LogManager.getLogger(MainRunCarrierResource.class); + + private final Carrier carrier; + private final Id fromLinkId; + private final Id toLinkId; + private final Collection clientElements; + private final MainRunCarrierScheduler mainRunScheduler; + + private final ResourceImplementationUtils.VehicleReturn vehicleReturn; + + MainRunCarrierResource(MainRunCarrierResourceBuilder builder) { + super(builder.getId()); + this.carrier = builder.getCarrier(); + this.fromLinkId = builder.getFromLinkId(); + this.toLinkId = builder.getToLinkId(); + this.clientElements = builder.getClientElements(); + this.mainRunScheduler = builder.getMainRunScheduler(); + if (builder.getVehicleReturn() != null) { + this.vehicleReturn = builder.getVehicleReturn(); + } else { + log.warn("Return behaviour was not specified. Using the following setting as default: {}", ResourceImplementationUtils.VehicleReturn.endAtToLink); + this.vehicleReturn = ResourceImplementationUtils.VehicleReturn.endAtToLink; + } + } + + @Override + public Id getStartLinkId() { + return fromLinkId; + } + + @Override + public Id getEndLinkId() { + return toLinkId; + } + + @Override + public Collection getClientElements() { + return clientElements; + } + + @Override + public void schedule(int bufferTime, LSPPlan lspPlan) { + mainRunScheduler.scheduleShipments(lspPlan, this, bufferTime); + } + + public Carrier getCarrier() { + return carrier; + } + + public ResourceImplementationUtils.VehicleReturn getVehicleReturn() { + return vehicleReturn; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierScheduler.java new file mode 100644 index 00000000000..99f49186e11 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/MainRunCarrierScheduler.java @@ -0,0 +1,388 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.*; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.population.routes.NetworkRoute; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.Tour.Leg; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; +import org.matsim.freight.carriers.jsprit.NetworkRouter; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; + +/** + * In the case of the MainRunResource, the incoming LSPShipments are bundled together until their + * total weight exceeds the capacity of the deployed vehicle type. Then, this bundle of LSPShipments + * is converted to a scheduled tour from the freight contrib of MATSim. The start of this tour is + * located at the first TranshipmentHub and the end at the second one. All LSPShipments are + * converted to services that take place at the end point of the tour. + * + *

Tour is routed by MATSim Network Router. + * + *

* The tour starts after the last shipment * has arrived and the time necessary for loading all + * shipments into the vehicle * has passed. + */ +/*package-private*/ class MainRunCarrierScheduler extends LSPResourceScheduler { + + private Carrier carrier; + private MainRunCarrierResource resource; + private ArrayList pairs; + private final Scenario scenario; + private int tourIdIndex = 1; // Have unique TourIds for the MainRun. + + /*package-private*/ MainRunCarrierScheduler(Scenario scenario) { + this.pairs = new ArrayList<>(); + this.scenario = scenario; + } + + @Override + protected void initializeValues(LSPResource resource) { + this.pairs = new ArrayList<>(); + if (resource.getClass() == MainRunCarrierResource.class) { + this.resource = (MainRunCarrierResource) resource; + this.carrier = this.resource.getCarrier(); + this.carrier.getServices().clear(); + this.carrier.getShipments().clear(); + this.carrier.getPlans().clear(); + } + } + + @Override + protected void scheduleResource() { + int load = 0; + List copyOfAssignedShipments = new ArrayList<>(lspShipmentsToSchedule); + copyOfAssignedShipments.sort(Comparator.comparingDouble(LspShipmentUtils::getTimeOfLspShipment)); + ArrayList shipmentsInCurrentTour = new ArrayList<>(); + // ArrayList scheduledTours = new ArrayList<>(); + List scheduledPlans = new LinkedList<>(); + + for (LspShipment lspShipment : copyOfAssignedShipments) { + // Add job as "services" to the carrier. So the carrier has this available + CarrierService carrierService = convertToCarrierService(lspShipment); + carrier.getServices().put(carrierService.getId(), carrierService); + + VehicleType vehicleType = + ResourceImplementationUtils.getVehicleTypeCollection(carrier).iterator().next(); + if ((load + lspShipment.getSize()) + > vehicleType.getCapacity().getOther().intValue()) { + load = 0; + CarrierPlan plan = createPlan(carrier, shipmentsInCurrentTour); + scheduledPlans.add(plan); + shipmentsInCurrentTour.clear(); + } + shipmentsInCurrentTour.add(lspShipment); + load = load + lspShipment.getSize(); + } + if (!shipmentsInCurrentTour.isEmpty()) { + CarrierPlan plan = createPlan(carrier, shipmentsInCurrentTour); + scheduledPlans.add(plan); + shipmentsInCurrentTour.clear(); + } + + List scheduledTours = new LinkedList<>(); + for (CarrierPlan scheduledPlan : scheduledPlans) { + scheduledTours.addAll(scheduledPlan.getScheduledTours()); + } + CarrierPlan plan = new CarrierPlan(carrier, scheduledTours); + plan.setScore(CarrierSchedulerUtils.sumUpScore(scheduledPlans)); + carrier.addPlan(plan); + carrier.setSelectedPlan(plan); + } + + private CarrierPlan createPlan(Carrier carrier, List lspShipments) { + + // TODO: Allgemein: Hier ist alles manuell zusammen gesetzt; es findet KEINE Tourenplanung + // statt! + NetworkBasedTransportCosts.Builder tpcostsBuilder = + NetworkBasedTransportCosts.Builder.newInstance( + scenario.getNetwork(), + ResourceImplementationUtils.getVehicleTypeCollection(resource.getCarrier())); + NetworkBasedTransportCosts netbasedTransportcosts = tpcostsBuilder.build(); + Collection tours = new ArrayList<>(); + + Tour.Builder tourBuilder = Tour.Builder.newInstance(Id.create(tourIdIndex, Tour.class)); + tourIdIndex++; + tourBuilder.scheduleStart(Id.create(resource.getStartLinkId(), Link.class)); + + double totalLoadingTime = 0; + double latestLspShipmentTime = 0; + + for (LspShipment lspShipment : lspShipments) { + totalLoadingTime = totalLoadingTime + lspShipment.getDeliveryServiceTime(); + if (LspShipmentUtils.getTimeOfLspShipment(lspShipment) > latestLspShipmentTime) { + latestLspShipmentTime = LspShipmentUtils.getTimeOfLspShipment(lspShipment); + } + tourBuilder.addLeg(new Leg()); + CarrierService carrierService = convertToCarrierService(lspShipment); + pairs.add(new LSPShipmentCarrierServicePair(lspShipment, carrierService)); + tourBuilder.scheduleService(carrierService); + } + + tourBuilder.addLeg(new Leg()); + switch (resource.getVehicleReturn()) { + case returnToFromLink -> // The more "urban" behaviour: The vehicle returns to its origin + // (startLink). + tourBuilder.scheduleEnd(Id.create(resource.getStartLinkId(), Link.class)); + case endAtToLink -> // The more "long-distance" behaviour: The vehicle ends at its destination + // (toLink). + tourBuilder.scheduleEnd(Id.create(resource.getEndLinkId(), Link.class)); + default -> throw new IllegalStateException( + "Unexpected value: " + resource.getVehicleReturn()); + } + Tour vehicleTour = tourBuilder.build(); + CarrierVehicle vehicle = + carrier.getCarrierCapabilities().getCarrierVehicles().values().iterator().next(); + double tourStartTime = latestLspShipmentTime + totalLoadingTime; + ScheduledTour sTour = ScheduledTour.newInstance(vehicleTour, vehicle, tourStartTime); + + tours.add(sTour); + CarrierPlan plan = new CarrierPlan(carrier, tours); + NetworkRouter.routePlan(plan, netbasedTransportcosts); + plan.setScore(scorePlanManually(plan)); + return plan; + } + + /** + * For the main run, there is currently (nov'22) no jsprit planning. The plan is instead + * constructed manually. As a consequence, there is no score (from jsprit) for this plan + * available. To avoid issues in later scoring of the LSP, we would like to hava also a score for + * the MainRunCarrier. This is calculated here manually + * + *

It bases on the - vehicle's fixed costs - distance dependent costs - (expected) travel time + * dependent costs NOT included is the calculation of activity times,... But this is currently + * also missing e.g. in the distributionCarrier, where the VRP setup does not include this :( + * + * @param plan The carrierPlan, that should get scored. + * @return the calculated score + */ + private double scorePlanManually(CarrierPlan plan) { + // score plan // Note: Activities are not scored, but they are also NOT scored for the + // Distribution carrier (as the VRP is currently set up) kmt nov'22 + double score = 0.; + for (ScheduledTour scheduledTour : plan.getScheduledTours()) { + // vehicle fixed costs + score = score + scheduledTour.getVehicle().getType().getCostInformation().getFixedCosts(); + + // distance + double distance = 0.0; + double time = 0.0; + for (TourElement tourElement : scheduledTour.getTour().getTourElements()) { + if (tourElement instanceof Leg leg) { + // distance + NetworkRoute route = (NetworkRoute) leg.getRoute(); + for (Id linkId : route.getLinkIds()) { + distance = distance + scenario.getNetwork().getLinks().get(linkId).getLength(); + } + if (route.getEndLinkId() + != route + .getStartLinkId()) { // Do not calculate any distance, if start and endpoint are + // identical + distance = + distance + scenario.getNetwork().getLinks().get(route.getEndLinkId()).getLength(); + } + + // travel time (exp.) + time = time + leg.getExpectedTransportTime(); + } + } + score = + score + + scheduledTour.getVehicle().getType().getCostInformation().getCostsPerMeter() + * distance; + score = + score + + scheduledTour.getVehicle().getType().getCostInformation().getCostsPerSecond() + * time; + } + return (-score); // negative, because we are looking at "costs" instead of "utility" + } + + private CarrierService convertToCarrierService(LspShipment lspShipment) { + Id serviceId = + Id.create(lspShipment.getId().toString(), CarrierService.class); + CarrierService.Builder builder = + CarrierService.Builder.newInstance(serviceId, resource.getEndLinkId()); + builder.setCapacityDemand(lspShipment.getSize()); + builder.setServiceDuration(lspShipment.getDeliveryServiceTime()); + return builder.build(); + } + + @Override + protected void updateShipments() { + for (LspShipment LspShipment : lspShipmentsToSchedule) { + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + Tour tour = scheduledTour.getTour(); + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity serviceActivity) { + LSPShipmentCarrierServicePair carrierPair = + new LSPShipmentCarrierServicePair( + LspShipment, serviceActivity.getService()); + for (LSPShipmentCarrierServicePair pair : pairs) { + if (pair.lspShipment == carrierPair.lspShipment + && pair.carrierService.getId() == carrierPair.carrierService.getId()) { + addShipmentLoadElement(LspShipment, tour); + addShipmentTransportElement(LspShipment, tour, serviceActivity); + addShipmentUnloadElement(LspShipment, tour); + addMainTourRunStartEventHandler(pair.carrierService, LspShipment, resource, tour); + addMainRunTourEndEventHandler(pair.carrierService, LspShipment, resource, tour); + } + } + } + } + } + } + } + + private void addShipmentLoadElement(LspShipment lspShipment, Tour tour) { + LspShipmentUtils.ScheduledShipmentLoadBuilder builder = + LspShipmentUtils.ScheduledShipmentLoadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + int startIndex = tour.getTourElements().indexOf(tour.getTourElements().indexOf(tour.getStart())); + Leg legAfterStart = (Leg) tour.getTourElements().get(startIndex + 1); + double startTimeOfTransport = legAfterStart.getExpectedDepartureTime(); + double cumulatedLoadingTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity activity) { + cumulatedLoadingTime = cumulatedLoadingTime + activity.getDuration(); + } + } + builder.setStartTime(startTimeOfTransport - cumulatedLoadingTime); + builder.setEndTime(startTimeOfTransport); + + LspShipmentPlanElement load = builder.build(); + String idString = + load.getResourceId() + + String.valueOf(load.getLogisticChainElement().getId()) + + load.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, load); + } + + private void addShipmentTransportElement(LspShipment lspShipment, Tour tour, Tour.ServiceActivity serviceActivity) { + LspShipmentUtils.ScheduledShipmentTransportBuilder builder = + LspShipmentUtils.ScheduledShipmentTransportBuilder.newInstance(); + builder.setResourceId(resource.getId()); + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticChainElement(element); + } + } + int startIndex = tour.getTourElements().indexOf(tour.getTourElements().indexOf(tour.getStart())); + Leg legAfterStart = (Leg) tour.getTourElements().get(startIndex + 1); + double startTimeOfTransport = legAfterStart.getExpectedDepartureTime(); + builder.setStartTime(startTimeOfTransport); + builder.setEndTime(legAfterStart.getExpectedTransportTime() + startTimeOfTransport); + builder.setCarrierId(carrier.getId()); + builder.setFromLinkId(tour.getStartLinkId()); + builder.setToLinkId(tour.getEndLinkId()); + builder.setCarrierService(serviceActivity.getService()); + LspShipmentPlanElement transport = builder.build(); + String idString = + transport.getResourceId() + + String.valueOf(transport.getLogisticChainElement().getId()) + + transport.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, transport); + } + + private void addShipmentUnloadElement(LspShipment lspShipment, Tour tour) { + LspShipmentUtils.ScheduledShipmentUnloadBuilder builder = + LspShipmentUtils.ScheduledShipmentUnloadBuilder.newInstance(); + builder.setResourceId(resource.getId()); + for (LogisticChainElement element : resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticsChainElement(element); + } + } + double cumulatedLoadingTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof Tour.ServiceActivity activity) { + cumulatedLoadingTime = cumulatedLoadingTime + activity.getDuration(); + } + } + int startIndex = tour.getTourElements().indexOf(tour.getTourElements().indexOf(tour.getStart())); + Leg legAfterStart = (Leg) tour.getTourElements().get(startIndex + 1); + builder.setStartTime( + legAfterStart.getExpectedDepartureTime() + legAfterStart.getExpectedTransportTime()); + builder.setEndTime( + legAfterStart.getExpectedDepartureTime() + + legAfterStart.getExpectedTransportTime() + + cumulatedLoadingTime); + + LspShipmentPlanElement unload = builder.build(); + String idString = + unload.getResourceId() + + String.valueOf(unload.getLogisticChainElement().getId()) + + unload.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, unload); + } + + private void addMainTourRunStartEventHandler( + CarrierService carrierService, + LspShipment lspShipment, + LSPCarrierResource resource, + Tour tour) { + + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + LSPTourStartEventHandler handler = + new LSPTourStartEventHandler(lspShipment, carrierService, element, resource, tour, null); + lspShipment.addSimulationTracker(handler); + break; + } + } + } + + private void addMainRunTourEndEventHandler( + CarrierService carrierService, + LspShipment lspShipment, + LSPCarrierResource resource, + Tour tour) { + for (LogisticChainElement element : this.resource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + LSPTourEndEventHandler handler = + new LSPTourEndEventHandler(lspShipment, carrierService, element, resource, tour); + lspShipment.addSimulationTracker(handler); + break; + } + } + } + + private record LSPShipmentCarrierServicePair(LspShipment lspShipment, CarrierService carrierService) {} +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/ResourceImplementationUtils.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/ResourceImplementationUtils.java new file mode 100644 index 00000000000..7e361725627 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/ResourceImplementationUtils.java @@ -0,0 +1,498 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierVehicle; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPResourceScheduler; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; + +@SuppressWarnings("ClassEscapesDefinedScope") +public class ResourceImplementationUtils { + + private static final Logger log = LogManager.getLogger(ResourceImplementationUtils.class); + private static final String CARRIER_TYPE_ATTR = "carrierType"; + + public static SimpleForwardLogisticChainScheduler + createDefaultSimpleForwardLogisticChainScheduler(List resources) { + return new SimpleForwardLogisticChainScheduler(resources); + } + + public static SingleLogisticChainShipmentAssigner createSingleLogisticChainShipmentAssigner() { + return new SingleLogisticChainShipmentAssigner(); + } + + /** + * Collects all the vehicleTyps from the different Vehicle of the carrier. This is needed since we + * do not use carrier.getCarrierCapabilities().getVehicleTypes() any more as second field to safe + * vehicleTypes ... TODO: Maybe move to CarriersUtils in MATSim-libs / freight contrib. + * + *

KMT/Jul22 + * + * @param carrier the carrier + * @return Collection of VehicleTypes + */ + public static Collection getVehicleTypeCollection(Carrier carrier) { + Set vehicleTypeCollection = new HashSet<>(); + for (CarrierVehicle carrierVehicle : + carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + vehicleTypeCollection.add(carrierVehicle.getType()); + } + return vehicleTypeCollection; + } + + public static void printShipmentsOfLSP(String outputDir, LSP lsp) { + System.out.println("Writing out shipments of LSP"); + try (BufferedWriter writer = + IOUtils.getBufferedWriter(outputDir + "/" + lsp.getId().toString() + "_shipments.tsv")) { + final String str0 = "LSP: " + lsp.getId(); + System.out.println(str0); + writer.write(str0 + "\n"); + for (LspShipment lspShipment : lsp.getLspShipments()) { + final String str1 = "Shipment: " + lspShipment; + System.out.println(str1); + writer.write(str1 + "\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void printResults_shipmentPlan(String outputDir, LSP lsp) { + System.out.println("Writing out shipmentPlan for LSP"); + try (BufferedWriter writer = + IOUtils.getBufferedWriter(outputDir + "/" + lsp.getId().toString() + "_schedules.tsv")) { + final String str0 = "LSP: " + lsp.getId(); + System.out.println(str0); + writer.write(str0 + "\n"); + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList elementList = + new ArrayList<>( + LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()) + .getPlanElements() + .values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + writeShipmentWithPlanElements(writer, shipment, elementList); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void writeShipmentWithPlanElements( + BufferedWriter writer, LspShipment lspShipment, ArrayList elementList) + throws IOException { + final String str1 = "Shipment: " + lspShipment; + System.out.println(str1); + writer.write(str1 + "\n"); + for (LspShipmentPlanElement element : elementList) { + final String str2 = + element.getLogisticChainElement().getId() + + "\t\t" + + element.getResourceId() + + "\t\t" + + element.getElementType() + + "\t\t" + + element.getStartTime() + + "\t\t" + + element.getEndTime(); + System.out.println(str2); + writer.write(str2 + "\n"); + } + System.out.println(); + writer.write("\n"); + } + + /** + * Prints out the log of the shipment - this is not the shipment's plan Maybe the log will get + * removed soon. kmt sep/oct'22 + * + * @param outputDir path, defining the location for the results + * @param lsp the LSP, for which the results should be written out. + */ + public static void printResults_shipmentLog(String outputDir, LSP lsp) { + System.out.println("Writing out shipmentLog for LSP"); + try (BufferedWriter writer = + IOUtils.getBufferedWriter(outputDir + "/" + lsp.getId().toString() + "_shipmentLogs.tsv")) { + final String str0 = "LSP: " + lsp.getId(); + System.out.println(str0); + writer.write(str0 + "\n"); + for (LspShipment lspShipment : lsp.getLspShipments()) { + ArrayList elementList = + new ArrayList<>(lspShipment.getShipmentLog().getPlanElements().values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + writeShipmentWithPlanElements(writer, lspShipment, elementList); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void printScores(String outputDir, LSP lsp) { + System.out.println("Writing out scores for LSP"); + try (BufferedWriter writer = + IOUtils.getBufferedWriter(outputDir + "/" + lsp.getId().toString() + "_scores.tsv")) { + final String str0 = "LSP: " + lsp.getId(); + System.out.println(str0); + writer.write(str0 + "\n"); + final String str1 = + "The LSP `` " + + lsp.getId() + + " ´´ has the following number of plans: " + + lsp.getPlans().size() + + "\n The scores are: "; + System.out.println(str1); + writer.write(str1 + "\n"); + for (LSPPlan plan : lsp.getPlans()) { + final String str2 = "Score: " + plan.getScore().toString(); + System.out.println(str2); + writer.write(str2 + "\n"); + } + final String str3 = "The selected plan has the score: " + lsp.getSelectedPlan().getScore(); + System.out.println(str3); + writer.write(str3 + "\n"); + System.out.println("###"); + writer.write("### \n"); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static CARRIER_TYPE getCarrierType(Carrier carrier) { + if (carrier.getAttributes().getAttribute(CARRIER_TYPE_ATTR) + instanceof CARRIER_TYPE carrierType) { + return carrierType; + } else { + String result = (String) carrier.getAttributes().getAttribute(CARRIER_TYPE_ATTR); + if (result == null) { + log.warn("Requested attribute " + CARRIER_TYPE_ATTR + " does not exists. Will return {}", CARRIER_TYPE.undefined); + return CARRIER_TYPE.undefined; + } else { + return CARRIER_TYPE.valueOf(result); + } + } + } + + public static void setCarrierType(Carrier carrier, CARRIER_TYPE carrierType) { + carrier.getAttributes().putAttribute(CARRIER_TYPE_ATTR, carrierType); + } + + /** + * Utils method to create a DistributionCarrierScheduler + * TODO: In the future, the scheduler should get the scenario via injection. This here is only a dirty workaround. KMT'Aug'24 + * + * @param scenario the scenario + */ + public static DistributionCarrierScheduler createDefaultDistributionCarrierScheduler(Scenario scenario) { + return new DistributionCarrierScheduler(scenario); + } + + /** + * Utils method to create a CollectionCarrierScheduler + * TODO: In the future, the scheduler should get the scenario via injection. This here is only a dirty workaround. KMT'Aug'24 + * + * @param scenario the scenario + */ + public static CollectionCarrierScheduler createDefaultCollectionCarrierScheduler(Scenario scenario) { + return new CollectionCarrierScheduler(scenario); + } + + /** + * Utils method to create a MainRunCarrierScheduler + * TODO: In the future, the scheduler should get the scenario via injection. This here is only a dirty workaround. KMT'Aug'24 + * + * @param scenario the scenario + */ + public static MainRunCarrierScheduler createDefaultMainRunCarrierScheduler(Scenario scenario) { + return new MainRunCarrierScheduler(scenario); + } + + public enum VehicleReturn { + returnToFromLink, + endAtToLink + } + + public enum CARRIER_TYPE { + collectionCarrier, + mainRunCarrier, + distributionCarrier, + undefined + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static class DistributionCarrierResourceBuilder { + + final Id id; + final ArrayList clientElements; + final Carrier carrier; + Id locationLinkId; + DistributionCarrierScheduler distributionHandler; + + private DistributionCarrierResourceBuilder(Carrier carrier) { + this.id = Id.create(carrier.getId().toString(), LSPResource.class); + setCarrierType(carrier, CARRIER_TYPE.distributionCarrier); + this.carrier = carrier; + this.clientElements = new ArrayList<>(); + } + + public static DistributionCarrierResourceBuilder newInstance(Carrier carrier) { + return new DistributionCarrierResourceBuilder(carrier); + } + + public DistributionCarrierResourceBuilder setLocationLinkId(Id locationLinkId) { + this.locationLinkId = locationLinkId; + return this; + } + + public DistributionCarrierResourceBuilder setDistributionScheduler( + DistributionCarrierScheduler distributionCarrierScheduler) { + this.distributionHandler = distributionCarrierScheduler; + return this; + } + + public DistributionCarrierResource build() { + return new DistributionCarrierResource(this); + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static class CollectionCarrierResourceBuilder { + + final Id id; + final ArrayList clientElements; + final Carrier carrier; + Id locationLinkId; + CollectionCarrierScheduler collectionScheduler; + + private CollectionCarrierResourceBuilder(Carrier carrier) { + this.id = Id.create(carrier.getId().toString(), LSPResource.class); + setCarrierType(carrier, CARRIER_TYPE.collectionCarrier); + this.carrier = carrier; + this.clientElements = new ArrayList<>(); + } + + public static CollectionCarrierResourceBuilder newInstance(Carrier carrier) { + return new CollectionCarrierResourceBuilder(carrier); + } + + public CollectionCarrierResourceBuilder setLocationLinkId(Id locationLinkId) { + this.locationLinkId = locationLinkId; + return this; + } + + public CollectionCarrierResourceBuilder setCollectionScheduler( + CollectionCarrierScheduler collectionCarrierScheduler) { + this.collectionScheduler = collectionCarrierScheduler; + return this; + } + + public CollectionCarrierResource build() { + return new CollectionCarrierResource(this); + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static class MainRunCarrierResourceBuilder { + + private final Id id; + private final ArrayList clientElements; + private Carrier carrier; + private Id fromLinkId; + private Id toLinkId; + private MainRunCarrierScheduler mainRunScheduler; + private VehicleReturn vehicleReturn; + + private MainRunCarrierResourceBuilder(Carrier carrier) { + this.id = Id.create(carrier.getId().toString(), LSPResource.class); + setCarrierType(carrier, CARRIER_TYPE.mainRunCarrier); + this.carrier = carrier; + this.clientElements = new ArrayList<>(); + } + + public static MainRunCarrierResourceBuilder newInstance(Carrier carrier) { + return new MainRunCarrierResourceBuilder(carrier); + } + + public MainRunCarrierResourceBuilder setMainRunCarrierScheduler( + MainRunCarrierScheduler mainRunScheduler) { + this.mainRunScheduler = mainRunScheduler; + return this; + } + + public MainRunCarrierResource build() { + return new MainRunCarrierResource(this); + } + + Id getId() { + return id; + } + + Carrier getCarrier() { + return carrier; + } + + public MainRunCarrierResourceBuilder setCarrier(Carrier carrier) { + setCarrierType(carrier, CARRIER_TYPE.mainRunCarrier); + this.carrier = carrier; + return this; + } + + Id getFromLinkId() { + return fromLinkId; + } + + // --- Getter --- + + public MainRunCarrierResourceBuilder setFromLinkId(Id fromLinkId) { + this.fromLinkId = fromLinkId; + return this; + } + + Id getToLinkId() { + return toLinkId; + } + + public MainRunCarrierResourceBuilder setToLinkId(Id toLinkId) { + this.toLinkId = toLinkId; + return this; + } + + ArrayList getClientElements() { + return clientElements; + } + + MainRunCarrierScheduler getMainRunScheduler() { + return mainRunScheduler; + } + + VehicleReturn getVehicleReturn() { + return vehicleReturn; + } + + public MainRunCarrierResourceBuilder setVehicleReturn(VehicleReturn vehicleReturn) { + this.vehicleReturn = vehicleReturn; + return this; + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static class TranshipmentHubSchedulerBuilder { + private double capacityNeedLinear; + private double capacityNeedFixed; + + private TranshipmentHubSchedulerBuilder() {} + + public static TranshipmentHubSchedulerBuilder newInstance() { + return new TranshipmentHubSchedulerBuilder(); + } + + public TransshipmentHubScheduler build() { + return new TransshipmentHubScheduler(this); + } + + double getCapacityNeedLinear() { + return capacityNeedLinear; + } + + public TranshipmentHubSchedulerBuilder setCapacityNeedLinear(double capacityNeedLinear) { + this.capacityNeedLinear = capacityNeedLinear; + return this; + } + + // --- Getters --- + + double getCapacityNeedFixed() { + return capacityNeedFixed; + } + + public TranshipmentHubSchedulerBuilder setCapacityNeedFixed(double capacityNeedFixed) { + this.capacityNeedFixed = capacityNeedFixed; + return this; + } + } + + public static final class TransshipmentHubBuilder { + + private final Id id; + private final Id locationLinkId; + private final ArrayList clientElements; + private final Scenario scenario; + private TransshipmentHubScheduler transshipmentHubScheduler; + + private TransshipmentHubBuilder( + Id id, Id locationLinkId, Scenario scenario) { + this.id = id; + this.clientElements = new ArrayList<>(); + this.locationLinkId = locationLinkId; + this.scenario = scenario; + } + + public static TransshipmentHubBuilder newInstance( + Id id, Id locationLinkId, Scenario scenario) { + return new TransshipmentHubBuilder(id, locationLinkId, scenario); + } + + public TransshipmentHubResource build() { + return new TransshipmentHubResource(this, scenario); + } + + Id getId() { + return id; + } + + // --- Getters --- + + Id getLocationLinkId() { + return locationLinkId; + } + + TransshipmentHubScheduler getTransshipmentHubScheduler() { + return transshipmentHubScheduler; + } + + public TransshipmentHubBuilder setTransshipmentHubScheduler( + LSPResourceScheduler TranshipmentHubScheduler) { + this.transshipmentHubScheduler = (TransshipmentHubScheduler) TranshipmentHubScheduler; + return this; + } + + ArrayList getClientElements() { + return clientElements; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SimpleForwardLogisticChainScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SimpleForwardLogisticChainScheduler.java new file mode 100644 index 00000000000..f046b80c846 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SimpleForwardLogisticChainScheduler.java @@ -0,0 +1,102 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * In the class SimpleForwardSolutionScheduler two tasks are performed: + * + *

1.) the {@link LspShipment}s that were assigned to the suitable {@link LogisticChain} by the + * {@link InitialShipmentAssigner} in a previous step are handed over to the first {@link + * LogisticChainElement}. + * + *

2.) all {@link LSPResource}s that were handed over to the SimpleForwardSolutionScheduler + * exogenously, are now scheduled sequentially in an order that was also specified exogenously. This + * order ensures that each {@link LogisticChain} is traversed from the first to the last {@link + * LogisticChainElement}. During this procedure, the concerned {@link LspShipment}s are taken from + * the collection of incoming shipments, handled by the {@link LSPResource} in charge and then added + * to the collection of outgoing shipments of the client {@link LogisticChainElement}. + * + *

The SimpleForwardSolutionScheduler needs the sequence in which the Resources are scheduled as + * exogenous input. + * + *

The expression "`forward"' refers to the fact that in both cases the scheduling process starts + * at the first element of each {@link LogisticChain} and from the earliest possible point of time. + */ +/*package-private*/ class SimpleForwardLogisticChainScheduler implements LogisticChainScheduler { + + private final List resources; + private LSP lsp; + private int bufferTime; + + SimpleForwardLogisticChainScheduler(List resources) { + this.resources = resources; + } + + @Override + public void scheduleLogisticChain() { + insertShipmentsAtBeginning(); + for (LSPResource resource : resources) { + for (LSPResource lspResource : lsp.getResources()) { + if (lspResource == resource) { + lspResource.schedule(bufferTime, lsp.getSelectedPlan()); + } + } + } + } + + @Override + public void setEmbeddingContainer(LSP lsp) { + this.lsp = lsp; + } + + private void insertShipmentsAtBeginning() { + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + LogisticChainElement firstElement = getFirstElement(solution); + assert firstElement != null; + for (Id lspShipmentId : solution.getLspShipmentIds()) { + var shipment = LSPUtils.findLspShipment(lsp, lspShipmentId); + assert shipment != null; + firstElement + .getIncomingShipments() + .addShipment(shipment.getPickupTimeWindow().getStart(), shipment); + } + } + } + + private LogisticChainElement getFirstElement(LogisticChain solution) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (element.getPreviousElement() == null) { + return element; + } + } + return null; + } + + @Override + public void setBufferTime(int bufferTime) { + this.bufferTime = bufferTime; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SingleLogisticChainShipmentAssigner.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SingleLogisticChainShipmentAssigner.java new file mode 100644 index 00000000000..a377be24ca3 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/SingleLogisticChainShipmentAssigner.java @@ -0,0 +1,48 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import org.matsim.core.gbl.Gbl; +import org.matsim.freight.logistics.InitialShipmentAssigner; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * Ganz einfacher {@link InitialShipmentAssigner}: Voraussetzung: Der {@link LSPPlan} hat genau 1 {@link + * LogisticChain}. + * + *

Dann wird das {@link LspShipment} diesem zugeordnet. + * + *

(Falls die Voraussetzung "exakt 1 LogisticChain pro Plan" nicht erfüllt ist, kommt eine + * RuntimeException) + */ +class SingleLogisticChainShipmentAssigner implements InitialShipmentAssigner { + + SingleLogisticChainShipmentAssigner() {} + + @Override + public void assignToPlan(LSPPlan lspPlan, LspShipment lspShipment) { + Gbl.assertIf(lspPlan.getLogisticChains().size() == 1); + LogisticChain singleSolution = lspPlan.getLogisticChains().iterator().next(); + singleSolution.addShipmentToChain(lspShipment); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubResource.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubResource.java new file mode 100644 index 00000000000..fd168b32b2b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubResource.java @@ -0,0 +1,110 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Collection; +import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.logistics.LSPDataObject; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; + +/** + * {@link LSPResource} bei der die geplanten Tätigkeiten NICHT am Verkehr teilnehmen. + * + *

Thus, these activities are entered directly in the Schedule of the LSPShipments that pass + * through the TranshipmentHub. + * + *

An entry is added to the schedule of the shipments that is an instance of + * ScheduledShipmentHandle. There, the name of the Resource and the client element are entered, so + * that the way that the {@link LspShipment} takes is + * specified. In addition, the planned start and end time of the handling (i.e. cross-docking) of + * the shipment is entered. In the example, cross-docking starts as soon as the considered + * LSPShipment arrives at the {@link TransshipmentHubResource} and ends after a fixed and a size + * dependent amount of time. + * + *

I (KMT, oct'22) have done this temporally public - including a "do not instantiate" + * constructor , because I need it the class for an instanceOf check for a quick scoring of hubs. + * This can be reverted, once hubs will appear in the MATSim events stream. + */ +public class TransshipmentHubResource extends LSPDataObject implements LSPResource { + + private final Id locationLinkId; + private final TransshipmentHubScheduler transshipmentHubScheduler; + private final List clientElements; + + private + TransshipmentHubResource() { // Do not instantiate. (removable once this class is package-private + // again) KMT oct'22 + super(null); + this.locationLinkId = null; + this.transshipmentHubScheduler = null; + this.clientElements = null; + throw new RuntimeException( + "This should have never been called, because it is not planed for getting instantiated."); + } + + TransshipmentHubResource( + TransshipmentHubBuilder builder, Scenario scenario) { + super(builder.getId()); + this.locationLinkId = builder.getLocationLinkId(); + this.transshipmentHubScheduler = builder.getTransshipmentHubScheduler(); + transshipmentHubScheduler.setTranshipmentHub(this); + TransshipmentHubTourEndEventHandler eventHandler = + new TransshipmentHubTourEndEventHandler(this, scenario); + transshipmentHubScheduler.setTransshipmentHubTourEndEventHandler(eventHandler); + this.clientElements = builder.getClientElements(); + } + + @Override + public Id getStartLinkId() { + return locationLinkId; + } + + @Override + public Id getEndLinkId() { + return locationLinkId; + } + + @Override + public Collection getClientElements() { + return clientElements; + } + + @Override + public void schedule(int bufferTime, LSPPlan lspPlan) { + transshipmentHubScheduler.scheduleShipments(lspPlan, this, bufferTime); + } + + public double getCapacityNeedFixed() { + return transshipmentHubScheduler.getCapacityNeedFixed(); + } + + public double getCapacityNeedLinear() { + return transshipmentHubScheduler.getCapacityNeedLinear(); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubScheduler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubScheduler.java new file mode 100644 index 00000000000..e4d151903e9 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubScheduler.java @@ -0,0 +1,123 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.ArrayList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPResourceScheduler; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.freight.logistics.shipment.LspShipment; + +/*package-private*/ class TransshipmentHubScheduler extends LSPResourceScheduler { + + final Logger log = LogManager.getLogger(TransshipmentHubScheduler.class); + private final double capacityNeedLinear; + private final double capacityNeedFixed; + private TransshipmentHubResource transshipmentHubResource; + private TransshipmentHubTourEndEventHandler eventHandler; + + TransshipmentHubScheduler(TranshipmentHubSchedulerBuilder builder) { + this.lspShipmentsToSchedule = new ArrayList<>(); + this.capacityNeedLinear = builder.getCapacityNeedLinear(); + this.capacityNeedFixed = builder.getCapacityNeedFixed(); + } + + @Override + protected void initializeValues(LSPResource resource) { + this.transshipmentHubResource = (TransshipmentHubResource) resource; + } + + @Override + protected void scheduleResource() { + for (LspShipment lspShipmentToBeAssigned : lspShipmentsToSchedule) { + updateSchedule(lspShipmentToBeAssigned); + } + } + + @Override + @Deprecated + protected void updateShipments() { + log.error("This method is not implemented. Nothing will happen here. "); + } + + private void updateSchedule(LspShipment lspShipment) { + addShipmentHandleElement(lspShipment); + addShipmentToEventHandler(lspShipment); + } + + private void addShipmentHandleElement(LspShipment lspShipment) { + LspShipmentUtils.ScheduledShipmentHandleBuilder builder = + LspShipmentUtils.ScheduledShipmentHandleBuilder.newInstance(); + builder.setStartTime(LspShipmentUtils.getTimeOfLspShipment(lspShipment)); + builder.setEndTime(LspShipmentUtils.getTimeOfLspShipment(lspShipment) + capacityNeedFixed + capacityNeedLinear * lspShipment.getSize()); + builder.setResourceId(transshipmentHubResource.getId()); + for (LogisticChainElement element : transshipmentHubResource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + builder.setLogisticsChainElement(element); + } + } + LspShipmentPlanElement handle = builder.build(); + + String idString = + handle.getResourceId() + + String.valueOf(handle.getLogisticChainElement().getId()) + + handle.getElementType(); + Id id = Id.create(idString, LspShipmentPlanElement.class); + LspShipmentUtils.getOrCreateShipmentPlan(super.lspPlan, lspShipment.getId()) + .addPlanElement(id, handle); + } + + private void addShipmentToEventHandler(LspShipment lspShipment) { + for (LogisticChainElement element : transshipmentHubResource.getClientElements()) { + if (element.getIncomingShipments().getLspShipmentsWTime().contains(lspShipment)) { + LspShipmentPlan lspShipmentPlan = + LspShipmentUtils.getOrCreateShipmentPlan(lspPlan, lspShipment.getId()); + eventHandler.addShipment(lspShipment, element, lspShipmentPlan); + break; + } + } + } + + public double getCapacityNeedLinear() { + return capacityNeedLinear; + } + + public double getCapacityNeedFixed() { + return capacityNeedFixed; + } + + public void setTranshipmentHub(TransshipmentHubResource transshipmentHubResource) { + this.transshipmentHubResource = transshipmentHubResource; + } + + public void setTransshipmentHubTourEndEventHandler( + TransshipmentHubTourEndEventHandler eventHandler) { + this.eventHandler = eventHandler; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubTourEndEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubTourEndEventHandler.java new file mode 100644 index 00000000000..bd476a54954 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/TransshipmentHubTourEndEventHandler.java @@ -0,0 +1,278 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.controler.events.AfterMobsimEvent; +import org.matsim.core.controler.listener.AfterMobsimListener; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.Tour.ServiceActivity; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.carriers.events.CarrierTourEndEvent; +import org.matsim.freight.carriers.events.eventhandler.CarrierTourEndEventHandler; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPSimulationTracker; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.events.HandlingInHubStartsEvent; +import org.matsim.freight.logistics.shipment.*; + +/*package-private*/ class TransshipmentHubTourEndEventHandler + implements AfterMobsimListener, LSPSimulationTracker, CarrierTourEndEventHandler { + + //This class *should* also get merged into {@link LSPTourEndEventHandler}. + //Currently, this is not possible very easily, because of missing injection (of the scenario.) + //KMT, KN (Jan'24) + + private final Scenario scenario; + private final HashMap servicesWaitedFor; + private final TransshipmentHubResource transshipmentHubResource; + private final Id resourceId; + private final Id linkId; + private EventsManager eventsManager; + + /** + * This is a TourEndEvent-Handler, doing some stuff regarding the {@link + * TransshipmentHubResource}. + * + * @param transshipmentHubResource hub + * @param scenario The scenario. Is used to get the Carrier(s). + */ + TransshipmentHubTourEndEventHandler( + TransshipmentHubResource transshipmentHubResource, Scenario scenario) { + this.transshipmentHubResource = transshipmentHubResource; + this.linkId = transshipmentHubResource.getEndLinkId(); + this.resourceId = transshipmentHubResource.getId(); + this.scenario = scenario; + this.servicesWaitedFor = new HashMap<>(); + this.transshipmentHubResource.addSimulationTracker(this); + } + + @Override + public void setEmbeddingContainer(LSPResource pointer) {} + + @Override + public void setEventsManager(EventsManager eventsManager) { + this.eventsManager = eventsManager; + } + + @Override + public void notifyAfterMobsim(AfterMobsimEvent event) { + servicesWaitedFor + .clear(); // cleanup after Mobsim ends (instead of doing it in reset() = before Mobsim + // starts.) kmt oct'22 + } + + @Override + public void reset(int iteration) { + // not implemented; cleanup is done after Mobsim ends, because the internal state is (re)set + // before Mobsim starts. + // --> cleaning up here is too late. + // This is maybe not ideal, but works; kmt oct'22 + } + + public void addShipment( + LspShipment lspShipment, LogisticChainElement logisticChainElement, LspShipmentPlan lspShipmentPlan) { + TransshipmentHubEventHandlerPair pair = + new TransshipmentHubEventHandlerPair(lspShipment, logisticChainElement); + + for (LspShipmentPlanElement planElement : lspShipmentPlan.getPlanElements().values()) { + if (planElement instanceof LspShipmentLeg transport) { + if (transport.getLogisticChainElement().getNextElement() == logisticChainElement) { + servicesWaitedFor.put(transport.getCarrierService(), pair); + } + } + } + } + + @Override + public void handleEvent(CarrierTourEndEvent event) { + Tour tour = null; + Carrier carrier = CarriersUtils.getCarriers(scenario).getCarriers().get(event.getCarrierId()); + Collection scheduledTours = carrier.getSelectedPlan().getScheduledTours(); + for (ScheduledTour scheduledTour : scheduledTours) { + if (scheduledTour.getTour().getId() == event.getTourId()) { + tour = scheduledTour.getTour(); + break; + } + } + if ((event.getLinkId() == this.linkId)) { + assert tour != null; + + if (ResourceImplementationUtils.getCarrierType(carrier) + == ResourceImplementationUtils.CARRIER_TYPE.mainRunCarrier) { + if (allShipmentsOfTourEndInOnePoint(tour)) { + for (TourElement tourElement : tour.getTourElements()) { + if (tourElement instanceof ServiceActivity serviceActivity) { + if (serviceActivity.getLocation() == transshipmentHubResource.getStartLinkId() + && allServicesAreInOnePoint(tour) + && (tour.getStartLinkId() != transshipmentHubResource.getStartLinkId())) { + + final CarrierService carrierService = serviceActivity.getService(); + final LspShipment lspShipment = servicesWaitedFor.get(carrierService).lspShipment; + // NOTE: Do NOT add time vor unloading all goods, because they are included for the + // main run (Service activity at end of tour) + final double expHandlingDuration = + transshipmentHubResource.getCapacityNeedFixed() + + (transshipmentHubResource.getCapacityNeedLinear() + * lspShipment.getSize()); + final double startTime = event.getTime(); + final double endTime = startTime + expHandlingDuration; + + logHandlingInHub(serviceActivity.getService(), startTime, endTime); + throwHandlingEvent(event, lspShipment, expHandlingDuration); + } + } + } + } + } else if ((ResourceImplementationUtils.getCarrierType(carrier) + == ResourceImplementationUtils.CARRIER_TYPE.collectionCarrier)) { + for (TourElement tourElement : tour.getTourElements()) { + if (tourElement instanceof ServiceActivity serviceActivity) { + if (tour.getEndLinkId() == transshipmentHubResource.getStartLinkId()) { + + final CarrierService carrierService = serviceActivity.getService(); + final LspShipment lspShipment = servicesWaitedFor.get(carrierService).lspShipment; + + // TODO: Adding this here to be more in line with the schedule and have the shipment + // log fitting to it. + // This does NOT mean, that it really makes sense, because we decided for some + // reasons, that the handlingEvent start once the vehicle has arrived. + // It may change again, once we have unloading events available. + final double expUnloadingTime = getTotalUnloadingTime(tour); + final double expHandlingDuration = + transshipmentHubResource.getCapacityNeedFixed() + + (transshipmentHubResource.getCapacityNeedLinear() * lspShipment.getSize()); + final double startTime = event.getTime() + expUnloadingTime; + final double endTime = startTime + expHandlingDuration; + + logHandlingInHub(carrierService, startTime, endTime); + throwHandlingEvent(event, lspShipment, expHandlingDuration); + } + } + } + } + } + } + + private boolean allShipmentsOfTourEndInOnePoint(Tour tour) { + boolean allShipmentsOfTourEndInOnePoint = true; + for (TourElement tourElement : tour.getTourElements()) { + if (tourElement instanceof ServiceActivity serviceActivity) { + if (!servicesWaitedFor.containsKey(serviceActivity.getService())) { + return false; + } + } + } + return allShipmentsOfTourEndInOnePoint; + } + + private double getTotalUnloadingTime(Tour tour) { + double totalTime = 0; + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity serviceActivity) { + totalTime = totalTime + serviceActivity.getDuration(); + } + } + return totalTime; + } + + private void logHandlingInHub( + CarrierService carrierService, double startTime, double endTime) { + + LspShipment lspShipment = servicesWaitedFor.get(carrierService).lspShipment; + + { // Old logging approach - will be removed at some point in time + LspShipmentPlanElement handle = + LspShipmentUtils.LoggedShipmentHandleBuilder.newInstance() + .setLinkId(linkId) + .setResourceId(resourceId) + .setStartTime(startTime) + .setEndTime(endTime) + .setLogisticsChainElement(servicesWaitedFor.get(carrierService).logisticChainElement) + .build(); + Id loadId = + Id.create( + handle.getResourceId() + + String.valueOf(handle.getLogisticChainElement().getId()) + + handle.getElementType(), + LspShipmentPlanElement.class); + if (!lspShipment.getShipmentLog().getPlanElements().containsKey(loadId)) { + lspShipment.getShipmentLog().addPlanElement(loadId, handle); + } + } + } + + private void throwHandlingEvent( + CarrierTourEndEvent event, LspShipment lspShipment, double expHandlingDuration) { + // New event-based approach + // Todo: We need to decide what we write into the exp. handling duration: See #175 for + // discussion. + // The start time, must start at the same time as the triggering event. -> keep events stream + // ordered. + eventsManager.processEvent( + new HandlingInHubStartsEvent( + event.getTime(), linkId, lspShipment.getId(), resourceId, expHandlingDuration)); + } + + private boolean allServicesAreInOnePoint(Tour tour) { + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity activity) { + if (activity.getLocation() != tour.getEndLinkId()) { + return false; + } + } + } + return true; + } + + public Map getServicesWaitedFor() { + return servicesWaitedFor; + } + + public TransshipmentHubResource getTranshipmentHub() { + return transshipmentHubResource; + } + + public Id getResourceId() { + return resourceId; + } + + public Id getLinkId() { + return linkId; + } + + public static class TransshipmentHubEventHandlerPair { + public final LspShipment lspShipment; + public final LogisticChainElement logisticChainElement; + + public TransshipmentHubEventHandlerPair(LspShipment lspShipment, LogisticChainElement element) { + this.lspShipment = lspShipment; + this.logisticChainElement = element; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentHandle.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentHandle.java new file mode 100644 index 00000000000..a9970d4bc67 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentHandle.java @@ -0,0 +1,65 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +/*package*/ class LoggedLspShipmentHandle implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + LoggedLspShipmentHandle(LspShipmentUtils.LoggedShipmentHandleBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + + @Override + public String getElementType() { + return "HANDLE"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentLoad.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentLoad.java new file mode 100644 index 00000000000..ac0941162cb --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentLoad.java @@ -0,0 +1,65 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +/*package-private*/ class LoggedLspShipmentLoad implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + LoggedLspShipmentLoad(LspShipmentUtils.LoggedShipmentLoadBuilder builder) { + this.startTime = builder.getStartTime(); + this.endTime = builder.getEndTime(); + this.element = builder.getElement(); + this.resourceId = builder.getResourceId(); + } + + @Override + public String getElementType() { + return "LOAD"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentTransport.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentTransport.java new file mode 100644 index 00000000000..6ab1650ccfe --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentTransport.java @@ -0,0 +1,97 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +final class LoggedLspShipmentTransport implements LspShipmentLeg { + + private final double startTime; + private final LogisticChainElement element; + private final Id resourceId; + private final Id fromLinkId; + private double endTime; + private Id toLinkId; + + LoggedLspShipmentTransport(LspShipmentUtils.LoggedShipmentTransportBuilder builder) { + this.startTime = builder.getStartTime(); + this.element = builder.getElement(); + this.resourceId = builder.getResourceId(); + this.fromLinkId = builder.getFromLinkId(); + this.toLinkId = builder.getToLinkId(); + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + + @Override + public String getElementType() { + return "TRANSPORT"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public Id getFromLinkId() { + return fromLinkId; + } + + @Override + public CarrierService getCarrierService() { + throw new RuntimeException("not implemented"); + } + + public Id getToLinkId() { + return toLinkId; + } + + public void setToLinkId(Id toLinkId) { + this.toLinkId = toLinkId; + } + + @Override + public Id getCarrierId() { + throw new RuntimeException("not implemented"); + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentUnload.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentUnload.java new file mode 100644 index 00000000000..20d88e7032e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LoggedLspShipmentUnload.java @@ -0,0 +1,65 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +class LoggedLspShipmentUnload implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + LoggedLspShipmentUnload(LspShipmentUtils.LoggedShipmentUnloadBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + + @Override + public String getElementType() { + return "UNLOAD"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipment.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipment.java new file mode 100644 index 00000000000..700f969d7ab --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipment.java @@ -0,0 +1,63 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.Collection; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Identifiable; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.HasSimulationTrackers; +import org.matsim.utils.objectattributes.attributable.Attributable; + +/** + * This is, for example, a shipment that DHL moves from A to B. It may use multiple carriers to + * achieve that. + * + *

Questions/comments: + * + *

    + *
  • Within more modern MATSim, we would probably prefer to have from and to in coordinates, not + * link IDs. + *
+ */ +public interface LspShipment + extends Identifiable, Attributable, HasSimulationTrackers { + + Id getFrom(); // same as in CarrierShipment + + Id getTo(); // same as in CarrierShipment + + TimeWindow getPickupTimeWindow(); // same as in CarrierShipment + + TimeWindow getDeliveryTimeWindow(); // same as in CarrierShipment + + int getSize(); // same as in CarrierShipment + + double getDeliveryServiceTime(); // same as in CarrierShipment + + double getPickupServiceTime(); // same as in CarrierShipment + + LspShipmentPlan getShipmentLog(); + + Collection getRequirements(); + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentImpl.java new file mode 100644 index 00000000000..8ff44b2aa79 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentImpl.java @@ -0,0 +1,137 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.LSPDataObject; + +class LspShipmentImpl extends LSPDataObject implements LspShipment { + + private final Id fromLinkId; + private final Id toLinkId; + private final TimeWindow startTimeWindow; + private final TimeWindow endTimeWindow; + private final int capacityDemand; + private final double deliveryServiceTime; + private final double pickupServiceTime; + // private final ShipmentPlan shipmentPlan; + @Deprecated // This will be removed in the future and replaced by using the events. KMT, Mai'23 + private final LspShipmentPlan shipmentLog; + private final List lspShipmentRequirements; + + // private Id lspId; + + LspShipmentImpl(LspShipmentUtils.LspShipmentBuilder builder) { + super(builder.id); + this.fromLinkId = builder.fromLinkId; + this.toLinkId = builder.toLinkId; + this.startTimeWindow = builder.startTimeWindow; + this.endTimeWindow = builder.endTimeWindow; + this.capacityDemand = builder.capacityDemand; + this.deliveryServiceTime = builder.deliveryServiceTime; + this.pickupServiceTime = builder.pickupServiceTime; + // this.shipmentPlan = new ShipmentPlanImpl(this.getId()); + this.shipmentLog = new LspShipmentPlanImpl(this.getId()); + this.lspShipmentRequirements = new ArrayList<>(); + this.lspShipmentRequirements.addAll(builder.lspShipmentRequirements); + } + + @Override + public Id getFrom() { + return fromLinkId; + } + + @Override + public Id getTo() { + return toLinkId; + } + + @Override + public TimeWindow getPickupTimeWindow() { + return startTimeWindow; + } + + @Override + public TimeWindow getDeliveryTimeWindow() { + return endTimeWindow; + } + + @Deprecated // This will be removed in the future and replaced by using the events. KMT, Mai'23 + @Override + public LspShipmentPlan getShipmentLog() { + return shipmentLog; + } + + @Override + public int getSize() { + return capacityDemand; + } + + @Override + public double getDeliveryServiceTime() { + return deliveryServiceTime; + } + + @Override + public Collection getRequirements() { + return lspShipmentRequirements; + } + + @Override + public double getPickupServiceTime() { + return pickupServiceTime; + } + + + + @Override + public String toString() { + return "LSPShipmentImpl{" + + "Id=" + + getId() + + "\t fromLinkId=" + + fromLinkId + + "\t toLinkId=" + + toLinkId + + "\t capacityDemand=" + + capacityDemand + + "\t startTimeWindow=" + + startTimeWindow + + "\t endTimeWindow=" + + endTimeWindow + + "\t capacityDemand=" + + capacityDemand + + "\t deliveryServiceTime=" + + deliveryServiceTime + + "\t pickupServiceTime=" + + pickupServiceTime + + + // "\t schedule=" + schedule + + // "\t log=" + log + + // "\t requirements=" + requirements + + '}'; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentLeg.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentLeg.java new file mode 100644 index 00000000000..3b5d4c00904 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentLeg.java @@ -0,0 +1,20 @@ +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; + +public interface LspShipmentLeg extends LspShipmentPlanElement { + Id getToLinkId(); + + void setToLinkId(Id endLinkId); + + Id getCarrierId(); + + Id getFromLinkId(); + + CarrierService getCarrierService(); + + void setEndTime(double time); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlan.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlan.java new file mode 100644 index 00000000000..03cb42d0dca --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlan.java @@ -0,0 +1,38 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.HasBackpointer; + +public interface LspShipmentPlan extends HasBackpointer> { + + Id getLspShipmentId(); + + Map, LspShipmentPlanElement> getPlanElements(); + + void addPlanElement(Id id, LspShipmentPlanElement element); + + LspShipmentPlanElement getMostRecentEntry(); + + void clear(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanElement.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanElement.java new file mode 100644 index 00000000000..5809ddfad28 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanElement.java @@ -0,0 +1,41 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +public interface LspShipmentPlanElement { + + LogisticChainElement getLogisticChainElement(); + + Id getResourceId(); + + // yyyy "type" feels like this makes it a tagged class. These should be avoided (Effective Java + // 2018, Item 23). It is, however, probably not + // used as a type, but rather as a description. Rename? + String getElementType(); + + double getStartTime(); + + double getEndTime(); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanImpl.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanImpl.java new file mode 100644 index 00000000000..89f1abcd52f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentPlanImpl.java @@ -0,0 +1,98 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.*; +import org.matsim.api.core.v01.Id; + +/*package-private*/ class LspShipmentPlanImpl implements LspShipmentPlan { + + private final Id lspShipmentId; + private final LinkedHashMap, LspShipmentPlanElement> planElements; + + LspShipmentPlanImpl(Id lspShipmentId) { + this.lspShipmentId = lspShipmentId; + this.planElements = new LinkedHashMap<>(); + } + + // TODO: Ist kein embedding container! + @Override + public void setEmbeddingContainer(Id pointer) { + throw new RuntimeException("not implemented"); + } + + @Override + public Id getLspShipmentId() { + return lspShipmentId; + } + + @Override + public void addPlanElement(Id id, LspShipmentPlanElement element) { + planElements.put(id, element); + } + + @Override + public Map, LspShipmentPlanElement> getPlanElements() { + return Collections.unmodifiableMap(planElements); + } + + @Override + public LspShipmentPlanElement getMostRecentEntry() { + + // there is no method to remove entries. in consequence, the only way to change the result of + // this method is to "add" additional material into the plan. Possibly, + // the method here is indeed there to find the plan element that was added most recently, to + // figure out how the next one can be added. However, this then + // should be sorted by sequence of addition, not by timing. ??? kai/kai, apr'21 + + ArrayList logList = new ArrayList<>(planElements.values()); + logList.sort(new LogElementComparator()); + Collections.reverse(logList); + return logList.getFirst(); + } + + @Override + public void clear() { + planElements.clear(); + } + + static class LogElementComparator implements Comparator { + + @Override + public int compare(LspShipmentPlanElement o1, LspShipmentPlanElement o2) { + if (o1.getStartTime() > o2.getStartTime()) { + return 1; + } + if (o1.getStartTime() < o2.getStartTime()) { + return -1; + } + if (o1.getStartTime() == o2.getStartTime()) { + if (o1.getEndTime() > o2.getEndTime()) { + return 1; + } + if (o1.getEndTime() < o2.getEndTime()) { + return -1; + } + } + return 0; + } + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentRequirement.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentRequirement.java new file mode 100644 index 00000000000..1bbd0f323dd --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentRequirement.java @@ -0,0 +1,28 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.freight.logistics.LogisticChain; + +public interface LspShipmentRequirement { + + boolean checkRequirement(LogisticChain solution); +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentUtils.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentUtils.java new file mode 100644 index 00000000000..3b2c46e8a98 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/LspShipmentUtils.java @@ -0,0 +1,541 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.CarrierShipment; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.LSPPlan; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +public final class LspShipmentUtils { + private LspShipmentUtils() {} // do not instantiate + + public static Comparator createShipmentPlanElementComparator() { + return new ShipmentPlanElementComparator(); + } + + /** + * Gives back the {@link LspShipmentPlan} object of the {@link LSPPlan}, which matches to the id of + * the {@link LspShipment} + * + * @param lspPlan The lspPlan in which this method tries to find the shipmentPlan. + * @param shipmentId Id of the shipment for which the Plan should be found. + * @return the ShipmentPlan object or null, if it is not found. + */ + public static LspShipmentPlan getOrCreateShipmentPlan(LSPPlan lspPlan, Id shipmentId) { + // Return shipmentPlan if already existing in LspPlan + for (LspShipmentPlan lspShipmentPlan : lspPlan.getShipmentPlans()) { + if (lspShipmentPlan.getLspShipmentId().equals(shipmentId)) { + return lspShipmentPlan; + } + } + // ShipmentPlan does not exist in LspPlan. Will create one, add it to the LspPlan. + LspShipmentPlan newLspShipmentPlan = new LspShipmentPlanImpl(shipmentId); + lspPlan.addShipmentPlan(newLspShipmentPlan); + return newLspShipmentPlan; + } + + /** + * Stores a time as Attribute in the LspShipment. + * This is needed for some kind of tracking the shipment. + *

+ * This will replace the LSPShipmentWithTime class and thus reduce the complexity of the code. + * KMT Jul'24 + * @param lspShipment the LspShipment to store the time in + * @param time the time to store + */ + public static void setTimeOfLspShipment(LspShipment lspShipment, double time){ + lspShipment.getAttributes().putAttribute("time", time); + } + + /** + * Returns the time stored in the LspShipment. + *

+ * This will replace the LSPShipmentWithTime class and thus reduce the complexity of the code. KMT Jul'24 + * @param lspShipment the LspShipment to get the time from + * @return the time as double + */ + public static double getTimeOfLspShipment(LspShipment lspShipment) { + return (double) lspShipment.getAttributes().getAttribute("time"); + } + + public static final class LspShipmentBuilder { + final Id id; + final List lspShipmentRequirements; + Id fromLinkId; + Id toLinkId; + TimeWindow startTimeWindow; + TimeWindow endTimeWindow; + int capacityDemand; + double deliveryServiceTime; + double pickupServiceTime; + + private LspShipmentBuilder(Id id) { + this.lspShipmentRequirements = new ArrayList<>(); + this.id = id; + } + + public static LspShipmentBuilder newInstance(Id id) { + return new LspShipmentBuilder(id); + } + + public void setFromLinkId(Id fromLinkId) { + this.fromLinkId = fromLinkId; + } + + public void setToLinkId(Id toLinkId) { + this.toLinkId = toLinkId; + } + + public void setStartTimeWindow(TimeWindow startTimeWindow) { + this.startTimeWindow = startTimeWindow; + } + + public void setEndTimeWindow(TimeWindow endTimeWindow) { + this.endTimeWindow = endTimeWindow; + } + + public void setCapacityDemand(int capacityDemand) { + this.capacityDemand = capacityDemand; + } + + public void setDeliveryServiceTime(double serviceTime) { + this.deliveryServiceTime = serviceTime; + } + + public LspShipmentBuilder setPickupServiceTime(double serviceTime) { + this.pickupServiceTime = serviceTime; + return this; + } + + public void addRequirement(LspShipmentRequirement requirement) { + lspShipmentRequirements.add(requirement); + } + + public LspShipment build() { + return new LspShipmentImpl(this); + } + } + + //----------------------------- + // LoggedShipment<..> builders + //----------------------------- + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class LoggedShipmentLoadBuilder { + private double startTime; + private double endTime; + private LogisticChainElement element; + private Id resourceId; + private Id carrierId; + private Id linkId; + + private LoggedShipmentLoadBuilder() {} + + public static LoggedShipmentLoadBuilder newInstance() { + return new LoggedShipmentLoadBuilder(); + } + + public void setLogisticsChainElement(LogisticChainElement element) { + this.element = element; + } + + public LoggedLspShipmentLoad build() { + return new LoggedLspShipmentLoad(this); + } + + public double getStartTime() { + return startTime; + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public double getEndTime() { + return endTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public LogisticChainElement getElement() { + return element; + } + + // --- Getters --- // + + public Id getResourceId() { + return resourceId; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public Id getCarrierId() { + return carrierId; + } + + public void setCarrierId(Id carrierId) { + this.carrierId = carrierId; + } + + public Id getLinkId() { + return linkId; + } + + public void setLinkId(Id linkId) { + this.linkId = linkId; + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class LoggedShipmentTransportBuilder { + private double startTime; + private LogisticChainElement element; + private Id resourceId; + private Id fromLinkId; + private Id toLinkId; + private Id carrierId; + + private LoggedShipmentTransportBuilder() {} + + public static LoggedShipmentTransportBuilder newInstance() { + return new LoggedShipmentTransportBuilder(); + } + + public void setLogisticChainElement(LogisticChainElement element) { + this.element = element; + } + + public LoggedLspShipmentTransport build() { + return new LoggedLspShipmentTransport(this); + } + + // --- Getters --- // + public double getStartTime() { + return startTime; + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public LogisticChainElement getElement() { + return element; + } + + public Id getResourceId() { + return resourceId; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public Id getFromLinkId() { + return fromLinkId; + } + + public void setFromLinkId(Id fromLinkId) { + this.fromLinkId = fromLinkId; + } + + public Id getToLinkId() { + return toLinkId; + } + + public void setToLinkId(Id toLinkId) { + this.toLinkId = toLinkId; + } + + public Id getCarrierId() { + return carrierId; + } + + public void setCarrierId(Id carrierId) { + this.carrierId = carrierId; + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class LoggedShipmentUnloadBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + Id carrierId; + Id linkId; + + private LoggedShipmentUnloadBuilder() {} + + public static LoggedShipmentUnloadBuilder newInstance() { + return new LoggedShipmentUnloadBuilder(); + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setLogisticChainElement(LogisticChainElement element) { + this.element = element; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public void setLinkId(Id linkId) { + this.linkId = linkId; + } + + public void setCarrierId(Id carrierId) { + this.carrierId = carrierId; + } + + public LoggedLspShipmentUnload build() { + return new LoggedLspShipmentUnload(this); + } + } + + public static final class LoggedShipmentHandleBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + Id linkId; + + private LoggedShipmentHandleBuilder() {} + + public static LoggedShipmentHandleBuilder newInstance() { + return new LoggedShipmentHandleBuilder(); + } + + public LoggedShipmentHandleBuilder setStartTime(double startTime) { + this.startTime = startTime; + return this; + } + + public LoggedShipmentHandleBuilder setEndTime(double endTime) { + this.endTime = endTime; + return this; + } + + public LoggedShipmentHandleBuilder setLogisticsChainElement(LogisticChainElement element) { + this.element = element; + return this; + } + + public LoggedShipmentHandleBuilder setResourceId(Id resourceId) { + this.resourceId = resourceId; + return this; + } + + public LoggedShipmentHandleBuilder setLinkId(Id linkId) { + this.linkId = linkId; + return this; + } + + public LspShipmentPlanElement build() { + return new LoggedLspShipmentHandle(this); + } + } + + //----------------------------- + // ScheduledShipment<..> builders + //----------------------------- + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class ScheduledShipmentLoadBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + + private ScheduledShipmentLoadBuilder() {} + + public static ScheduledShipmentLoadBuilder newInstance() { + return new ScheduledShipmentLoadBuilder(); + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setLogisticChainElement(LogisticChainElement element) { + this.element = element; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public ScheduledLspShipmentLoad build() { + return new ScheduledLspShipmentLoad(this); + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class ScheduledShipmentTransportBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + Id carrierId; + Id fromLinkId; + Id toLinkId; + CarrierService carrierService; + CarrierShipment carrierShipment; //TODO: Put CarrierShipment and CarrieTask behind one interface and use that here (CarrierTask...) + + private ScheduledShipmentTransportBuilder() {} + + public static ScheduledShipmentTransportBuilder newInstance() { + return new ScheduledShipmentTransportBuilder(); + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setLogisticChainElement(LogisticChainElement element) { + this.element = element; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public void setCarrierId(Id carrierId) { + this.carrierId = carrierId; + } + + public void setFromLinkId(Id fromLinkId) { + this.fromLinkId = fromLinkId; + } + + public void setToLinkId(Id toLinkId) { + this.toLinkId = toLinkId; + } + + public void setCarrierService(CarrierService carrierService) { + this.carrierService = carrierService; + } + + public void setCarrierShipment(CarrierShipment carrierShipment) { + this.carrierShipment = carrierShipment; + } + + public ScheduledLspShipmentTransport build() { + return new ScheduledLspShipmentTransport(this); + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class ScheduledShipmentUnloadBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + + private ScheduledShipmentUnloadBuilder() {} + + public static ScheduledShipmentUnloadBuilder newInstance() { + return new ScheduledShipmentUnloadBuilder(); + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setLogisticsChainElement(LogisticChainElement element) { + this.element = element; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public ScheduledLspShipmentUnload build() { + return new ScheduledLspShipmentUnload(this); + } + } + + @SuppressWarnings("ClassEscapesDefinedScope") + public static final class ScheduledShipmentHandleBuilder { + double startTime; + double endTime; + LogisticChainElement element; + Id resourceId; + + private ScheduledShipmentHandleBuilder() {} + + public static ScheduledShipmentHandleBuilder newInstance() { + return new ScheduledShipmentHandleBuilder(); + } + + public void setStartTime(double startTime) { + this.startTime = startTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setLogisticsChainElement(LogisticChainElement element) { + this.element = element; + } + + public void setResourceId(Id resourceId) { + this.resourceId = resourceId; + } + + public ScheduledLspShipmentHandle build() { + return new ScheduledLspShipmentHandle(this); + } + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentHandle.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentHandle.java new file mode 100644 index 00000000000..54e6bef95a4 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentHandle.java @@ -0,0 +1,65 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +class ScheduledLspShipmentHandle implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + ScheduledLspShipmentHandle(LspShipmentUtils.ScheduledShipmentHandleBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + } + + @Override + public String getElementType() { + return "HANDLE"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentLoad.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentLoad.java new file mode 100644 index 00000000000..df709de193d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentLoad.java @@ -0,0 +1,66 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +class ScheduledLspShipmentLoad implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + ScheduledLspShipmentLoad(LspShipmentUtils.ScheduledShipmentLoadBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + } + + @Override + public String getElementType() { + return "LOAD"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentTransport.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentTransport.java new file mode 100644 index 00000000000..71b084e2843 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentTransport.java @@ -0,0 +1,113 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarrierService; +import org.matsim.freight.carriers.CarrierShipment; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +final class ScheduledLspShipmentTransport implements LspShipmentLeg { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + private final Id carrierId; + private final Id fromLinkId; + private final Id toLinkId; + private final CarrierService carrierService; + private final CarrierShipment carrierShipment; //TODO: Put CarrierShipment and CarrieTask behind one interface and use that here (CarrierTask...) + + ScheduledLspShipmentTransport(LspShipmentUtils.ScheduledShipmentTransportBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + this.carrierId = builder.carrierId; + this.fromLinkId = builder.fromLinkId; + this.toLinkId = builder.toLinkId; + this.carrierService = builder.carrierService; + this.carrierShipment = builder.carrierShipment; + } + + @Override + public String getElementType() { + return "TRANSPORT"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + @Override + public void setEndTime(double time) { + throw new RuntimeException("not implemented"); + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + + @Override + public Id getToLinkId() { + return toLinkId; + } + + @Override + public void setToLinkId(Id endLinkId) { + throw new RuntimeException("not implemented"); + } + + @Override + public Id getCarrierId() { + return carrierId; + } + + @Override + public Id getFromLinkId() { + return fromLinkId; + } + + @Override + public CarrierService getCarrierService() { + return carrierService; + } + + public CarrierShipment getCarrierShipment() { + return carrierShipment; + } +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentUnload.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentUnload.java new file mode 100644 index 00000000000..1746e854ffe --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ScheduledLspShipmentUnload.java @@ -0,0 +1,66 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LogisticChainElement; + +class ScheduledLspShipmentUnload implements LspShipmentPlanElement { + + private final double startTime; + private final double endTime; + private final LogisticChainElement element; + private final Id resourceId; + + ScheduledLspShipmentUnload(LspShipmentUtils.ScheduledShipmentUnloadBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.element = builder.element; + this.resourceId = builder.resourceId; + } + + @Override + public String getElementType() { + return "UNLOAD"; + } + + @Override + public double getStartTime() { + return startTime; + } + + @Override + public double getEndTime() { + return endTime; + } + + @Override + public LogisticChainElement getLogisticChainElement() { + return element; + } + + @Override + public Id getResourceId() { + return resourceId; + } + +} diff --git a/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ShipmentPlanElementComparator.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ShipmentPlanElementComparator.java new file mode 100644 index 00000000000..39eec06637e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/shipment/ShipmentPlanElementComparator.java @@ -0,0 +1,46 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.shipment; + +import java.util.Comparator; + +final class ShipmentPlanElementComparator implements Comparator { + + ShipmentPlanElementComparator() {} + + public int compare(LspShipmentPlanElement o1, LspShipmentPlanElement o2) { + if (o1.getStartTime() > o2.getStartTime()) { + return 1; + } + if (o1.getStartTime() < o2.getStartTime()) { + return -1; + } + if (o1.getStartTime() == o2.getStartTime()) { + if (o1.getEndTime() > o2.getEndTime()) { + return 1; + } + if (o1.getEndTime() < o2.getEndTime()) { + return -1; + } + } + return 0; + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/Doxyfile b/contribs/freight/src/test/java/org/matsim/freight/logistics/Doxyfile new file mode 100644 index 00000000000..1b91b479d8e --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/Doxyfile @@ -0,0 +1,2526 @@ +# Doxyfile 1.8.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = dfg-freight + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = /Users/kainagel/doxygen-html/dfg-freight + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = org/matsim + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = YES + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = NO + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = lsp + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.java + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */jaxb/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = /Users/kainagel/git/all-matsim/freight-dfg17/src/main/java/doxyfilter.sh + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = YES + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 1 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = /Users/nagel/doxygen-html/matsim + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 400 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png The default and svg Looks nicer but requires the +# pdf2svg tool. +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /

+ * This class here is in contrast used as a Replanning strategy. This behavior is not wanted anymore. + *

+ * Please use the new Approach as shown in + * org.matsim.freight.logistics.example.lsp.multipleChains.ExampleMultipleOneEchelonChainsReplanning instead. + *

+ * * KMT, Jul'24 + */ +@Deprecated +public class CollectionLSPReplanningTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = network.getLinks().get(collectionLinkId); + if (collectionLink == null) { + System.exit(1); + } + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + + List linkList = new LinkedList<>(network.getLinks().values()); + + + for (int i = 1; i < 21; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + +// ShipmentAssigner maybeTodayAssigner = new MaybeTodayAssigner(); +// maybeTodayAssigner.setLSP(collectionLSP); +// final GenericPlanStrategy strategy = new TomorrowShipmentAssignerStrategyFactory(maybeTodayAssigner).createStrategy(); +// +// GenericStrategyManager strategyManager = new GenericStrategyManagerImpl<>(); +// strategyManager.addStrategy(strategy, null, 1); +// +// LSPReplanner replanner = LSPReplanningUtils.createDefaultLSPReplanner(strategyManager); +// +// +// collectionLSP.setReplanner(replanner); + + + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(collectionLSP))); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new LSPModule() ); + + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager manager = new LSPStrategyManagerImpl(); + { + final GenericPlanStrategy strategy = new TomorrowShipmentAssignerStrategyFactory(new MaybeTodayAssigner()).createStrategy(); + // (a factory makes sense if it is passed around; in this case it feels like overkill. kai, jul'22) + manager.addStrategy( strategy, null, 1 ); + } + return manager; + }); + + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + + + @Test + public void testCollectionLSPReplanning() { + System.out.println(collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLspShipmentIds().size()); + assertTrue(collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLspShipmentIds().size() < 20); + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest.java new file mode 100644 index 00000000000..6f8c7594cac --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest.java @@ -0,0 +1,199 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspScoring; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler; +import static org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner; + +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLSPScoringTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private final int numberOfShipments = 25; + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + Config config = ConfigUtils.createConfig(); + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.loadScenario(config); + Network network = scenario.getNetwork(); + + + VehicleType collectionVehType = VehicleUtils.createVehicleType(Id.create("CollectionCarrierVehicleType", VehicleType.class), TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + collectionVehType.setNetworkMode(TransportMode.car); + + + Link collectionLink = network.getLinks().get(Id.createLinkId("(4 2) (4 3)")); // (make sure that the link exists) + + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), collectionVehType); + + Carrier carrier = CarriersUtils.createCarrier(Id.create("CollectionCarrier", Carrier.class)); + carrier.setCarrierCapabilities(CarrierCapabilities.Builder.newInstance() + .addVehicle(carrierVehicle) + .setFleetSize(FleetSize.INFINITE) + .build()); + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)).setLocationLinkId(collectionLink.getId()).build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder + .newInstance(Id.create("CollectionElement", LogisticChainElement.class)).setResource(collectionResource).build(); + + LogisticChain collectionSolution = LSPUtils.LogisticChainBuilder.newInstance(Id.create("CollectionSolution", LogisticChain.class)) + .addLogisticChainElement(collectionElement).build(); + + collectionLSP = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)) + .setInitialPlan(LSPUtils.createLSPPlan().setInitialShipmentAssigner(createSingleLogisticChainShipmentAssigner()).addLogisticChain(collectionSolution)) + .setLogisticChainScheduler(createDefaultSimpleForwardLogisticChainScheduler(Collections.singletonList(collectionResource))) +// .setSolutionScorer(new ExampleLSPScoring.TipScorer()) + .build(); + +// TipEventHandler handler = new TipEventHandler(); +// LSPAttribute value = LSPInfoFunctionUtils.createInfoFunctionValue("TIP IN EUR" ); +// LSPAttributes function = LSPInfoFunctionUtils.createDefaultInfoFunction(); +// function.getAttributes().add(value ); +// TipInfo info = new TipInfo(); +// TipScorer.TipSimulationTracker tipTracker = new TipScorer.TipSimulationTracker(); +// collectionResource.addSimulationTracker(tipTracker); +// TipScorer tipScorer = new TipScorer(); +// collectionLSP.addSimulationTracker( tipScorer ); +// collectionLSP.setScorer(tipScorer); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < (numberOfShipments + 1); i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLink.getId()); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + + collectionLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule( new LSPModule() ); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPScorerFactory.class ).toInstance(ExampleLSPScoring.TipScorer::new); + } + }); + + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionLSPScoring() { + System.out.println(collectionLSP.getSelectedPlan().getScore()); + assertEquals(numberOfShipments, collectionLSP.getLspShipments().size()); + assertEquals(numberOfShipments, collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLspShipmentIds() + .size()); + assertTrue(collectionLSP.getSelectedPlan().getScore() > 0); + assertTrue(collectionLSP.getSelectedPlan().getScore() <= (numberOfShipments * 5)); + /*noch zu testen + * tipTracker + * InfoFunction + * Info + * Scorer + */ + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoringTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoringTest.java new file mode 100644 index 00000000000..78f968387b9 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoringTest.java @@ -0,0 +1,58 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspScoring; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.config.Config; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.Controler; +import org.matsim.freight.logistics.LSP; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.testcases.MatsimTestUtils; + +public class ExampleLSPScoringTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + public void testMain() { + + Config config = ExampleLSPScoring.prepareConfig(); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + + Scenario scenario = ExampleLSPScoring.prepareScenario(config); + + Controler controler = ExampleLSPScoring.prepareControler(scenario); + + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(scenario).getLSPs().values()) { + Assertions.assertEquals(13.245734044444207, lsp.getSelectedPlan().getScore(), Double.MIN_VALUE); + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest.java new file mode 100644 index 00000000000..5c4f66efdea --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest.java @@ -0,0 +1,211 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.lspScoring; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleIterationsCollectionLSPScoringTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + private final int numberOfShipments = 25; + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = network.getLinks().get(collectionLinkId); + if (collectionLink == null) { + System.exit(1); + } + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder + .newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder + .newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + List resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); +// collectionLSPBuilder.setSolutionScorer(new ExampleLSPScoring.TipScorer()); + collectionLSP = collectionLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < (numberOfShipments + 1); i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 + && pendingFromLink.getFromNode().getCoord().getY() <= 4000 + && pendingFromLink.getToNode().getCoord().getX() <= 4000 + && pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + + collectionLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule( new LSPModule() ); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPScorerFactory.class ).toInstance(ExampleLSPScoring.TipScorer::new); + bind( LSPStrategyManager.class ).toInstance( new LSPModule.LSPStrategyManagerEmptyImpl() ); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(10); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionLSPScoring() { + System.out.println("score=" + collectionLSP.getSelectedPlan().getScore()); + assertEquals(numberOfShipments, collectionLSP.getLspShipments().size()); + assertEquals(numberOfShipments, collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLspShipmentIds().size()); + assertTrue(collectionLSP.getSelectedPlan().getScore() > 0); + assertTrue(collectionLSP.getSelectedPlan().getScore() <= (numberOfShipments * 5)); + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest.java new file mode 100644 index 00000000000..89c841a26bb --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest.java @@ -0,0 +1,55 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.mobsimExamples; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.testcases.MatsimTestUtils; + +/** + * @author Kai Martins-Turner (kturner) + */ +public class ExampleMobsimOfSimpleLSPTest { + private static final Logger log = LogManager.getLogger(ExampleMobsimOfSimpleLSPTest.class); + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + public void testForRuntimeExceptionsAndCompareEvents() { + try { + ExampleMobsimOfSimpleLSP.main(new String[]{ + "--config:controller.outputDirectory=" + utils.getOutputDirectory() + }); + + } catch (Exception ee) { + log.fatal(ee); + fail(); + } + + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } + +} \ No newline at end of file diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest.java new file mode 100644 index 00000000000..5f9d04aa959 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest.java @@ -0,0 +1,64 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.testcases.MatsimTestUtils; + +public class ExampleTwoLspsGroceryDeliveryMultipleChainsTest { + private static final Logger log = LogManager.getLogger(ExampleTwoLspsGroceryDeliveryMultipleChainsTest.class); + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + +/** + * This Test should ensure that the results are stable by checking for LSP File and events File to be equal to a previous run. + * It is **not** meat to get never chanced. In contrast, it will prevent me from unintended changes. + * I assume that with ongoing work, I will adapt the test input regularly. + */ + @Test + public void testOutputIsEqual() { + + try { + ExampleTwoLspsGroceryDeliveryMultipleChains.main(new String[]{ + "--config:controller.outputDirectory=" + utils.getOutputDirectory() + , "--config:controller.lastIteration=1" + }); + + } catch (Exception ee) { + log.fatal(ee); + fail(); + } + + //Compare LSP files + MatsimTestUtils.assertEqualFilesLineByLine(utils.getClassInputDirectory() + "output_lsps.xml.gz", utils.getOutputDirectory() + "output_lsps.xml.gz" ); + + //Compare events files + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsReplanningTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsReplanningTest.java new file mode 100644 index 00000000000..501e710b12f --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsReplanningTest.java @@ -0,0 +1,312 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleChainsReplanningTest { + + private static final Id DEPOT_LINK_ID = Id.createLinkId("i(5,0)"); + private static final VehicleType VEH_TYPE_LARGE_50 = createVehTypeLarge50(); + + private static VehicleType createVehTypeLarge50() { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create("large50", VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(0.01); + vehicleType.getCostInformation().setCostsPerSecond(0.01); + vehicleType.getCostInformation().setFixedCost(150.); + vehicleType.setMaximumVelocity(10); + vehicleType.setNetworkMode(TransportMode.car); + + return vehicleType; + } + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + int initialPlanCount; + int initialPlanShipmentPlanCount; + + int updatedPlanCount; + int innovatedPlanShipmentPlanCount; + int innovatedPlanFirstLogisticChainShipmentCount; + boolean innovatedPlanHasEmptyShipmentPlanElements = false; + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + scenario.getNetwork(); + + // A plan with two different logistic chains on the left and right, with respective carriers is created + LSPPlan multipleOneEchelonChainsPlan; + { + LogisticChainElement leftCarrierElement; + { + Carrier carrierLeft = CarriersUtils.createCarrier(Id.create("carrierLeft", Carrier.class)); + carrierLeft.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(carrierLeft, CarrierVehicle.newInstance(Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource carrierLeftResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrierLeft) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + leftCarrierElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("leftCarrierElement", LogisticChainElement.class)) + .setResource(carrierLeftResource) + .build(); + } + + LogisticChainElement rightCarrierElement; + { + Carrier carrierRight = CarriersUtils.createCarrier(Id.create("carrierRight", Carrier.class)); + carrierRight.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(carrierRight, CarrierVehicle.newInstance(Id.createVehicleId("veh_small"), DEPOT_LINK_ID, VEH_TYPE_LARGE_50)); + LSPResource carrierRightResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrierRight) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + rightCarrierElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("rightCarrierElement", LogisticChainElement.class)) + .setResource(carrierRightResource) + .build(); + } + + LogisticChain leftChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("leftChain", LogisticChain.class)) + .addLogisticChainElement(leftCarrierElement) + .build(); + + LogisticChain rightChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("rightChain", LogisticChain.class)) + .addLogisticChainElement(rightCarrierElement) + .build(); + + final InitialShipmentAssigner shipmentAssigner = MultipleChainsUtils.createRoundRobinLogisticChainShipmentAssigner(); + multipleOneEchelonChainsPlan = LSPUtils.createLSPPlan() + .addLogisticChain(leftChain) + .addLogisticChain(rightChain) + .setInitialShipmentAssigner(shipmentAssigner); + + multipleOneEchelonChainsPlan.setType(MultipleChainsUtils.LspPlanTypes.MULTIPLE_ONE_ECHELON_CHAINS.toString()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(multipleOneEchelonChainsPlan); + + LSP lsp = LSPUtils.LSPBuilder.getInstance(Id.create("myLSP", LSP.class)) + .setInitialPlan(multipleOneEchelonChainsPlan) + .setLogisticChainScheduler(ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(createResourcesListFromLSPPlans(lspPlans))) + .build(); + + for (LspShipment shipment : createInitialLSPShipments()) { + lsp.assignShipmentToLSP(shipment); + } + + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments() { + List shipmentList = new ArrayList<>(); + int capacityDemand = 1; + + for (int i = 1; i <= 10; i++) { + if (i % 2 != 0) { + Id id = Id.create("ShipmentLeft_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentLeftLinkId = Id.createLinkId("i(1,9)R"); + builder.setToLinkId(shipmentLeftLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } else { + Id id = Id.create("ShipmentRight_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + builder.setCapacityDemand(capacityDemand); + builder.setFromLinkId(DEPOT_LINK_ID); + final Id shipmentRightLinkId = Id.createLinkId("j(9,9)"); + builder.setToLinkId(shipmentRightLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + } + return shipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain logisticChain : lspPlan.getLogisticChains()) { + for (LogisticChainElement logisticChainElement : logisticChain.getLogisticChainElements()) { + resourceList.add(logisticChainElement.getResource()); + } + } + } + return resourceList; + } + + @BeforeEach + public void initialize() { + + Config config = prepareConfig(); + + Scenario scenario = prepareScenario(config); + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = new EventBasedCarrierScorer4MultipleChains(); + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy( RandomShiftingStrategyFactory.createStrategy(), null, 1); + return strategyManager; + }); + } + }); + + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + + LSP lsp = LSPUtils.getLSPs(controler.getScenario()).getLSPs().values().iterator().next(); + + initialPlanCount = lsp.getPlans().size(); + initialPlanShipmentPlanCount = lsp.getPlans().getFirst().getShipmentPlans().size(); + + controler.run(); + + updatedPlanCount = lsp.getPlans().size(); + innovatedPlanShipmentPlanCount = lsp.getPlans().get(1).getShipmentPlans().size(); + + innovatedPlanFirstLogisticChainShipmentCount = lsp.getPlans().get(1).getLogisticChains().iterator().next().getLspShipmentIds().size(); + for (LspShipmentPlan lspShipmentPlan : lsp.getPlans().get(1).getShipmentPlans()) { + if (lspShipmentPlan.getPlanElements().isEmpty()) { + innovatedPlanHasEmptyShipmentPlanElements = true; + } + } + + + } + + private Config prepareConfig() { + Config config = ConfigUtils.createConfig(); + + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(1); + + config.network().setInputFile(String.valueOf(IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + @Test + public void testGeneratedInnovatedPlan() { + // a new innovative plan should have been added + assertEquals(initialPlanCount + 1, updatedPlanCount); + + // number of shipmentPlans should remain the same + assertEquals(initialPlanShipmentPlanCount, innovatedPlanShipmentPlanCount); + } + + @Test + public void testShipmentDistributionChanged() { + // starting from 5 shipments, exactly one shipment should have shifted the logistic chain + assertTrue(innovatedPlanFirstLogisticChainShipmentCount == 4 || innovatedPlanFirstLogisticChainShipmentCount == 6); + } + + @Test + public void testScheduledLogisticChains() { + assertFalse(innovatedPlanHasEmptyShipmentPlanElements); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/WorstPlanSelectorTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/WorstPlanSelectorTest.java new file mode 100644 index 00000000000..fccfa68e09d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/WorstPlanSelectorTest.java @@ -0,0 +1,319 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.multipleChains; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.BestPlanSelector; +import org.matsim.core.replanning.selectors.ExpBetaPlanSelector; +import org.matsim.core.replanning.selectors.GenericWorstPlanForRemovalSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class WorstPlanSelectorTest { + + private static final Id DEPOT_SOUTH_LINK_ID = Id.createLinkId("i(1,0)"); + private static final Id DEPOT_NORTH_LINK_ID = Id.createLinkId("i(1,8)"); + private static final VehicleType VEH_TYPE_CHEAP = createVehType("cheap", 1., 0.001, 0.001); + private static final VehicleType VEH_TYPE_EXPENSIVE = createVehType("expensive", 100., 0.01, 0.01); + + private static VehicleType createVehType(String vehicleTypeId, double fix, double perDistanceUnit, double perTimeUnit) { + VehicleType vehicleType = VehicleUtils.createVehicleType(Id.create(vehicleTypeId, VehicleType.class), TransportMode.car); + vehicleType.getCapacity().setOther(50); + vehicleType.getCostInformation().setCostsPerMeter(perDistanceUnit); + vehicleType.getCostInformation().setCostsPerSecond(perTimeUnit); + vehicleType.getCostInformation().setFixedCost(fix); + vehicleType.setMaximumVelocity(10); + + return vehicleType; + } + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + private static Scenario prepareScenario(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + for (Link link : scenario.getNetwork().getLinks().values()) { + link.setFreespeed(30 / 3.6); + link.setCapacity(1000); + } + + LSPUtils.addLSPs(scenario, new LSPs(Collections.singletonList(createLSP(scenario)))); + + return scenario; + } + + private static LSP createLSP(Scenario scenario) { + Network network = scenario.getNetwork(); + + // A plan with one logistic chain, containing a single carrier is created + LSPPlan lspPlan_singleChain; + { + Carrier singleCarrier = CarriersUtils.createCarrier(Id.create("singleCarrier", Carrier.class)); + singleCarrier.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(singleCarrier, CarrierVehicle.newInstance(Id.createVehicleId("directTruck"), DEPOT_SOUTH_LINK_ID, VEH_TYPE_EXPENSIVE)); + LSPResource singleCarrierResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(singleCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + LogisticChainElement singleCarrierElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("singleCarrierElement", LogisticChainElement.class)) + .setResource(singleCarrierResource) + .build(); + + LogisticChain singleChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("singleChain", LogisticChain.class)) + .addLogisticChainElement(singleCarrierElement) + .build(); + + final InitialShipmentAssigner singleSolutionShipmentAssigner = MultipleChainsUtils.createPrimaryLogisticChainShipmentAssigner(); + lspPlan_singleChain = LSPUtils.createLSPPlan() + .addLogisticChain(singleChain) + .setInitialShipmentAssigner(singleSolutionShipmentAssigner); + + lspPlan_singleChain.setType(MultipleChainsUtils.LspPlanTypes.SINGLE_ONE_ECHELON_CHAIN.toString()); + } + + // A plan with two different logistic chains in the south and north, with respective carriers is created + LSPPlan lspPlan_twoChains; + { + LogisticChainElement southCarrierElement; + { + Carrier carrierSouth = CarriersUtils.createCarrier(Id.create("carrierSouth", Carrier.class)); + carrierSouth.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(carrierSouth, CarrierVehicle.newInstance(Id.createVehicleId("directTruck"), DEPOT_SOUTH_LINK_ID, VEH_TYPE_CHEAP)); + LSPResource carrierSouthResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrierSouth) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + southCarrierElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("southCarrierElement", LogisticChainElement.class)) + .setResource(carrierSouthResource) + .build(); + } + + LogisticChainElement northCarrierElement; + { + Carrier carrierNorth = CarriersUtils.createCarrier(Id.create("CarrierNorth", Carrier.class)); + carrierNorth.getCarrierCapabilities().setFleetSize(CarrierCapabilities.FleetSize.INFINITE); + + CarriersUtils.addCarrierVehicle(carrierNorth, CarrierVehicle.newInstance(Id.createVehicleId("directTruck"), DEPOT_NORTH_LINK_ID, VEH_TYPE_CHEAP)); + LSPResource carrierNorthResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrierNorth) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .build(); + + northCarrierElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("northCarrierElement", LogisticChainElement.class)) + .setResource(carrierNorthResource) + .build(); + } + + LogisticChain southChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("southChain", LogisticChain.class)) + .addLogisticChainElement(southCarrierElement) + .build(); + + LogisticChain northChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("northChain", LogisticChain.class)) + .addLogisticChainElement(northCarrierElement) + .build(); + + final InitialShipmentAssigner shipmentAssigner = MultipleChainsUtils.createPrimaryLogisticChainShipmentAssigner(); + lspPlan_twoChains = LSPUtils.createLSPPlan() + .addLogisticChain(southChain) + .addLogisticChain(northChain) + .setInitialShipmentAssigner(shipmentAssigner); + + lspPlan_twoChains.setType(MultipleChainsUtils.LspPlanTypes.MULTIPLE_ONE_ECHELON_CHAINS.toString()); + } + + List lspPlans = new ArrayList<>(); + lspPlans.add(lspPlan_singleChain); + lspPlans.add(lspPlan_twoChains); + + LSP lsp = LSPUtils.LSPBuilder.getInstance(Id.create("org/matsim/freight/logistics/lsp", LSP.class)) + .setInitialPlan(lspPlan_singleChain) + .setLogisticChainScheduler(ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(createResourcesListFromLSPPlans(lspPlans))) + .build(); + lsp.addPlan(lspPlan_twoChains); + + for (LspShipment shipment : createInitialLSPShipments(network)) { + lsp.assignShipmentToLSP(shipment); + } + + lsp.scheduleLogisticChains(); + + return lsp; + } + + private static Collection createInitialLSPShipments(Network network) { + List shipmentList = new ArrayList<>(); + + Random rand2 = MatsimRandom.getLocalInstance(); + + + List zoneLinkList = Arrays.asList("i(4,4)", "i(5,4)", "i(6,4)", "i(4,6)", "i(5,6)", "i(6,6)", + "j(3,5)", "j(3,6)", "j(3,7)", "j(5,5)", "j(5,6)", "j(5,7)", + "i(4,5)R", "i(5,5)R", "i(6,5)R", "i(4,7)R", "i(5,7)R", "i(6,7)R", + "j(4,5)R", "j(4,6)R", "j(4,7)R", "j(6,5)R", "j(6,6)R", "j(6,7)R"); + for (String linkIdString : zoneLinkList) { + if (!network.getLinks().containsKey( Id.createLinkId(linkIdString))) { + throw new RuntimeException("Link is not in Network!"); + } + } + + for(int i = 1; i <= 10; i++) { + Id id = Id.create("Shipment_" + i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + + int capacityDemand = 1; + builder.setCapacityDemand(capacityDemand); + + builder.setFromLinkId(DEPOT_SOUTH_LINK_ID); + final Id toLinkId = Id.createLinkId(zoneLinkList.get(rand2.nextInt(zoneLinkList.size()-1))); + builder.setToLinkId(toLinkId); + + builder.setEndTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setStartTimeWindow(TimeWindow.newInstance(0, (24 * 3600))); + builder.setDeliveryServiceTime(capacityDemand * 60); + + shipmentList.add(builder.build()); + } + return shipmentList; + } + + private static List createResourcesListFromLSPPlans(List lspPlans) { + List resourceList = new ArrayList<>(); + for (LSPPlan lspPlan : lspPlans) { + for (LogisticChain solution : lspPlan.getLogisticChains()) { + for (LogisticChainElement solutionElement : solution.getLogisticChainElements()) { + resourceList.add(solutionElement.getResource()); + } + } + } + return resourceList; + } + + @BeforeEach + public void initialize() { + + Config config = prepareConfig(); + + Scenario scenario = prepareScenario(config); + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + final EventBasedCarrierScorer4MultipleChains carrierScorer = new EventBasedCarrierScorer4MultipleChains(); + + bind(CarrierScoringFunctionFactory.class).toInstance(carrierScorer); + bind(LSPScorerFactory.class).toInstance(MyLSPScorer::new); + bind(CarrierStrategyManager.class).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 1); + return strategyManager; + }); + bind(LSPStrategyManager.class).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new ExpBetaPlanSelector<>(new ScoringConfigGroup())), null, 1); + strategyManager.addStrategy( RandomDistributionAllShipmentsStrategyFactory.createStrategy(), null, 1); + strategyManager.setMaxPlansPerAgent(2); + strategyManager.setPlanSelectorForRemoval(new GenericWorstPlanForRemovalSelector<>() ); + return strategyManager; + }); + } + }); + + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + this.lsp = LSPUtils.getLSPs(controler.getScenario()).getLSPs().values().iterator().next(); + } + + private Config prepareConfig() { + Config config = ConfigUtils.createConfig(); + + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(10); + + config.network().setInputFile(String.valueOf(IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"), "grid9x9.xml"))); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setWriteEventsInterval(1); + + FreightCarriersConfigGroup freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + return config; + } + + @Test + public void testPreserveLastPlanOfType() { + Set planTypes = new HashSet<>(); + + for (LSPPlan lspPlan : lsp.getPlans()) { + planTypes.add(lspPlan.getType()); + + if (planTypes.size() > 1) { + break; + } + } + + assertTrue(planTypes.size() > 1); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/requirementsChecking/AssignerRequirementsTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/requirementsChecking/AssignerRequirementsTest.java new file mode 100644 index 00000000000..d24065a0c4c --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/requirementsChecking/AssignerRequirementsTest.java @@ -0,0 +1,197 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.requirementsChecking; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class AssignerRequirementsTest { + + private LogisticChain blueChain; + private LogisticChain redChain; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id redCarrierId = Id.create("RedCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + collectionVehType.setNetworkMode(TransportMode.car); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id redVehicleId = Id.createVehicleId("RedVehicle"); + CarrierVehicle redVehicle = CarrierVehicle.newInstance(redVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities redCapabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(redVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier redCarrier = CarriersUtils.createCarrier(redCarrierId); + redCarrier.setCarrierCapabilities(redCapabilities); + + LSPResource redCollectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(redCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id redElementId = Id.create("RedCollectionElement", LogisticChainElement.class); + LogisticChainElement redCollectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(redElementId) + .setResource(redCollectionResource) + .build(); + + redChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("RedCollectionSolution", LogisticChain.class)) + .addLogisticChainElement(redCollectionElement) + .build(); + redChain.getAttributes().putAttribute("color", "red"); + + InitialShipmentAssigner assigner = new RequirementsAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(redChain); + + Id blueCarrierId = Id.create("BlueCarrier", Carrier.class); + Id blueVehicleId = Id.createVehicleId("BlueVehicle"); + CarrierVehicle blueVehicle = CarrierVehicle.newInstance(blueVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities blueCapabilities = CarrierCapabilities.Builder.newInstance() + .addVehicle(blueVehicle) + .setFleetSize(FleetSize.INFINITE) + .build(); + Carrier blueCarrier = CarriersUtils.createCarrier(blueCarrierId); + blueCarrier.setCarrierCapabilities(blueCapabilities); + + LSPResource blueCollectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(blueCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id blueElementId = Id.create("BlueCollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder blueCollectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(blueElementId); + blueCollectionElementBuilder.setResource(blueCollectionResource); + LogisticChainElement blueCollectionElement = blueCollectionElementBuilder.build(); + + blueChain = LSPUtils.LogisticChainBuilder.newInstance(Id.create("BlueCollectionSolution", LogisticChain.class)) + .addLogisticChainElement(blueCollectionElement) + .build(); + blueChain.getAttributes().putAttribute("color", "blue"); + collectionPlan.addLogisticChain(blueChain); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(redCollectionResource); + resourcesList.add(blueCollectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + LSP collectionLSP = collectionLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + Random rand = new Random(1); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + boolean blue = rand.nextBoolean(); + if (blue) { + builder.addRequirement(new BlueRequirement()); + } else { + builder.addRequirement(new RedRequirement()); + } + + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + } + + @Test + public void testAssignerRequirements() { + for (Id shipmentId : blueChain.getLspShipmentIds()) { + LspShipment shipment = LSPUtils.findLspShipment(blueChain.getLSP(), shipmentId); + assert shipment != null; + assertInstanceOf(BlueRequirement.class, shipment.getRequirements().iterator().next()); + } + for (Id shipmentId : redChain.getLspShipmentIds()) { + LspShipment shipment = LSPUtils.findLspShipment(redChain.getLSP(), shipmentId); + assert shipment != null; + assertInstanceOf(RedRequirement.class, shipment.getRequirements().iterator().next()); + } + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest.java new file mode 100644 index 00000000000..42e2c581b43 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest.java @@ -0,0 +1,325 @@ +/* + *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2022 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** + */ + +package org.matsim.freight.logistics.examples.simulationTrackers; + +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.population.routes.NetworkRoute; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.Tour.Leg; +import org.matsim.freight.carriers.Tour.ServiceActivity; +import org.matsim.freight.carriers.Tour.TourElement; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +import static org.junit.jupiter.api.Assertions.*; + +public class CollectionTrackerTest { + private static final Logger log = LogManager.getLogger(CollectionTrackerTest.class); + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private Network network; + private Carrier carrier; + private LogisticChain logisticChain; + private double shareOfFixedCosts; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + this.network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = network.getLinks().get(collectionLinkId); + + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + logisticChain = collectionSolutionBuilder.build(); + + { + shareOfFixedCosts = 0.2; + LinearCostTracker tracker = new LinearCostTracker(shareOfFixedCosts); + tracker.getEventHandlers().add(new TourStartHandler(scenario)); + tracker.getEventHandlers().add(new CollectionServiceHandler(scenario)); + tracker.getEventHandlers().add(new DistanceAndTimeHandler(scenario)); + // I think that it would be better to use delegation inside LinearCostTracker, i.e. to not expose getEventHandlers(). kai, jun'22 + + logisticChain.addSimulationTracker(tracker); + } + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(logisticChain); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + LSP collectionLSP = collectionLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); +// config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionTracker() { + + assertEquals(1, logisticChain.getSimulationTrackers().size()); + LSPSimulationTracker tracker = logisticChain.getSimulationTrackers().iterator().next(); + assertInstanceOf(LinearCostTracker.class, tracker); + LinearCostTracker linearTracker = (LinearCostTracker) tracker; + double totalScheduledCosts = 0; + double totalTrackedCosts = 0; + double totalScheduledWeight = 0; + double totalTrackedWeight = 0; + int totalNumberOfScheduledShipments = 0; + int totalNumberOfTrackedShipments = 0; + for (EventHandler handler : linearTracker.getEventHandlers()) { + if (handler instanceof TourStartHandler startHandler) { + double scheduledCosts = 0; + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + scheduledCosts += ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getFixedCosts(); + totalScheduledCosts += scheduledCosts; + } + double trackedCosts = startHandler.getVehicleFixedCosts(); + totalTrackedCosts += trackedCosts; + assertEquals(trackedCosts, scheduledCosts, 0.1); + } + if (handler instanceof CollectionServiceHandler serviceHandler) { + totalTrackedWeight = serviceHandler.getTotalWeightOfShipments(); + totalNumberOfTrackedShipments = serviceHandler.getTotalNumberOfShipments(); + double scheduledCosts = 0; + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + Tour tour = scheduledTour.getTour(); + for (TourElement element : tour.getTourElements()) { + if (element instanceof ServiceActivity activity) { + scheduledCosts += activity.getService().getServiceDuration() * ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getCostsPerSecond(); + totalScheduledCosts += scheduledCosts; + totalScheduledWeight += activity.getService().getCapacityDemand(); + totalNumberOfScheduledShipments++; + } + } + } + double trackedCosts = serviceHandler.getTotalLoadingCosts(); + totalTrackedCosts += trackedCosts; + assertEquals(trackedCosts, scheduledCosts, 0.1); + } + if (handler instanceof DistanceAndTimeHandler distanceHandler) { + double trackedTimeCosts = distanceHandler.getTimeCosts(); + totalTrackedCosts += trackedTimeCosts; + double scheduledTimeCosts = 0; + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + Tour tour = scheduledTour.getTour(); + for (TourElement element : tour.getTourElements()) { + if (element instanceof Leg leg) { + scheduledTimeCosts += leg.getExpectedTransportTime() * ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getCostsPerSecond(); + } + } + } + totalScheduledCosts += scheduledTimeCosts; + assertEquals(scheduledTimeCosts, trackedTimeCosts, Math.max(scheduledTimeCosts, trackedTimeCosts) * 0.01); + + double scheduledDistanceCosts = 0; + double trackedDistanceCosts = distanceHandler.getDistanceCosts(); + totalTrackedCosts += trackedDistanceCosts; + for (ScheduledTour scheduledTour : carrier.getSelectedPlan().getScheduledTours()) { + scheduledDistanceCosts += network.getLinks().get(scheduledTour.getTour().getEndLinkId()).getLength() * ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getCostsPerMeter(); + for (TourElement element : scheduledTour.getTour().getTourElements()) { + System.out.println(element); + if (element instanceof Leg leg) { + NetworkRoute linkRoute = (NetworkRoute) leg.getRoute(); + for (Id linkId : linkRoute.getLinkIds()) { + scheduledDistanceCosts += network.getLinks().get(linkId).getLength() * ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getCostsPerMeter(); + } + } + if (element instanceof ServiceActivity activity) { + scheduledDistanceCosts += network.getLinks().get(activity.getLocation()).getLength() * ((Vehicle) scheduledTour.getVehicle()).getType().getCostInformation().getCostsPerMeter(); + // (I think that we need this since the last link is not in the route. Or is it? kai, jul'22) + // (yy I do not understand why we do not need to do this for the end activity of the tour.) + } + } + log.warn("scheduledDistanceCosts={}", scheduledDistanceCosts); + } + totalScheduledCosts += scheduledDistanceCosts; + assertEquals(scheduledDistanceCosts, trackedDistanceCosts, Math.max(scheduledDistanceCosts, trackedDistanceCosts) * 0.01); + } + } + + double linearTrackedCostsPerShipment = (totalTrackedCosts * (1 - shareOfFixedCosts)) / totalTrackedWeight; + double linearScheduledCostsPerShipment = (totalScheduledCosts * (1 - shareOfFixedCosts)) / totalScheduledWeight; + double fixedTrackedCostsPerShipment = (totalTrackedCosts * shareOfFixedCosts) / totalNumberOfTrackedShipments; + double fixedScheduledCostsPerShipment = (totalScheduledCosts * shareOfFixedCosts) / totalNumberOfScheduledShipments; + + assertEquals(totalTrackedWeight, totalScheduledWeight, 0); + assertEquals(totalNumberOfTrackedShipments, totalNumberOfScheduledShipments, 0); + assertEquals(totalTrackedCosts, totalScheduledCosts, Math.max(totalScheduledCosts, totalTrackedCosts) * 0.01); + assertEquals(linearTrackedCostsPerShipment, linearScheduledCostsPerShipment, Math.max(linearTrackedCostsPerShipment, linearScheduledCostsPerShipment) * 0.01); + assertEquals(fixedScheduledCostsPerShipment, fixedTrackedCostsPerShipment, Math.max(fixedTrackedCostsPerShipment, fixedScheduledCostsPerShipment) * 0.01); + +// LSPInfo info = collectionSolution.getAttributes().iterator().next(); +// assertTrue(info instanceof CostInfo ); +// CostInfo costInfo = (CostInfo) info; + +// assertEquals(costInfo.getVariableCost() ,linearTrackedCostsPerShipment , Math.max(linearTrackedCostsPerShipment,costInfo.getVariableCost() ) * 0.01 ); +// assertEquals(costInfo.getVariableCost() , linearScheduledCostsPerShipment, Math.max(linearScheduledCostsPerShipment,costInfo.getVariableCost() ) * 0.01 ); +// assertEquals(costInfo.getFixedCost() ,fixedTrackedCostsPerShipment, Math.max(fixedTrackedCostsPerShipment,costInfo.getFixedCost()) * 0.01 ); +// assertEquals(costInfo.getFixedCost(),fixedScheduledCostsPerShipment, Math.max(fixedScheduledCostsPerShipment,costInfo.getFixedCost()) * 0.01 ); + + // I cannot say how the above was supposed to work, since costInfo.getVariableCost() was the same in both cases. kai, may'22 + + assertEquals(2, logisticChain.getAttributes().size()); + assertEquals(LSPUtils.getVariableCost(logisticChain), linearTrackedCostsPerShipment, Math.max(linearTrackedCostsPerShipment, LSPUtils.getVariableCost(logisticChain)) * 0.01); + assertEquals(LSPUtils.getVariableCost(logisticChain), linearScheduledCostsPerShipment, Math.max(linearScheduledCostsPerShipment, LSPUtils.getVariableCost(logisticChain)) * 0.01); + assertEquals(LSPUtils.getFixedCost(logisticChain), fixedTrackedCostsPerShipment, Math.max(fixedTrackedCostsPerShipment, LSPUtils.getFixedCost(logisticChain)) * 0.01); + assertEquals(LSPUtils.getFixedCost(logisticChain), fixedScheduledCostsPerShipment, Math.max(fixedScheduledCostsPerShipment, LSPUtils.getFixedCost(logisticChain)) * 0.01); + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/io/LSPReadWriteTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/io/LSPReadWriteTest.java new file mode 100644 index 00000000000..9d3083cca8b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/io/LSPReadWriteTest.java @@ -0,0 +1,78 @@ +package org.matsim.freight.logistics.io; + +import java.util.Collections; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.freight.carriers.CarrierPlanXmlReader; +import org.matsim.freight.carriers.CarrierVehicleTypeReader; +import org.matsim.freight.carriers.CarrierVehicleTypes; +import org.matsim.freight.carriers.Carriers; +import org.matsim.freight.logistics.LSPs; +import org.matsim.testcases.MatsimTestUtils; + +public class LSPReadWriteTest { + + @RegisterExtension + public MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + public void readWriteTest() { + + LSPs lsPs = new LSPs(Collections.emptyList()); + Carriers carriers = new Carriers(); + CarrierVehicleTypes carrierVehicleTypes = new CarrierVehicleTypes(); + + String inputFilename = utils.getPackageInputDirectory() + "lsps.xml"; + String outputFilename = utils.getOutputDirectory() + "/outputLsps.xml"; + + CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(carrierVehicleTypes); + vehicleTypeReader.readFile(utils.getPackageInputDirectory() + "vehicles.xml"); + + CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, carrierVehicleTypes); + carrierReader.readFile(utils.getPackageInputDirectory() + "carriers.xml"); + + LSPPlanXmlReader reader = new LSPPlanXmlReader(lsPs, carriers); + reader.readFile(inputFilename); + + new LSPPlanXmlWriter(lsPs).write(outputFilename); + + MatsimTestUtils.assertEqualFilesLineByLine(inputFilename, outputFilename); + } + + @Test + public void readWriteReadTest() { + + LSPs lsps = new LSPs(Collections.emptyList()); + Carriers carriers = new Carriers(); + CarrierVehicleTypes carrierVehicleTypes = new CarrierVehicleTypes(); + + String inputFilename = utils.getPackageInputDirectory() + "lsps.xml"; + String outputFilename = utils.getOutputDirectory() + "/outputLsps.xml"; + String outputFilename2 = utils.getOutputDirectory() + "/outputLsps2.xml"; + + CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(carrierVehicleTypes); + vehicleTypeReader.readFile(utils.getPackageInputDirectory() + "vehicles.xml"); + + CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, carrierVehicleTypes); + carrierReader.readFile(utils.getPackageInputDirectory() + "carriers.xml"); + + LSPPlanXmlReader reader = new LSPPlanXmlReader(lsps, carriers); + reader.readFile(inputFilename); + + new LSPPlanXmlWriter(lsps).write(outputFilename); + + //clear and 2nd read - based on written file. + lsps.getLSPs().clear(); + + LSPPlanXmlReader reader2 = new LSPPlanXmlReader(lsps, carriers); + reader2.readFile(outputFilename); + + new LSPPlanXmlWriter(lsps).write(outputFilename2); + + MatsimTestUtils.assertEqualFilesLineByLine(inputFilename, outputFilename2); + } + + + + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/CollectionElementTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/CollectionElementTest.java new file mode 100644 index 00000000000..80eb07648a0 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/CollectionElementTest.java @@ -0,0 +1,105 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainElementTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionElementTest { + + private LogisticChainElement collectionElement; + private LSPCarrierResource carrierResource; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + carrierResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(carrierResource) + .build(); + } + + @Test + public void testCollectionElement() { + assertNotNull(collectionElement.getIncomingShipments()); + assertNotNull(collectionElement.getIncomingShipments().getLspShipmentsWTime()); + assertTrue(collectionElement.getIncomingShipments().getSortedLspShipments().isEmpty()); + assertNotNull(collectionElement.getAttributes()); + assertTrue(collectionElement.getAttributes().isEmpty()); +// assertNull(collectionElement.getEmbeddingContainer() ); + assertNull(collectionElement.getNextElement()); + assertNotNull(collectionElement.getOutgoingShipments()); + assertNotNull(collectionElement.getOutgoingShipments().getLspShipmentsWTime()); + assertTrue(collectionElement.getOutgoingShipments().getSortedLspShipments().isEmpty()); + assertNull(collectionElement.getPreviousElement()); + assertSame(collectionElement.getResource(), carrierResource); + assertSame(collectionElement.getResource().getClientElements().iterator().next(), collectionElement); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/DistributionElementTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/DistributionElementTest.java new file mode 100644 index 00000000000..fed58343ac8 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/DistributionElementTest.java @@ -0,0 +1,111 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainElementTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class DistributionElementTest { + + private LSPCarrierResource adapter; + private LogisticChainElement distributionElement; + + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id carrierId = Id.create("DistributionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("DistributionCarrierResource", LSPResource.class); + adapter = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id elementId = Id.create("DistributionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder distributionBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + distributionBuilder.setResource(adapter); + distributionElement = distributionBuilder.build(); + + } + + @Test + public void testDistributionElement() { + assertNotNull(distributionElement.getIncomingShipments()); + assertNotNull(distributionElement.getIncomingShipments().getLspShipmentsWTime()); + assertTrue(distributionElement.getIncomingShipments().getSortedLspShipments().isEmpty()); + assertNotNull(distributionElement.getAttributes()); + assertTrue(distributionElement.getAttributes().isEmpty()); +// assertNull(distributionElement.getEmbeddingContainer() ); + assertNull(distributionElement.getNextElement()); + assertNotNull(distributionElement.getOutgoingShipments()); + assertNotNull(distributionElement.getOutgoingShipments().getLspShipmentsWTime()); + assertTrue(distributionElement.getOutgoingShipments().getSortedLspShipments().isEmpty()); + assertNull(distributionElement.getPreviousElement()); + assertSame(distributionElement.getResource(), adapter); + assertSame(distributionElement.getResource().getClientElements().iterator().next(), distributionElement); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/MainRunElementTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/MainRunElementTest.java new file mode 100644 index 00000000000..d3a63df9001 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/MainRunElementTest.java @@ -0,0 +1,111 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainElementTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MainRunElementTest { + + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + + Id carrierId = Id.create("MainRunCarrier", Carrier.class); + Id vehicleTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(vollectionVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier mainRunCarrierResourceBuilder = CarriersUtils.createCarrier(carrierId); + mainRunCarrierResourceBuilder.setCarrierCapabilities(capabilities); + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrierResourceBuilder) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + } + + @Test + public void testDistributionElement() { + assertNotNull(mainRunElement.getIncomingShipments()); + assertNotNull(mainRunElement.getIncomingShipments().getLspShipmentsWTime()); + assertTrue(mainRunElement.getIncomingShipments().getSortedLspShipments().isEmpty()); + assertNotNull(mainRunElement.getAttributes()); + assertTrue(mainRunElement.getAttributes().isEmpty()); +// assertNull(mainRunElement.getEmbeddingContainer() ); + assertNull(mainRunElement.getNextElement()); + assertNotNull(mainRunElement.getOutgoingShipments()); + assertNotNull(mainRunElement.getOutgoingShipments().getLspShipmentsWTime()); + assertTrue(mainRunElement.getOutgoingShipments().getSortedLspShipments().isEmpty()); + assertNull(mainRunElement.getPreviousElement()); + assertSame(mainRunElement.getResource(), mainRunResource); + assertSame(mainRunElement.getResource().getClientElements().iterator().next(), mainRunElement); + } + + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/SecondHubElementTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/SecondHubElementTest.java new file mode 100644 index 00000000000..3b60dc7d00d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/SecondHubElementTest.java @@ -0,0 +1,73 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainElementTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; + +public class SecondHubElementTest { + + private LSPResource point; + private LogisticChainElement hubElement; + + @BeforeEach + public void initialize() { + TranshipmentHubSchedulerBuilder schedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + schedulerBuilder.setCapacityNeedFixed(10); + schedulerBuilder.setCapacityNeedLinear(1); + + + point = ResourceImplementationUtils.TransshipmentHubBuilder + .newInstance(Id.create("TranshipmentHub2", LSPResource.class), Id.createLinkId("(14 2) (14 3)"), null) + .setTransshipmentHubScheduler(schedulerBuilder.build()) + .build(); + + hubElement = LSPUtils.LogisticChainElementBuilder + .newInstance(Id.create("SecondHubElement", LogisticChainElement.class)) + .setResource(point) + .build(); + } + + @Test + public void testDistributionElement() { + assertNotNull(hubElement.getIncomingShipments()); + assertNotNull(hubElement.getIncomingShipments().getLspShipmentsWTime()); + assertTrue(hubElement.getIncomingShipments().getSortedLspShipments().isEmpty()); + assertNotNull(hubElement.getAttributes()); + assertTrue(hubElement.getAttributes().isEmpty()); +// assertNull(hubElement.getEmbeddingContainer() ); + assertNull(hubElement.getNextElement()); + assertNotNull(hubElement.getOutgoingShipments()); + assertNotNull(hubElement.getOutgoingShipments().getLspShipmentsWTime()); + assertTrue(hubElement.getOutgoingShipments().getSortedLspShipments().isEmpty()); + assertNull(hubElement.getPreviousElement()); + assertSame(hubElement.getResource(), point); + assertSame(hubElement.getResource().getClientElements().iterator().next(), hubElement); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CollectionChainTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CollectionChainTest.java new file mode 100644 index 00000000000..2bd8d6d0b7f --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CollectionChainTest.java @@ -0,0 +1,120 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionChainTest { + + private LogisticChain logisticChain; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + LSPCarrierResource carrierResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder + .newInstance(carrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder + .newInstance(elementId); + collectionElementBuilder.setResource(carrierResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder + .newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + logisticChain = collectionSolutionBuilder.build(); + + } + + @Test + public void testCollectionChain() { + assertNotNull(logisticChain.getSimulationTrackers()); + assertTrue(logisticChain.getSimulationTrackers().isEmpty()); + assertNotNull(logisticChain.getAttributes()); + assertTrue(logisticChain.getAttributes().isEmpty()); + assertNull(logisticChain.getLSP()); + assertNotNull(logisticChain.getLspShipmentIds()); + assertTrue(logisticChain.getLspShipmentIds().isEmpty()); + assertEquals(1, logisticChain.getLogisticChainElements().size()); + ArrayList elements = new ArrayList<>(logisticChain.getLogisticChainElements()); + for (LogisticChainElement element : elements) { + if (elements.indexOf(element) == 0) { + assertNull(element.getPreviousElement()); + } + if (elements.indexOf(element) == (elements.size() - 1)) { + assertNull(element.getNextElement()); + } +// assertSame(element.getEmbeddingContainer(), collectionSolution ); + } + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CompleteLogisticChainTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CompleteLogisticChainTest.java new file mode 100644 index 00000000000..b80740990c8 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CompleteLogisticChainTest.java @@ -0,0 +1,248 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.logisticChainTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChain; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLogisticChainTest { + + private LogisticChainElement collectionElement; + private LogisticChainElement firstHubElement; + private LogisticChainElement mainRunElement; + private LogisticChainElement secondHubElement; + private LogisticChainElement distributionElement; + private LogisticChain logisticChain; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + CollectionCarrierResourceBuilder collectionResourceBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder + .newInstance(collectionCarrier); + collectionResourceBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + collectionResourceBuilder.setLocationLinkId(collectionLinkId); + + Id collectionElementId = Id.create("CollectionElement", + LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionBuilder = LSPUtils.LogisticChainElementBuilder + .newInstance(collectionElementId); + collectionBuilder.setResource(collectionResourceBuilder.build()); + collectionElement = collectionBuilder.build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, + firstTransshipmentHub_LinkId, scenario) + .setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + firstHubElement = LSPUtils.LogisticChainElementBuilder + .newInstance(firstHubElementId) + .setResource(firstTransshipmentHubBuilder.build()) + .build(); + + + final VehicleType mainRunType = VehicleUtils.createVehicleType(Id.create("small05", VehicleType.class), TransportMode.car); + mainRunType.getCapacity().setOther(30); + mainRunType.getCostInformation().setCostsPerMeter(0.0002); + mainRunType.getCostInformation().setCostsPerSecond(0.38); + mainRunType.getCostInformation().setFixedCost(120.); + mainRunType.setMaximumVelocity(50 / 3.6); + mainRunType.setNetworkMode(TransportMode.car); + + final Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("MainRunVehicle"), fromLinkId, mainRunType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = collectionCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(collectionCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + Id mainRunElementId = Id.create("MainRunElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder mainRunBuilder = LSPUtils.LogisticChainElementBuilder + .newInstance(mainRunElementId); + mainRunBuilder.setResource(mainRunResource); + mainRunElement = mainRunBuilder.build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, + secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + + Id secondHubElementId = Id.create("SecondHubElement", + LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder + .newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTransshipmentHubBuilder.build()); + secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + final LSPResource distributionCarrierResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder + .newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + distributionElement = LSPUtils.LogisticChainElementBuilder + .newInstance(distributionElementId) + .setResource(distributionCarrierResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + completeSolutionBuilder.addLogisticChainElement(distributionElement); + logisticChain = completeSolutionBuilder.build(); + + } + + @Test + public void testCompleteLogisticChain() { + assertNotNull(logisticChain.getSimulationTrackers()); + assertTrue(logisticChain.getSimulationTrackers().isEmpty()); + assertNotNull(logisticChain.getAttributes()); + assertTrue(logisticChain.getAttributes().isEmpty()); + assertNull(logisticChain.getLSP()); + assertNotNull(logisticChain.getLspShipmentIds()); + assertTrue(logisticChain.getLspShipmentIds().isEmpty()); + assertEquals(5, logisticChain.getLogisticChainElements().size()); + ArrayList elements = new ArrayList<>(logisticChain.getLogisticChainElements()); + for (LogisticChainElement element : elements) { + if (elements.indexOf(element) == 0) { + assertNull(element.getPreviousElement()); + } + if (elements.indexOf(element) == (elements.size() - 1)) { + assertNull(element.getNextElement()); + } +// assertSame(element.getEmbeddingContainer(), solution ); + } + assertNull(collectionElement.getPreviousElement()); + assertSame(collectionElement.getNextElement(), firstHubElement); + assertSame(firstHubElement.getPreviousElement(), collectionElement); + assertSame(firstHubElement.getNextElement(), mainRunElement); + assertSame(mainRunElement.getPreviousElement(), firstHubElement); + assertSame(mainRunElement.getNextElement(), secondHubElement); + assertSame(secondHubElement.getPreviousElement(), mainRunElement); + assertSame(secondHubElement.getNextElement(), distributionElement); + assertSame(distributionElement.getPreviousElement(), secondHubElement); + assertNull(distributionElement.getNextElement()); + } + + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CollectionLSPCreationTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CollectionLSPCreationTest.java new file mode 100644 index 00000000000..3b3cf3c4189 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CollectionLSPCreationTest.java @@ -0,0 +1,126 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspCreationTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLSPCreationTest { + + private LogisticChain logisticChain; + private InitialShipmentAssigner assigner; + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + logisticChain = collectionSolutionBuilder.build(); + + assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(logisticChain); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + } + + @Test + public void testCollectionLSPCreation() { + assertNotNull(collectionLSP.getPlans()); + assertFalse(collectionLSP.getPlans().isEmpty()); + assertNotNull(collectionLSP.getResources()); + LSPPlan selectedPlan = collectionLSP.getSelectedPlan(); + assertNull(selectedPlan.getScore()); + assertSame(selectedPlan.getLSP(), collectionLSP); + assertSame(selectedPlan.getInitialShipmentAssigner(), assigner); + assertSame(selectedPlan.getLogisticChains().iterator().next(), logisticChain); + assertSame(selectedPlan.getLogisticChains().iterator().next().getLSP(), collectionLSP); +// assertTrue(selectedPlan.getAssigner().getLSP()== collectionLSP); + assertSame(selectedPlan.getLSP(), collectionLSP); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CompleteLSPCreationTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CompleteLSPCreationTest.java new file mode 100644 index 00000000000..6c1ea0f9776 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CompleteLSPCreationTest.java @@ -0,0 +1,234 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspCreationTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLSPCreationTest { + private LSP completeLSP; + private InitialShipmentAssigner assigner; + private LogisticChain logisticChain; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = collectionCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(collectionCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + distributionVehType.setNetworkMode(TransportMode.car); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LogisticChainElement distributionElement= LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + final Id chainId = Id.create("SolutionId", LogisticChain.class); + logisticChain = LSPUtils.LogisticChainBuilder.newInstance(chainId).addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(logisticChain); + + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + completeLSP = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)) + .setInitialPlan(completePlan) + .setLogisticChainScheduler(ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList)) + .build(); + } + + @Test + public void testCollectionLSPCreation() { + assertNotNull(completeLSP.getPlans()); + assertFalse(completeLSP.getPlans().isEmpty()); + assertNotNull(completeLSP.getResources()); + LSPPlan selectedPlan = completeLSP.getSelectedPlan(); + assertNull(selectedPlan.getScore()); + assertSame(selectedPlan.getLSP(), completeLSP); + assertSame(selectedPlan.getInitialShipmentAssigner(), assigner); + assertSame(selectedPlan.getLogisticChains().iterator().next(), logisticChain); + assertSame(selectedPlan.getLogisticChains().iterator().next().getLSP(), completeLSP); +// assertTrue(selectedPlan.getAssigner().getLSP()== completeLSP); + assertSame(selectedPlan.getLSP(), completeLSP); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest.java new file mode 100644 index 00000000000..0906c7b0a0f --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest.java @@ -0,0 +1,247 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; +import static org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler; +import static org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.events.Event; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.events.handler.BasicEventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLSPMobsimTest { + + private static final Logger log = LogManager.getLogger(CollectionLSPMobsimTest.class); + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP collectionLSP; + private Carrier carrier; + private LSPResource collectionResource; + + @BeforeEach + public void initialize() { + + // create config: + Config config = ConfigUtils.createConfig(); + config.network().setInputFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + // load scenario: + Scenario scenario = ScenarioUtils.loadScenario(config); + + // define vehicle type: + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + // define starting link (?): + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = scenario.getNetwork().getLinks().get(collectionLinkId); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLink.getId(), collectionVehType); + + // define carrier: + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)).setLocationLinkId(collectionLinkId) + .build(); + + final LogisticChainElement collectionElement; + { + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + collectionElement = collectionElementBuilder.build(); + } + final LogisticChain collectionSolution; + { + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + collectionSolution = collectionSolutionBuilder.build(); + } + final LSPPlan collectionPlan; + { + InitialShipmentAssigner assigner = createSingleLogisticChainShipmentAssigner(); + collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + } + { + final LSPUtils.LSPBuilder collectionLSPBuilder; + ArrayList resourcesList = new ArrayList<>(); + collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + resourcesList.add(collectionResource); + LogisticChainScheduler simpleScheduler = createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + } + { + List linkList = new LinkedList<>(scenario.getNetwork().getLinks().values()); + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + } + final LSPs lsps; + { + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + lsps = new LSPs(lspList); + } + Controler controler = new Controler(scenario); + controler.getEvents().addHandler((BasicEventHandler) event -> log.warn(event)); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + LSPUtils.addLSPs(scenario, lsps); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionLSPMobsim() { + for (LspShipment shipment : collectionLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + + log.warn(""); + log.warn("shipment schedule plan elements:"); + for (LspShipmentPlanElement planElement : LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()) { + log.warn(planElement); + } + log.warn(""); + log.warn("shipment log plan elements:"); + for (LspShipmentPlanElement planElement : shipment.getShipmentLog().getPlanElements().values()) { + log.warn(planElement); + } + log.warn(""); + + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + //Das muss besser in den SchedulingTest rein + assertSame(collectionLSP.getResources().iterator().next(), collectionResource); + LSPCarrierResource carrierResource = (LSPCarrierResource) collectionResource; + assertSame(carrierResource.getCarrier(), carrier); + assertEquals(1, carrier.getServices().size()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest.java new file mode 100644 index 00000000000..51fc37343e1 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest.java @@ -0,0 +1,333 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP completeLSP; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder distributionBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId); + distributionBuilder.setResource(distributionResource); + LogisticChainElement distributionElement = distributionBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + completeSolutionBuilder.addLogisticChainElement(distributionElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + completeLSP = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + rand.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + completeLSP.assignShipmentToLSP(shipment); + } + completeLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(completeLSP); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : completeLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(completeLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} + diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest.java new file mode 100644 index 00000000000..79e0db94bd7 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest.java @@ -0,0 +1,304 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class FirstAndSecondReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest.java new file mode 100644 index 00000000000..0b0b246c417 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest.java @@ -0,0 +1,250 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class FirstReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + LinkedList resourcesList = new LinkedList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest.java new file mode 100644 index 00000000000..1a55498e97a --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest.java @@ -0,0 +1,280 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MainRunLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest.java new file mode 100644 index 00000000000..d239f760ed5 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest.java @@ -0,0 +1,228 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MainRunOnlyLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + LSPUtils.addLSPs(scenario, lsps); + + Controler controler = new Controler(scenario); + + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest.java new file mode 100644 index 00000000000..1051b36a0e8 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest.java @@ -0,0 +1,227 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleIterationsCollectionLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = network.getLinks().get(collectionLinkId); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toInstance( new LSPModule.LSPStrategyManagerEmptyImpl() ); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionLSPMobsim() { + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest.java new file mode 100644 index 00000000000..7edc52ee1a7 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest.java @@ -0,0 +1,360 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleIterationsCompleteLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP completeLSP; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LogisticChainElement distributionElement = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + final Id chainId = Id.create("SolutionId", LogisticChain.class); + LogisticChain completeSolution = LSPUtils.LogisticChainBuilder.newInstance(chainId) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + completeLSP = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + //Random rand = new Random(1); + int numberOfShipments = MatsimRandom.getRandom().nextInt(50); + + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + completeLSP.assignShipmentToLSP(shipment); + } + completeLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(completeLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controler.getControlerIO().getOutputPath(), lsp); + } + } + + @Test + public void testCompleteLSPMobsim() { + for (LspShipment shipment : completeLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(completeLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } + +} + + + diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest.java new file mode 100644 index 00000000000..2671cbc7c67 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest.java @@ -0,0 +1,319 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleIterationsFirstAndSecondReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + //Todo/Fixme: In the result there only the second hub is used. -- see Issue #170. KMT Nov'23 + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + //Please note, that this result contains also reloading / hubHandlingStarts after the main run (even if there is no further distribution carrier) + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest.java new file mode 100644 index 00000000000..6e13da80a55 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest.java @@ -0,0 +1,263 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleIterationsFirstReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest.java new file mode 100644 index 00000000000..e48c7315959 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest.java @@ -0,0 +1,303 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +@SuppressWarnings("ALL") +public class MultipleIterationsMainRunLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controler.getControlerIO().getOutputPath(), lsp); + } + + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest.java new file mode 100644 index 00000000000..a8c22352177 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest.java @@ -0,0 +1,212 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsCollectionLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType vehicleType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + vehicleType.getCapacity().setOther(10); + vehicleType.getCostInformation().setCostsPerMeter(0.0004); + vehicleType.getCostInformation().setCostsPerSecond(0.38); + vehicleType.getCostInformation().setFixedCost(49.); + vehicleType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Link collectionLink = network.getLinks().get(collectionLinkId); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLink.getId(), vehicleType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(collectionLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCollectionLSPMobsim() { + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest.java new file mode 100644 index 00000000000..b2345a6e338 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest.java @@ -0,0 +1,361 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsCompleteLSPMobsimTest { + + private static final Logger log = LogManager.getLogger(MultipleShipmentsCompleteLSPMobsimTest.class); + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP completeLSP; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LogisticChainElement distributionElement= LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + final Id chainId = Id.create("SolutionId", LogisticChain.class); + LogisticChain completeSolution = LSPUtils.LogisticChainBuilder.newInstance(chainId) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + completeLSP = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + //Random rand = new Random(1); + int numberOfShipments = MatsimRandom.getRandom().nextInt(50); + + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + completeLSP.assignShipmentToLSP(shipment); + } + completeLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(completeLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(1 + MatsimRandom.getRandom().nextInt(10)); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controler.getControlerIO().getOutputPath(), lsp); + } + } + + @Test + public void testCompleteLSPMobsim() { + for (LspShipment shipment : completeLSP.getLspShipments()) { + log.info("comparing shipment: {}", shipment.getId()); + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(completeLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} + diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest.java new file mode 100644 index 00000000000..8b9e1fba2f6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest.java @@ -0,0 +1,317 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.examples.lspReplanning.AssignmentStrategyFactory; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsFirstAndSecondReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new LSPModule()); + controler.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toProvider(() -> { + LSPStrategyManager strategyManager = new LSPStrategyManagerImpl(); + strategyManager.addStrategy(new AssignmentStrategyFactory().createStrategy(), null, 1); + return strategyManager; + }); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy(new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + } ); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(4); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest.java new file mode 100644 index 00000000000..642c831f016 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest.java @@ -0,0 +1,255 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsFirstReloadLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controler.getControlerIO().getOutputPath(), lsp); + } + } + + @Test + public void testFirstReloadLSPMobsim() { + + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest.java new file mode 100644 index 00000000000..03ef87aa39c --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest.java @@ -0,0 +1,288 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsMainRunLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP lsp; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + collectionVehType.setNetworkMode(TransportMode.car); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + + int numberOfShipments = 1 + MatsimRandom.getRandom().nextInt(50); + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + + for (LSP lsp : LSPUtils.getLSPs(controler.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controler.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controler.getControlerIO().getOutputPath(), lsp); + } + } + + @Test + public void testFirstReloadLSPMobsim() { + for (LspShipment shipment : lsp.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + assertEquals(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(), shipment.getShipmentLog().getPlanElements().size()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest.java new file mode 100644 index 00000000000..12109f117bf --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest.java @@ -0,0 +1,354 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspMobsimTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class RepeatedMultipleShipmentsCompleteLSPMobsimTest { + + @RegisterExtension + public final MatsimTestUtils utils = new MatsimTestUtils(); + private LSP completeLSP; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + + var freightConfig = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); + freightConfig.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.ignore); + + + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder distributionBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId); + distributionBuilder.setResource(distributionResource); + LogisticChainElement distributionElement = distributionBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + final Id chainId = Id.create("SolutionId", LogisticChain.class); + LogisticChain completeSolution = LSPUtils.LogisticChainBuilder.newInstance(chainId) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + completeLSP = completeLSPBuilder.build(); + + List linkList = new LinkedList<>(network.getLinks().values()); + //Random rand = new Random(1); + int numberOfShipments = MatsimRandom.getRandom().nextInt(50); + + for (int i = 1; i < 1 + numberOfShipments; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = 1 + MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, MatsimRandom.getRandom()); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + completeLSP.assignShipmentToLSP(shipment); + } + completeLSP.scheduleLogisticChains(); + + ArrayList lspList = new ArrayList<>(); + lspList.add(completeLSP); + LSPs lsps = new LSPs(lspList); + + Controler controler = new Controler(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + config.controller().setFirstIteration(0); + config.controller().setLastIteration(0); + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + //The VSP default settings are designed for person transport simulation. After talking to Kai, they will be set to WARN here. Kai MT may'23 + controler.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controler.run(); + } + + @Test + public void testCompleteLSPMobsim() { + int numberOfIterations = 1 + MatsimRandom.getRandom().nextInt(10); + for (int i = 0; i < numberOfIterations; i++) { + initialize(); + for (LspShipment shipment : completeLSP.getLspShipments()) { + assertFalse(shipment.getShipmentLog().getPlanElements().isEmpty()); + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(completeLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList logElements = new ArrayList<>(shipment.getShipmentLog().getPlanElements().values()); + logElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + for (LspShipmentPlanElement scheduleElement : scheduleElements) { + LspShipmentPlanElement logElement = logElements.get(scheduleElements.indexOf(scheduleElement)); + if (!scheduleElement.getElementType().equals(logElement.getElementType())) { + System.out.println(scheduleElement.getElementType()); + System.out.println(logElement.getElementType()); + for (int j = 0; j < LspShipmentUtils.getOrCreateShipmentPlan(completeLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(); j++) { + System.out.println("Scheduled: " + scheduleElements.get(j).getLogisticChainElement().getId() + " " + scheduleElements.get(j).getResourceId() + " " + scheduleElements.get(j).getElementType() + " Start: " + scheduleElements.get(j).getStartTime() + " End: " + scheduleElements.get(j).getEndTime()); + } + System.out.println(); + for (int j = 0; j < shipment.getShipmentLog().getPlanElements().size(); j++) { + System.out.println("Logged: " + logElements.get(j).getLogisticChainElement().getId() + " " + logElements.get(j).getResourceId() + " " + logElements.get(j).getElementType() + " Start: " + logElements.get(j).getStartTime() + " End: " + logElements.get(j).getEndTime()); + } + System.out.println(); + } + + assertEquals(scheduleElement.getElementType(), logElement.getElementType()); + assertSame(scheduleElement.getResourceId(), logElement.getResourceId()); + assertSame(scheduleElement.getLogisticChainElement(), logElement.getLogisticChainElement()); + assertEquals(scheduleElement.getStartTime(), logElement.getStartTime(), 300); + } + } + } + } + + @Test + public void compareEvents(){ + MatsimTestUtils.assertEqualEventsFiles(utils.getClassInputDirectory() + "output_events.xml.gz", utils.getOutputDirectory() + "output_events.xml.gz" ); + } +} + diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CollectionLSPPlanTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CollectionLSPPlanTest.java new file mode 100644 index 00000000000..271de9bd80c --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CollectionLSPPlanTest.java @@ -0,0 +1,109 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspPlanTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLSPPlanTest { + + private LogisticChain logisticChain; + private InitialShipmentAssigner assigner; + private LSPPlan collectionPlan; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(adapterBuilder.build()); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + logisticChain = collectionSolutionBuilder.build(); + + assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(logisticChain); + } + + @Test + public void collectionLSPPlanTest() { + assertSame(collectionPlan.getInitialShipmentAssigner(), assigner); + assertNull(collectionPlan.getScore()); + assertNull(collectionPlan.getLSP()); + assertEquals(1, collectionPlan.getLogisticChains().size()); + assertSame(collectionPlan.getLogisticChains().iterator().next(), logisticChain); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CompleteLSPPlanTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CompleteLSPPlanTest.java new file mode 100644 index 00000000000..0fd9ba6ad7b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CompleteLSPPlanTest.java @@ -0,0 +1,218 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspPlanTests; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.Config; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLSPPlanTest { + + private InitialShipmentAssigner assigner; + private LSPPlan completePlan; + private LogisticChain logisticChain; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + final LSPResource collectionCarrierResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionCarrierResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTransshipmentHubBuilder.build()); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = collectionCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(collectionCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario ); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTransshipmentHubBuilder.build()); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + + final LSPResource distributionCarrierResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LogisticChainElement distributionElement = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionCarrierResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + final Id chainId = Id.create("SolutionId", LogisticChain.class); + logisticChain = LSPUtils.LogisticChainBuilder.newInstance(chainId) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(logisticChain); + } + + @Test + public void testCompleteLSPPlan() { + assertSame(completePlan.getInitialShipmentAssigner(), assigner); + assertNull(completePlan.getLSP()); + assertNull(completePlan.getScore()); + assertEquals(1, completePlan.getLogisticChains().size()); + assertSame(completePlan.getLogisticChains().iterator().next(), logisticChain); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CollectionLspShipmentAssigmentTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CollectionLspShipmentAssigmentTest.java new file mode 100644 index 00000000000..6ad523b1a9d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CollectionLspShipmentAssigmentTest.java @@ -0,0 +1,167 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspShipmentAssignmentTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLspShipmentAssigmentTest { + + private LSPPlan collectionPlan; + private LSP collectionLSP; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + LSPResource collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + LogisticChainElement collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + } + + @Test + public void testCollectionLSPShipmentAssignment() { + assertSame(collectionLSP.getSelectedPlan(), collectionPlan); + assertFalse(collectionLSP.getLspShipments().isEmpty()); + ArrayList solutions = new ArrayList<>(collectionLSP.getSelectedPlan().getLogisticChains()); + + for (LogisticChain solution : solutions) { + if (solutions.indexOf(solution) == 0) { + assertEquals(10, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (element.getPreviousElement() == null) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } else { + assertTrue(solution.getLspShipmentIds().isEmpty()); + } + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CompleteLspShipmentAssignerTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CompleteLspShipmentAssignerTest.java new file mode 100644 index 00000000000..a3497a6d34d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CompleteLspShipmentAssignerTest.java @@ -0,0 +1,289 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspShipmentAssignmentTests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLspShipmentAssignerTest { + + private LSPPlan completePlan; + private LSP completeLSP; + + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + LSPResource collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + LogisticChainElement collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + LSPResource firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + LogisticChainElement firstHubElement = firstHubElementBuilder.build(); + + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50 / 3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = collectionCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(collectionCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + LSPResource mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(Id.createLinkId("(4 2) (4 3)")) + .setToLinkId(Id.createLinkId("(14 2) (14 3)")) + .build(); + + LogisticChainElement mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + LSPResource secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + LogisticChainElement secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50 / 3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(distributionCarrierId); + carrier.setCarrierCapabilities(distributionCapabilities); + + LSPResource distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(carrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + LogisticChainElement distributionElement= LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + LogisticChain completeSolution = LSPUtils.LogisticChainBuilder.newInstance(Id.create("SolutionId", LogisticChain.class)) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + completeLSP = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + completeLSP.assignShipmentToLSP(builder.build()); + } + } + + @Test + public void testCollectionLSPShipmentAssignment() { + assertSame(completeLSP.getSelectedPlan(), completePlan); + ArrayList solutions = new ArrayList<>(completeLSP.getSelectedPlan().getLogisticChains()); + + for (LogisticChain solution : solutions) { + if (solutions.indexOf(solution) == 0) { + assertEquals(10, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + if (element.getPreviousElement() == null) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } else { + assertTrue(solution.getLspShipmentIds().isEmpty()); + } + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CollectionShipmentBuilderTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CollectionShipmentBuilderTest.java new file mode 100644 index 00000000000..a390624dd1d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CollectionShipmentBuilderTest.java @@ -0,0 +1,119 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspShipmentTest; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +public class CollectionShipmentBuilderTest { + + private Network network; + private ArrayList shipments; + + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + this.network = scenario.getNetwork(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id toLinkId = network.getLinks().get(collectionLinkId).getId(); + this.shipments = new ArrayList<>(); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + builder.setToLinkId(toLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipments.add(builder.build()); + } + } + + @Test + public void testShipments() { + assertEquals(10, shipments.size()); + for (LspShipment shipment : shipments) { + assertNotNull(shipment.getId()); + assertNotNull(shipment.getSize()); + assertNotNull(shipment.getDeliveryTimeWindow()); + assertNotNull(shipment.getFrom()); + assertNotNull(shipment.getDeliveryServiceTime()); + assertNotNull(shipment.getTo()); + assertNotNull(shipment.getPickupTimeWindow()); +// assertNotNull(shipment.getShipmentPlan()); + assertNotNull(shipment.getShipmentLog()); + assertNotNull(shipment.getSimulationTrackers()); + + assertTrue(shipment.getSimulationTrackers().isEmpty()); + assertEquals(shipment.getShipmentLog().getLspShipmentId(), shipment.getId()); + assertTrue(shipment.getShipmentLog().getPlanElements().isEmpty()); + +// assertEquals(shipment.getShipmentPlan().getEmbeddingContainer(), shipment.getId()); +// assertTrue(shipment.getShipmentPlan().getPlanElements().isEmpty()); + + Link link = network.getLinks().get(shipment.getFrom()); + assertTrue(link.getFromNode().getCoord().getX() <= 4000); + assertTrue(link.getFromNode().getCoord().getY() <= 4000); + + } + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CompleteShipmentBuilderTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CompleteShipmentBuilderTest.java new file mode 100644 index 00000000000..88ff9a08e36 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CompleteShipmentBuilderTest.java @@ -0,0 +1,134 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspShipmentTest; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +public class CompleteShipmentBuilderTest { + + private Network network; + private ArrayList shipments; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + this.network = scenario.getNetwork(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + this.shipments = new ArrayList<>(); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipments.add(builder.build()); + } + } + + + @Test + public void testShipments() { + assertEquals(10, shipments.size()); + for (LspShipment shipment : shipments) { + assertNotNull(shipment.getId()); + assertNotNull(shipment.getSize()); + assertNotNull(shipment.getDeliveryTimeWindow()); + assertNotNull(shipment.getFrom()); + assertNotNull(shipment.getDeliveryServiceTime()); + assertNotNull(shipment.getTo()); + assertNotNull(shipment.getPickupTimeWindow()); +// assertNotNull(shipment.getShipmentPlan()); + assertNotNull(shipment.getShipmentLog()); + assertNotNull(shipment.getSimulationTrackers()); + + assertTrue(shipment.getSimulationTrackers().isEmpty()); + assertEquals(shipment.getShipmentLog().getLspShipmentId(), shipment.getId()); + assertTrue(shipment.getShipmentLog().getPlanElements().isEmpty()); + +// assertEquals(shipment.getShipmentPlan().getEmbeddingContainer(), shipment.getId()); +// assertTrue(shipment.getShipmentPlan().getPlanElements().isEmpty()); + Link link = network.getLinks().get(shipment.getTo()); + assertTrue(link.getFromNode().getCoord().getX() <= 18000); + assertTrue(link.getFromNode().getCoord().getX() >= 14000); + assertTrue(link.getToNode().getCoord().getX() <= 18000); + assertTrue(link.getToNode().getCoord().getX() >= 14000); + + link = network.getLinks().get(shipment.getFrom()); + assertTrue(link.getFromNode().getCoord().getX() <= 4000); + assertTrue(link.getFromNode().getCoord().getY() <= 4000); + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/DistributionShipmentBuilderTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/DistributionShipmentBuilderTest.java new file mode 100644 index 00000000000..4a9f1c93160 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/DistributionShipmentBuilderTest.java @@ -0,0 +1,120 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.lspShipmentTest; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.TimeWindow; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +public class DistributionShipmentBuilderTest { + + private Network network; + private ArrayList shipments; + + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + this.network = scenario.getNetwork(); + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Id distributionLinkId = Id.createLinkId("(14 2) (14 3)"); + Id fromLinkId = network.getLinks().get(distributionLinkId).getId(); + this.shipments = new ArrayList<>(); + + for (int i = 1; i < 11; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + builder.setFromLinkId(fromLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + shipments.add(builder.build()); + } + } + + @Test + public void testShipments() { + assertEquals(10, shipments.size()); + for (LspShipment shipment : shipments) { + assertNotNull(shipment.getId()); + assertNotNull(shipment.getSize()); + assertNotNull(shipment.getDeliveryTimeWindow()); + assertNotNull(shipment.getFrom()); + assertNotNull(shipment.getDeliveryServiceTime()); + assertNotNull(shipment.getTo()); + assertNotNull(shipment.getPickupTimeWindow()); +// assertNotNull(shipment.getShipmentPlan()); + assertNotNull(shipment.getShipmentLog()); + assertNotNull(shipment.getSimulationTrackers()); + + assertTrue(shipment.getSimulationTrackers().isEmpty()); + assertEquals(shipment.getShipmentLog().getLspShipmentId(), shipment.getId()); + assertTrue(shipment.getShipmentLog().getPlanElements().isEmpty()); + +// assertEquals(shipment.getShipmentPlan().getEmbeddingContainer(), shipment.getId()); +// assertTrue(shipment.getShipmentPlan().getPlanElements().isEmpty()); + Link link = network.getLinks().get(shipment.getTo()); + assertTrue(link.getFromNode().getCoord().getX() <= 18000); + assertTrue(link.getFromNode().getCoord().getX() >= 14000); + assertTrue(link.getToNode().getCoord().getX() <= 18000); + assertTrue(link.getToNode().getCoord().getX() >= 14000); + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CollectionLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CollectionLSPSchedulingTest.java new file mode 100644 index 00000000000..b6a920add3b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CollectionLSPSchedulingTest.java @@ -0,0 +1,242 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CollectionLSPSchedulingTest { + + private LSP collectionLSP; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50 / 3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(Id.createVehicleId("CollectionVehicle"), collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + } + + @Test + public void testCollectionLSPScheduling() { + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + System.out.println(); + for (int i = 0; i < LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getLogisticChainElement().getId() + " " + scheduleElements.get(i).getResourceId() + " " + scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + } + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + assertEquals(3, LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.get(0).getEndTime() <= (24*3600)); + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + assertTrue(planElements.get(0).getStartTime() <= planElements.get(0).getEndTime()); + assertTrue(planElements.get(0).getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + + assertEquals(2, shipment.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + + { + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), collectionLSP.getResources().iterator().next().getId()); + } + + { + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), collectionLSP.getResources().iterator().next().getId()); + } + } + + for (LogisticChain solution : collectionLSP.getSelectedPlan().getLogisticChains()) { + assertEquals(1, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CompleteLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CompleteLSPSchedulingTest.java new file mode 100644 index 00000000000..76de85b3a2c --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CompleteLSPSchedulingTest.java @@ -0,0 +1,610 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Random; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class CompleteLSPSchedulingTest { + + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private LSPResource secondTranshipmentHubResource; + private LogisticChainElement secondHubElement; + private LSPResource distributionResource; + private LogisticChainElement distributionElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(toLinkId) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50/3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier distributionCarrier = CarriersUtils.createCarrier(distributionCarrierId); + distributionCarrier.setCarrierCapabilities(distributionCapabilities); + + distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(distributionCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + distributionElement = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + completeSolutionBuilder.addLogisticChainElement(distributionElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testCompletedLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList elementList = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + System.out.println(); + for (LspShipmentPlanElement element : elementList) { + System.out.println(element.getLogisticChainElement().getId() + "\t\t" + element.getResourceId() + "\t\t" + element.getElementType() + "\t\t" + element.getStartTime() + "\t\t" + element.getEndTime()); + } + System.out.println(); + } + + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(11, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertEquals("UNLOAD", planElements.get(10).getElementType()); + assertTrue(planElements.get(10).getEndTime() >= (0)); + assertTrue(planElements.get(10).getEndTime() <= (24*3600)); + assertTrue(planElements.get(10).getStartTime() <= planElements.get(10).getEndTime()); + assertTrue(planElements.get(10).getStartTime() >= (0)); + assertTrue(planElements.get(10).getStartTime() <= (24*3600)); + assertSame(planElements.get(10).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(10).getLogisticChainElement(), distributionElement); + + assertEquals(planElements.get(10).getStartTime(), planElements.get(9).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(9).getElementType()); + assertTrue(planElements.get(9).getEndTime() >= (0)); + assertTrue(planElements.get(9).getEndTime() <= (24*3600)); + assertTrue(planElements.get(9).getStartTime() <= planElements.get(9).getEndTime()); + assertTrue(planElements.get(9).getStartTime() >= (0)); + assertTrue(planElements.get(9).getStartTime() <= (24*3600)); + assertSame(planElements.get(9).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(9).getLogisticChainElement(), distributionElement); + + assertEquals(planElements.get(9).getStartTime(), planElements.get(8).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(8).getElementType()); + assertTrue(planElements.get(8).getEndTime() >= (0)); + assertTrue(planElements.get(8).getEndTime() <= (24*3600)); + assertTrue(planElements.get(8).getStartTime() <= planElements.get(8).getEndTime()); + assertTrue(planElements.get(8).getStartTime() >= (0)); + assertTrue(planElements.get(8).getStartTime() <= (24*3600)); + assertSame(planElements.get(8).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(8).getLogisticChainElement(), distributionElement); + + assertTrue(planElements.get(8).getStartTime() >= (planElements.get(7).getEndTime() / 1.0001) + 300); + + assertEquals("HANDLE", planElements.get(7).getElementType()); + assertTrue(planElements.get(7).getEndTime() >= (0)); + assertTrue(planElements.get(7).getEndTime() <= (24*3600)); + assertTrue(planElements.get(7).getStartTime() <= planElements.get(7).getEndTime()); + assertTrue(planElements.get(7).getStartTime() >= (0)); + assertTrue(planElements.get(7).getStartTime() <= (24*3600)); + assertSame(planElements.get(7).getResourceId(), secondTranshipmentHubResource.getId()); + assertSame(planElements.get(7).getLogisticChainElement(), secondHubElement); + + assertEquals(planElements.get(7).getStartTime(), (planElements.get(6).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= (planElements.get(3).getEndTime() / (1.0001)) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator> iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + assertEquals(1, secondTranshipmentHubResource.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(secondTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), toLinkId); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(6, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), resources.getFirst().getId()); + + //CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), solutionElements.getFirst()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(serviceHandler.getResourceId(), resources.getFirst().getId()); + + //MainRunStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + + //MainRunEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + + //DistributionRunStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(4)); + LSPTourStartEventHandler lspTourStartEventHandler = (LSPTourStartEventHandler) eventHandlers.get(4); + assertSame(lspTourStartEventHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertEquals(lspTourStartEventHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(lspTourStartEventHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(8).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(9).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(10).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), solutionElements.get(4)); + assertSame(lspTourStartEventHandler.getLspShipment(), shipment); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(8).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(9).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(10).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), resources.get(4).getId()); + + //DistributionServiceStart + assertInstanceOf(DistributionServiceStartEventHandler.class, eventHandlers.get(5)); + DistributionServiceStartEventHandler distributionServiceHandler = (DistributionServiceStartEventHandler) eventHandlers.get(5); + assertSame(distributionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertEquals(distributionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(distributionServiceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(8).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(9).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(10).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), solutionElements.get(4)); + assertSame(distributionServiceHandler.getLspShipment(), shipment); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(8).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(9).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(10).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), resources.get(4).getId()); + + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + assertEquals(1, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstHubElementTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstHubElementTest.java new file mode 100644 index 00000000000..6e9db008a4b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstHubElementTest.java @@ -0,0 +1,73 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.LSPUtils; +import org.matsim.freight.logistics.LogisticChainElement; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; + +public class FirstHubElementTest { + + private TransshipmentHubResource point; + private LogisticChainElement reloadingElement; + + @BeforeEach + public void initialize() { + TranshipmentHubSchedulerBuilder schedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + schedulerBuilder.setCapacityNeedFixed(10); + schedulerBuilder.setCapacityNeedLinear(1); + + + point = ResourceImplementationUtils.TransshipmentHubBuilder + .newInstance(Id.create("TranshipmentHub1", LSPResource.class), Id.createLinkId("(4 2) (4 3)"), null) + .setTransshipmentHubScheduler(schedulerBuilder.build()) + .build(); + + reloadingElement = LSPUtils.LogisticChainElementBuilder + .newInstance(Id.create("FirstHubElement", LogisticChainElement.class)) + .setResource(point) + .build(); + } + + @Test + public void testDistributionElement() { + assertNotNull(reloadingElement.getIncomingShipments()); + assertNotNull(reloadingElement.getIncomingShipments().getLspShipmentsWTime()); + assertTrue(reloadingElement.getIncomingShipments().getSortedLspShipments().isEmpty()); + assertNotNull(reloadingElement.getAttributes()); + assertTrue(reloadingElement.getAttributes().isEmpty()); +// assertNull(reloadingElement.getEmbeddingContainer() ); + assertNull(reloadingElement.getNextElement()); + assertNotNull(reloadingElement.getOutgoingShipments()); + assertNotNull(reloadingElement.getOutgoingShipments().getLspShipmentsWTime()); + assertTrue(reloadingElement.getOutgoingShipments().getSortedLspShipments().isEmpty()); + assertNull(reloadingElement.getPreviousElement()); + assertSame(reloadingElement.getResource(), point); + assertSame(reloadingElement.getResource().getClientElements().iterator().next(), reloadingElement); + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadLSPSchedulingTest.java new file mode 100644 index 00000000000..ee1d8d4153f --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadLSPSchedulingTest.java @@ -0,0 +1,326 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class FirstReloadLSPSchedulingTest { + private LSP lsp; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LogisticChainElement collectionElement; + private LSPResource collectionResource; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testFirstReloadLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + System.out.println(); + for (int i = 0; i < LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getLogisticChainElement().getId() + " " + scheduleElements.get(i).getResourceId() + " " + scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + + for (Entry entry : reloadEventHandler.getServicesWaitedFor().entrySet()) { + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(2, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), lsp.getResources().iterator().next().getId()); + + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.getFirst().getLogisticChainElement()); + assertSame(serviceHandler.getElement(), lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.getFirst().getResourceId()); + assertSame(serviceHandler.getResourceId(), lsp.getResources().iterator().next().getId()); + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + assertEquals(1, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadResourceTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadResourceTest.java new file mode 100644 index 00000000000..d69105472f6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadResourceTest.java @@ -0,0 +1,67 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; + +public class FirstReloadResourceTest { + + private static final Id hubLinkId = Id.createLinkId("(4 2) (4 3)"); + private TransshipmentHubResource transshipmentHubResource; + + @BeforeEach + public void initialize() { + + + TranshipmentHubSchedulerBuilder schedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + schedulerBuilder.setCapacityNeedFixed(10); + schedulerBuilder.setCapacityNeedLinear(1); + + transshipmentHubResource = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(Id.create("TranshipmentHub1", LSPResource.class), hubLinkId, null) + .setTransshipmentHubScheduler(schedulerBuilder.build()) + .build(); + } + + @Test + public void TranshipmentHubTest() { + assertEquals(10, transshipmentHubResource.getCapacityNeedFixed(), 0.0); + assertEquals(1, transshipmentHubResource.getCapacityNeedLinear(), 0.0); + assertFalse(LSPCarrierResource.class.isAssignableFrom(transshipmentHubResource.getClass())); +// assertSame(TranshipmentHub.getClassOfResource(), TranshipmentHub.class); + assertNotNull(transshipmentHubResource.getClientElements()); + assertTrue(transshipmentHubResource.getClientElements().isEmpty()); + assertSame(transshipmentHubResource.getEndLinkId(), hubLinkId); + assertSame(transshipmentHubResource.getStartLinkId(), hubLinkId); + assertNotNull(transshipmentHubResource.getSimulationTrackers()); + assertFalse(transshipmentHubResource.getSimulationTrackers().isEmpty()); + assertEquals(1, transshipmentHubResource.getSimulationTrackers().size()); + assertNotNull(transshipmentHubResource.getAttributes()); + assertTrue(transshipmentHubResource.getAttributes().isEmpty()); + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MainRunLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MainRunLSPSchedulingTest.java new file mode 100644 index 00000000000..8ffa62b7811 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MainRunLSPSchedulingTest.java @@ -0,0 +1,438 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MainRunLSPSchedulingTest { + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(toLinkId) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testMainRunLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + System.out.println(); + for (int i = 0; i < LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getLogisticChainElement().getId() + " " + scheduleElements.get(i).getResourceId() + " " + scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(7, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= (planElements.get(3).getEndTime() / (1.0001)) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + + for (Entry entry : reloadEventHandler.getServicesWaitedFor().entrySet()) { + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), resources.getFirst().getId()); + + //CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), solutionElements.getFirst()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(serviceHandler.getResourceId(), resources.getFirst().getId()); + + //MainRunTourStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + + //MainRunTourEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + assertEquals(1, solution.getLspShipmentIds().size()); + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCollectionLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCollectionLSPSchedulingTest.java new file mode 100644 index 00000000000..8729e384907 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCollectionLSPSchedulingTest.java @@ -0,0 +1,239 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.CollectionCarrierResourceBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsCollectionLSPSchedulingTest { + + private LSP collectionLSP; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + + @BeforeEach + public void initialize() { + + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id carrierId = Id.create("CollectionCarrier", Carrier.class); + Id vehicleTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(vehicleTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id vollectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(vollectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(carrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities capabilities = capabilitiesBuilder.build(); + Carrier carrier = CarriersUtils.createCarrier(carrierId); + carrier.setCarrierCapabilities(capabilities); + + + Id.create("CollectionCarrierResource", LSPResource.class); + CollectionCarrierResourceBuilder adapterBuilder = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(carrier); + adapterBuilder.setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)); + adapterBuilder.setLocationLinkId(collectionLinkId); + collectionResource = adapterBuilder.build(); + + Id elementId = Id.create("CollectionElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder collectionElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(elementId); + collectionElementBuilder.setResource(collectionResource); + collectionElement = collectionElementBuilder.build(); + + Id collectionSolutionId = Id.create("CollectionSolution", LogisticChain.class); + LSPUtils.LogisticChainBuilder collectionSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(collectionSolutionId); + collectionSolutionBuilder.addLogisticChainElement(collectionElement); + LogisticChain collectionSolution = collectionSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan collectionPlan = LSPUtils.createLSPPlan(); + collectionPlan.setInitialShipmentAssigner(assigner); + collectionPlan.addLogisticChain(collectionSolution); + + LSPUtils.LSPBuilder collectionLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + collectionLSPBuilder.setInitialPlan(collectionPlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + collectionLSPBuilder.setLogisticChainScheduler(simpleScheduler); + collectionLSP = collectionLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + + for (int i = 1; i < 100; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + Random random = new Random(1); + int capacityDemand = random.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, random); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + } + + builder.setToLinkId(collectionLinkId); + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + collectionLSP.assignShipmentToLSP(shipment); + } + collectionLSP.scheduleLogisticChains(); + + } + + @Test + public void testCollectionLSPScheduling() { + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + System.out.println(); + for (int i = 0; i < LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getLogisticChainElement().getId() + " " + scheduleElements.get(i).getResourceId() + " " + scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + } + + for (LspShipment shipment : collectionLSP.getLspShipments()) { + assertEquals(3, LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(collectionLSP.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.get(0).getEndTime() <= (24*3600)); + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + assertTrue(planElements.get(0).getStartTime() <= planElements.get(0).getEndTime()); + assertTrue(planElements.get(0).getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + + assertEquals(2, shipment.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), collectionLSP.getResources().iterator().next().getId()); + + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), collectionLSP.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), collectionLSP.getResources().iterator().next().getId()); + } + + for (LogisticChain solution : collectionLSP.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCompleteLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCompleteLSPSchedulingTest.java new file mode 100644 index 00000000000..21404b22417 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCompleteLSPSchedulingTest.java @@ -0,0 +1,612 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Random; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsCompleteLSPSchedulingTest { + + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private LSPResource secondTranshipmentHubResource; + private LogisticChainElement secondHubElement; + private LSPResource distributionResource; + private LogisticChainElement distributionElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(toLinkId) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + secondHubElement = secondHubElementBuilder.build(); + + Id distributionCarrierId = Id.create("DistributionCarrier", Carrier.class); + Id distributionVehTypeId = Id.create("DistributionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType distributionVehType = VehicleUtils.createVehicleType(distributionVehTypeId, TransportMode.car); + distributionVehType.getCapacity().setOther(10); + distributionVehType.getCostInformation().setCostsPerMeter(0.0004); + distributionVehType.getCostInformation().setCostsPerSecond(0.38); + distributionVehType.getCostInformation().setFixedCost(49.); + distributionVehType.setMaximumVelocity(50/3.6); + + Id distributionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id distributionVehicleId = Id.createVehicleId("DistributionVehicle"); + CarrierVehicle distributionCarrierVehicle = CarrierVehicle.newInstance(distributionVehicleId, distributionLinkId, distributionVehType); + + CarrierCapabilities.Builder capabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + capabilitiesBuilder.addVehicle(distributionCarrierVehicle); + capabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities distributionCapabilities = capabilitiesBuilder.build(); + Carrier distributionCarrier = CarriersUtils.createCarrier(distributionCarrierId); + distributionCarrier.setCarrierCapabilities(distributionCapabilities); + + + distributionResource = ResourceImplementationUtils.DistributionCarrierResourceBuilder.newInstance(distributionCarrier) + .setDistributionScheduler(ResourceImplementationUtils.createDefaultDistributionCarrierScheduler(scenario)) + .setLocationLinkId(distributionLinkId) + .build(); + + Id distributionElementId = Id.create("DistributionElement", LogisticChainElement.class); + distributionElement = LSPUtils.LogisticChainElementBuilder.newInstance(distributionElementId) + .setResource(distributionResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + secondHubElement.connectWithNextElement(distributionElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LogisticChain completeSolution = LSPUtils.LogisticChainBuilder.newInstance(solutionId) + .addLogisticChainElement(collectionElement) + .addLogisticChainElement(firstHubElement) + .addLogisticChainElement(mainRunElement) + .addLogisticChainElement(secondHubElement) + .addLogisticChainElement(distributionElement) + .build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + resourcesList.add(distributionResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + Random rand = new Random(1); + for (int i = 1; i < 100; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = rand.nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList, rand); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testCompletedLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList elementList = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + System.out.println(); + for (LspShipmentPlanElement element : elementList) { + System.out.println(element.getLogisticChainElement().getId() + "\t\t" + element.getResourceId() + "\t\t" + element.getElementType() + "\t\t" + element.getStartTime() + "\t\t" + element.getEndTime()); + } + System.out.println(); + } + + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(11, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertEquals("UNLOAD", planElements.get(10).getElementType()); + assertTrue(planElements.get(10).getEndTime() >= (0)); + assertTrue(planElements.get(10).getEndTime() <= (24*3600)); + assertTrue(planElements.get(10).getStartTime() <= planElements.get(10).getEndTime()); + assertTrue(planElements.get(10).getStartTime() >= (0)); + assertTrue(planElements.get(10).getStartTime() <= (24*3600)); + assertSame(planElements.get(10).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(10).getLogisticChainElement(), distributionElement); + + assertEquals(planElements.get(10).getStartTime(), planElements.get(9).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(9).getElementType()); + assertTrue(planElements.get(9).getEndTime() >= (0)); + assertTrue(planElements.get(9).getEndTime() <= (24*3600)); + assertTrue(planElements.get(9).getStartTime() <= planElements.get(9).getEndTime()); + assertTrue(planElements.get(9).getStartTime() >= (0)); + assertTrue(planElements.get(9).getStartTime() <= (24*3600)); + assertSame(planElements.get(9).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(9).getLogisticChainElement(), distributionElement); + + assertEquals(planElements.get(9).getStartTime(), planElements.get(8).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(8).getElementType()); + assertTrue(planElements.get(8).getEndTime() >= (0)); + assertTrue(planElements.get(8).getEndTime() <= (24*3600)); + assertTrue(planElements.get(8).getStartTime() <= planElements.get(8).getEndTime()); + assertTrue(planElements.get(8).getStartTime() >= (0)); + assertTrue(planElements.get(8).getStartTime() <= (24*3600)); + assertSame(planElements.get(8).getResourceId(), distributionResource.getId()); + assertSame(planElements.get(8).getLogisticChainElement(), distributionElement); + + assertTrue(planElements.get(8).getStartTime() >= planElements.get(7).getEndTime() / 1.0001 + 300); + + assertEquals("HANDLE", planElements.get(7).getElementType()); + assertTrue(planElements.get(7).getEndTime() >= (0)); + assertTrue(planElements.get(7).getEndTime() <= (24*3600)); + assertTrue(planElements.get(7).getStartTime() <= planElements.get(7).getEndTime()); + assertTrue(planElements.get(7).getStartTime() >= (0)); + assertTrue(planElements.get(7).getStartTime() <= (24*3600)); + assertSame(planElements.get(7).getResourceId(), secondTranshipmentHubResource.getId()); + assertSame(planElements.get(7).getLogisticChainElement(), secondHubElement); + + assertEquals(planElements.get(7).getStartTime(), planElements.get(6).getEndTime() + 300, 0.0); + + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= planElements.get(3).getEndTime() / (1.0001) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), planElements.get(2).getEndTime() + 300, 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator> iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + assertEquals(1, secondTranshipmentHubResource.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(secondTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), toLinkId); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(6, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), resources.getFirst().getId()); + + //CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), solutionElements.getFirst()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(serviceHandler.getResourceId(), resources.getFirst().getId()); + + //MainRunTourStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + + //MainRunTourEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + + //DistributionTourStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(4)); + LSPTourStartEventHandler lspTourStartEventHandler = (LSPTourStartEventHandler) eventHandlers.get(4); + assertSame(lspTourStartEventHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertEquals(lspTourStartEventHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(lspTourStartEventHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(8).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(9).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), planElements.get(10).getLogisticChainElement()); + assertSame(lspTourStartEventHandler.getLogisticChainElement(), solutionElements.get(4)); + assertSame(lspTourStartEventHandler.getLspShipment(), shipment); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(8).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(9).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), planElements.get(10).getResourceId()); + assertSame(lspTourStartEventHandler.getResourceId(), resources.get(4).getId()); + + //DistributionServiceStart + assertInstanceOf(DistributionServiceStartEventHandler.class, eventHandlers.get(5)); + DistributionServiceStartEventHandler distributionServiceHandler = (DistributionServiceStartEventHandler) eventHandlers.get(5); + assertSame(distributionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertEquals(distributionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(distributionServiceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(8).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(9).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), planElements.get(10).getLogisticChainElement()); + assertSame(distributionServiceHandler.getLogisticChainElement(), solutionElements.get(4)); + assertSame(distributionServiceHandler.getLspShipment(), shipment); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(8).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(9).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), planElements.get(10).getResourceId()); + assertSame(distributionServiceHandler.getResource().getId(), resources.get(4).getId()); + + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + + } + +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsFirstReloadLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsFirstReloadLSPSchedulingTest.java new file mode 100644 index 00000000000..38ad6c2f905 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsFirstReloadLSPSchedulingTest.java @@ -0,0 +1,323 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsFirstReloadLSPSchedulingTest { + private LSP lsp; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LogisticChainElement collectionElement; + private LSPResource collectionResource; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + collectionElement.connectWithNextElement(firstHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 100; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testFirstReloadLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList scheduleElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + scheduleElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + System.out.println(); + for (int i = 0; i < LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getLogisticChainElement().getId() + " " + scheduleElements.get(i).getResourceId() + " " + scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), planElements.get(2).getEndTime() + 300, 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + + for (Entry entry : reloadEventHandler.getServicesWaitedFor().entrySet()) { + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(2, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), lsp.getResources().iterator().next().getId()); + + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.getFirst().getLogisticChainElement()); + assertSame(serviceHandler.getElement(), lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements().iterator().next()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.getFirst().getResourceId()); + assertSame(serviceHandler.getResourceId(), lsp.getResources().iterator().next().getId()); + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsMainRunLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsMainRunLSPSchedulingTest.java new file mode 100644 index 00000000000..44a7561b5a1 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsMainRunLSPSchedulingTest.java @@ -0,0 +1,436 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsMainRunLSPSchedulingTest { + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(toLinkId) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 100; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + //Random random = new Random(1); + int capacityDemand = MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testMainRunLSPScheduling() { + + /*for(LSPShipment shipment : lsp.getShipments()) { + ArrayList scheduleElements = new ArrayList(shipment.getSchedule().getPlanElements().values()); + Collections.sort(scheduleElements, new AbstractShipmentPlanElementComparator()); + + System.out.println(); + for(int i = 0; i < shipment.getSchedule().getPlanElements().size(); i++) { + System.out.println("Scheduled: " + scheduleElements.get(i).getSolutionElement().getId() + " " + scheduleElements.get(i).getResourceId() +" "+ scheduleElements.get(i).getElementType() + " Start: " + scheduleElements.get(i).getStartTime() + " End: " + scheduleElements.get(i).getEndTime()); + } + System.out.println(); + }*/ + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(7, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= planElements.get(3).getEndTime() / (1.0001) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + + for (Entry entry : reloadEventHandler.getServicesWaitedFor().entrySet()) { + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, shipment.getSimulationTrackers().size()); + eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(endHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(endHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(endHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(endHandler.getLspShipment(), shipment); + assertSame(endHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(endHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(endHandler.getResourceId(), resources.getFirst().getId()); + + //CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(serviceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(serviceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(serviceHandler.getElement(), solutionElements.getFirst()); + assertSame(serviceHandler.getLspShipment(), shipment); + assertSame(serviceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(serviceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(serviceHandler.getResourceId(), resources.getFirst().getId()); + + //MainRunTourStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + + //MainRunEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsSecondReloadLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsSecondReloadLSPSchedulingTest.java new file mode 100644 index 00000000000..261164440ca --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsSecondReloadLSPSchedulingTest.java @@ -0,0 +1,520 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class MultipleShipmentsSecondReloadLSPSchedulingTest { + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private LSPResource secondTranshipmentHubResource; + private LogisticChainElement secondHubElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(Id.createLinkId(toLinkId)) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + secondHubElement = secondHubElementBuilder.build(); + + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 100; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(4); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testSecondReloadLSPScheduling() { + + /*for(LSPShipment shipment : lsp.getShipments()) { + ArrayList elementList = new ArrayList(shipment.getSchedule().getPlanElements().values()); + Collections.sort(elementList, new AbstractShipmentPlanElementComparator()); + System.out.println(); + for(AbstractShipmentPlanElement element : elementList) { + System.out.println(element.getSolutionElement().getId() + " " + element.getResourceId() + " " + element.getElementType() + " " + element.getStartTime() + " " + element.getEndTime()); + } + System.out.println(); + }*/ + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(8, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertEquals("HANDLE", planElements.get(7).getElementType()); + assertTrue(planElements.get(7).getEndTime() >= (0)); + assertTrue(planElements.get(7).getEndTime() <= (24*3600)); + assertTrue(planElements.get(7).getStartTime() <= planElements.get(7).getEndTime()); + assertTrue(planElements.get(7).getStartTime() >= (0)); + assertTrue(planElements.get(7).getStartTime() <= (24*3600)); + assertSame(planElements.get(7).getResourceId(), secondTranshipmentHubResource.getId()); + assertSame(planElements.get(7).getLogisticChainElement(), secondHubElement); + + assertEquals(planElements.get(7).getStartTime(), (planElements.get(6).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= (planElements.get(3).getEndTime() / (1.0001)) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + { + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator> + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry + entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : + reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + //There IS a next element following the 1st hub, so the outgoing shipments does NOT contain the shipment anymore (got handled). + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + } + + { + assertEquals(1, secondTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(secondTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator> + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), toLinkId); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + //There is NO next element following the 2nd hub, so the outgoing shipments remain in the list of the 2nd hub. + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, shipment.getSimulationTrackers().size()); + ArrayList> eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + //CollectionTourEnd + { + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler collectionEndHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(collectionEndHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(collectionEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(collectionEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(collectionEndHandler.getLspShipment(), shipment); + assertSame(collectionEndHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), resources.getFirst().getId()); + } + + {//CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler collectionServiceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(collectionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(collectionServiceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(collectionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(collectionServiceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), solutionElements.getFirst()); + assertSame(collectionServiceHandler.getLspShipment(), shipment); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), resources.getFirst().getId()); + } + + {//MainRunStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + } + + {//MainRunEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + } + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadLSPSchedulingTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadLSPSchedulingTest.java new file mode 100644 index 00000000000..bed697af413 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadLSPSchedulingTest.java @@ -0,0 +1,527 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map.Entry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.config.Config; +import org.matsim.core.events.handler.EventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.logistics.*; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; +import org.matsim.freight.logistics.shipment.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; + +public class SecondReloadLSPSchedulingTest { + private LSP lsp; + private LSPResource collectionResource; + private LogisticChainElement collectionElement; + private LSPResource firstTranshipmentHubResource; + private LogisticChainElement firstHubElement; + private LSPResource mainRunResource; + private LogisticChainElement mainRunElement; + private LSPResource secondTranshipmentHubResource; + private LogisticChainElement secondHubElement; + private Id toLinkId; + + @BeforeEach + public void initialize() { + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "logistics-2regions" ), "2regions-network.xml" ).getFile()); + Network network = scenario.getNetwork(); + + + Id collectionCarrierId = Id.create("CollectionCarrier", Carrier.class); + Id collectionVehTypeId = Id.create("CollectionCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType collectionVehType = VehicleUtils.createVehicleType(collectionVehTypeId, TransportMode.car); + collectionVehType.getCapacity().setOther(10); + collectionVehType.getCostInformation().setCostsPerMeter(0.0004); + collectionVehType.getCostInformation().setCostsPerSecond(0.38); + collectionVehType.getCostInformation().setFixedCost(49.); + collectionVehType.setMaximumVelocity(50/3.6); + + Id collectionLinkId = Id.createLinkId("(4 2) (4 3)"); + Id collectionVehicleId = Id.createVehicleId("CollectionVehicle"); + CarrierVehicle collectionCarrierVehicle = CarrierVehicle.newInstance(collectionVehicleId, collectionLinkId, collectionVehType); + + CarrierCapabilities.Builder collectionCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + collectionCapabilitiesBuilder.addVehicle(collectionCarrierVehicle); + collectionCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities collectionCapabilities = collectionCapabilitiesBuilder.build(); + Carrier collectionCarrier = CarriersUtils.createCarrier(collectionCarrierId); + collectionCarrier.setCarrierCapabilities(collectionCapabilities); + + + collectionResource = ResourceImplementationUtils.CollectionCarrierResourceBuilder.newInstance(collectionCarrier) + .setCollectionScheduler(ResourceImplementationUtils.createDefaultCollectionCarrierScheduler(scenario)) + .setLocationLinkId(collectionLinkId) + .build(); + + collectionElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("CollectionElement", LogisticChainElement.class)) + .setResource(collectionResource) + .build(); + + TranshipmentHubSchedulerBuilder firstReloadingSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + firstReloadingSchedulerBuilder.setCapacityNeedFixed(10); + firstReloadingSchedulerBuilder.setCapacityNeedLinear(1); + + + Id firstTransshipmentHubId = Id.create("TranshipmentHub1", LSPResource.class); + Id firstTransshipmentHub_LinkId = Id.createLinkId("(4 2) (4 3)"); + + TransshipmentHubBuilder firstTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(firstTransshipmentHubId, firstTransshipmentHub_LinkId, scenario); + firstTransshipmentHubBuilder.setTransshipmentHubScheduler(firstReloadingSchedulerBuilder.build()); + firstTranshipmentHubResource = firstTransshipmentHubBuilder.build(); + + Id firstHubElementId = Id.create("FirstHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder firstHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(firstHubElementId); + firstHubElementBuilder.setResource(firstTranshipmentHubResource); + firstHubElement = firstHubElementBuilder.build(); + + Id mainRunCarrierId = Id.create("MainRunCarrier", Carrier.class); + Id mainRunVehTypeId = Id.create("MainRunCarrierVehicleType", VehicleType.class); + org.matsim.vehicles.VehicleType mainRunVehType = VehicleUtils.createVehicleType(mainRunVehTypeId, TransportMode.car); + mainRunVehType.getCapacity().setOther(30); + mainRunVehType.getCostInformation().setCostsPerMeter(0.0002); + mainRunVehType.getCostInformation().setCostsPerSecond(0.38); + mainRunVehType.getCostInformation().setFixedCost(120.); + mainRunVehType.setMaximumVelocity(50/3.6); + + + Id fromLinkId = Id.createLinkId("(4 2) (4 3)"); + toLinkId = Id.createLinkId("(14 2) (14 3)"); + Id mainRunVehicleId = Id.createVehicleId("MainRunVehicle"); + CarrierVehicle mainRunCarrierVehicle = CarrierVehicle.newInstance(mainRunVehicleId, fromLinkId, mainRunVehType); + + + CarrierCapabilities.Builder mainRunCapabilitiesBuilder = CarrierCapabilities.Builder.newInstance(); + mainRunCapabilitiesBuilder.addVehicle(mainRunCarrierVehicle); + mainRunCapabilitiesBuilder.setFleetSize(FleetSize.INFINITE); + CarrierCapabilities mainRunCapabilities = mainRunCapabilitiesBuilder.build(); + Carrier mainRunCarrier = CarriersUtils.createCarrier(mainRunCarrierId); + mainRunCarrier.setCarrierCapabilities(mainRunCapabilities); + + + mainRunResource = ResourceImplementationUtils.MainRunCarrierResourceBuilder.newInstance(mainRunCarrier) + .setMainRunCarrierScheduler(ResourceImplementationUtils.createDefaultMainRunCarrierScheduler(scenario)) + .setFromLinkId(fromLinkId) + .setToLinkId(Id.createLinkId(toLinkId)) + .build(); + + mainRunElement = LSPUtils.LogisticChainElementBuilder.newInstance(Id.create("MainRunElement", LogisticChainElement.class)) + .setResource(mainRunResource) + .build(); + + TranshipmentHubSchedulerBuilder secondSchedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + secondSchedulerBuilder.setCapacityNeedFixed(10); + secondSchedulerBuilder.setCapacityNeedLinear(1); + + + Id secondTransshipmentHubId = Id.create("TranshipmentHub2", LSPResource.class); + Id secondTransshipmentHub_LinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder secondTransshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(secondTransshipmentHubId, secondTransshipmentHub_LinkId, scenario); + secondTransshipmentHubBuilder.setTransshipmentHubScheduler(secondSchedulerBuilder.build()); + secondTranshipmentHubResource = secondTransshipmentHubBuilder.build(); + + Id secondHubElementId = Id.create("SecondHubElement", LogisticChainElement.class); + LSPUtils.LogisticChainElementBuilder secondHubElementBuilder = LSPUtils.LogisticChainElementBuilder.newInstance(secondHubElementId); + secondHubElementBuilder.setResource(secondTranshipmentHubResource); + secondHubElement = secondHubElementBuilder.build(); + + + collectionElement.connectWithNextElement(firstHubElement); + firstHubElement.connectWithNextElement(mainRunElement); + mainRunElement.connectWithNextElement(secondHubElement); + + + Id solutionId = Id.create("SolutionId", LogisticChain.class); + LSPUtils.LogisticChainBuilder completeSolutionBuilder = LSPUtils.LogisticChainBuilder.newInstance(solutionId); + completeSolutionBuilder.addLogisticChainElement(collectionElement); + completeSolutionBuilder.addLogisticChainElement(firstHubElement); + completeSolutionBuilder.addLogisticChainElement(mainRunElement); + completeSolutionBuilder.addLogisticChainElement(secondHubElement); + LogisticChain completeSolution = completeSolutionBuilder.build(); + + InitialShipmentAssigner assigner = ResourceImplementationUtils.createSingleLogisticChainShipmentAssigner(); + LSPPlan completePlan = LSPUtils.createLSPPlan(); + completePlan.setInitialShipmentAssigner(assigner); + completePlan.addLogisticChain(completeSolution); + + LSPUtils.LSPBuilder completeLSPBuilder = LSPUtils.LSPBuilder.getInstance(Id.create("CollectionLSP", LSP.class)); + completeLSPBuilder.setInitialPlan(completePlan); + ArrayList resourcesList = new ArrayList<>(); + resourcesList.add(collectionResource); + resourcesList.add(firstTranshipmentHubResource); + resourcesList.add(mainRunResource); + resourcesList.add(secondTranshipmentHubResource); + + LogisticChainScheduler simpleScheduler = ResourceImplementationUtils.createDefaultSimpleForwardLogisticChainScheduler(resourcesList); + simpleScheduler.setBufferTime(300); + completeLSPBuilder.setLogisticChainScheduler(simpleScheduler); + lsp = completeLSPBuilder.build(); + + ArrayList linkList = new ArrayList<>(network.getLinks().values()); + + for (int i = 1; i < 2; i++) { + Id id = Id.create(i, LspShipment.class); + LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance(id); + int capacityDemand = MatsimRandom.getRandom().nextInt(10); + builder.setCapacityDemand(capacityDemand); + + while (true) { + Collections.shuffle(linkList); + Link pendingToLink = linkList.getFirst(); + if ((pendingToLink.getFromNode().getCoord().getX() <= 18000 && + pendingToLink.getFromNode().getCoord().getY() <= 4000 && + pendingToLink.getFromNode().getCoord().getX() >= 14000 && + pendingToLink.getToNode().getCoord().getX() <= 18000 && + pendingToLink.getToNode().getCoord().getY() <= 4000 && + pendingToLink.getToNode().getCoord().getX() >= 14000)) { + builder.setToLinkId(pendingToLink.getId()); + break; + } + + } + + while (true) { + Collections.shuffle(linkList); + Link pendingFromLink = linkList.getFirst(); + if (pendingFromLink.getFromNode().getCoord().getX() <= 4000 && + pendingFromLink.getFromNode().getCoord().getY() <= 4000 && + pendingFromLink.getToNode().getCoord().getX() <= 4000 && + pendingFromLink.getToNode().getCoord().getY() <= 4000) { + builder.setFromLinkId(pendingFromLink.getId()); + break; + } + + } + + TimeWindow endTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setEndTimeWindow(endTimeWindow); + TimeWindow startTimeWindow = TimeWindow.newInstance(0, (24 * 3600)); + builder.setStartTimeWindow(startTimeWindow); + builder.setDeliveryServiceTime(capacityDemand * 60); + LspShipment shipment = builder.build(); + lsp.assignShipmentToLSP(shipment); + } + lsp.scheduleLogisticChains(); + + } + + @Test + public void testSecondReloadLSPScheduling() { + + for (LspShipment shipment : lsp.getLspShipments()) { + ArrayList elementList = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + elementList.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + System.out.println(); + for (LspShipmentPlanElement element : elementList) { + System.out.println(element.getLogisticChainElement().getId() + " " + element.getResourceId() + " " + element.getElementType() + " " + element.getStartTime() + " " + element.getEndTime()); + } + System.out.println(); + } + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(8, LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().size()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + + assertEquals("HANDLE", planElements.get(7).getElementType()); + assertTrue(planElements.get(7).getEndTime() >= (0)); + assertTrue(planElements.get(7).getEndTime() <= (24*3600)); + assertTrue(planElements.get(7).getStartTime() <= planElements.get(7).getEndTime()); + assertTrue(planElements.get(7).getStartTime() >= (0)); + assertTrue(planElements.get(7).getStartTime() <= (24*3600)); + assertSame(planElements.get(7).getResourceId(), secondTranshipmentHubResource.getId()); + assertSame(planElements.get(7).getLogisticChainElement(), secondHubElement); + + assertEquals(planElements.get(7).getStartTime(), (planElements.get(6).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(6).getElementType()); + assertTrue(planElements.get(6).getEndTime() >= (0)); + assertTrue(planElements.get(6).getEndTime() <= (24*3600)); + assertTrue(planElements.get(6).getStartTime() <= planElements.get(6).getEndTime()); + assertTrue(planElements.get(6).getStartTime() >= (0)); + assertTrue(planElements.get(6).getStartTime() <= (24*3600)); + assertSame(planElements.get(6).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(6).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(6).getStartTime(), planElements.get(5).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(5).getElementType()); + assertTrue(planElements.get(5).getEndTime() >= (0)); + assertTrue(planElements.get(5).getEndTime() <= (24*3600)); + assertTrue(planElements.get(5).getStartTime() <= planElements.get(5).getEndTime()); + assertTrue(planElements.get(5).getStartTime() >= (0)); + assertTrue(planElements.get(5).getStartTime() <= (24*3600)); + assertSame(planElements.get(5).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(5).getLogisticChainElement(), mainRunElement); + + assertEquals(planElements.get(5).getStartTime(), planElements.get(4).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(4).getElementType()); + assertTrue(planElements.get(4).getEndTime() >= (0)); + assertTrue(planElements.get(4).getEndTime() <= (24*3600)); + assertTrue(planElements.get(4).getStartTime() <= planElements.get(4).getEndTime()); + assertTrue(planElements.get(4).getStartTime() >= (0)); + assertTrue(planElements.get(4).getStartTime() <= (24*3600)); + assertSame(planElements.get(4).getResourceId(), mainRunResource.getId()); + assertSame(planElements.get(4).getLogisticChainElement(), mainRunElement); + + assertTrue(planElements.get(4).getStartTime() >= (planElements.get(3).getEndTime() / (1.0001)) + 300); + + assertEquals("HANDLE", planElements.get(3).getElementType()); + assertTrue(planElements.get(3).getEndTime() >= (0)); + assertTrue(planElements.get(3).getEndTime() <= (24*3600)); + assertTrue(planElements.get(3).getStartTime() <= planElements.get(3).getEndTime()); + assertTrue(planElements.get(3).getStartTime() >= (0)); + assertTrue(planElements.get(3).getStartTime() <= (24*3600)); + assertSame(planElements.get(3).getResourceId(), firstTranshipmentHubResource.getId()); + assertSame(planElements.get(3).getLogisticChainElement(), firstHubElement); + + assertEquals(planElements.get(3).getStartTime(), (planElements.get(2).getEndTime() + 300), 0.0); + + assertEquals("UNLOAD", planElements.get(2).getElementType()); + assertTrue(planElements.get(2).getEndTime() >= (0)); + assertTrue(planElements.get(2).getEndTime() <= (24*3600)); + assertTrue(planElements.get(2).getStartTime() <= planElements.get(2).getEndTime()); + assertTrue(planElements.get(2).getStartTime() >= (0)); + assertTrue(planElements.get(2).getStartTime() <= (24*3600)); + assertSame(planElements.get(2).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(2).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(2).getStartTime(), planElements.get(1).getEndTime(), 0.0); + + assertEquals("TRANSPORT", planElements.get(1).getElementType()); + assertTrue(planElements.get(1).getEndTime() >= (0)); + assertTrue(planElements.get(1).getEndTime() <= (24*3600)); + assertTrue(planElements.get(1).getStartTime() <= planElements.get(1).getEndTime()); + assertTrue(planElements.get(1).getStartTime() >= (0)); + assertTrue(planElements.get(1).getStartTime() <= (24*3600)); + assertSame(planElements.get(1).getResourceId(), collectionResource.getId()); + assertSame(planElements.get(1).getLogisticChainElement(), collectionElement); + + assertEquals(planElements.get(1).getStartTime(), planElements.get(0).getEndTime(), 0.0); + + assertEquals("LOAD", planElements.get(0).getElementType()); + assertTrue(planElements.get(0).getEndTime() >= (0)); + assertTrue(planElements.getFirst().getEndTime() <= (24*3600)); + assertTrue(planElements.getFirst().getStartTime() <= planElements.getFirst().getEndTime()); + assertTrue(planElements.getFirst().getStartTime() >= (0)); + assertTrue(planElements.getFirst().getStartTime() <= (24*3600)); + assertSame(planElements.getFirst().getResourceId(), collectionResource.getId()); + assertSame(planElements.getFirst().getLogisticChainElement(), collectionElement); + } + + { + assertEquals(1, firstTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(firstTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator> + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry + entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : + reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + //There IS a next element following the 1st hub, so the outgoing shipments does NOT contain the shipment anymore (got handled). + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + } + + { + assertEquals(1, secondTranshipmentHubResource.getSimulationTrackers().size()); + ArrayList eventHandlers = + new ArrayList<>(secondTranshipmentHubResource.getSimulationTrackers()); + assertInstanceOf(TransshipmentHubTourEndEventHandler.class, eventHandlers.getFirst()); + TransshipmentHubTourEndEventHandler reloadEventHandler = + (TransshipmentHubTourEndEventHandler) eventHandlers.getFirst(); + Iterator< + Entry< + CarrierService, + TransshipmentHubTourEndEventHandler.TransshipmentHubEventHandlerPair>> + iter = reloadEventHandler.getServicesWaitedFor().entrySet().iterator(); + + while (iter.hasNext()) { + Entry + entry = iter.next(); + CarrierService service = entry.getKey(); + LspShipment shipment = entry.getValue().lspShipment; + LogisticChainElement element = entry.getValue().logisticChainElement; + assertSame(service.getLocationLinkId(), toLinkId); + assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + boolean handledByTranshipmentHub = false; + for (LogisticChainElement clientElement : + reloadEventHandler.getTranshipmentHub().getClientElements()) { + if (clientElement == element) { + handledByTranshipmentHub = true; + break; + } + } + assertTrue(handledByTranshipmentHub); + + //There is NO next element following the 2nd hub, so the outgoing shipments remain in the list of the 2nd hub. + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().contains(shipment)); + assertFalse(element.getIncomingShipments().getLspShipmentsWTime().contains(shipment)); + } + } + + + for (LspShipment shipment : lsp.getLspShipments()) { + assertEquals(4, shipment.getSimulationTrackers().size()); + ArrayList eventHandlers = new ArrayList<>(shipment.getSimulationTrackers()); + ArrayList planElements = new ArrayList<>(LspShipmentUtils.getOrCreateShipmentPlan(lsp.getSelectedPlan(), shipment.getId()).getPlanElements().values()); + planElements.sort(LspShipmentUtils.createShipmentPlanElementComparator()); + ArrayList solutionElements = new ArrayList<>(lsp.getSelectedPlan().getLogisticChains().iterator().next().getLogisticChainElements()); + ArrayList resources = new ArrayList<>(lsp.getResources()); + + {//CollectionTourEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); + LSPTourEndEventHandler collectionEndHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); + assertSame(collectionEndHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(collectionEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(collectionEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(0).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(1).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), planElements.get(2).getLogisticChainElement()); + assertSame(collectionEndHandler.getLogisticChainElement(), solutionElements.getFirst()); + assertSame(collectionEndHandler.getLspShipment(), shipment); + assertSame(collectionEndHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(collectionEndHandler.getResourceId(), resources.getFirst().getId()); + } + + {//CollectionServiceEnd + assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); + CollectionServiceEndEventHandler collectionServiceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); + assertSame(collectionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertEquals(collectionServiceHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(collectionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); + assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), shipment.getPickupTimeWindow().getEnd(), 0.0); + assertSame(collectionServiceHandler.getElement(), planElements.get(0).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), planElements.get(1).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), planElements.get(2).getLogisticChainElement()); + assertSame(collectionServiceHandler.getElement(), solutionElements.getFirst()); + assertSame(collectionServiceHandler.getLspShipment(), shipment); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(0).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(1).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), planElements.get(2).getResourceId()); + assertSame(collectionServiceHandler.getResourceId(), resources.getFirst().getId()); + } + + {//MainRunStart + assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); + LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); + assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunStartHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunStartHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunStartHandler.getLspShipment(), shipment); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunStartHandler.getResourceId(), resources.get(2).getId()); + } + + {//MainRunEnd + assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); + LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); + assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); + assertEquals(mainRunEndHandler.getCarrierService().getCapacityDemand(), shipment.getSize()); + assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); + assertEquals(Integer.MAX_VALUE, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getEnd(), 0.0); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(4).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(5).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), planElements.get(6).getLogisticChainElement()); + assertSame(mainRunEndHandler.getLogisticChainElement(), solutionElements.get(2)); + assertSame(mainRunEndHandler.getLspShipment(), shipment); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(4).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(5).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), planElements.get(6).getResourceId()); + assertSame(mainRunEndHandler.getResourceId(), resources.get(2).getId()); + } + } + + for (LogisticChain solution : lsp.getSelectedPlan().getLogisticChains()) { + for (LogisticChainElement element : solution.getLogisticChainElements()) { + assertTrue(element.getIncomingShipments().getLspShipmentsWTime().isEmpty()); + if (element.getNextElement() != null) { + assertTrue(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } else { + assertFalse(element.getOutgoingShipments().getLspShipmentsWTime().isEmpty()); + } + } + } + } +} diff --git a/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadResourceTest.java b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadResourceTest.java new file mode 100644 index 00000000000..d76ad918254 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadResourceTest.java @@ -0,0 +1,71 @@ +/* + * *********************************************************************** * + * * project: org.matsim.* + * * *********************************************************************** * + * * * + * * copyright : (C) 2022 by the members listed in the COPYING, * + * * LICENSE and WARRANTY file. * + * * email : info at matsim dot org * + * * * + * * *********************************************************************** * + * * * + * * This program is free software; you can redistribute it and/or modify * + * * it under the terms of the GNU General Public License as published by * + * * the Free Software Foundation; either version 2 of the License, or * + * * (at your option) any later version. * + * * See also COPYING, LICENSE and WARRANTY file * + * * * + * * *********************************************************************** + */ + +package org.matsim.freight.logistics.resourceImplementations; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.freight.logistics.LSPCarrierResource; +import org.matsim.freight.logistics.LSPResource; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TranshipmentHubSchedulerBuilder; +import org.matsim.freight.logistics.resourceImplementations.ResourceImplementationUtils.TransshipmentHubBuilder; + +public class SecondReloadResourceTest { + + private TransshipmentHubResource transshipmentHubResource; + private Id reloadingLinkId; + + @BeforeEach + public void initialize() { + TranshipmentHubSchedulerBuilder schedulerBuilder = ResourceImplementationUtils.TranshipmentHubSchedulerBuilder.newInstance(); + schedulerBuilder.setCapacityNeedFixed(10); + schedulerBuilder.setCapacityNeedLinear(1); + + Id reloadingId = Id.create("TranshipmentHub2", LSPResource.class); + reloadingLinkId = Id.createLinkId("(14 2) (14 3)"); + + TransshipmentHubBuilder transshipmentHubBuilder = ResourceImplementationUtils.TransshipmentHubBuilder.newInstance(reloadingId, reloadingLinkId, null); + transshipmentHubBuilder.setTransshipmentHubScheduler(schedulerBuilder.build()); + transshipmentHubResource = transshipmentHubBuilder.build(); + + } + + @Test + public void TranshipmentHubTest() { + assertEquals(10, transshipmentHubResource.getCapacityNeedFixed(), 0.0); + assertEquals(1, transshipmentHubResource.getCapacityNeedLinear(), 0.0); + assertFalse(LSPCarrierResource.class.isAssignableFrom(transshipmentHubResource.getClass())); +// assertSame(TranshipmentHub.getClassOfResource(), TranshipmentHub.class); + assertNotNull(transshipmentHubResource.getClientElements()); + assertTrue(transshipmentHubResource.getClientElements().isEmpty()); + assertSame(transshipmentHubResource.getEndLinkId(), reloadingLinkId); + assertSame(transshipmentHubResource.getStartLinkId(), reloadingLinkId); + assertNotNull(transshipmentHubResource.getSimulationTrackers()); + assertFalse(transshipmentHubResource.getSimulationTrackers().isEmpty()); + assertEquals(1, transshipmentHubResource.getSimulationTrackers().size()); + assertNotNull(transshipmentHubResource.getAttributes()); + assertTrue(transshipmentHubResource.getAttributes().isEmpty()); + } + +} diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain1/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain1/output_events.xml.gz new file mode 100644 index 00000000000..c7bb86ba149 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain1/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain2_direct/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain2_direct/output_events.xml.gz new file mode 100644 index 00000000000..da9f8fe99ef Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirectTest/testMain2_direct/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspReplanning/CollectionLSPReplanningTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspReplanning/CollectionLSPReplanningTest/output_events.xml.gz new file mode 100644 index 00000000000..953044d825c Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspReplanning/CollectionLSPReplanningTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest/output_events.xml.gz new file mode 100644 index 00000000000..e03c47b6e73 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest/output_events.xml.gz new file mode 100644 index 00000000000..55b637c1592 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest/output_events.xml.gz new file mode 100644 index 00000000000..11deb8015c0 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSPTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_events.xml.gz new file mode 100644 index 00000000000..6da265f5157 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_lsps.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_lsps.xml.gz new file mode 100644 index 00000000000..a81a27f6410 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsTest/output_lsps.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest/output_events.xml.gz new file mode 100644 index 00000000000..8a42fcbf5b5 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/io/carriers.xml b/contribs/freight/test/input/org/matsim/freight/logistics/io/carriers.xml new file mode 100644 index 00000000000..6e6493a0ff7 --- /dev/null +++ b/contribs/freight/test/input/org/matsim/freight/logistics/io/carriers.xml @@ -0,0 +1,291 @@ + + + + + + distributionCarrier + + + + + + + + + + + + + + + + j(1,1) j(1,2) j(1,3) j(1,4) j(1,5) j(1,6) j(1,7) j(1,8) i(2,8) i(3,8) i(4,8) i(5,8) i(6,8) i(7,8) i(8,8) + + + + j(9,9) i(9,9)R j(8,9)R j(8,8)R j(8,7)R j(8,6)R j(8,5)R j(8,4)R j(8,3)R j(8,2)R j(8,1)R + + + + j(9,1) i(9,1)R i(8,1)R i(7,1)R i(6,1)R i(5,1)R i(4,1)R i(3,1)R i(2,1)R i(1,1)R j(0,1)R + + + + + + + + + distributionCarrier + + + + + + + + + + + + + + distributionCarrier + + + + + + + + + + + + + + mainRunCarrier + + + + + + + + + + + + + + + + + + + + + + + + j(1,1) j(1,2) j(1,3) j(1,4) j(1,5) j(1,6) j(1,7) j(1,8) i(2,8) i(3,8) i(4,8) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + i(6,8) j(6,8)R j(6,7)R j(6,6)R j(6,5)R j(6,4)R j(6,3)R j(6,2)R i(6,1)R i(5,1)R i(4,1)R i(3,1)R i(2,1)R i(1,1)R j(0,1)R + + + + + + + + + distributionCarrier + + + + + + + + + + + + + + + + + + + + + + + + i(6,8) j(6,8)R i(6,7)R + + + + + + + + + + + + j(5,7) i(5,7)R i(4,7)R i(3,7)R j(2,7)R i(3,6) + + + + j(4,6)R i(4,5)R j(3,6) + + + + j(3,8) i(4,8) + + + + + + + i(6,8) j(6,8)R i(6,7)R i(5,7)R j(4,7)R i(5,6) + + + + + + + + i(6,5)R j(5,6) + + + + i(5,7)R i(4,7)R i(3,7)R j(2,7)R i(3,6) + + + + j(4,6)R i(4,5)R j(3,6) + + + + j(3,8) i(4,8) + + + + + + + + + distributionCarrier + + + + + + + + + + + + + + + + + + + + + + + + j(1,1) j(1,2) j(1,3) j(1,4) j(1,5) j(1,6) i(2,6) i(3,6) + + + + + + + + i(3,7)R j(2,7)R i(3,6) + + + + + + + + i(5,6) j(5,7) i(5,7)R + + + + + + + + + + + + + + + + i(6,5)R j(5,6) + + + + + + + + j(4,7)R j(4,6)R j(4,5)R j(4,4)R j(4,3)R j(4,2)R i(4,1)R i(3,1)R i(2,1)R i(1,1)R j(0,1)R + + + + + + + \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/io/lsps.xml b/contribs/freight/test/input/org/matsim/freight/logistics/io/lsps.xml new file mode 100644 index 00000000000..556ef25c6c6 --- /dev/null +++ b/contribs/freight/test/input/org/matsim/freight/logistics/io/lsps.xml @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml b/contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml new file mode 100644 index 00000000000..a98419ac59d --- /dev/null +++ b/contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..7a3a269cd78 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..d7897531de3 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..6def492ec5d Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..4e8cc4957a1 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..9da5513322e Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..8cd33ffda2b Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..45e527febdf Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..d36cdc25b87 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..0bab600b81b Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..39eeab60be2 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..99f6e933591 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..af5f5b3cecf Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..ab288426f05 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..298d349f4a0 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..fbb89f77428 Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..ca605ab9f9e Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz new file mode 100644 index 00000000000..8cc1ea40edb Binary files /dev/null and b/contribs/freight/test/input/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest/output_events.xml.gz differ