Skip to content

Commit

Permalink
Merge pull request #3602 from kt86/kmt_mergeLogisticsProjectIntoMATSim2
Browse files Browse the repository at this point in the history
Merge Logistics (LSP) into freight contrib
  • Loading branch information
kt86 authored Nov 28, 2024
2 parents 7c38271 + 9708c11 commit adadbe4
Show file tree
Hide file tree
Showing 221 changed files with 36,109 additions and 2 deletions.
19 changes: 17 additions & 2 deletions contribs/freight/README.md
Original file line number Diff line number Diff line change
@@ -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.


229 changes: 229 additions & 0 deletions contribs/freight/scenarios/2regions/2regions-network.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -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.
*
* <p>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<LSPResource> sortedResourceList;

/**
* The determination of the neighborhood structure among the Resources resulted in the
* neighborList.
*/
private final ArrayList<ResourceNeighbours> 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<LspShipment> 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<LSPResource> predecessors;
private final ArrayList<LSPResource> 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<String, String> getComments() {
Map<String, String> 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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.matsim.freight.logistics;

@SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
public interface HasBackpointer<T> {
// In general, we set backpointers when we add to the container.

// yy maybe also have interface HasSettableBackpointer?
void setEmbeddingContainer(T pointer);

// T getEmbeddingContainer();

}
Loading

0 comments on commit adadbe4

Please sign in to comment.