diff --git a/.github/workflows/deploy-dtds.yaml b/.github/workflows/deploy-dtds.yaml index bb48f61d27b..09d94069d76 100644 --- a/.github/workflows/deploy-dtds.yaml +++ b/.github/workflows/deploy-dtds.yaml @@ -1,18 +1,20 @@ name: deploy-dtds-on-website on: - push: - branches: - - master + pull_request: + types: + - closed paths: - - matsim/src/main/resources/dtd + - 'matsim/src/main/resources/dtd/**' jobs: rsync-dtds: + if: github.event.pull_request.merged == true # only if PR closed by merging name: sync DTDs to website runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - name: rsync dtds uses: burnett01/rsync-deployments@7.0.1 with: diff --git a/.github/workflows/full-integration.yaml b/.github/workflows/full-integration.yaml index a75ea5767da..2c20cb48d31 100644 --- a/.github/workflows/full-integration.yaml +++ b/.github/workflows/full-integration.yaml @@ -14,7 +14,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest] + #os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Prepare git diff --git a/contribs/accessibility/pom.xml b/contribs/accessibility/pom.xml index c4ead8bf378..f08160490b9 100644 --- a/contribs/accessibility/pom.xml +++ b/contribs/accessibility/pom.xml @@ -37,12 +37,12 @@ org.matsim.contrib matrixbasedptrouter - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib roadpricing - 2025.0-SNAPSHOT + ${project.parent.version} net.sf.trove4j @@ -70,7 +70,7 @@ org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/analysis/pom.xml b/contribs/analysis/pom.xml index 74a32b64c03..eea01c79ffb 100644 --- a/contribs/analysis/pom.xml +++ b/contribs/analysis/pom.xml @@ -13,7 +13,7 @@ org.matsim.contrib roadpricing - 2025.0-SNAPSHOT + ${project.parent.version} org.osgeo diff --git a/contribs/application/pom.xml b/contribs/application/pom.xml index e8ec00d4800..b427dfbfcf9 100644 --- a/contribs/application/pom.xml +++ b/contribs/application/pom.xml @@ -40,37 +40,37 @@ org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib osm - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib sumo - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib emissions - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib noise - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib freight - 2025.0-SNAPSHOT + ${project.parent.version} @@ -87,7 +87,7 @@ com.github.matsim-org gtfs2matsim - 47b0802a29 + 19f1676fc6 @@ -151,7 +151,7 @@ org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} compile diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java index 120f9711ba6..8d8e341154d 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/ApplyNetworkParams.java @@ -53,7 +53,8 @@ public class ApplyNetworkParams implements MATSimAppCommand { @CommandLine.Option(names = "--model", description = "Reference to the network model class", required = true) private Class modelClazz; - @CommandLine.Option(names = "--factor-bounds", split = ",", description = "Speed factor limits (lower,upper bound)", defaultValue = NetworkParamsOpt.DEFAULT_FACTOR_BOUNDS) + @CommandLine.Option(names = "--factor-bounds", split = ",", description = "Speed factor limits (lower, upper bound). " + + "Can be negative to indicate absolute speed bounds (in km/h)", defaultValue = NetworkParamsOpt.DEFAULT_FACTOR_BOUNDS) private double[] speedFactorBounds; @CommandLine.Option(names = "--capacity-bounds", split = ",", defaultValue = "0.4,0.6,0.8", @@ -234,23 +235,40 @@ private boolean applyFreeSpeed(Link link, Feature ft) { return false; } + double allowedSpeed = (double) link.getAttributes().getAttribute("allowed_speed"); + double freeSpeed = allowedSpeed * speedFactor; + boolean modified = false; - if (speedFactor > speedFactorBounds[1]) { + if (speedFactor > speedFactorBounds[1] && speedFactorBounds[1] >= 0) { log.warn("Reducing speed factor on {} from {} to {}", link.getId(), speedFactor, speedFactorBounds[1]); speedFactor = speedFactorBounds[1]; modified = true; } + // Use absolute bound for speed + if (freeSpeed > -speedFactorBounds[1]/3.6 && speedFactorBounds[1] < 0) { + log.warn("Reducing speed on {} from {} to {}", link.getId(), freeSpeed, -speedFactorBounds[1]/3.6); + speedFactor = (-speedFactorBounds[1] / 3.6) / allowedSpeed; + modified = true; + } + // Threshold for very low speed factors - if (speedFactor < speedFactorBounds[0]) { + if (speedFactor < speedFactorBounds[0] && speedFactorBounds[0] >= 0) { log.warn("Increasing speed factor on {} from {} to {}", link, speedFactor, speedFactorBounds[0]); speedFactor = speedFactorBounds[0]; modified = true; } - double freeSpeed = (double) link.getAttributes().getAttribute("allowed_speed") * speedFactor; + // Absolute negative speed factor + if (freeSpeed < -speedFactorBounds[0]/3.6 && speedFactorBounds[0] < 0) { + log.warn("Increasing speed on {} from {} to {}", link, freeSpeed, -speedFactorBounds[0]/3.6); + speedFactor = (-speedFactorBounds[0] / 3.6) / allowedSpeed; + modified = true; + } + // Recalculate with updated speed factor + freeSpeed = allowedSpeed * speedFactor; freeSpeed = BigDecimal.valueOf(freeSpeed).setScale(3, RoundingMode.HALF_EVEN).doubleValue(); if (decrease && freeSpeed > link.getFreespeed()) diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/EvalFreespeedParams.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/EvalFreespeedParams.java index cd2ba4e016a..68cd6099058 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/EvalFreespeedParams.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/EvalFreespeedParams.java @@ -121,12 +121,27 @@ static Result applyAndEvaluateParams( speedFactor = speedModel.predict(ft.features(), ft.categories()); // apply lower and upper bound - speedFactor = Math.max(speedFactorBounds[0], speedFactor); - speedFactor = Math.min(speedFactorBounds[1], speedFactor); + if (speedFactorBounds[0] >= 0) + speedFactor = Math.max(speedFactorBounds[0], speedFactor); + + if (speedFactorBounds[1] >= 0) + speedFactor = Math.min(speedFactorBounds[1], speedFactor); attributes.put(link.getId(), speedModel.getData(ft.features(), ft.categories())); - link.setFreespeed(allowedSpeed * speedFactor); + double freespeed = allowedSpeed * speedFactor; + + // Check absolute bounds on the freespeed + if (speedFactorBounds[0] < 0 && freespeed < -speedFactorBounds[0]/3.6) { + freespeed = -speedFactorBounds[0]/3.6; + speedFactor = freespeed / allowedSpeed; + } + if (speedFactorBounds[1] < 0 && freespeed > -speedFactorBounds[1]/3.6) { + freespeed = -speedFactorBounds[1]/3.6; + speedFactor = freespeed / allowedSpeed; + } + + link.setFreespeed(freespeed); link.getAttributes().putAttribute("speed_factor", speedFactor); } else diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/FreespeedOptServer.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/FreespeedOptServer.java index fef19850305..c17189b3a95 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/params/FreespeedOptServer.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/params/FreespeedOptServer.java @@ -57,7 +57,8 @@ public class FreespeedOptServer implements MATSimAppCommand { @CommandLine.Parameters(arity = "1..*", description = "Input validation files loaded from APIs") private List validationFiles; - @CommandLine.Option(names = "--factor-bounds", split = ",", description = "Speed factor limits (lower,upper bound)", defaultValue = NetworkParamsOpt.DEFAULT_FACTOR_BOUNDS) + @CommandLine.Option(names = "--factor-bounds", split = ",", description = "Speed factor limits (lower, upper bound). " + + "Can be negative to indicate absolute speed bounds (in km/h)", defaultValue = NetworkParamsOpt.DEFAULT_FACTOR_BOUNDS) private double[] speedFactorBounds; @CommandLine.Option(names = "--ref-hours", description = "Reference hours", defaultValue = "3,21", split = ",") diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/pt/CreateTransitScheduleFromGtfs.java b/contribs/application/src/main/java/org/matsim/application/prepare/pt/CreateTransitScheduleFromGtfs.java index ddbe0e7868a..5483167fcdf 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/pt/CreateTransitScheduleFromGtfs.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/pt/CreateTransitScheduleFromGtfs.java @@ -25,6 +25,7 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.pt.transitSchedule.api.*; import org.matsim.pt.utils.CreatePseudoNetwork; +import org.matsim.pt.utils.CreatePseudoNetworkWithLoopLinks; import org.matsim.pt.utils.TransitScheduleValidator; import org.matsim.vehicles.*; import picocli.CommandLine; @@ -85,8 +86,8 @@ public class CreateTransitScheduleFromGtfs implements MATSimAppCommand { @CommandLine.Option(names = "--transform-schedule", description = "Fully qualified class name to a Consumer to be executed after the schedule was created", arity = "0..*", split = ",") private List> transformSchedule; - @CommandLine.Option(names = "--merge-stops", description = "Whether stops should be merged by coordinate") - private boolean mergeStops; + @CommandLine.Option(names = "--merge-stops", description = "Whether stops should be merged by coordinate", defaultValue = "doNotMerge") + private GtfsConverter.MergeGtfsStops mergeStops; @CommandLine.Option(names = "--prefix", description = "Prefixes to add to the gtfs ids. Required if multiple inputs are used and ids are not unique.", split = ",") private List prefixes = new ArrayList<>(); @@ -100,10 +101,29 @@ public class CreateTransitScheduleFromGtfs implements MATSimAppCommand { @CommandLine.Option(names = "--shp-crs", description = "Overwrite coordinate system of the shape file") private String shpCrs; + @CommandLine.Option(names = "--pseudo-network", description = "Define how the pseudo network should be created", defaultValue = "singleLinkBetweenStops") + private PseudoNetwork pseudoNetwork; + + public static void main(String[] args) { System.exit(new CommandLine(new CreateTransitScheduleFromGtfs()).execute(args)); } + private static void addHbefaMapping(VehicleType vehicleType, HbefaVehicleCategory category) { + EngineInformation carEngineInformation = vehicleType.getEngineInformation(); + VehicleUtils.setHbefaVehicleCategory(carEngineInformation, String.valueOf(category)); + VehicleUtils.setHbefaTechnology(carEngineInformation, "average"); + VehicleUtils.setHbefaSizeClass(carEngineInformation, "average"); + VehicleUtils.setHbefaEmissionsConcept(carEngineInformation, "average"); + vehicleType.setNetworkMode(TransportMode.pt); + } + + private static void increaseLinkFreespeedIfLower(Link link, double newFreespeed) { + if (link.getFreespeed() < newFreespeed) { + link.setFreespeed(newFreespeed); + } + } + @Override public Integer call() throws Exception { @@ -183,6 +203,13 @@ public Integer call() throws Exception { Scenario ptScenario = getScenarioWithPseudoPtNetworkAndTransitVehicles(network, scenario.getTransitSchedule(), "pt_"); + for (TransitLine line : new ArrayList<>(scenario.getTransitSchedule().getTransitLines().values())) { + if (line.getRoutes().isEmpty()) { + log.warn("Line {} with no routes removed.", line.getId()); + scenario.getTransitSchedule().removeTransitLine(line); + } + } + if (validate) { //Check schedule and network TransitScheduleValidator.ValidationResult checkResult = TransitScheduleValidator.validateAll(ptScenario.getTransitSchedule(), ptScenario.getNetwork()); @@ -237,14 +264,19 @@ private Predicate createFilter(int i) throws Exception { /** * Creates the pt scenario and network. */ - private static Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network network, TransitSchedule schedule, String ptNetworkIdentifier) { + private Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network network, TransitSchedule schedule, String ptNetworkIdentifier) { ScenarioUtils.ScenarioBuilder builder = new ScenarioUtils.ScenarioBuilder(ConfigUtils.createConfig()); builder.setNetwork(network); builder.setTransitSchedule(schedule); Scenario scenario = builder.build(); // add pseudo network for pt - new CreatePseudoNetwork(scenario.getTransitSchedule(), scenario.getNetwork(), ptNetworkIdentifier, 0.1, 100000.0).createNetwork(); + switch (pseudoNetwork) { + case singleLinkBetweenStops -> + new CreatePseudoNetwork(scenario.getTransitSchedule(), scenario.getNetwork(), ptNetworkIdentifier, 0.1, 100000.0).createNetwork(); + case withLoopLinks -> + new CreatePseudoNetworkWithLoopLinks(scenario.getTransitSchedule(), scenario.getNetwork(), ptNetworkIdentifier, 0.1, 100000.0).createNetwork(); + } // create TransitVehicle types // see https://svn.vsp.tu-berlin.de/repos/public-svn/publications/vspwp/2014/14-24/ for veh capacities @@ -449,8 +481,12 @@ private static Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network // so we need to add time for passengers to board and alight double minStopTime = 30.0; + List> routeIds = new LinkedList<>(); + routeIds.add(route.getRoute().getStartLinkId()); + routeIds.addAll(route.getRoute().getLinkIds()); + routeIds.add(route.getRoute().getEndLinkId()); + for (int i = 1; i < routeStops.size(); i++) { - // TODO cater for loop link at first stop? Seems to just work without. TransitRouteStop routeStop = routeStops.get(i); // if there is no departure offset set (or infinity), it is the last stop of the line, // so we don't need to care about the stop duration @@ -462,8 +498,23 @@ private static Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network // Math.max to avoid negative values of travelTime double travelTime = Math.max(1, routeStop.getArrivalOffset().seconds() - lastDepartureOffset - 1.0 - (stopDuration >= minStopTime ? 0 : (minStopTime - stopDuration))); - Link link = network.getLinks().get(routeStop.getStopFacility().getLinkId()); - increaseLinkFreespeedIfLower(link, link.getLength() / travelTime); + + + Id stopLink = routeStop.getStopFacility().getLinkId(); + List> subRoute = new LinkedList<>(); + do { + Id linkId = routeIds.removeFirst(); + subRoute.add(linkId); + } while (!subRoute.contains(stopLink)); + + List links = subRoute.stream().map(scenario.getNetwork().getLinks()::get) + .toList(); + + double length = links.stream().mapToDouble(Link::getLength).sum(); + + for (Link link : links) { + increaseLinkFreespeedIfLower(link, length / travelTime); + } lastDepartureOffset = routeStop.getDepartureOffset().seconds(); } @@ -481,20 +532,15 @@ private static Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network return scenario; } - private static void addHbefaMapping(VehicleType vehicleType, HbefaVehicleCategory category) { - EngineInformation carEngineInformation = vehicleType.getEngineInformation(); - VehicleUtils.setHbefaVehicleCategory(carEngineInformation, String.valueOf(category)); - VehicleUtils.setHbefaTechnology(carEngineInformation, "average"); - VehicleUtils.setHbefaSizeClass(carEngineInformation, "average"); - VehicleUtils.setHbefaEmissionsConcept(carEngineInformation, "average"); - vehicleType.setNetworkMode(TransportMode.pt); - } - - private static void increaseLinkFreespeedIfLower(Link link, double newFreespeed) { - if (link.getFreespeed() < newFreespeed) { - link.setFreespeed(newFreespeed); - } + public enum PseudoNetwork { + /** + * Create links between all stops and possibly duplicate stops. + */ + singleLinkBetweenStops, + /** + * Create a pseudo network with loop links at each stop. + */ + withLoopLinks, } - } diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java b/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java index 4dcd8a6bf5a..909d311d64f 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/scenario/CreateScenarioCutOut.java @@ -590,9 +590,12 @@ public void run(Person person) { } // Remove all unselected plans because these are not handled - person.getPlans().stream() - .filter(p -> p != person.getSelectedPlan()) - .forEach(person::removePlan); + List plans = new ArrayList<>(person.getPlans()); + for(Plan p : plans){ + if (p != person.getSelectedPlan()){ + person.removePlan(p); + } + } } diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java new file mode 100644 index 00000000000..42ddbc4068a --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DefaultJobDurationCalculator.java @@ -0,0 +1,37 @@ +package org.matsim.freightDemandGeneration; + +import org.matsim.api.core.v01.Scenario; + +public class DefaultJobDurationCalculator implements JobDurationCalculator { + @Override + public double calculateServiceDuration(Integer serviceTimePerUnit, int demandForThisService) { + return getDefaultCalculation(serviceTimePerUnit, demandForThisService); + } + + @Override + public double calculatePickupDuration(Integer pickupDurationPerUnit, int demandForThisShipment) { + return getDefaultCalculation(pickupDurationPerUnit, demandForThisShipment); + } + + @Override + public double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int demandForThisShipment) { + return getDefaultCalculation(deliveryDurationPerUnit, demandForThisShipment); + } + + @Override + public void recalculateJobDurations(Scenario scenario) { + // do nothing + } + + /** + * @param timePerUnit time per unit + * @param demandForThisService demand for this service + * @return default calculation + */ + private int getDefaultCalculation(int timePerUnit, int demandForThisService) { + if (demandForThisService == 0) + return timePerUnit; + else + return timePerUnit * demandForThisService; + } +} diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java index e39eedd9ad4..63179128cc4 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -324,16 +324,18 @@ public String getTypeOfDemand() { * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file * @param population Population * @param shapeCategory Column name in the shape file for the data connection in the csv files - * @throws IOException if the csv file cannot be read + * @param jobDurationCalculator Calculator for the job duration + * @throws IOException if the csv file cannot be read */ static void readAndCreateDemand(Scenario scenario, Path csvLocationDemand, ShpOptions.Index indexShape, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape, Population population, String shapeCategory) throws IOException { + CoordinateTransformation crsTransformationNetworkAndShape, Population population, String shapeCategory, + JobDurationCalculator jobDurationCalculator) throws IOException { Set demandInformation = readDemandInformation(csvLocationDemand); checkNewDemand(scenario, demandInformation, indexShape, shapeCategory); createDemandForCarriers(scenario, indexShape, demandInformation, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + crsTransformationNetworkAndShape, jobDurationCalculator); } /** @@ -538,42 +540,45 @@ static void checkNewDemand(Scenario scenario, Set dema /** * Creates for every demand information the services/shipments for the carriers * - * @param scenario Scenario - * @param indexShape ShpOptions.Index for the shape file - * @param demandInformation Set with the demand information - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param indexShape ShpOptions.Index for the shape file + * @param demandInformation Set with the demand information + * @param population Population + * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ static void createDemandForCarriers(Scenario scenario, ShpOptions.Index indexShape, - Set demandInformation, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + Set demandInformation, Population population, boolean combineSimilarJobs, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { for (DemandInformationElement newDemandInformationElement : demandInformation) { log.info("Create demand for carrier {}", newDemandInformationElement.getCarrierName()); if (newDemandInformationElement.getTypeOfDemand().equals("service")) - createServices(scenario, newDemandInformationElement, indexShape, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + createServices(scenario, newDemandInformationElement, indexShape, population, + crsTransformationNetworkAndShape, jobDurationCalculator); else if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) - createShipments(scenario, newDemandInformationElement, indexShape, population, combineSimilarJobs, - crsTransformationNetworkAndShape); + createShipments(scenario, newDemandInformationElement, indexShape, population, + crsTransformationNetworkAndShape, jobDurationCalculator); } - + if (combineSimilarJobs) + combineSimilarJobs(scenario); + jobDurationCalculator.recalculateJobDurations(scenario); } /** * Creates the services. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement - * @param indexShape ShpOptions.Index - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param newDemandInformationElement single DemandInformationElement + * @param indexShape ShpOptions.Index + * @param population Population + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ private static void createServices(Scenario scenario, DemandInformationElement newDemandInformationElement, - ShpOptions.Index indexShape, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + ShpOptions.Index indexShape, Population population, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { int countOfLinks = 1; int distributedDemand = 0; @@ -643,8 +648,8 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { Link link = findNextUsedLink(scenario, indexShape, possibleLinksForService, numberOfJobs, areasForServiceLocations, locationsOfServices, usedServiceLocations, possiblePersonsForService, nearestLinkPerPerson, crsTransformationNetworkAndShape, i); - double serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit(); int demandForThisLink = 1; + double serviceTime = jobDurationCalculator.calculateServiceDuration(newDemandInformationElement.getFirstJobElementTimePerUnit(), demandForThisLink); usedServiceLocations.add(link.getId().toString()); Id idNewService = Id.create( createJobId(scenario, newDemandInformationElement, link.getId(), null), @@ -673,13 +678,19 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { countOfLinks++; Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - for (int i = 0; i < numberOfJobsForDemand; i++) { - int singleDemandForThisLink = demandForThisLink / numberOfJobsForDemand; - if (i == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - double serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() - * singleDemandForThisLink; + int handledDemand = 0; + //the number of jobs on this link is calculated based on the available vehicles + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + while (handledDemand < demandForThisLink) { + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; + else + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; + double serviceTime = jobDurationCalculator.calculateServiceDuration( + newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); + Id idNewService = Id.create( createJobId(scenario, newDemandInformationElement, link.getId(), null), CarrierService.class); @@ -718,16 +729,18 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { int demandForThisLink = calculateDemandForThisLink(demandToDistribute, numberOfJobs, distributedDemand, i); Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - for (int j = 0; j < numberOfJobsForDemand; j++) { - int singleDemandForThisLink = demandForThisLink / numberOfJobsForDemand; - if (j == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - double serviceTime; - if (singleDemandForThisLink == 0) - serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit(); + int handledDemand = 0; + //the number of jobs on this link is calculated based on the available vehicles + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + while (handledDemand < demandForThisLink || demandToDistribute == 0) { + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; else - serviceTime = newDemandInformationElement.getFirstJobElementTimePerUnit() * demandForThisLink; + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; + double serviceTime = jobDurationCalculator.calculateServiceDuration( + newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); usedServiceLocations.add(link.getId().toString()); Id idNewService = Id.create( @@ -740,28 +753,28 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)).getServices() .put(thisService.getId(), thisService); + if (demandToDistribute == 0) + break; } } distributedDemand = distributedDemand + demandForThisLink; } } - if (combineSimilarJobs) - reduceNumberOfJobsIfSameCharacteristics(scenario, newDemandInformationElement); } /** * Creates the shipments of a carrier. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement - * @param indexShape ShpOptions.Index for the shape file - * @param population Population - * @param combineSimilarJobs boolean if the jobs of the same carrier with same location and time will be combined - * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param scenario Scenario + * @param newDemandInformationElement single DemandInformationElement + * @param indexShape ShpOptions.Index for the shape file + * @param population Population + * @param crsTransformationNetworkAndShape CoordinateTransformation for the network and shape file + * @param jobDurationCalculator Calculator for the job duration */ private static void createShipments(Scenario scenario, DemandInformationElement newDemandInformationElement, - ShpOptions.Index indexShape, Population population, boolean combineSimilarJobs, - CoordinateTransformation crsTransformationNetworkAndShape) { + ShpOptions.Index indexShape, Population population, + CoordinateTransformation crsTransformationNetworkAndShape, JobDurationCalculator jobDurationCalculator) { int countOfLinks = 1; int distributedDemand = 0; @@ -900,7 +913,7 @@ else if (population == null) if (!usedDeliveryLocations.contains(linkDelivery.getId().toString())) usedDeliveryLocations.add(linkDelivery.getId().toString()); - createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, demandForThisLink); + createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, demandForThisLink, jobDurationCalculator); } } else // creates a demand on each link, demand depends on the length of the link @@ -968,7 +981,7 @@ else if (numberOfPickupLocations != null) { if (demandForThisLink > 0) { createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, - demandForThisLink); + demandForThisLink, jobDurationCalculator); } distributedDemand = distributedDemand + demandForThisLink; } @@ -998,52 +1011,52 @@ else if (numberOfPickupLocations != null) { usedDeliveryLocations.add(linkDelivery.getId().toString()); createSingleShipment(scenario, newDemandInformationElement, linkPickup, linkDelivery, - demandForThisLink); + demandForThisLink, jobDurationCalculator); distributedDemand = distributedDemand + demandForThisLink; } } - if (combineSimilarJobs) - reduceNumberOfJobsIfSameCharacteristics(scenario, newDemandInformationElement); } - /** Creates a single shipment. + /** + * Creates a single shipment. + * * @param scenario Scenario * @param newDemandInformationElement single DemandInformationElement * @param linkPickup Link for the pickup * @param linkDelivery Link for the delivery * @param demandForThisLink Demand for this link + * @param jobDurationCalculator Calculator for the job duration */ private static void createSingleShipment(Scenario scenario, DemandInformationElement newDemandInformationElement, - Link linkPickup, Link linkDelivery, int demandForThisLink) { + Link linkPickup, Link linkDelivery, int demandForThisLink, JobDurationCalculator jobDurationCalculator) { Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - int numberOfJobsForDemand = calculateNumberOfJobsForDemand(thisCarrier, demandForThisLink); - + double largestPossibleDemandSize = getLargestVehicleCapacity(thisCarrier); + int handledDemand = 0; TimeWindow timeWindowPickup = newDemandInformationElement.getFirstJobElementTimeWindow(); TimeWindow timeWindowDelivery = newDemandInformationElement.getSecondJobElementTimeWindow(); - for (int i = 0; i < numberOfJobsForDemand; i++) { + while (handledDemand < demandForThisLink || demandForThisLink == 0) { Id idNewShipment = Id.create(createJobId(scenario, newDemandInformationElement, linkPickup.getId(), linkDelivery.getId()), CarrierShipment.class); - double serviceTimePickup; - double serviceTimeDelivery; - int singleDemandForThisLink = Math.round ((float) demandForThisLink / numberOfJobsForDemand); - if (i == numberOfJobsForDemand - 1) - singleDemandForThisLink = demandForThisLink - (numberOfJobsForDemand - 1) * singleDemandForThisLink; - if (singleDemandForThisLink == 0) { - serviceTimePickup = newDemandInformationElement.getFirstJobElementTimePerUnit(); - serviceTimeDelivery = newDemandInformationElement.getSecondJobElementTimePerUnit(); - } else { - serviceTimePickup = newDemandInformationElement.getFirstJobElementTimePerUnit() * singleDemandForThisLink; - serviceTimeDelivery = newDemandInformationElement.getSecondJobElementTimePerUnit() * singleDemandForThisLink; - } + int singleDemandForThisLink; + if (demandForThisLink - handledDemand < largestPossibleDemandSize) + singleDemandForThisLink = demandForThisLink - handledDemand; + else + singleDemandForThisLink = (int)largestPossibleDemandSize; + handledDemand = handledDemand + singleDemandForThisLink; + double serviceTimePickup = jobDurationCalculator.calculatePickupDuration(newDemandInformationElement.getFirstJobElementTimePerUnit(), singleDemandForThisLink); + double serviceTimeDelivery = jobDurationCalculator.calculateDeliveryDuration(newDemandInformationElement.getSecondJobElementTimePerUnit(), singleDemandForThisLink); + CarrierShipment thisShipment = CarrierShipment.Builder .newInstance(idNewShipment, linkPickup.getId(), linkDelivery.getId(), singleDemandForThisLink) .setPickupServiceTime(serviceTimePickup).setPickupTimeWindow(timeWindowPickup) .setDeliveryServiceTime(serviceTimeDelivery).setDeliveryTimeWindow(timeWindowDelivery) .build(); thisCarrier.getShipments().put(thisShipment.getId(), thisShipment); + if (demandForThisLink == 0) + break; } } @@ -1051,21 +1064,16 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle * Method calculates the number of jobs for a demand on one link based on the largest vehicle capacity of the carrier. * * @param thisCarrier the carrier of a job - * @param demandForThisLink Demand for this link * @return Number of jobs for this demand */ - private static int calculateNumberOfJobsForDemand(Carrier thisCarrier, int demandForThisLink) { + private static double getLargestVehicleCapacity(Carrier thisCarrier) { double largestVehicleCapacity = 0; for (CarrierVehicle vehicle : thisCarrier.getCarrierCapabilities().getCarrierVehicles().values()) { if (vehicle.getType().getCapacity().getOther() > largestVehicleCapacity) { largestVehicleCapacity = vehicle.getType().getCapacity().getOther(); } } - if (demandForThisLink > largestVehicleCapacity) { - log.info("Demand {} is larger than the largest vehicle capacity ({}). Splitting demand into multiple jobs.", demandForThisLink, largestVehicleCapacity); - return (int) Math.ceil((double) demandForThisLink / largestVehicleCapacity); - } - return 1; + return largestVehicleCapacity; } /** @@ -1160,109 +1168,102 @@ private static int calculateDemandBasedOnLinkLength(int countOfLinks, int distri * If jobs of a carrier have the same characteristics (time window, location), * they will be combined to one job. * - * @param scenario Scenario - * @param newDemandInformationElement single DemandInformationElement + * @param scenario Scenario */ - private static void reduceNumberOfJobsIfSameCharacteristics(Scenario scenario, - DemandInformationElement newDemandInformationElement) { + private static void combineSimilarJobs(Scenario scenario) { log.warn( "The number of Jobs will be reduced if jobs have the same characteristics (e.g. time, location, carrier)"); - int connectedJobs = 0; - if (newDemandInformationElement.getTypeOfDemand().equals("shipment")) { - HashMap, CarrierShipment> shipmentsToRemove = new HashMap<>(); - ArrayList shipmentsToAdd = new ArrayList<>(); - Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() - .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - for (Id baseShipmentId : thisCarrier.getShipments().keySet()) { - if (!shipmentsToRemove.containsKey(baseShipmentId)) { - CarrierShipment baseShipment = thisCarrier.getShipments().get(baseShipmentId); - HashMap, CarrierShipment> shipmentsToConnect = new HashMap<>(); - shipmentsToConnect.put(baseShipmentId, baseShipment); - for (Id thisShipmentId : thisCarrier.getShipments().keySet()) { - if (!shipmentsToRemove.containsKey(thisShipmentId)) { - CarrierShipment thisShipment = thisCarrier.getShipments().get(thisShipmentId); - if (baseShipment.getId() != thisShipment.getId() + for (Carrier thisCarrier : CarriersUtils.getCarriers(scenario).getCarriers().values()) { + if (!thisCarrier.getShipments().isEmpty()) { + int shipmentsBeforeConnection = thisCarrier.getShipments().size(); + HashMap, CarrierShipment> shipmentsToRemove = new HashMap<>(); + ArrayList shipmentsToAdd = new ArrayList<>(); + for (Id baseShipmentId : thisCarrier.getShipments().keySet()) { + if (!shipmentsToRemove.containsKey(baseShipmentId)) { + CarrierShipment baseShipment = thisCarrier.getShipments().get(baseShipmentId); + HashMap, CarrierShipment> shipmentsToConnect = new HashMap<>(); + shipmentsToConnect.put(baseShipmentId, baseShipment); + for (Id thisShipmentId : thisCarrier.getShipments().keySet()) { + if (!shipmentsToRemove.containsKey(thisShipmentId)) { + CarrierShipment thisShipment = thisCarrier.getShipments().get(thisShipmentId); + if (baseShipment.getId() != thisShipment.getId() && baseShipment.getFrom() == thisShipment.getFrom() && baseShipment.getTo() == thisShipment.getTo() && baseShipment.getPickupTimeWindow() == thisShipment.getPickupTimeWindow() && baseShipment.getDeliveryTimeWindow() == thisShipment.getDeliveryTimeWindow()) - shipmentsToConnect.put(thisShipmentId, thisShipment); + shipmentsToConnect.put(thisShipmentId, thisShipment); + } } - } - Id idNewShipment = baseShipment.getId(); - int demandForThisLink = 0; - double serviceTimePickup = 0; - double serviceTimeDelivery = 0; - for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { - demandForThisLink = demandForThisLink + carrierShipment.getSize(); - serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); - serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); - shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); - connectedJobs++; - } - CarrierShipment newShipment = CarrierShipment.Builder + Id idNewShipment = baseShipment.getId(); + int demandForThisLink = 0; + double serviceTimePickup = 0; + double serviceTimeDelivery = 0; + for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { + demandForThisLink = demandForThisLink + carrierShipment.getSize(); + serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); + serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); + shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); + } + CarrierShipment newShipment = CarrierShipment.Builder .newInstance(idNewShipment, baseShipment.getFrom(), baseShipment.getTo(), demandForThisLink) .setPickupServiceTime(serviceTimePickup) .setPickupTimeWindow(baseShipment.getPickupTimeWindow()) .setDeliveryServiceTime(serviceTimeDelivery) .setDeliveryTimeWindow(baseShipment.getDeliveryTimeWindow()).build(); + shipmentsToAdd.add(newShipment); + } + } + for (CarrierShipment id : shipmentsToRemove.values()) + thisCarrier.getShipments().remove(id.getId(), id); - shipmentsToAdd.add(newShipment); - connectedJobs++; + for (CarrierShipment carrierShipment : shipmentsToAdd) { + thisCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); } - } - for (CarrierShipment id : shipmentsToRemove.values()) - thisCarrier.getShipments().remove(id.getId(), id); - for (CarrierShipment carrierShipment : shipmentsToAdd) { - thisCarrier.getShipments().put(carrierShipment.getId(), carrierShipment); + log.warn("Number of reduced shipments for carrier {}: {}", thisCarrier.getId().toString(), shipmentsBeforeConnection - thisCarrier.getShipments().size()); } - log.warn("Number of reduced shipments: {}", connectedJobs); - } - if (newDemandInformationElement.getTypeOfDemand().equals("service")) { - HashMap, CarrierService> servicesToRemove = new HashMap<>(); - ArrayList servicesToAdd = new ArrayList<>(); - Carrier thisCarrier = CarriersUtils.getCarriers(scenario).getCarriers() - .get(Id.create(newDemandInformationElement.getCarrierName(), Carrier.class)); - for (Id baseServiceId : thisCarrier.getServices().keySet()) { - if (!servicesToRemove.containsKey(baseServiceId)) { - CarrierService baseService = thisCarrier.getServices().get(baseServiceId); - HashMap, CarrierService> servicesToConnect = new HashMap<>(); - servicesToConnect.put(baseServiceId, baseService); - for (Id thisServiceId : thisCarrier.getServices().keySet()) { - if (!servicesToRemove.containsKey(thisServiceId)) { - CarrierService thisService = thisCarrier.getServices().get(thisServiceId); - if (baseService.getId() != thisService.getId() + if (!thisCarrier.getServices().isEmpty()) { + int servicesBeforeConnection = thisCarrier.getServices().size(); + HashMap, CarrierService> servicesToRemove = new HashMap<>(); + ArrayList servicesToAdd = new ArrayList<>(); + for (Id baseServiceId : thisCarrier.getServices().keySet()) { + if (!servicesToRemove.containsKey(baseServiceId)) { + CarrierService baseService = thisCarrier.getServices().get(baseServiceId); + HashMap, CarrierService> servicesToConnect = new HashMap<>(); + servicesToConnect.put(baseServiceId, baseService); + for (Id thisServiceId : thisCarrier.getServices().keySet()) { + if (!servicesToRemove.containsKey(thisServiceId)) { + CarrierService thisService = thisCarrier.getServices().get(thisServiceId); + if (baseService.getId() != thisService.getId() && baseService.getLocationLinkId() == thisService.getLocationLinkId() && baseService - .getServiceStartTimeWindow() == thisService.getServiceStartTimeWindow()) - servicesToConnect.put(thisServiceId, thisService); + .getServiceStartTimeWindow() == thisService.getServiceStartTimeWindow()) + servicesToConnect.put(thisServiceId, thisService); + } } - } - Id idNewService = baseService.getId(); - int demandForThisLink = 0; - double serviceTimeService = 0; - for (CarrierService carrierService : servicesToConnect.values()) { - demandForThisLink = demandForThisLink + carrierService.getCapacityDemand(); - serviceTimeService = serviceTimeService + carrierService.getServiceDuration(); - servicesToRemove.put(carrierService.getId(), carrierService); - connectedJobs++; - } - CarrierService newService = CarrierService.Builder + Id idNewService = baseService.getId(); + int demandForThisLink = 0; + double serviceTimeService = 0; + for (CarrierService carrierService : servicesToConnect.values()) { + demandForThisLink = demandForThisLink + carrierService.getCapacityDemand(); + serviceTimeService = serviceTimeService + carrierService.getServiceDuration(); + servicesToRemove.put(carrierService.getId(), carrierService); + } + CarrierService newService = CarrierService.Builder .newInstance(idNewService, baseService.getLocationLinkId()) .setServiceDuration(serviceTimeService) .setServiceStartTimeWindow(baseService.getServiceStartTimeWindow()) .setCapacityDemand(demandForThisLink).build(); - servicesToAdd.add(newService); - connectedJobs++; + servicesToAdd.add(newService); + } } + for (CarrierService id : servicesToRemove.values()) + thisCarrier.getServices().remove(id.getId(), id); + for (CarrierService carrierService : servicesToAdd) { + thisCarrier.getServices().put(carrierService.getId(), carrierService); + } + log.warn("Number of reduced services for carrier {}: {}", thisCarrier.getId().toString(), servicesBeforeConnection - thisCarrier.getServices().size()); } - for (CarrierService id : servicesToRemove.values()) - thisCarrier.getServices().remove(id.getId(), id); - for (CarrierService carrierService : servicesToAdd) { - thisCarrier.getServices().put(carrierService.getId(), carrierService); - } - log.warn("Number of reduced shipments: {}", connectedJobs); } } diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java index 368dddaad69..d01a6226691 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGeneration.java @@ -37,8 +37,8 @@ import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.CarrierModule; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.CarrierModule; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; import org.matsim.freight.carriers.usecases.chessboard.CarrierScoringFunctionFactoryImpl; import picocli.CommandLine; @@ -62,6 +62,8 @@ + " * these files are given in the example project. See: TODO", showDefaultValues = true) public class FreightDemandGeneration implements MATSimAppCommand { + private final JobDurationCalculator jobDurationCalculator; + private enum CarrierInputOptions { readCarrierFile, createCarriersFromCSV, addCSVDataToExistingCarrierFileData } @@ -154,6 +156,16 @@ private enum OptionsOfVRPSolutions { @CommandLine.Option(names = "--defaultJspritIterations", description = "Set the default number of jsprit iterations.") private int defaultJspritIterations; + public FreightDemandGeneration() { + this.jobDurationCalculator = new DefaultJobDurationCalculator(); + log.info("Using default {} for job duration calculation", jobDurationCalculator.getClass().getSimpleName()); + } + + public FreightDemandGeneration(JobDurationCalculator jobDurationCalculator) { + this.jobDurationCalculator = jobDurationCalculator; + log.info("Using {} for job duration calculation", jobDurationCalculator.getClass().getSimpleName()); + } + public static void main(String[] args) { System.exit(new CommandLine(new FreightDemandGeneration()).execute(args)); } @@ -353,7 +365,7 @@ private void createDemand(DemandGenerationOptions selectedDemandGenerationOption case createDemandFromCSV -> // creates the demand by using the information given in the read csv file DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, combineSimilarJobs, - crsTransformationNetworkAndShape, null, shapeCategory); + crsTransformationNetworkAndShape, null, shapeCategory, jobDurationCalculator); case createDemandFromCSVAndUsePopulation -> { /* * Option creates the demand by using the information given in the read csv file @@ -399,14 +411,14 @@ private void createDemand(DemandGenerationOptions selectedDemandGenerationOption case useHolePopulation: // uses the hole population as possible demand locations DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, - combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory); + combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory, jobDurationCalculator); break; case usePopulationInShape: // uses only the population with home location in the given shape file FreightDemandGenerationUtils.reducePopulationToShapeArea(population, shp.createIndex(populationCRS, "_")); DemandReaderFromCSV.readAndCreateDemand(scenario, csvLocationDemand, indexShape, - combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory); + combineSimilarJobs, crsTransformationNetworkAndShape, population, shapeCategory, jobDurationCalculator); break; default: throw new RuntimeException("No valid population option selected!"); diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java index c60a8a39390..ede28ace76d 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java @@ -152,7 +152,7 @@ static void createDemandLocationsFile(Controler controler) { writer.flush(); } catch (IOException e) { - e.printStackTrace(); + log.error("Could not write job locations file under " + "/outputLocationFile.xml.gz"); } log.info("Wrote job locations file under " + "/outputLocationFile.xml.gz"); } diff --git a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java new file mode 100644 index 00000000000..85d30908fa0 --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/JobDurationCalculator.java @@ -0,0 +1,39 @@ +package org.matsim.freightDemandGeneration; + +import org.matsim.api.core.v01.Scenario; + +public interface JobDurationCalculator { + /** + * Calculates the duration of a service in seconds. + * + * @param serviceDurationPerUnit in seconds + * @param demandForThisService amount of demand for this service + * @return duration in seconds + */ + double calculateServiceDuration(Integer serviceDurationPerUnit, int demandForThisService); + + /** + * Calculates the duration of a pickup in seconds. + * + * @param pickupDurationPerUnit in seconds + * @param demandForThisShipment amount of demand for this shipment + * @return duration in seconds + */ + double calculatePickupDuration(Integer pickupDurationPerUnit, int demandForThisShipment); + + /** + * Calculates the duration of a delivery in seconds. + * + * @param deliveryDurationPerUnit in seconds + * @param demandForThisShipment amount of demand for this shipment + * @return duration in seconds + */ + double calculateDeliveryDuration(Integer deliveryDurationPerUnit, int demandForThisShipment); + + /** + * Recalculates the job durations for all jobs in the scenario. The devault implementation does nothing. + * + * @param scenario scenario + */ + void recalculateJobDurations(Scenario scenario); +} diff --git a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java index c27b251afc4..9cd21c16d9d 100644 --- a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java +++ b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java @@ -79,10 +79,10 @@ void demandCreationWithSampleWithChangeNumberOfLocations() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeNumberOfLocationsWithDemand"); - + Boolean combineSimilarJobs = false; // run methods createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, - population); + population, combineSimilarJobs); Network network = scenario.getNetwork(); @@ -147,10 +147,11 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeDemandOnLocation"); + Boolean combineSimilarJobs = false; - createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, population); + createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, + population, combineSimilarJobs); - // check carrier 1 Network network = scenario.getNetwork(); checkCarrier1and2(scenario, network, indexShape); @@ -194,6 +195,74 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { } } + @Test + void demandCreationWithSampleWithDemandOnLocationWithCombiningJobs() throws IOException { + // read inputs + Config config = ConfigUtils.createConfig(); + config.network().setInputFile( + "https://raw.githubusercontent.com/matsim-org/matsim-libs/master/examples/scenarios/freight-chessboard-9x9/grid9x9.xml"); + Scenario scenario = ScenarioUtils.loadScenario(config); + FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(scenario.getConfig(), + FreightCarriersConfigGroup.class); + freightCarriersConfigGroup.setCarriersVehicleTypesFile(utils.getPackageInputDirectory() + "testVehicleTypes.xml"); + Path carrierCSVLocation = Path.of(utils.getPackageInputDirectory() + "testCarrierCSV.csv"); + Path demandCSVLocation = Path.of(utils.getPackageInputDirectory() + "testDemandCSV.csv"); + Path shapeFilePath = Path.of(utils.getPackageInputDirectory() + "testShape/testShape.shp"); + ShpOptions shp = new ShpOptions(shapeFilePath, "WGS84", null); + String shapeCategory = "Ortsteil"; + ShpOptions.Index indexShape = shp.createIndex("Ortsteil"); + String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; + Population population = PopulationUtils.readPopulation(populationLocation); + FreightDemandGenerationUtils.preparePopulation(population, 0.5, 1.0, "changeDemandOnLocation"); + Boolean combineSimilarJobs = true; + + createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, + population, combineSimilarJobs); + + Network network = scenario.getNetwork(); + + checkCarrier1and2WithCombiningJobs(scenario, network, indexShape); + int countDemand; + Object2IntMap countShipmentsWithCertainDemand; + Map> locationsPerShipmentElement; + + // check carrier 3 + Carrier testCarrier3 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier3", Carrier.class)); + Assertions.assertEquals(0, testCarrier3.getServices().size()); + Assertions.assertEquals(2, testCarrier3.getShipments().size()); + countShipmentsWithCertainDemand = new Object2IntOpenHashMap<>(); + locationsPerShipmentElement = new HashMap<>(); + countDemand = 0; + for (CarrierShipment shipment : testCarrier3.getShipments().values()) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getSize(), 1, Integer::sum); + countDemand = countDemand + shipment.getSize(); + Assertions.assertEquals(10, shipment.getSize()); + Assertions.assertEquals(4000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2500, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } + Assertions.assertEquals(20, countDemand); + Assertions.assertEquals(2, countShipmentsWithCertainDemand.getInt(10)); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement1_pickup").size()); + Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement1_delivery").size()); + for (String locationsOfShipmentElement : locationsPerShipmentElement.get("ShipmentElement1_delivery")) { + Link link = network.getLinks().get(Id.createLinkId(locationsOfShipmentElement)); + Assertions.assertTrue( + FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, null, null)); + Assertions.assertTrue(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area1" }, null)); + Assertions.assertFalse(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area2" }, null)); + } + } + + @Test void demandCreationNoSampling() throws IOException { // read inputs @@ -213,10 +282,11 @@ void demandCreationNoSampling() throws IOException { String populationLocation = utils.getPackageInputDirectory() + "testPopulation.xml"; Population population = PopulationUtils.readPopulation(populationLocation); FreightDemandGenerationUtils.preparePopulation(population, 0.5, 0.5, "changeDemandOnLocation"); + Boolean combineSimilarJobs = false; // run methods createDemandAndCheckCarrier(carrierCSVLocation, scenario, freightCarriersConfigGroup, indexShape, demandCSVLocation, shapeCategory, - population); + population, combineSimilarJobs); // check carrier 1 Network network = scenario.getNetwork(); @@ -367,7 +437,8 @@ void csvDemandReader() throws IOException { private static void createDemandAndCheckCarrier(Path carrierCSVLocation, Scenario scenario, FreightCarriersConfigGroup freightCarriersConfigGroup, ShpOptions.Index indexShape, Path demandCSVLocation, String shapeCategory, - Population population) throws IOException { + Population population, Boolean combineSimilarJobs) throws IOException { + JobDurationCalculator jobDurationCalculator = new DefaultJobDurationCalculator(); // run methods Set allNewCarrierInformation = CarrierReaderFromCSV .readCarrierInformation(carrierCSVLocation); @@ -375,8 +446,8 @@ private static void createDemandAndCheckCarrier(Path carrierCSVLocation, Scenari indexShape, 1, null); Set demandInformation = DemandReaderFromCSV.readDemandInformation(demandCSVLocation); DemandReaderFromCSV.checkNewDemand(scenario, demandInformation, indexShape, shapeCategory); - DemandReaderFromCSV.createDemandForCarriers(scenario, indexShape, demandInformation, population, false, - null); + DemandReaderFromCSV.createDemandForCarriers(scenario, indexShape, demandInformation, population, combineSimilarJobs, + null, jobDurationCalculator); Assertions.assertEquals(3, CarriersUtils.getCarriers(scenario).getCarriers().size()); Assertions.assertTrue( CarriersUtils.getCarriers(scenario).getCarriers().containsKey(Id.create("testCarrier1", Carrier.class))); @@ -491,4 +562,89 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement2_pickup").size()); Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement2_delivery").size()); } + + /** + * Results after combing jobs. + * + * @param scenario the scenario + * @param network the network + * @param indexShape the index of the shape + */ + private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Network network, ShpOptions.Index indexShape) { + Carrier testCarrier1 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier1", Carrier.class)); + Assertions.assertEquals(8, testCarrier1.getServices().size()); + Assertions.assertEquals(0, testCarrier1.getShipments().size()); + Object2IntMap countServicesWithCertainDemand = new Object2IntOpenHashMap<>(); + Map> locationsPerServiceElement = new HashMap<>(); + int countDemand = 0; + for (CarrierService service : testCarrier1.getServices().values()) { + countServicesWithCertainDemand.merge((Integer) service.getCapacityDemand(), 1, Integer::sum); + countDemand = countDemand + service.getCapacityDemand(); + if (service.getCapacityDemand() == 0) { + Assertions.assertEquals(180, service.getServiceDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(3000, 13000), service.getServiceStartTimeWindow()); + locationsPerServiceElement.computeIfAbsent("serviceElement1", (k) -> new HashSet<>()) + .add(service.getLocationLinkId().toString()); + } else { + Assertions.assertEquals(service.getCapacityDemand() * 100, service.getServiceDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); + locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) + .add(service.getLocationLinkId().toString()); + } + } + Assertions.assertEquals(12, countDemand); + Assertions.assertEquals(4, countServicesWithCertainDemand.getInt(0)); + Assertions.assertEquals(4, locationsPerServiceElement.get("serviceElement1").size()); + for (String locationsOfServiceElement : locationsPerServiceElement.get("serviceElement1")) { + Link link = network.getLinks().get(Id.createLinkId(locationsOfServiceElement)); + Assertions.assertTrue( + FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, null, null)); + Assertions.assertFalse(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area1" }, null)); + Assertions.assertTrue(FreightDemandGenerationUtils.checkPositionInShape(link, null, indexShape, + new String[] { "area2" }, null)); + } + Assertions.assertEquals(4, locationsPerServiceElement.get("serviceElement2").size()); + Assertions.assertTrue(locationsPerServiceElement.get("serviceElement2").contains("i(2,0)")); + + // check carrier 2 + Carrier testCarrier2 = CarriersUtils.getCarriers(scenario).getCarriers() + .get(Id.create("testCarrier2", Carrier.class)); + Assertions.assertEquals(0, testCarrier2.getServices().size()); + Assertions.assertEquals(6, testCarrier2.getShipments().size()); + Object2IntMap countShipmentsWithCertainDemand = new Object2IntOpenHashMap<>(); + Map> locationsPerShipmentElement = new HashMap<>(); + countDemand = 0; + for (CarrierShipment shipment : testCarrier2.getShipments().values()) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getSize(), 1, Integer::sum); + countDemand = countDemand + shipment.getSize(); + if (shipment.getSize() == 0) { + Assertions.assertEquals(300, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(350, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } else { + Assertions.assertEquals(shipment.getSize() * 200, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(shipment.getSize() * 200, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryTimeWindow()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) + .add(shipment.getFrom().toString()); + locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) + .add(shipment.getTo().toString()); + } + } + Assertions.assertEquals(15, countDemand); + Assertions.assertEquals(4, countShipmentsWithCertainDemand.getInt(0)); + Assertions.assertEquals(4, locationsPerShipmentElement.get("ShipmentElement1_pickup").size()); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement1_delivery").size()); + Assertions.assertTrue(locationsPerShipmentElement.get("ShipmentElement1_delivery").contains("i(2,0)")); + Assertions.assertEquals(1, locationsPerShipmentElement.get("ShipmentElement2_pickup").size()); + Assertions.assertEquals(2, locationsPerShipmentElement.get("ShipmentElement2_delivery").size()); + } } diff --git a/contribs/av/pom.xml b/contribs/av/pom.xml index 1536e9e78ef..590c8f7e7a1 100644 --- a/contribs/av/pom.xml +++ b/contribs/av/pom.xml @@ -16,19 +16,19 @@ org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} compile org.matsim.contrib taxi - 2025.0-SNAPSHOT + ${project.parent.version} compile org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} compile diff --git a/contribs/bicycle/pom.xml b/contribs/bicycle/pom.xml index f3ffdc96601..9bd3a41df5e 100644 --- a/contribs/bicycle/pom.xml +++ b/contribs/bicycle/pom.xml @@ -23,7 +23,7 @@ org.matsim.contrib osm - 2025.0-SNAPSHOT + ${project.parent.version} compile diff --git a/contribs/cadytsIntegration/pom.xml b/contribs/cadytsIntegration/pom.xml index 2d4b716db7e..5fba4fc8e57 100644 --- a/contribs/cadytsIntegration/pom.xml +++ b/contribs/cadytsIntegration/pom.xml @@ -17,7 +17,7 @@ org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} 2012 diff --git a/contribs/carsharing/pom.xml b/contribs/carsharing/pom.xml index 2580047b892..54eb37ac992 100644 --- a/contribs/carsharing/pom.xml +++ b/contribs/carsharing/pom.xml @@ -12,7 +12,7 @@ org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/commercialTrafficApplications/pom.xml b/contribs/commercialTrafficApplications/pom.xml index 2d6f1061274..4804f34b6d9 100644 --- a/contribs/commercialTrafficApplications/pom.xml +++ b/contribs/commercialTrafficApplications/pom.xml @@ -14,13 +14,13 @@ org.matsim.contrib freight - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/commercialTrafficApplications/src/test/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/TestScenarioGeneration.java b/contribs/commercialTrafficApplications/src/test/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/TestScenarioGeneration.java index 1d6b845a665..601038f2f73 100644 --- a/contribs/commercialTrafficApplications/src/test/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/TestScenarioGeneration.java +++ b/contribs/commercialTrafficApplications/src/test/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/TestScenarioGeneration.java @@ -126,8 +126,6 @@ private static CarrierVehicle getLightVehicle(Id id, VehicleType type, Id zones = new IdMap<>(Zone.class); - private final IdMap> zoneToLinksMap = new IdMap<>(Zone.class); + private final Map> index2Links; private final Network network; @@ -76,6 +77,7 @@ public SquareGridZoneSystem(Network network, double cellSize, boolean filterByNe this.rows = Math.max(1, (int) Math.ceil((maxY - minY) / cellSize)); this.cols = Math.max(1, (int)Math.ceil((maxX - minX) / cellSize)); this.internalZones = new Zone[rows * cols +1]; + this.index2Links = getIndexToLink(network); if(filterByNetwork) { network.getLinks().values().forEach(l -> getOrCreateZone(l.getToNode().getCoord())); @@ -111,7 +113,7 @@ public Optional getZoneForCoord(Coord coord) { @Override public List getLinksForZoneId(Id zone) { - return zoneToLinksMap.get(zone); + return this.index2Links.get(Integer.parseInt(zone.toString())); } private Optional getOrCreateZone(Coord coord) { @@ -126,13 +128,6 @@ private Optional getOrCreateZone(Coord coord) { if(zoneFilter.test(zone)) { internalZones[index] = zone; zones.put(zone.getId(), zone); - - for (Link link : network.getLinks().values()) { - if (getIndex(link.getToNode().getCoord()) == index) { - List links = zoneToLinksMap.computeIfAbsent(zone.getId(), zoneId -> new ArrayList<>()); - links.add(link); - } - } } else { return Optional.empty(); } @@ -140,6 +135,11 @@ private Optional getOrCreateZone(Coord coord) { return Optional.of(zone); } + private Map> getIndexToLink(Network network) { + return network.getLinks().values().stream() + .collect(Collectors.groupingBy(link -> getIndex(link.getToNode().getCoord()))); + } + private PreparedPolygon getGeometry(int r, int c) { List coords = new ArrayList<>(); coords.add(new Coord(minX + c * cellSize, minY + r * cellSize)); diff --git a/contribs/decongestion/pom.xml b/contribs/decongestion/pom.xml index 62d2f912040..992bd7c6a12 100644 --- a/contribs/decongestion/pom.xml +++ b/contribs/decongestion/pom.xml @@ -8,7 +8,7 @@ org.matsim.contrib otfvis - ${parent.version} + ${project.parent.version} test diff --git a/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java b/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java new file mode 100644 index 00000000000..bebc456de8f --- /dev/null +++ b/contribs/discrete_mode_choice/src/test/java/org/matsim/contrib/discrete_mode_choice/DeterminismTest.java @@ -0,0 +1,55 @@ +package org.matsim.contrib.discrete_mode_choice; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.contribs.discrete_mode_choice.modules.DiscreteModeChoiceModule; +import org.matsim.contribs.discrete_mode_choice.modules.ModeAvailabilityModule; +import org.matsim.contribs.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.misc.CRCChecksum; +import org.matsim.examples.ExamplesUtils; + +import java.net.URL; + +public class DeterminismTest { + private static void runConfig(URL configUrl, String outputDirectory) { + Config config = ConfigUtils.loadConfig(configUrl, new DiscreteModeChoiceConfigGroup()); + config.controller().setLastIteration(2); + config.controller().setOutputDirectory(outputDirectory); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + Scenario scenario = ScenarioUtils.createScenario(config); + ScenarioUtils.loadScenario(scenario); + Controler controler = new Controler(scenario); + controler.addOverridingModule(new DiscreteModeChoiceModule()); + controler.addOverridingModule(new ModeAvailabilityModule()); + controler.run(); + } + + + @Test + public void testSimulationDeterminism() { + Logger logger = LogManager.getLogger(DeterminismTest.class); + logger.info("Testing simulation determinism"); + URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("siouxfalls-2014"), "config_default.xml"); + int samples = 10; + for(int i=0; i org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib ev - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib informed-mode-choice - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib simwrapper - 2025.0-SNAPSHOT + ${project.parent.version} @@ -45,7 +45,7 @@ org.matsim.contrib vsp - 2025.0-SNAPSHOT + ${project.parent.version} test diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java index 00dabefc585..90773153294 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java @@ -59,6 +59,7 @@ import org.matsim.contrib.dvrp.schedule.ScheduleTimingUpdater; import org.matsim.contrib.dvrp.vrpagent.VrpAgentLogic; import org.matsim.contrib.dvrp.vrpagent.VrpLegFactory; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.infrastructure.ChargingInfrastructure; import org.matsim.contrib.ev.infrastructure.ChargingInfrastructureUtils; import org.matsim.core.api.experimental.events.EventsManager; @@ -116,7 +117,8 @@ protected void configureQSim() { public EmptyVehicleChargingScheduler get() { var taskFactory = getModalInstance(DrtTaskFactory.class); var chargingInfrastructure = getModalInstance(ChargingInfrastructure.class); - return new EmptyVehicleChargingScheduler(timer, taskFactory, chargingInfrastructure); + ChargingStrategy.Factory chargingStrategyFactory = getModalInstance(ChargingStrategy.Factory.class); + return new EmptyVehicleChargingScheduler(timer, taskFactory, chargingInfrastructure, chargingStrategyFactory); } }).asEagerSingleton(); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenario.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenario.java index 741c4047786..915c5efa220 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenario.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/RunEDrtScenario.java @@ -22,15 +22,17 @@ import java.net.URL; +import org.matsim.contrib.drt.extension.edrt.optimizer.EDrtVehicleDataEntryFactory.EDrtVehicleDataEntryFactoryProvider; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; -import org.matsim.contrib.drt.extension.edrt.optimizer.EDrtVehicleDataEntryFactory.EDrtVehicleDataEntryFactoryProvider; +import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.ev.EvConfigGroup; import org.matsim.contrib.ev.charging.ChargeUpToMaxSocStrategy; import org.matsim.contrib.ev.charging.ChargingLogic; import org.matsim.contrib.ev.charging.ChargingPower; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithQueueingAndAssignmentLogic; import org.matsim.contrib.ev.charging.FixedSpeedCharging; import org.matsim.contrib.ev.temperature.TemperatureService; @@ -40,6 +42,8 @@ import org.matsim.core.controler.Controler; import org.matsim.vis.otfvis.OTFVisConfigGroup; +import com.google.inject.Key; + /** * @author Michal Maciejewski (michalm) */ @@ -69,10 +73,13 @@ public void install() { controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bind(ChargingLogic.Factory.class).toProvider(new ChargingWithQueueingAndAssignmentLogic.FactoryProvider( - charger -> new ChargeUpToMaxSocStrategy(charger, MAX_RELATIVE_SOC))); + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingAndAssignmentLogic.Factory.class); bind(ChargingPower.Factory.class).toInstance(ev -> new FixedSpeedCharging(ev, CHARGING_SPEED_FACTOR)); bind(TemperatureService.class).toInstance(linkId -> TEMPERATURE); + + for (DrtConfigGroup drtCfg : MultiModeDrtConfigGroup.get(config).getModalElements()) { + bind(Key.get(ChargingStrategy.Factory.class, DvrpModes.mode(drtCfg.mode))).toInstance(new ChargeUpToMaxSocStrategy.Factory(MAX_RELATIVE_SOC)); + } } }); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtChargingTask.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtChargingTask.java index e2dcfdba751..95b36f65889 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtChargingTask.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtChargingTask.java @@ -20,6 +20,7 @@ package org.matsim.contrib.drt.extension.edrt.schedule; import org.matsim.contrib.drt.schedule.DrtTaskType; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; import org.matsim.contrib.evrp.ChargingTaskImpl; @@ -27,7 +28,7 @@ public class EDrtChargingTask extends ChargingTaskImpl { public static final DrtTaskType TYPE = new DrtTaskType("CHARGING"); - public EDrtChargingTask(double beginTime, double endTime, Charger charger, ElectricVehicle ev, double totalEnergy) { - super(TYPE, beginTime, endTime, charger, ev, totalEnergy); + public EDrtChargingTask(double beginTime, double endTime, Charger charger, ElectricVehicle ev, double totalEnergy, ChargingStrategy chargingStrategy) { + super(TYPE, beginTime, endTime, charger, ev, totalEnergy, chargingStrategy); } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtTaskFactoryImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtTaskFactoryImpl.java index 4ec83dc7a15..d99fdc6fbfe 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtTaskFactoryImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/schedule/EDrtTaskFactoryImpl.java @@ -26,6 +26,7 @@ import org.matsim.contrib.dvrp.schedule.DefaultStayTask; import org.matsim.contrib.evrp.EvDvrpVehicle; import org.matsim.contrib.evrp.VrpPathEnergyConsumptions; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; @@ -59,8 +60,8 @@ public DefaultStayTask createInitialTask(DvrpVehicle vehicle, double beginTime, } public EDrtChargingTask createChargingTask(DvrpVehicle vehicle, double beginTime, double endTime, Charger charger, - double totalEnergy) { + double totalEnergy, ChargingStrategy chargingStrategy) { return new EDrtChargingTask(beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), - totalEnergy); + totalEnergy, chargingStrategy); } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/scheduler/EmptyVehicleChargingScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/scheduler/EmptyVehicleChargingScheduler.java index eea29745e80..2df2ed57028 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/scheduler/EmptyVehicleChargingScheduler.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/scheduler/EmptyVehicleChargingScheduler.java @@ -47,10 +47,12 @@ public class EmptyVehicleChargingScheduler { private final MobsimTimer timer; private final EDrtTaskFactoryImpl taskFactory; private final Map, List> linkToChargersMap; + private final ChargingStrategy.Factory chargingStrategyFactory; public EmptyVehicleChargingScheduler(MobsimTimer timer, DrtTaskFactory taskFactory, - ChargingInfrastructure chargingInfrastructure) { + ChargingInfrastructure chargingInfrastructure, ChargingStrategy.Factory chargingStrategyFactory) { this.timer = timer; + this.chargingStrategyFactory = chargingStrategyFactory; this.taskFactory = (EDrtTaskFactoryImpl)taskFactory; linkToChargersMap = chargingInfrastructure.getChargers() .values() @@ -68,15 +70,16 @@ public void chargeVehicle(DvrpVehicle vehicle) { // Empty charger or at least smallest queue charger Charger charger = freeCharger.orElseGet(() -> chargers.stream().min(Comparator.comparingInt(e -> e.getLogic().getQueuedVehicles().size())).orElseThrow()); ElectricVehicle ev = ((EvDvrpVehicle)vehicle).getElectricVehicle(); - if (!charger.getLogic().getChargingStrategy().isChargingCompleted(ev)) { - chargeVehicleImpl(vehicle, charger); + ChargingStrategy strategy = chargingStrategyFactory.createStrategy(charger.getSpecification(), ev); + if (!strategy.isChargingCompleted()) { + chargeVehicleImpl(vehicle, ev, charger, strategy); } } } - private void chargeVehicleImpl(DvrpVehicle vehicle, Charger charger) { + private void chargeVehicleImpl(DvrpVehicle vehicle, ElectricVehicle ev, Charger charger, ChargingStrategy strategy) { Schedule schedule = vehicle.getSchedule(); DrtStayTask stayTask = (DrtStayTask)schedule.getCurrentTask(); if (stayTask.getTaskIdx() != schedule.getTaskCount() - 1) { @@ -86,19 +89,17 @@ private void chargeVehicleImpl(DvrpVehicle vehicle, Charger charger) { // add CHARGING TASK double beginTime = stayTask.getEndTime(); - ChargingStrategy strategy = charger.getLogic().getChargingStrategy(); - ElectricVehicle ev = ((EvDvrpVehicle)vehicle).getElectricVehicle(); - double totalEnergy = -strategy.calcRemainingEnergyToCharge(ev); + double totalEnergy = -strategy.calcRemainingEnergyToCharge(); - double chargingDuration = Math.min(strategy.calcRemainingTimeToCharge(ev), + double chargingDuration = Math.min(strategy.calcRemainingTimeToCharge(), vehicle.getServiceEndTime() - beginTime); if (chargingDuration <= 0) { return;// no charging } double endTime = beginTime + chargingDuration; - schedule.addTask(taskFactory.createChargingTask(vehicle, beginTime, endTime, charger, totalEnergy)); - ((ChargingWithAssignmentLogic)charger.getLogic()).assignVehicle(ev); + schedule.addTask(taskFactory.createChargingTask(vehicle, beginTime, endTime, charger, totalEnergy, strategy)); + ((ChargingWithAssignmentLogic)charger.getLogic()).assignVehicle(ev, strategy); // append STAY schedule.addTask(taskFactory.createStayTask(vehicle, endTime, vehicle.getServiceEndTime(), charger.getLink())); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/dispatcher/EDrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/dispatcher/EDrtShiftDispatcherImpl.java index ace6e8d66e0..b3469edbc2e 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/dispatcher/EDrtShiftDispatcherImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/dispatcher/EDrtShiftDispatcherImpl.java @@ -42,15 +42,18 @@ public class EDrtShiftDispatcherImpl implements DrtShiftDispatcher { private final Fleet fleet; + private final ChargingStrategy.Factory chargingStrategyFactory; + public EDrtShiftDispatcherImpl(EShiftTaskScheduler shiftTaskScheduler, ChargingInfrastructure chargingInfrastructure, ShiftsParams drtShiftParams, OperationFacilities operationFacilities, - DrtShiftDispatcher delegate, Fleet fleet) { + DrtShiftDispatcher delegate, Fleet fleet, ChargingStrategy.Factory chargingStrategyFactory) { this.shiftTaskScheduler = shiftTaskScheduler; this.chargingInfrastructure = chargingInfrastructure; this.drtShiftParams = drtShiftParams; this.operationFacilities = operationFacilities; this.delegate = delegate; this.fleet = fleet; + this.chargingStrategyFactory = chargingStrategyFactory; } @Override @@ -112,18 +115,18 @@ private void checkChargingAtHub(double timeStep) { if (selectedCharger.isPresent()) { Charger selectedChargerImpl = selectedCharger.get(); - ChargingStrategy chargingStrategy = selectedChargerImpl.getLogic().getChargingStrategy(); - if (!chargingStrategy.isChargingCompleted(electricVehicle)) { + ChargingStrategy chargingStrategy = chargingStrategyFactory.createStrategy(selectedChargerImpl.getSpecification(), electricVehicle); + if (!chargingStrategy.isChargingCompleted()) { final double waitTime = ChargingEstimations .estimateMaxWaitTimeForNextVehicle(selectedChargerImpl); final double chargingTime = chargingStrategy - .calcRemainingTimeToCharge(electricVehicle); + .calcRemainingTimeToCharge(); double energy = -chargingStrategy - .calcRemainingEnergyToCharge(electricVehicle); + .calcRemainingEnergyToCharge(); final double endTime = timeStep + waitTime + chargingTime; if (endTime < currentTask.getEndTime()) { shiftTaskScheduler.chargeAtHub((WaitForShiftTask) currentTask, eShiftVehicle, - electricVehicle, selectedChargerImpl, timeStep, endTime, energy); + electricVehicle, selectedChargerImpl, timeStep, endTime, energy, chargingStrategy); } } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java index 32bf96909bf..95b6feb85e3 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/run/ShiftEDrtModeOptimizerQSimModule.java @@ -34,6 +34,7 @@ import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.contrib.dvrp.vrpagent.VrpAgentLogic; import org.matsim.contrib.dvrp.vrpagent.VrpLegFactory; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.infrastructure.ChargingInfrastructure; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.mobsim.framework.MobsimTimer; @@ -72,7 +73,7 @@ protected void configureQSim() { drtShiftParams, new EDrtShiftStartLogic(new DefaultShiftStartLogic()), new EDrtAssignShiftToVehicleLogic(new DefaultAssignShiftToVehicleLogic(drtShiftParams), drtShiftParams), getter.getModal(ShiftScheduler.class)), - getter.getModal(Fleet.class))) + getter.getModal(Fleet.class), getter.getModal(ChargingStrategy.Factory.class))) ).asEagerSingleton(); bindModal(VehicleEntry.EntryFactory.class).toProvider(modalProvider(getter -> @@ -87,7 +88,8 @@ drtShiftParams, new EDrtShiftStartLogic(new DefaultShiftStartLogic()), getter -> new EShiftTaskScheduler(getter.getModal(Network.class), getter.getModal(TravelTime.class), getter.getModal(TravelDisutilityFactory.class).createTravelDisutility(getter.getModal(TravelTime.class)), getter.get(MobsimTimer.class), getter.getModal(ShiftDrtTaskFactory.class), drtShiftParams, getter.getModal(ChargingInfrastructure.class), - getter.getModal(OperationFacilities.class), getter.getModal(Fleet.class)) + getter.getModal(OperationFacilities.class), getter.getModal(Fleet.class), + getter.getModal(ChargingStrategy.Factory.class)) )).asEagerSingleton(); // See EDrtModeOptimizerQSimModule diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/schedule/ShiftEDrtTaskFactoryImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/schedule/ShiftEDrtTaskFactoryImpl.java index b7c2657f1bf..c74713d9f73 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/schedule/ShiftEDrtTaskFactoryImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/schedule/ShiftEDrtTaskFactoryImpl.java @@ -19,6 +19,7 @@ import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.path.VrpPathWithTravelData; import org.matsim.contrib.dvrp.schedule.DefaultStayTask; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.infrastructure.Charger; import org.matsim.contrib.evrp.ChargingTask; import org.matsim.contrib.evrp.ChargingTaskImpl; @@ -99,21 +100,21 @@ public WaitForShiftTask createWaitForShiftStayTask(DvrpVehicle vehicle, double b public WaitForShiftTask createChargingWaitForShiftStayTask(DvrpVehicle vehicle, double beginTime, double endTime, Link link, OperationFacility facility, - double totalEnergy, Charger charger) { - ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy); + double totalEnergy, Charger charger, ChargingStrategy strategy) { + ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy, strategy); return new EDrtWaitForShiftTask(beginTime, endTime, link, totalEnergy, facility, chargingTask); } public EDrtShiftBreakTaskImpl createChargingShiftBreakTask(DvrpVehicle vehicle, double beginTime, double endTime, Link link, - DrtShiftBreak shiftBreak, Charger charger, double totalEnergy, OperationFacility facility) { - ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy); + DrtShiftBreak shiftBreak, Charger charger, double totalEnergy, OperationFacility facility, ChargingStrategy strategy) { + ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy, strategy); return new EDrtShiftBreakTaskImpl(beginTime, endTime, link, shiftBreak, totalEnergy, chargingTask, facility); } public ShiftChangeOverTask createChargingShiftChangeoverTask(DvrpVehicle vehicle, double beginTime, double endTime, Link link, Charger charger, double totalEnergy, - DrtShift shift, OperationFacility facility) { - ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy); + DrtShift shift, OperationFacility facility, ChargingStrategy strategy) { + ChargingTask chargingTask = new ChargingTaskImpl(EDrtChargingTask.TYPE, beginTime, endTime, charger, ((EvDvrpVehicle)vehicle).getElectricVehicle(), totalEnergy, strategy); return new EDrtShiftChangeoverTaskImpl(beginTime, endTime, link, shift, totalEnergy, chargingTask, facility); } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java index 9c5a7172282..2bc42cc1925 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java @@ -1,5 +1,11 @@ package org.matsim.contrib.drt.extension.operations.eshifts.scheduler; +import static org.matsim.contrib.drt.schedule.DrtTaskBaseType.DRIVE; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -12,7 +18,11 @@ import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; import org.matsim.contrib.drt.extension.operations.shifts.config.ShiftsParams; import org.matsim.contrib.drt.extension.operations.shifts.fleet.ShiftDvrpVehicle; -import org.matsim.contrib.drt.extension.operations.shifts.schedule.*; +import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftBreakTask; +import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftChangeOverTask; +import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftDrtTaskFactory; +import org.matsim.contrib.drt.extension.operations.shifts.schedule.ShiftSchedules; +import org.matsim.contrib.drt.extension.operations.shifts.schedule.WaitForShiftTask; import org.matsim.contrib.drt.extension.operations.shifts.scheduler.ShiftTaskScheduler; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShift; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftBreak; @@ -23,11 +33,16 @@ import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.path.VrpPathWithTravelData; import org.matsim.contrib.dvrp.path.VrpPaths; -import org.matsim.contrib.dvrp.schedule.*; +import org.matsim.contrib.dvrp.schedule.DriveTask; +import org.matsim.contrib.dvrp.schedule.Schedule; +import org.matsim.contrib.dvrp.schedule.Schedules; +import org.matsim.contrib.dvrp.schedule.StayTask; +import org.matsim.contrib.dvrp.schedule.Task; import org.matsim.contrib.dvrp.tracker.OnlineDriveTaskTracker; import org.matsim.contrib.dvrp.util.LinkTimePair; import org.matsim.contrib.ev.charging.BatteryCharging; import org.matsim.contrib.ev.charging.ChargingEstimations; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithAssignmentLogic; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; @@ -38,12 +53,7 @@ import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.TravelDisutility; import org.matsim.core.router.util.TravelTime; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static org.matsim.contrib.drt.schedule.DrtTaskBaseType.DRIVE; +import org.matsim.core.utils.collections.Tuple; /** * @author nkuehnel / MOIA @@ -61,10 +71,12 @@ public class EShiftTaskScheduler implements ShiftTaskScheduler { private final Network network; private final ChargingInfrastructure chargingInfrastructure; + private final ChargingStrategy.Factory chargingStrategyFactory; public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutility travelDisutility, MobsimTimer timer, ShiftDrtTaskFactory taskFactory, ShiftsParams shiftsParams, - ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet) { + ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet, + ChargingStrategy.Factory chargingStrategyFactory) { this.travelTime = travelTime; this.timer = timer; this.taskFactory = taskFactory; @@ -72,6 +84,7 @@ public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutil this.shiftsParams = shiftsParams; this.router = new SpeedyALTFactory().createPathCalculator(network, travelDisutility, travelTime); this.chargingInfrastructure = chargingInfrastructure; + this.chargingStrategyFactory = chargingStrategyFactory; } public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFacility, DrtShift shift) { @@ -169,23 +182,25 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do ShiftBreakTask dropoffStopTask; ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); - Optional charger = charge(breakFacility, ev); + Optional charger = charge(breakFacility, ev); if (charger.isPresent()) { - final Charger chargerImpl = charger.get(); + final ChargerWithStrategy chargerImpl = charger.get(); final double waitTime = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(chargerImpl); + .estimateMaxWaitTimeForNextVehicle(chargerImpl.charger); if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() > shiftsParams.chargeDuringBreakThreshold || waitTime > 0) { dropoffStopTask = taskFactory.createShiftBreakTask(vehicle, startTime, endTime, link, shiftBreak, breakFacility); } else { - double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.getSpecification(), endTime - startTime); + ChargingStrategy strategy = chargingStrategyFactory.createStrategy(chargerImpl.charger.getSpecification(), ev); + + double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.charger.getSpecification(), endTime - startTime); double totalEnergy = -energyCharge; - ((ChargingWithAssignmentLogic) chargerImpl.getLogic()).assignVehicle(ev); + ((ChargingWithAssignmentLogic) chargerImpl.charger.getLogic()).assignVehicle(ev, strategy); dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftBreakTask(vehicle, - startTime, endTime, link, shiftBreak, chargerImpl, totalEnergy, breakFacility); + startTime, endTime, link, shiftBreak, chargerImpl.charger, totalEnergy, breakFacility, chargerImpl.strategy); } } else { dropoffStopTask = taskFactory.createShiftBreakTask(vehicle, startTime, @@ -202,7 +217,7 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do shiftBreak.schedule(Math.min(latestDetourArrival, latestTimeConstraintArrival)); } - private Optional charge(OperationFacility breakFacility, ElectricVehicle electricVehicle) { + private Optional charge(OperationFacility breakFacility, ElectricVehicle electricVehicle) { if (chargingInfrastructure != null) { List> chargerIds = breakFacility.getChargers(); if (!chargerIds.isEmpty()) { @@ -218,16 +233,19 @@ private Optional charge(OperationFacility breakFacility, ElectricVehicl return Double.compare(waitTime, waitTime2); }); if (selectedCharger.isPresent()) { - if (selectedCharger.get().getLogic().getChargingStrategy().isChargingCompleted(electricVehicle)) { + ChargingStrategy strategy = chargingStrategyFactory.createStrategy(selectedCharger.get().getSpecification(), electricVehicle); + if (strategy.isChargingCompleted()) { return Optional.empty(); } + return Optional.of(new ChargerWithStrategy(selectedCharger.get(), strategy)); } - return selectedCharger; } } return Optional.empty(); } + private record ChargerWithStrategy(Charger charger, ChargingStrategy strategy) {} + public void relocateForShiftChange(DvrpVehicle vehicle, Link link, DrtShift shift, OperationFacility breakFacility) { final Schedule schedule = vehicle.getSchedule(); @@ -318,24 +336,24 @@ private void appendShiftChange(DvrpVehicle vehicle, DrtShift shift, OperationFac // append SHIFT_CHANGEOVER task ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); - Optional charger = charge(breakFacility, ev); + Optional charger = charge(breakFacility, ev); if (charger.isPresent()) { - Charger chargingImpl = charger.get(); - + ChargerWithStrategy chargingImpl = charger.get(); + final double waitTime = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(chargingImpl); + .estimateMaxWaitTimeForNextVehicle(chargingImpl.charger); if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() < shiftsParams.chargeDuringBreakThreshold - || ((ChargingWithAssignmentLogic) chargingImpl.getLogic()).getAssignedVehicles().contains(ev) + || ((ChargingWithAssignmentLogic) chargingImpl.charger.getLogic()).isAssigned(ev) || waitTime > 0) { dropoffStopTask = taskFactory.createShiftChangeoverTask(vehicle, startTime, endTime, link, shift, breakFacility); } else { - double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.getSpecification(), endTime - startTime); + double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.charger.getSpecification(), endTime - startTime); double totalEnergy = -energyCharge; - ((ChargingWithAssignmentLogic) chargingImpl.getLogic()).assignVehicle(ev); + ((ChargingWithAssignmentLogic) chargingImpl.charger.getLogic()).assignVehicle(ev, chargingImpl.strategy); dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftChangeoverTask(vehicle, - startTime, endTime, link, chargingImpl, totalEnergy, shift, breakFacility); + startTime, endTime, link, chargingImpl.charger, totalEnergy, shift, breakFacility, chargingImpl.strategy); } } else { dropoffStopTask = taskFactory.createShiftChangeoverTask(vehicle, startTime, @@ -470,12 +488,12 @@ private void updateShiftChangeImpl(DvrpVehicle vehicle, VrpPathWithTravelData vr public void chargeAtHub(WaitForShiftTask currentTask, ShiftDvrpVehicle vehicle, ElectricVehicle electricVehicle, Charger charger, double beginTime, - double endTime, double energy) { + double endTime, double energy, ChargingStrategy strategy) { final double initialEndTime = currentTask.getEndTime(); currentTask.setEndTime(beginTime); - ((ChargingWithAssignmentLogic) charger.getLogic()).assignVehicle(electricVehicle); + ((ChargingWithAssignmentLogic) charger.getLogic()).assignVehicle(electricVehicle, strategy); final WaitForShiftTask chargingWaitForShiftTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingWaitForShiftStayTask(vehicle, - beginTime, endTime, currentTask.getLink(), currentTask.getFacility(), energy, charger); + beginTime, endTime, currentTask.getLink(), currentTask.getFacility(), energy, charger, strategy); final WaitForShiftTask waitForShiftTask = taskFactory.createWaitForShiftStayTask(vehicle, endTime, initialEndTime, currentTask.getLink(), currentTask.getFacility()); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/eshifts/run/RunEShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/eshifts/run/RunEShiftDrtScenarioIT.java index a137d932fe5..a65091c6102 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/eshifts/run/RunEShiftDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/eshifts/run/RunEShiftDrtScenarioIT.java @@ -17,6 +17,7 @@ import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.ev.EvConfigGroup; import org.matsim.contrib.ev.charging.*; import org.matsim.contrib.ev.temperature.TemperatureService; @@ -32,6 +33,8 @@ import org.matsim.core.controler.OutputDirectoryHierarchy; import org.matsim.examples.ExamplesUtils; +import com.google.inject.Key; + import java.util.HashSet; import java.util.Set; @@ -177,8 +180,8 @@ void test() { controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bind(ChargingLogic.Factory.class).toProvider(new ChargingWithQueueingAndAssignmentLogic.FactoryProvider( - charger -> new ChargeUpToMaxSocStrategy(charger, MAX_RELATIVE_SOC))); + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingAndAssignmentLogic.Factory.class); + bind(Key.get(ChargingStrategy.Factory.class, DvrpModes.mode(drtConfigGroup.mode))).toInstance(new ChargeUpToMaxSocStrategy.Factory(MAX_RELATIVE_SOC)); bind(ChargingPower.Factory.class).toInstance(FastThenSlowCharging::new); bind(TemperatureService.class).toInstance(linkId -> TEMPERATURE); } diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java index 61e3a64a97a..e4286bed31c 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/run/RunPrebookingShiftDrtScenarioIT.java @@ -280,8 +280,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(5000); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 1800.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 5000.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 1800.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 5000.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); @@ -295,8 +295,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(5000); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 900.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 5005.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 900.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 5005.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); @@ -310,8 +310,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(5000); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 4000.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 5000.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 4000.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 5000.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); @@ -325,8 +325,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(8000); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 4000.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 11000.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 4000.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 11000.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); @@ -340,8 +340,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(6000.); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 4000.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 6000.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 4000.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 6000.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); @@ -355,8 +355,8 @@ private void preparePopulation(Scenario scenario) { Plan plan = factory.createPlan(); Activity start = factory.createActivityFromLinkId("start", Id.createLinkId(1)); start.setEndTime(6500.); - start.getAttributes().putAttribute("prebooking:submissionTime" + "drt", 4000.); - start.getAttributes().putAttribute("prebooking:plannedDepartureTime" + "drt", 6500.); + AttributeBasedPrebookingLogic.setSubmissionTime("drt", start, 4000.0); + AttributeBasedPrebookingLogic.setPlannedDepartureTime("drt", start, 6500.0); plan.addActivity(start); plan.addLeg(factory.createLeg("drt")); plan.addActivity(factory.createActivityFromLinkId("end", Id.createLinkId(2))); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/services/RunEDrtWithServicesScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/services/RunEDrtWithServicesScenarioIT.java index b16dca56807..da8b28c6c82 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/services/RunEDrtWithServicesScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/services/RunEDrtWithServicesScenarioIT.java @@ -14,6 +14,7 @@ import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.ev.charging.*; import org.matsim.contrib.ev.temperature.TemperatureService; import org.matsim.core.config.Config; @@ -22,6 +23,8 @@ import org.matsim.core.controler.Controler; import org.matsim.testcases.MatsimTestUtils; +import com.google.inject.Key; + public class RunEDrtWithServicesScenarioIT { public static final double MINIMUM_RELATIVE_SOC = 0.2; public static final double MAX_SOC = 1.0; @@ -77,7 +80,8 @@ public void install() { controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bind(ChargingLogic.Factory.class).toProvider(new ChargingWithQueueingAndAssignmentLogic.FactoryProvider(charger -> new ChargeUpToMaxSocStrategy(charger, MAX_SOC))); + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingAndAssignmentLogic.Factory.class); + bind(Key.get(ChargingStrategy.Factory.class, DvrpModes.mode(drtConfigGroup.mode))).toInstance(new ChargeUpToMaxSocStrategy.Factory(MAX_SOC)); bind(ChargingPower.Factory.class).toInstance(ev -> new FixedSpeedCharging(ev, RELATIVE_SPEED)); bind(TemperatureService.class).toInstance(linkId -> TEMPERATURE); } diff --git a/contribs/drt/pom.xml b/contribs/drt/pom.xml index 7790f252b3c..99fd9d77ec7 100644 --- a/contribs/drt/pom.xml +++ b/contribs/drt/pom.xml @@ -15,19 +15,19 @@ org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java index 90836e785cc..cee1304544d 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/DrtEventSequenceCollector.java @@ -159,7 +159,10 @@ public List getDrtFares() { } public boolean isCompleted() { - return submitted.getPersonIds().stream().allMatch(personId -> personEvents.get(personId).droppedOff != null); + return submitted.getPersonIds().stream().allMatch(personId -> { + var events = personEvents.get(personId); + return events != null && personEvents.get(personId).droppedOff != null; + }); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java index ce140ce1772..610511c61e2 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/analysis/zonal/DrtZonalWaitTimesAnalyzer.java @@ -37,6 +37,7 @@ import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector; import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector.EventSequence; import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.events.ShutdownEvent; import org.matsim.core.controler.listener.IterationEndsListener; @@ -79,7 +80,7 @@ public void notifyIterationEnds(IterationEndsEvent event) { } public void write(String fileName) { - Map, DescriptiveStatistics> zoneStats = createZonalStats(); + Map, ZonalStatistics> zoneStats = createZonalStats(); BufferedWriter bw = IOUtils.getBufferedWriter(fileName); try { DecimalFormat format = new DecimalFormat(); @@ -90,7 +91,8 @@ public void write(String fileName) { String header = new StringJoiner(delimiter) .add("zone").add("centerX").add("centerY").add("nRequests") .add("sumWaitTime").add("meanWaitTime").add("min").add("max") - .add("p95").add("p90").add("p80").add("p75").add("p50").toString(); + .add("p95").add("p90").add("p80").add("p75").add("p50") + .add("rejections").add("rejectionRate").toString(); bw.append(header); // sorted output SortedSet> zoneIdsAndOutside = new TreeSet<>(zones.getZones().keySet()); @@ -100,7 +102,8 @@ public void write(String fileName) { Zone drtZone = zones.getZones().get(zoneId); String centerX = drtZone != null ? String.valueOf(drtZone.getCentroid().getX()) : notAvailableString; String centerY = drtZone != null ? String.valueOf(drtZone.getCentroid().getY()) : notAvailableString; - DescriptiveStatistics stats = zoneStats.get(zoneId); + DescriptiveStatistics stats = zoneStats.get(zoneId).waitStats; + Set> rejections = zoneStats.get(zoneId).rejections; bw.newLine(); bw.append( new StringJoiner(delimiter) @@ -116,7 +119,10 @@ public void write(String fileName) { .add(String.valueOf(stats.getPercentile(90))) .add(String.valueOf(stats.getPercentile(80))) .add(String.valueOf(stats.getPercentile(75))) - .add(String.valueOf(stats.getPercentile(50))).toString() + .add(String.valueOf(stats.getPercentile(50))) + .add(String.valueOf(rejections.size())) + .add(String.valueOf(rejections.size() / (double) (rejections.size() + stats.getN()))) + .toString() ); } bw.flush(); @@ -126,13 +132,15 @@ public void write(String fileName) { } } - private Map, DescriptiveStatistics> createZonalStats() { - Map, DescriptiveStatistics> zoneStats = new IdMap<>(Zone.class); + record ZonalStatistics(DescriptiveStatistics waitStats, Set> rejections){} + + private Map, ZonalStatistics> createZonalStats() { + Map, ZonalStatistics> zoneStats = new IdMap<>(Zone.class); // prepare stats for all zones for (Id zoneId : zones.getZones().keySet()) { - zoneStats.put(zoneId, new DescriptiveStatistics()); + zoneStats.put(zoneId, new ZonalStatistics(new DescriptiveStatistics(), new HashSet<>())); } - zoneStats.put(zoneIdForOutsideOfZonalSystem, new DescriptiveStatistics()); + zoneStats.put(zoneIdForOutsideOfZonalSystem, new ZonalStatistics(new DescriptiveStatistics(), new HashSet<>())); for (EventSequence seq : requestAnalyzer.getPerformedRequestSequences().values()) { for (Map.Entry, EventSequence.PersonEvents> entry : seq.getPersonEvents().entrySet()) { @@ -140,10 +148,17 @@ private Map, DescriptiveStatistics> createZonalStats() { Id zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()) .map(Identifiable::getId).orElse(zoneIdForOutsideOfZonalSystem); double waitTime = entry.getValue().getPickedUp().get() .getTime() - seq.getSubmitted().getTime(); - zoneStats.get(zone).addValue(waitTime); + zoneStats.get(zone).waitStats.addValue(waitTime); } } } + + for (EventSequence seq : requestAnalyzer.getRejectedRequestSequences().values()) { + Id zone = zones.getZoneForLinkId(seq.getSubmitted().getFromLinkId()) + .map(Identifiable::getId).orElse(zoneIdForOutsideOfZonalSystem); + zoneStats.get(zone).rejections.add(seq.getSubmitted().getRequestId()); + } + return zoneStats; } @@ -191,16 +206,19 @@ private Collection convertGeometriesToSimpleFeatures(String targe simpleFeatureBuilder.add("p80", Double.class); simpleFeatureBuilder.add("p75", Double.class); simpleFeatureBuilder.add("p50", Double.class); + simpleFeatureBuilder.add("rejections", Double.class); + simpleFeatureBuilder.add("rejectRate", Double.class); SimpleFeatureBuilder builder = new SimpleFeatureBuilder(simpleFeatureBuilder.buildFeatureType()); Collection features = new ArrayList<>(); - Map, DescriptiveStatistics> zoneStats = createZonalStats(); + Map, ZonalStatistics> zoneStats = createZonalStats(); for (Zone zone : zones.getZones().values()) { - Object[] routeFeatureAttributes = new Object[14]; + Object[] routeFeatureAttributes = new Object[16]; Geometry geometry = zone.getPreparedGeometry() != null ? zone.getPreparedGeometry().getGeometry() : null; - DescriptiveStatistics stats = zoneStats.get(zone.getId()); + DescriptiveStatistics stats = zoneStats.get(zone.getId()).waitStats; + Set> rejections = zoneStats.get(zone.getId()).rejections; routeFeatureAttributes[0] = geometry; routeFeatureAttributes[1] = zone.getId(); routeFeatureAttributes[2] = zone.getCentroid().getX(); @@ -215,6 +233,8 @@ private Collection convertGeometriesToSimpleFeatures(String targe routeFeatureAttributes[11] = stats.getPercentile(80); routeFeatureAttributes[12] = stats.getPercentile(75); routeFeatureAttributes[13] = stats.getPercentile(50); + routeFeatureAttributes[14] = rejections.size(); + routeFeatureAttributes[15] = rejections.size() / (double) (rejections.size() + stats.getN()); try { features.add(builder.buildFeature(zone.getId().toString(), routeFeatureAttributes)); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/constraints/DefaultDrtOptimizationConstraintsSet.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/constraints/DefaultDrtOptimizationConstraintsSet.java index 3ba0a7ce169..fd26a90256a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/constraints/DefaultDrtOptimizationConstraintsSet.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/constraints/DefaultDrtOptimizationConstraintsSet.java @@ -23,34 +23,35 @@ public class DefaultDrtOptimizationConstraintsSet extends DrtOptimizationConstra @Parameter @Comment( - "Defines the maximum allowed absolute detour in seconds. Note that the detour is computed from the latest promised pickup time. " + - "To enable the max detour constraint, maxAllowedPickupDelay has to be specified. maxAbsoluteDetour should not be smaller than 0, " + "Defines the maximum allowed absolute detour in seconds. maxAbsoluteDetour should not be smaller than 0, " + "and should be higher than the offset maxDetourBeta. By default, this limit is disabled (i.e. set to Inf)") @PositiveOrZero public double maxAbsoluteDetour = Double.POSITIVE_INFINITY;// [s] @Parameter @Comment( - "Defines the maximum allowed absolute detour based on the unsharedRideTime. Note that the detour is computed from the latest promised " - + "pickup time. To enable the max detour constraint, maxAllowedPickupDelay has to be specified. A linear combination similar to travel " + "Defines the maximum allowed absolute detour based on the unsharedRideTime. A linear combination similar to travel " + "time constrain is used. This is the ratio part. By default, this limit is disabled (i.e. set to Inf, together with maxDetourBeta).") @DecimalMin("1.0") public double maxDetourAlpha = Double.POSITIVE_INFINITY; @Parameter @Comment( - "Defines the maximum allowed absolute detour based on the unsharedRideTime. Note that the detour is computed from the latest promised " - + "pickup time. To enable the max detour constraint, maxAllowedPickupDelay has to be specified. A linear combination similar to travel " + "Defines the maximum allowed absolute detour based on the unsharedRideTime. A linear combination similar to travel " + "time constrain is used. This is the constant part. By default, this limit is disabled (i.e. set to Inf, together with maxDetourAlpha).") @PositiveOrZero public double maxDetourBeta = Double.POSITIVE_INFINITY;// [s] + @Parameter + @Comment( + "Defines the minimum allowed absolute detour in seconds. By default, this bound is disabled (i.e. set to 0.)") + @PositiveOrZero + public double minimumAllowedDetour = 0; + @Override protected void checkConsistency(Config config) { super.checkConsistency(config); - if ((maxDetourAlpha != Double.POSITIVE_INFINITY && maxDetourBeta != Double.POSITIVE_INFINITY) || maxAbsoluteDetour != Double.POSITIVE_INFINITY) { - Verify.verify(maxAllowedPickupDelay != Double.POSITIVE_INFINITY, "Detour constraints are activated, " + - "maxAllowedPickupDelay must be specified! A value between 0 and 240 seconds can be a good choice for maxAllowedPickupDelay."); - } + Verify.verify(maxAbsoluteDetour > minimumAllowedDetour, "The minimum allowed detour must" + + "be lower than the maximum allowed detour."); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java index 4e06666ed05..f3892019345 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategy.java @@ -40,6 +40,9 @@ */ public class MinCostFlowRebalancingStrategy implements RebalancingStrategy { + public static final String REBALANCING_ZONAL_TARGET_ALPHA = "rebalalpha"; + public static final String REBALANCING_ZONAL_TARGET_BETA = "rebalbeta"; + private final RebalancingTargetCalculator rebalancingTargetCalculator; private final ZoneSystem zonalSystem; private final Fleet fleet; @@ -68,18 +71,37 @@ public List calcRelocations(Stream rebalancab return calculateMinCostRelocations(time, rebalancableVehiclesPerZone, soonIdleVehiclesPerZone); } - private List calculateMinCostRelocations(double time, + List calculateMinCostRelocations(double time, Map> rebalancableVehiclesPerZone, Map> soonIdleVehiclesPerZone) { ToDoubleFunction targetFunction = rebalancingTargetCalculator.calculate(time, rebalancableVehiclesPerZone); var minCostFlowRebalancingStrategyParams = (MinCostFlowRebalancingStrategyParams)params.getRebalancingStrategyParams(); - double alpha = minCostFlowRebalancingStrategyParams.targetAlpha; - double beta = minCostFlowRebalancingStrategyParams.targetBeta; - List vehicleSurpluses = zonalSystem.getZones().values().stream().map(z -> { + List vehicleSurpluses = zonalSystem.getZones().values().stream().map(z -> { + double alpha; + double beta; int rebalancable = rebalancableVehiclesPerZone.getOrDefault(z, List.of()).size(); int soonIdle = soonIdleVehiclesPerZone.getOrDefault(z, List.of()).size(); + + switch (minCostFlowRebalancingStrategyParams.targetCoefficientSource) { + case Static -> { + alpha = minCostFlowRebalancingStrategyParams.targetAlpha; + beta = minCostFlowRebalancingStrategyParams.targetBeta; + } + case FromZoneAttribute -> { + alpha = (Double) z.getAttributes().getAttribute(REBALANCING_ZONAL_TARGET_ALPHA); + beta = (Double) z.getAttributes().getAttribute(REBALANCING_ZONAL_TARGET_BETA); + } + case FromZoneAttributeOrStatic -> { + Object alphaAttribute = z.getAttributes().getAttribute(REBALANCING_ZONAL_TARGET_ALPHA); + alpha = alphaAttribute == null ? minCostFlowRebalancingStrategyParams.targetAlpha : (Double) alphaAttribute; + Object betaAttribute = z.getAttributes().getAttribute(REBALANCING_ZONAL_TARGET_BETA); + beta = betaAttribute == null ? minCostFlowRebalancingStrategyParams.targetBeta : (Double) betaAttribute; + } + default -> throw new IllegalStateException("Unknown target coefficient source " + minCostFlowRebalancingStrategyParams.targetCoefficientSource); + } + int target = (int)Math.floor(alpha * targetFunction.applyAsDouble(z) + beta); int surplus = Math.min(rebalancable + soonIdle - target, rebalancable); return new DrtZoneVehicleSurplus(z, surplus); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyParams.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyParams.java index 7c0a72e3a07..a09867d4785 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyParams.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyParams.java @@ -56,6 +56,19 @@ public enum RebalancingTargetCalculatorType { @NotNull public RebalancingTargetCalculatorType rebalancingTargetCalculatorType = RebalancingTargetCalculatorType.EstimatedDemand; + + public enum TargetCoefficientSource { + Static, FromZoneAttribute, FromZoneAttributeOrStatic + } + + @Parameter + @Comment("Defines whether the alpha and beta of the target function should be" + + " [Static] or [FromZoneAttribute] in which case alpha and beta can be provided per zone as an attribute." + + " [FromZoneAttributeOrStatic] will fall back to the static coefficients if no attribute is found for a given zone." + + " Use " + MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_ALPHA + " and " + MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_BETA + + " to set values accordingly.") + public TargetCoefficientSource targetCoefficientSource = TargetCoefficientSource.Static; + public enum ZonalDemandEstimatorType {PreviousIterationDemand, None} @Parameter diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java index a5dad2f114b..69aef1db822 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingManager.java @@ -399,22 +399,31 @@ private void processRejections(double now) { int index = WithinDayAgentUtils.getCurrentPlanElementIndex(agent); Plan plan = WithinDayAgentUtils.getModifiablePlan(agent); PlanElement planElement = plan.getPlanElements().get(index); - Activity activity; - if(planElement instanceof Activity currentActivity) { - activity = currentActivity; + + if (planElement instanceof Activity currentActivity) { + Activity activity = currentActivity; + activity.setEndTime(Double.POSITIVE_INFINITY); + activity.setMaximumDurationUndefined(); + + ((HasModifiablePlan) agent).resetCaches(); + internalInterface.getMobsim().rescheduleActivityEnd(agent); + eventsManager.processEvent(new PersonStuckEvent(now, agent.getId(), agent.getCurrentLinkId(), + this.mode)); + + internalInterface.getMobsim().getAgentCounter().incLost(); + internalInterface.getMobsim().getAgentCounter().decLiving(); } else { // If the current element is a leg, the agent is walking towards the pickup location // We make the agent stuck at the interaction activity - activity = (Activity) plan.getPlanElements().get(index+1); + while (index < plan.getPlanElements().size()) { + if (plan.getPlanElements().get(index) instanceof Activity activity) { + activity.setEndTime(Double.POSITIVE_INFINITY); + activity.setMaximumDurationUndefined(); + } + + index++; + } } - activity.setEndTime(Double.POSITIVE_INFINITY); - activity.setMaximumDurationUndefined(); - - ((HasModifiablePlan) agent).resetCaches(); - internalInterface.getMobsim().rescheduleActivityEnd(agent); - eventsManager.processEvent(new PersonStuckEvent(now, agent.getId(), agent.getCurrentLinkId(), - this.mode)); - internalInterface.getMobsim().getAgentCounter().incLost(); } } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/logic/AttributeBasedPrebookingLogic.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/logic/AttributeBasedPrebookingLogic.java index a48cbe50e46..7908ca1378c 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/logic/AttributeBasedPrebookingLogic.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/logic/AttributeBasedPrebookingLogic.java @@ -2,6 +2,7 @@ import java.util.Optional; +import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Leg; import org.matsim.api.core.v01.population.PlanElement; import org.matsim.contrib.drt.prebooking.logic.helpers.PopulationIterator; @@ -35,23 +36,40 @@ * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class AttributeBasedPrebookingLogic implements PrebookingLogic, MobsimInitializedListener { - static private final String SUBMISSION_TIME_ATTRIBUTE_PREFIX = "prebooking:submissionTime"; - static private final String PLANNED_DEPARTURE_ATTRIBUTE_PREFIX = "prebooking:plannedDepartureTime"; + static private final String SUBMISSION_TIME_ATTRIBUTE_PREFIX = "prebooking:submissionTime:"; + static private final String PLANNED_DEPARTURE_ATTRIBUTE_PREFIX = "prebooking:plannedDepartureTime:"; - static public String getSubmissionAttribute(String mode) { + static public String getSubmissionTimeAttribute(String mode) { return SUBMISSION_TIME_ATTRIBUTE_PREFIX + mode; } - static public String getPlannedDepartureAttribute(String mode) { + static public String getPlannedDepartureTimeAttribute(String mode) { return PLANNED_DEPARTURE_ATTRIBUTE_PREFIX + mode; } static public Optional getSubmissionTime(String mode, Trip trip) { - return Optional.ofNullable((Double) trip.getTripAttributes().getAttribute(getSubmissionAttribute(mode))); + return Optional.ofNullable((Double) trip.getTripAttributes().getAttribute(getSubmissionTimeAttribute(mode))); } static public Optional getPlannedDepartureTime(String mode, Trip trip) { - return Optional.ofNullable((Double) trip.getTripAttributes().getAttribute(getPlannedDepartureAttribute(mode))); + return Optional + .ofNullable((Double) trip.getTripAttributes().getAttribute(getPlannedDepartureTimeAttribute(mode))); + } + + static public void setSubmissionTime(String mode, Trip trip, double submissionTime) { + trip.getTripAttributes().putAttribute(getSubmissionTimeAttribute(mode), submissionTime); + } + + static public void setPlannedDepartureTime(String mode, Trip trip, double plannedDepartureTime) { + trip.getTripAttributes().putAttribute(getPlannedDepartureTimeAttribute(mode), plannedDepartureTime); + } + + static public void setSubmissionTime(String mode, Activity originActivity, double submissionTime) { + originActivity.getAttributes().putAttribute(getSubmissionTimeAttribute(mode), submissionTime); + } + + static public void setPlannedDepartureTime(String mode, Activity originActivity, double plannedDepartureTime) { + originActivity.getAttributes().putAttribute(getPlannedDepartureTimeAttribute(mode), plannedDepartureTime); } private final PrebookingQueue prebookingQueue; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteConstraintsCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteConstraintsCalculator.java index f8e1f9b36eb..cfcaaa3e5c8 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteConstraintsCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/routing/DefaultDrtRouteConstraintsCalculator.java @@ -25,9 +25,12 @@ public DefaultDrtRouteConstraintsCalculator(DrtConfigGroup drtCfg, ConstraintSet /** * Calculates the maximum travel time defined as: drtCfg.getMaxTravelTimeAlpha() * unsharedRideTime + drtCfg.getMaxTravelTimeBeta() - * - * Calculates the maximum ride time defined as: drtCfg.maxDetourAlpha * - * unsharedRideTime + drtCfg.maxDetourBeta + * + * Calculates the maximum ride time defined as: + * unsharedRideTime + min( + * maxAbsoluteDetour, + * max(minimumAllowedDetour, unsharedRideTime * (1-drtCfg.maxDetourAlpha) + drtCfg.maxDetourBeta) + * ) * * @return DrtRouteConstraints constraints */ @@ -40,8 +43,8 @@ public DrtRouteConstraints calculateRouteConstraints(double departureTime, Link if (constraintsSet instanceof DefaultDrtOptimizationConstraintsSet defaultSet) { double maxTravelTime = defaultSet.maxTravelTimeAlpha * unsharedRideTime + defaultSet.maxTravelTimeBeta; - double maxRideTime = Math.min(unsharedRideTime + defaultSet.maxAbsoluteDetour, - defaultSet.maxDetourAlpha * unsharedRideTime + defaultSet.maxDetourBeta); + double maxDetour = Math.max(defaultSet.minimumAllowedDetour, unsharedRideTime * (defaultSet.maxDetourAlpha -1) + defaultSet.maxDetourBeta); + double maxRideTime = unsharedRideTime + Math.min(defaultSet.maxAbsoluteDetour, maxDetour); double maxWaitTime = constraintsSet.maxWaitTime; return new DrtRouteConstraints(maxTravelTime, maxRideTime, maxWaitTime); diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java index 7f43fd42d8b..cca630fcf0c 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/demandestimator/PreviousIterationDrtDemandEstimatorTest.java @@ -199,9 +199,9 @@ static Network createNetwork() { network.addNode(b); Link ab = network.getFactory().createLink(Id.createLinkId("link_1"), a, b); - Link bc = network.getFactory().createLink(Id.createLinkId("link_2"), b, a); + Link ba = network.getFactory().createLink(Id.createLinkId("link_2"), b, a); network.addLink(ab); - network.addLink(bc); + network.addLink(ba); return network; } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyTest.java new file mode 100644 index 00000000000..8aba7eefc00 --- /dev/null +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/rebalancing/mincostflow/MinCostFlowRebalancingStrategyTest.java @@ -0,0 +1,279 @@ +package org.matsim.contrib.drt.optimizer.rebalancing.mincostflow; + +import com.google.common.collect.ImmutableMap; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.prep.PreparedPolygon; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.events.PersonDepartureEvent; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.network.Node; +import org.matsim.contrib.common.zones.Zone; +import org.matsim.contrib.common.zones.ZoneImpl; +import org.matsim.contrib.common.zones.ZoneSystem; +import org.matsim.contrib.common.zones.ZoneSystemImpl; +import org.matsim.contrib.drt.analysis.zonal.MostCentralDrtZoneTargetLinkSelector; +import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingParams; +import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy; +import org.matsim.contrib.drt.optimizer.rebalancing.demandestimator.PreviousIterationDrtDemandEstimator; +import org.matsim.contrib.drt.optimizer.rebalancing.targetcalculator.DemandEstimatorAsTargetCalculator; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.dvrp.fleet.*; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.utils.geometry.GeometryUtils; + +import java.util.*; + +public class MinCostFlowRebalancingStrategyTest { + + private static final int ESTIMATION_PERIOD = 1800; + + private final Network network = createNetwork(); + + private final Link link1 = network.getLinks().get(Id.createLinkId("link_1")); + private final Link link2 = network.getLinks().get(Id.createLinkId("link_2")); + + private final Zone zone1 = new ZoneImpl( + Id.create("zone_1", Zone.class), + new PreparedPolygon(GeometryUtils.createGeotoolsPolygon( + List.of( + new Coord(0, 0), + new Coord(0, 500), + new Coord(500, 500), + new Coord(500, 0), + new Coord(0, 0) + ))), "dummy"); + + private final Zone zone2 = new ZoneImpl( + Id.create("zone_2", Zone.class), + new PreparedPolygon(GeometryUtils.createGeotoolsPolygon( + List.of( + new Coord(500, 0), + new Coord(500, 500), + new Coord(1000, 500), + new Coord(1000, 0), + new Coord(500, 0) + ))), "dummy"); + + private final ZoneSystem zonalSystem = new ZoneSystemImpl(List.of(zone1, zone2), coord -> { + if (coord == link1.getToNode().getCoord()) { + return Optional.of(zone1); + } else if (coord == link2.getToNode().getCoord()) { + return Optional.of(zone2); + } else { + throw new RuntimeException(); + } + }, network); + + + @Test + void testEmptyDemandAndTarget() { + PreviousIterationDrtDemandEstimator estimator = createEstimator(); + DemandEstimatorAsTargetCalculator targetCalculator = new DemandEstimatorAsTargetCalculator(estimator, ESTIMATION_PERIOD); + + RebalancingParams rebalancingParams = new RebalancingParams(); + MinCostFlowRebalancingStrategyParams minCostFlowRebalancingStrategyParams = new MinCostFlowRebalancingStrategyParams(); + minCostFlowRebalancingStrategyParams.targetAlpha = 1.; + minCostFlowRebalancingStrategyParams.targetBeta = 0.; + rebalancingParams.addParameterSet(minCostFlowRebalancingStrategyParams); + + AggregatedMinCostRelocationCalculator relocationCalculator = new AggregatedMinCostRelocationCalculator(new MostCentralDrtZoneTargetLinkSelector(zonalSystem)); + MinCostFlowRebalancingStrategy strategy = new MinCostFlowRebalancingStrategy(targetCalculator, + zonalSystem, createEmptyFleet(), relocationCalculator, rebalancingParams); + + Map> rebalanceableVehicles = new HashMap<>(); + List relocations = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations.isEmpty()); + } + + @Test + void testDemandWithoutSurplus() { + PreviousIterationDrtDemandEstimator estimator = createEstimator(); + DemandEstimatorAsTargetCalculator targetCalculator = new DemandEstimatorAsTargetCalculator(estimator, ESTIMATION_PERIOD); + + RebalancingParams rebalancingParams = new RebalancingParams(); + MinCostFlowRebalancingStrategyParams minCostFlowRebalancingStrategyParams = new MinCostFlowRebalancingStrategyParams(); + minCostFlowRebalancingStrategyParams.targetAlpha = 1.; + minCostFlowRebalancingStrategyParams.targetBeta = 0.; + rebalancingParams.addParameterSet(minCostFlowRebalancingStrategyParams); + + AggregatedMinCostRelocationCalculator relocationCalculator = new AggregatedMinCostRelocationCalculator(new MostCentralDrtZoneTargetLinkSelector(zonalSystem)); + MinCostFlowRebalancingStrategy strategy = new MinCostFlowRebalancingStrategy(targetCalculator, + zonalSystem, createEmptyFleet(), relocationCalculator, rebalancingParams); + + //time bin 0-1800 + estimator.handleEvent(departureEvent(100, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(200, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(500, link2, TransportMode.drt)); + estimator.handleEvent(departureEvent(1500, link1, TransportMode.drt)); + estimator.reset(1); + + Map> rebalanceableVehicles = new HashMap<>(); + List relocations = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations.isEmpty()); + } + + @Test + void testDemandWithSurplus() { + PreviousIterationDrtDemandEstimator estimator = createEstimator(); + DemandEstimatorAsTargetCalculator targetCalculator = new DemandEstimatorAsTargetCalculator(estimator, ESTIMATION_PERIOD); + + RebalancingParams rebalancingParams = new RebalancingParams(); + MinCostFlowRebalancingStrategyParams minCostFlowRebalancingStrategyParams = new MinCostFlowRebalancingStrategyParams(); + minCostFlowRebalancingStrategyParams.targetAlpha = 1.; + minCostFlowRebalancingStrategyParams.targetBeta = 0.; + rebalancingParams.addParameterSet(minCostFlowRebalancingStrategyParams); + + AggregatedMinCostRelocationCalculator relocationCalculator = new AggregatedMinCostRelocationCalculator(new MostCentralDrtZoneTargetLinkSelector(zonalSystem)); + MinCostFlowRebalancingStrategy strategy = new MinCostFlowRebalancingStrategy(targetCalculator, + zonalSystem, createEmptyFleet(), relocationCalculator, rebalancingParams); + + // 3 expected trips in zone 1 + estimator.handleEvent(departureEvent(100, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(200, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(300, link1, TransportMode.drt)); + // 1 expected trip in zone 2 + estimator.handleEvent(departureEvent(100, link2, TransportMode.drt)); + estimator.reset(1); + + Map> rebalanceableVehicles = new HashMap<>(); + + // 4 vehicles in zone 1 (surplus = 1) + List rebalanceableVehiclesZone1 = new ArrayList<>(); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a1", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a2", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a3", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a4", DvrpVehicle.class), link1)); + rebalanceableVehicles.put(zone1, rebalanceableVehiclesZone1); + + List relocations = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations.size()).isEqualTo(1); + Assertions.assertThat(relocations.getFirst().link.getId()).isEqualTo(link2.getId()); + + rebalanceableVehicles.clear(); + + // 5 vehicles in zone 1 (surplus = 2) + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a1", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a2", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a3", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a4", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a5", DvrpVehicle.class), link1)); + rebalanceableVehicles.put(zone1, rebalanceableVehiclesZone1); + + //set alpha to 2 -> send two vehicles to zone 2 + minCostFlowRebalancingStrategyParams.targetAlpha = 2.; + List relocations2 = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations2.size()).isEqualTo(2); + Assertions.assertThat(relocations2.getFirst().link.getId()).isEqualTo(link2.getId()); + Assertions.assertThat(relocations2.getLast().link.getId()).isEqualTo(link2.getId()); + } + + @Test + void testDemandWithSurplusZoneBasedTargetRates() { + + // set attributes + zone1.getAttributes().putAttribute(MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_ALPHA, 0.); + zone1.getAttributes().putAttribute(MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_BETA, 0.); + zone2.getAttributes().putAttribute(MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_ALPHA, 1.); + zone2.getAttributes().putAttribute(MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_BETA, 0.); + + + PreviousIterationDrtDemandEstimator estimator = createEstimator(); + DemandEstimatorAsTargetCalculator targetCalculator = new DemandEstimatorAsTargetCalculator(estimator, ESTIMATION_PERIOD); + + RebalancingParams rebalancingParams = new RebalancingParams(); + MinCostFlowRebalancingStrategyParams minCostFlowRebalancingStrategyParams = new MinCostFlowRebalancingStrategyParams(); + minCostFlowRebalancingStrategyParams.targetCoefficientSource = MinCostFlowRebalancingStrategyParams.TargetCoefficientSource.FromZoneAttribute; + rebalancingParams.addParameterSet(minCostFlowRebalancingStrategyParams); + + AggregatedMinCostRelocationCalculator relocationCalculator = new AggregatedMinCostRelocationCalculator(new MostCentralDrtZoneTargetLinkSelector(zonalSystem)); + MinCostFlowRebalancingStrategy strategy = new MinCostFlowRebalancingStrategy(targetCalculator, + zonalSystem, createEmptyFleet(), relocationCalculator, rebalancingParams); + + // 3 expected trips in zone 1 + estimator.handleEvent(departureEvent(100, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(200, link1, TransportMode.drt)); + estimator.handleEvent(departureEvent(300, link1, TransportMode.drt)); + // 1 expected trip in zone 2 + estimator.handleEvent(departureEvent(100, link2, TransportMode.drt)); + estimator.reset(1); + + Map> rebalanceableVehicles = new HashMap<>(); + + // 4 vehicles in zone 1 (surplus = 1) + List rebalanceableVehiclesZone1 = new ArrayList<>(); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a1", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a2", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a3", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a4", DvrpVehicle.class), link1)); + rebalanceableVehicles.put(zone1, rebalanceableVehiclesZone1); + + List relocations = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations.size()).isEqualTo(1); + Assertions.assertThat(relocations.getFirst().link.getId()).isEqualTo(link2.getId()); + + rebalanceableVehicles.clear(); + + // 5 vehicles in zone 1 (surplus = 2) + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a1", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a2", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a3", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a4", DvrpVehicle.class), link1)); + rebalanceableVehiclesZone1.add(getDvrpVehicle(Id.create("a5", DvrpVehicle.class), link1)); + rebalanceableVehicles.put(zone1, rebalanceableVehiclesZone1); + + //set alpha to 2 -> send two vehicles to zone 2 + zone2.getAttributes().putAttribute(MinCostFlowRebalancingStrategy.REBALANCING_ZONAL_TARGET_ALPHA, 2.); + List relocations2 = strategy.calculateMinCostRelocations(0, rebalanceableVehicles, Collections.emptyMap()); + Assertions.assertThat(relocations2.size()).isEqualTo(2); + Assertions.assertThat(relocations2.getFirst().link.getId()).isEqualTo(link2.getId()); + Assertions.assertThat(relocations2.getLast().link.getId()).isEqualTo(link2.getId()); + } + + private DvrpVehicleImpl getDvrpVehicle(Id id, Link link) { + return new DvrpVehicleImpl( + ImmutableDvrpVehicleSpecification.newBuilder() + .id(id) + .capacity(0) + .serviceBeginTime(0) + .serviceEndTime(0) + .startLinkId(link.getId()) + .build(), link); + } + + private static Fleet createEmptyFleet() { + return () -> ImmutableMap., DvrpVehicle>builder().build(); + } + + + private PreviousIterationDrtDemandEstimator createEstimator() { + RebalancingParams rebalancingParams = new RebalancingParams(); + rebalancingParams.interval = ESTIMATION_PERIOD; + + DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); + drtConfigGroup.addParameterSet(rebalancingParams); + + return new PreviousIterationDrtDemandEstimator(zonalSystem, drtConfigGroup, ESTIMATION_PERIOD); + } + + private PersonDepartureEvent departureEvent(double time, Link link, String mode) { + return new PersonDepartureEvent(time, null, link.getId(), mode, mode); + } + + static Network createNetwork() { + Network network = NetworkUtils.createNetwork(); + Node a = network.getFactory().createNode(Id.createNodeId("a"), new Coord(0,0)); + Node b = network.getFactory().createNode(Id.createNodeId("b"), new Coord(500,0)); + network.addNode(a); + network.addNode(b); + + Link ab = network.getFactory().createLink(Id.createLinkId("link_1"), a, b); + Link ba = network.getFactory().createLink(Id.createLinkId("link_2"), b, a); + network.addLink(ab); + network.addLink(ba); + return network; + } +} diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java index 4809a205c8a..22f9bef8d06 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTest.java @@ -4,6 +4,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Plan; import org.matsim.contrib.drt.passenger.DrtRequest; import org.matsim.contrib.drt.prebooking.PrebookingTestEnvironment.RequestInfo; import org.matsim.contrib.drt.prebooking.logic.AttributeBasedPrebookingLogic; @@ -13,6 +18,7 @@ import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.core.controler.Controler; +import org.matsim.core.population.PopulationUtils; import org.matsim.testcases.MatsimTestUtils; /** @@ -67,7 +73,8 @@ static PrebookingParams installPrebooking(Controler controller, boolean installL return installPrebooking(controller, installLogic, new PrebookingParams()); } - static PrebookingParams installPrebooking(Controler controller, boolean installLogic, PrebookingParams prebookingParams) { + static PrebookingParams installPrebooking(Controler controller, boolean installLogic, + PrebookingParams prebookingParams) { DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(controller.getConfig()); drtConfig.addParameterSet(prebookingParams); @@ -647,12 +654,12 @@ void intraStopTiming_pickupTooEarly() { .addRequest("requestA1", 1, 1, 8, 8, 2000.0, 1.0) // forward .addRequest("requestA2", 1, 1, 8, 8, 2000.0, 2.0) // forward .addRequest("requestB1", 8, 8, 1, 1, 2356.0, 3.0) // backward - .configure(300.0, 2.0, 1800.0, 60.0) // + .configure(300.0, 2.0, 1800.0, 60.0) // .endTime(12.0 * 3600.0); Controler controller = environment.build(); installPrebooking(controller); - + controller.addOverridingModule(new AbstractDvrpModeModule("drt") { @Override public void install() { @@ -665,7 +672,7 @@ public double calcPickupDuration(DvrpVehicle vehicle, DrtRequest request) { return 30.0; // shorter than the dropoff duration (see below) } } - + @Override public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { return 60.0; @@ -673,7 +680,7 @@ public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { }); } }); - + controller.run(); { @@ -693,13 +700,14 @@ public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { { RequestInfo requestInfo = environment.getRequestInfo().get("requestB1"); assertEquals(3.0, requestInfo.submissionTime, 1e-3); - assertEquals(2356.0 + 60.0, requestInfo.pickupTime, 1e-3); // NOT 30s because we need to wait for the dropoffs + assertEquals(2356.0 + 60.0, requestInfo.pickupTime, 1e-3); // NOT 30s because we need to wait for the + // dropoffs assertEquals(2753.0 + 60.0, requestInfo.dropoffTime, 1e-3); } assertEquals(3, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count()); } - + @Test void intraStopTiming_dropoffTooLate() { /*- @@ -715,12 +723,12 @@ void intraStopTiming_dropoffTooLate() { .addRequest("requestA", 1, 1, 8, 8, 2000.0, 1.0) // forward .addRequest("requestB1", 8, 8, 1, 1, 2356.0, 2.0) // backward .addRequest("requestB2", 8, 8, 1, 1, 2356.0, 3.0) // backward - .configure(300.0, 2.0, 1800.0, 60.0) // + .configure(300.0, 2.0, 1800.0, 60.0) // .endTime(12.0 * 3600.0); Controler controller = environment.build(); installPrebooking(controller); - + controller.addOverridingModule(new AbstractDvrpModeModule("drt") { @Override public void install() { @@ -729,7 +737,7 @@ public void install() { public double calcPickupDuration(DvrpVehicle vehicle, DrtRequest request) { return 60.0; } - + @Override public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { if (request.getPassengerIds().get(0).toString().equals("requestA")) { @@ -741,7 +749,7 @@ public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { }); } }); - + controller.run(); { @@ -755,9 +763,10 @@ public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { RequestInfo requestInfo = environment.getRequestInfo().get("requestB1"); assertEquals(2.0, requestInfo.submissionTime, 1e-3); assertEquals(2356.0 + 60.0, requestInfo.pickupTime, 1e-3); - assertEquals(2753.0 + 60.0 + 30.0, requestInfo.dropoffTime, 1e-3); // +30 because we wait for dropoff of A for B2 to enter + assertEquals(2753.0 + 60.0 + 30.0, requestInfo.dropoffTime, 1e-3); // +30 because we wait for dropoff of A + // for B2 to enter } - + { RequestInfo requestInfo = environment.getRequestInfo().get("requestB2"); assertEquals(3.0, requestInfo.submissionTime, 1e-3); @@ -767,4 +776,62 @@ public double calcDropoffDuration(DvrpVehicle vehicle, DrtRequest request) { assertEquals(3, environment.getTaskInfo().get("vehicleA").stream().filter(t -> t.type.equals("STOP")).count()); } + + @Test + void abortAfterRejection_onActivity() { + PrebookingTestEnvironment environment = new PrebookingTestEnvironment(utils) // + .addVehicle("vehicleA", 1, 1) // + .setVehicleCapacity(1) // + .addRequest("requestA", 1, 1, 8, 8, 2000.0, 1800.0) + .configure(10.0, 1.0, 0.0, 5.0) + .endTime(12.0 * 3600.0); + + Controler controller = environment.build(); + installPrebooking(controller); + + controller.run(); + + { + RequestInfo requestInfo = environment.getRequestInfo().get("requestA"); + assertEquals(1800.0, requestInfo.submissionTime); + assertEquals(Double.NaN, requestInfo.pickupTime, 1e-3); + assertEquals(1, requestInfo.submissionTimes.size()); + assertEquals(1, environment.getStuckInfo().size()); + } + } + + @Test + void abortAfterRejection_onLeg() { + PrebookingTestEnvironment environment = new PrebookingTestEnvironment(utils) // + .addVehicle("vehicleA", 1, 1) // + .setVehicleCapacity(1) // + .addRequest("requestA", 1, 1, 8, 8, 2000.0, 1800.0) + .configure(10.0, 1.0, 0.0, 5.0) + .endTime(12.0 * 3600.0); + + Controler controller = environment.build(); + installPrebooking(controller); + + // make sure the agent will be on a leg + for (Person person : controller.getScenario().getPopulation().getPersons().values()) { + Plan plan = person.getSelectedPlan(); + + Activity activity = PopulationUtils.createActivityFromCoord("generic", new Coord(-50000.0, -50000.0)); + activity.setEndTime(0.0); + Leg leg = PopulationUtils.createLeg("walk"); + + plan.getPlanElements().add(0, activity); + plan.getPlanElements().add(1, leg); + } + + controller.run(); + + { + RequestInfo requestInfo = environment.getRequestInfo().get("requestA"); + assertEquals(1800.0, requestInfo.submissionTime); + assertEquals(Double.NaN, requestInfo.pickupTime, 1e-3); + assertEquals(1, requestInfo.submissionTimes.size()); + assertEquals(1, environment.getStuckInfo().size()); + } + } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTestEnvironment.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTestEnvironment.java index 60108070ab8..fcdb7ab7d7a 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTestEnvironment.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/prebooking/PrebookingTestEnvironment.java @@ -1,14 +1,26 @@ package org.matsim.contrib.drt.prebooking; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import org.apache.commons.lang3.tuple.Pair; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.events.PersonStuckEvent; +import org.matsim.api.core.v01.events.handler.PersonStuckEventHandler; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.NetworkFactory; import org.matsim.api.core.v01.network.Node; -import org.matsim.api.core.v01.population.*; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Plan; +import org.matsim.api.core.v01.population.Population; +import org.matsim.api.core.v01.population.PopulationFactory; import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams; import org.matsim.contrib.drt.optimizer.constraints.DefaultDrtOptimizationConstraintsSet; import org.matsim.contrib.drt.optimizer.insertion.DrtInsertionSearchParams; @@ -26,7 +38,12 @@ import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.fleet.FleetSpecificationImpl; import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification; -import org.matsim.contrib.dvrp.passenger.*; +import org.matsim.contrib.dvrp.passenger.PassengerDroppedOffEvent; +import org.matsim.contrib.dvrp.passenger.PassengerDroppedOffEventHandler; +import org.matsim.contrib.dvrp.passenger.PassengerPickedUpEvent; +import org.matsim.contrib.dvrp.passenger.PassengerPickedUpEventHandler; +import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent; +import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.contrib.dvrp.run.DvrpModule; @@ -48,11 +65,6 @@ import org.matsim.core.scenario.ScenarioUtils; import org.matsim.testcases.MatsimTestUtils; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - public class PrebookingTestEnvironment { private final MatsimTestUtils utils; @@ -164,6 +176,7 @@ public Controler build() { configureRequestListener(controller); configureVehicleListener(controller); + configureStuckListener(controller); return controller; } @@ -227,9 +240,9 @@ private void buildConfig(Config config) { DrtConfigGroup modeConfig = new DrtConfigGroup(); drtConfig.addParameterSet(modeConfig); modeConfig.mode = "drt"; - DefaultDrtOptimizationConstraintsSet defaultConstraintsSet = - (DefaultDrtOptimizationConstraintsSet) modeConfig.addOrGetDrtOptimizationConstraintsParams() - .addOrGetDefaultDrtOptimizationConstraintsSet(); + DefaultDrtOptimizationConstraintsSet defaultConstraintsSet = (DefaultDrtOptimizationConstraintsSet) modeConfig + .addOrGetDrtOptimizationConstraintsParams() + .addOrGetDefaultDrtOptimizationConstraintsSet(); defaultConstraintsSet.maxWaitTime = maximumWaitTime; defaultConstraintsSet.maxTravelTimeAlpha = detourRelative; defaultConstraintsSet.maxTravelTimeBeta = detourAbsolute; @@ -270,13 +283,13 @@ private void buildPopulation(Scenario scenario) { plan.addLeg(firstLeg); if (!Double.isNaN(request.submissionTime)) { - firstActivity.getAttributes().putAttribute(AttributeBasedPrebookingLogic.getSubmissionAttribute("drt"), + firstActivity.getAttributes().putAttribute(AttributeBasedPrebookingLogic.getSubmissionTimeAttribute("drt"), request.submissionTime); } if (!Double.isNaN(request.plannedDepartureTime)) { firstActivity.getAttributes().putAttribute( - AttributeBasedPrebookingLogic.getPlannedDepartureAttribute("drt"), + AttributeBasedPrebookingLogic.getPlannedDepartureTimeAttribute("drt"), request.plannedDepartureTime); } @@ -444,4 +457,26 @@ public void handleEvent(TaskEndedEvent event) { taskInfo.get(event.getDvrpVehicleId().toString()).getLast().endTime = event.getTime(); } } + + private final List stuckEvents = new LinkedList<>(); + + public List getStuckInfo() { + return stuckEvents; + } + + private void configureStuckListener(Controler controller) { + controller.addOverridingModule(new AbstractModule() { + @Override + public void install() { + addEventHandlerBinding().toInstance(new StuckListener()); + } + }); + } + + private class StuckListener implements PersonStuckEventHandler { + @Override + public void handleEvent(PersonStuckEvent event) { + stuckEvents.add(event); + } + } } diff --git a/contribs/dvrp/pom.xml b/contribs/dvrp/pom.xml index 716fab806f2..e6fc424004c 100644 --- a/contribs/dvrp/pom.xml +++ b/contribs/dvrp/pom.xml @@ -24,17 +24,17 @@ org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib ev - 2025.0-SNAPSHOT + ${project.parent.version} org.apache.commons diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java index 076ce4876ec..3b8463a1119 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/router/DvrpModeRoutingNetworkModule.java @@ -20,6 +20,7 @@ package org.matsim.contrib.dvrp.router; +import java.io.File; import java.util.Collections; import java.util.Set; @@ -32,6 +33,7 @@ import org.matsim.contrib.zone.skims.FreeSpeedTravelTimeMatrix; import org.matsim.contrib.zone.skims.TravelTimeMatrix; import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.groups.GlobalConfigGroup; import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.core.network.NetworkUtils; @@ -86,9 +88,16 @@ public void install() { DvrpTravelTimeMatrixParams matrixParams = dvrpConfigGroup.getTravelTimeMatrixParams(); ZoneSystem zoneSystem = ZoneSystemUtils.createZoneSystem(getConfig().getContext(), network, matrixParams.getZoneSystemParams(), getConfig().global().getCoordinateSystem(), zone -> true); - return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, - matrixParams, globalConfigGroup.getNumberOfThreads(), - qSimConfigGroup.getTimeStepSize()); + + + if (matrixParams.cachePath == null) { + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, matrixParams, globalConfigGroup.getNumberOfThreads(), + qSimConfigGroup.getTimeStepSize()); + } else { + File cachePath = new File(ConfigGroup.getInputFileURL(getConfig().getContext(), matrixParams.cachePath).getPath()); + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, matrixParams, globalConfigGroup.getNumberOfThreads(), + qSimConfigGroup.getTimeStepSize(), cachePath); + } })).in(Singleton.class); } else { //use DVRP-routing (dvrp-global) network diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java index d31fe11499d..769ea423515 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/run/DvrpModule.java @@ -19,7 +19,7 @@ package org.matsim.contrib.dvrp.run; -import jakarta.inject.Provider; +import java.io.File; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.common.zones.ZoneSystem; @@ -33,6 +33,7 @@ import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams; import org.matsim.contrib.zone.skims.FreeSpeedTravelTimeMatrix; import org.matsim.contrib.zone.skims.TravelTimeMatrix; +import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.mobsim.framework.MobsimTimer; @@ -44,6 +45,8 @@ import com.google.inject.name.Named; import com.google.inject.name.Names; +import jakarta.inject.Provider; + /** * This module initialises generic (i.e. not taxi or drt-specific) AND global (not mode-specific) dvrp objects. *

@@ -90,8 +93,15 @@ public TravelTimeMatrix get() { DvrpTravelTimeMatrixParams matrixParams = dvrpConfigGroup.getTravelTimeMatrixParams(); ZoneSystem zoneSystem = ZoneSystemUtils.createZoneSystem(getConfig().getContext(), network, matrixParams.getZoneSystemParams(), getConfig().global().getCoordinateSystem(), zone -> true); - return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, params, numberOfThreads, + + if (params.cachePath == null) { + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrix(network, zoneSystem, params, numberOfThreads, qSimConfigGroup.getTimeStepSize()); + } else { + File cachePath = new File(ConfigGroup.getInputFileURL(getConfig().getContext(), params.cachePath).getPath()); + return FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, params, numberOfThreads, + qSimConfigGroup.getTimeStepSize(), cachePath); + } } }).in(Singleton.class); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dynagent/DynAgent.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dynagent/DynAgent.java index 8915326d992..d7c15d7552f 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dynagent/DynAgent.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dynagent/DynAgent.java @@ -19,8 +19,6 @@ package org.matsim.contrib.dynagent; -import java.util.List; - import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.events.ActivityEndEvent; import org.matsim.api.core.v01.events.ActivityStartEvent; @@ -40,6 +38,8 @@ import org.matsim.pt.transitSchedule.api.TransitStopFacility; import org.matsim.vehicles.Vehicle; +import java.util.List; + public final class DynAgent implements MobsimDriverPassengerAgent { private final DynAgentLogic agentLogic; @@ -83,11 +83,11 @@ private void computeNextAction(DynAction oldDynAction, double now) { DynAction nextDynAction = agentLogic.computeNextAction(oldDynAction, now); if (nextDynAction instanceof DynActivity) { - dynActivity = (DynActivity)nextDynAction; + dynActivity = (DynActivity) nextDynAction; state = MobsimAgent.State.ACTIVITY; events.processEvent(new ActivityStartEvent(now, id, currentLinkId, null, dynActivity.getActivityType())); } else { - dynLeg = (DynLeg)nextDynAction; + dynLeg = (DynLeg) nextDynAction; state = MobsimAgent.State.LEG; } } @@ -145,7 +145,7 @@ public String getMode() { // VehicleUsingAgent @Override public final Id getPlannedVehicleId() { - Id vehId = ((DriverDynLeg)dynLeg).getPlannedVehicleId(); + Id vehId = ((DriverDynLeg) dynLeg).getPlannedVehicleId(); // according to BasicPlanAgentImpl return vehId != null ? vehId : Id.create(id, Vehicle.class); } @@ -177,13 +177,13 @@ public Id getDestinationLinkId() { // DriverAgent @Override public Id chooseNextLinkId() { - return ((DriverDynLeg)dynLeg).getNextLinkId(); + return ((DriverDynLeg) dynLeg).getNextLinkId(); } // DriverAgent @Override public void notifyMoveOverNode(Id newLinkId) { - ((DriverDynLeg)dynLeg).movedOverNode(newLinkId); + ((DriverDynLeg) dynLeg).movedOverNode(newLinkId); currentLinkId = newLinkId; } @@ -226,26 +226,28 @@ public boolean isWantingToArriveOnCurrentLink() { // PTPassengerAgent @Override public boolean getEnterTransitRoute(TransitLine line, TransitRoute transitRoute, List stopsToCome, - TransitVehicle transitVehicle) { - return ((PTPassengerDynLeg)dynLeg).getEnterTransitRoute(line, transitRoute, stopsToCome, transitVehicle); + TransitVehicle transitVehicle) { + return ((PTPassengerDynLeg) dynLeg).getEnterTransitRoute(line, transitRoute, stopsToCome, transitVehicle); } // PTPassengerAgent + // yyyy seems a bit odd, that this and the following methods are implemented for DynAgent as not every DynAgent is a PTPassengerAgent. paul, + // nov'24 @Override public boolean getExitAtStop(TransitStopFacility stop) { - return ((PTPassengerDynLeg)dynLeg).getExitAtStop(stop); + return ((PTPassengerDynLeg) dynLeg).getExitAtStop(stop); } // PTPassengerAgent @Override public Id getDesiredAccessStopId() { - return ((PTPassengerDynLeg)dynLeg).getDesiredAccessStopId(); + return ((PTPassengerDynLeg) dynLeg).getDesiredAccessStopId(); } // PTPassengerAgent @Override public Id getDesiredDestinationStopId() { - return ((PTPassengerDynLeg)dynLeg).getDesiredDestinationStopId(); + return ((PTPassengerDynLeg) dynLeg).getDesiredDestinationStopId(); } // PTPassengerAgent diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingActivity.java b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingActivity.java index 05217bf940e..8c1cb0adee3 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingActivity.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingActivity.java @@ -21,6 +21,7 @@ package org.matsim.contrib.evrp; import org.matsim.contrib.dynagent.DynActivity; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithAssignmentLogic; import org.matsim.contrib.ev.fleet.ElectricVehicle; @@ -64,7 +65,7 @@ private void initialize(double now) { ChargingWithAssignmentLogic logic = chargingTask.getChargingLogic(); ElectricVehicle ev = chargingTask.getElectricVehicle(); logic.unassignVehicle(ev); - logic.addVehicle(ev, new DvrpChargingListener(this), now); + logic.addVehicle(ev, chargingTask.getChargingStrategy(), new DvrpChargingListener(this), now); state = State.added; } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTask.java b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTask.java index 21ad8303ae5..7326e1bedd9 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTask.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTask.java @@ -20,6 +20,7 @@ package org.matsim.contrib.evrp; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithAssignmentLogic; import org.matsim.contrib.ev.fleet.ElectricVehicle; @@ -29,6 +30,8 @@ public interface ChargingTask extends ETask { ChargingWithAssignmentLogic getChargingLogic(); + ChargingStrategy getChargingStrategy(); + ElectricVehicle getElectricVehicle(); double getChargingStartedTime(); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTaskImpl.java b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTaskImpl.java index 969fa50da00..8cbd525cbea 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTaskImpl.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/evrp/ChargingTaskImpl.java @@ -24,6 +24,7 @@ import com.google.common.base.Preconditions; import org.matsim.contrib.dvrp.schedule.DefaultStayTask; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithAssignmentLogic; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; @@ -33,18 +34,20 @@ */ public class ChargingTaskImpl extends DefaultStayTask implements ChargingTask { private final ChargingWithAssignmentLogic chargingLogic; + private final ChargingStrategy chargingStrategy; private final ElectricVehicle ev; private Double chargingStartedTime; private final double totalEnergy; public ChargingTaskImpl(TaskType taskType, double beginTime, double endTime, Charger charger, ElectricVehicle ev, - double totalEnergy) { + double totalEnergy, ChargingStrategy chargingStrategy) { super(taskType, beginTime, endTime, charger.getLink()); Preconditions.checkArgument(totalEnergy < 0, "Total energy consumption is not negative: %s", totalEnergy); this.chargingLogic = (ChargingWithAssignmentLogic)charger.getLogic(); this.ev = ev; this.totalEnergy = totalEnergy; + this.chargingStrategy = chargingStrategy; } @Override @@ -57,6 +60,11 @@ public ChargingWithAssignmentLogic getChargingLogic() { return chargingLogic; } + @Override + public ChargingStrategy getChargingStrategy() { + return chargingStrategy; + } + @Override public ElectricVehicle getElectricVehicle() { return ev; @@ -76,6 +84,7 @@ public double getChargingStartedTime() { public String toString() { return MoreObjects.toStringHelper(this) .add("chargingLogic", chargingLogic) + .add("chargingStrategy", chargingStrategy) .add("ev", ev) .add("chargingStartedTime", chargingStartedTime) .add("totalEnergy", totalEnergy) diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java index 52c3c332f09..9b959a87ba2 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/DvrpTravelTimeMatrixParams.java @@ -28,6 +28,7 @@ import org.matsim.contrib.common.zones.systems.grid.GISFileZoneSystemParams; import org.matsim.contrib.common.zones.systems.grid.h3.H3GridZoneSystemParams; import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams; +import org.matsim.core.config.ReflectiveConfigGroup.Parameter; /** * @author Michal Maciejewski (michalm) @@ -59,6 +60,9 @@ public class DvrpTravelTimeMatrixParams extends ReflectiveConfigGroupWithConfigu @NotNull private ZoneSystemParams zoneSystemParams; + @Parameter + @Comment("Caches the travel time matrix data into a binary file. If the file exists, the matrix will be read from the file, if not, the file will be created.") + public String cachePath = null; public DvrpTravelTimeMatrixParams() { super(SET_NAME); diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java index 6351dd3bce8..356625f4295 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrix.java @@ -20,14 +20,34 @@ package org.matsim.contrib.zone.skims; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdSet; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; +import org.matsim.contrib.common.zones.Zone; import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.common.zones.ZoneSystemUtils; import org.matsim.contrib.dvrp.router.TimeAsTravelDisutility; import org.matsim.contrib.dvrp.trafficmonitoring.QSimFreeSpeedTravelTime; +import org.matsim.contrib.zone.skims.SparseMatrix.NodeAndTime; +import org.matsim.contrib.zone.skims.SparseMatrix.SparseRow; import org.matsim.core.router.util.TravelTime; +import com.google.common.base.Verify; +import com.google.common.collect.Sets; + /** * @author Michal Maciejewski (michalm) */ @@ -68,4 +88,151 @@ public int getTravelTime(Node fromNode, Node toNode, double departureTime) { public int getZonalTravelTime(Node fromNode, Node toNode, double departureTime) { return freeSpeedTravelTimeMatrix.get(zoneSystem.getZoneForNodeId(fromNode.getId()).orElseThrow(), zoneSystem.getZoneForNodeId(toNode.getId()).orElseThrow()); } + + public static FreeSpeedTravelTimeMatrix createFreeSpeedMatrixFromCache(Network dvrpNetwork, ZoneSystem zoneSystem, DvrpTravelTimeMatrixParams params, int numberOfThreads, double qSimTimeStepSize, File cachePath) { + boolean exists = cachePath.exists(); + + final FreeSpeedTravelTimeMatrix matrix; + if (exists) { + matrix = new FreeSpeedTravelTimeMatrix(dvrpNetwork, zoneSystem, cachePath); + } else { + matrix = createFreeSpeedMatrix(dvrpNetwork, zoneSystem, params, numberOfThreads, qSimTimeStepSize); + matrix.write(cachePath, dvrpNetwork); + } + + return matrix; + } + + public FreeSpeedTravelTimeMatrix(Network dvrpNetwork, ZoneSystem zoneSystem, File cachePath) { + this.zoneSystem = zoneSystem; + + try (DataInputStream inputStream = new DataInputStream(new FileInputStream(cachePath))) { + // number of zones + int numberOfZones = inputStream.readInt(); + Verify.verify(numberOfZones == zoneSystem.getZones().size()); + + // read zone list + List> zoneIds = new ArrayList<>(numberOfZones); + for (int i = 0; i < numberOfZones; i++) { + zoneIds.add(Id.create(inputStream.readUTF(), Zone.class)); + } + + IdSet systemZones = new IdSet<>(Zone.class); + systemZones.addAll(zoneSystem.getZones().keySet()); + + IdSet dataZones = new IdSet<>(Zone.class); + dataZones.addAll(zoneIds); + + Verify.verify(Sets.difference(systemZones, dataZones).size() == 0); + Verify.verify(Sets.difference(dataZones, systemZones).size() == 0); + + // fill matrix + freeSpeedTravelTimeMatrix = new Matrix(new HashSet<>(zoneSystem.getZones().values())); + + for (var from : zoneIds) { + for (var to : zoneIds) { + Zone fromZone = zoneSystem.getZones().get(from); + Zone toZone = zoneSystem.getZones().get(to); + freeSpeedTravelTimeMatrix.set(fromZone, toZone, inputStream.readInt()); + } + } + + // sparse matrix available? + boolean hasSparseMatrix = inputStream.readBoolean(); + + if (!hasSparseMatrix) { + freeSpeedTravelTimeSparseMatrix = null; + } else { + freeSpeedTravelTimeSparseMatrix = new SparseMatrix(); + + // read nodes + int numberOfNodes = inputStream.readInt(); + Verify.verify(numberOfNodes == dvrpNetwork.getNodes().size()); + + List nodes = new ArrayList<>(numberOfNodes); + for (int i = 0; i < numberOfNodes; i++) { + Id nodeId = Id.createNodeId(inputStream.readUTF()); + nodes.add(Objects.requireNonNull(dvrpNetwork.getNodes().get(nodeId))); + } + + // read rows + for (int i = 0; i < numberOfNodes; i++) { + Node from = nodes.get(i); + int numberOfElements = inputStream.readInt(); + + if (numberOfElements > 0) { + List nodeTimeList = new ArrayList<>(numberOfElements); + + for (int j = 0; j < numberOfElements; j++) { + Node to = nodes.get(inputStream.readInt()); + int value = inputStream.readInt(); + + nodeTimeList.add(new NodeAndTime(to.getId().index(), value)); + } + + SparseRow row = new SparseRow(nodeTimeList); + freeSpeedTravelTimeSparseMatrix.setRow(from, row); + } + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void write(File outputPath, Network dvrpNetwork) { + try (DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(outputPath))) { + // obtain fixed order of zones + List zones = new ArrayList<>(zoneSystem.getZones().values()); + outputStream.writeInt(zones.size()); + for (Zone zone : zones) { + outputStream.writeUTF(zone.getId().toString()); + } + + // write matrix + for (var from : zones) { + for (var to : zones) { + int value = freeSpeedTravelTimeMatrix.get(from, to); + outputStream.writeInt(value); + } + } + + // write if sparse exists + outputStream.writeBoolean(freeSpeedTravelTimeSparseMatrix != null); + + if (freeSpeedTravelTimeSparseMatrix != null) { + // obtain fixed order of nodes + List nodes = new ArrayList<>(dvrpNetwork.getNodes().values()); + outputStream.writeInt(nodes.size()); + for (Node node : nodes) { + outputStream.writeUTF(node.getId().toString()); + } + + for (Node from : nodes) { + // write size of the matrix row + int rowSize = 0; + + for (Node to : nodes) { + int value = freeSpeedTravelTimeSparseMatrix.get(from, to); + if (value >= 0) { + rowSize++; + } + } + + outputStream.writeInt(rowSize); + + // write matrix row + for (Node to : nodes) { + int value = freeSpeedTravelTimeSparseMatrix.get(from, to); + if (value >= 0) { + outputStream.writeInt(nodes.indexOf(to)); + outputStream.writeInt(value); + } + } + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } } diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java index 8aaf6001258..2cf4cc30934 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/zone/skims/FreeSpeedTravelTimeMatrixTest.java @@ -22,7 +22,10 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Network; @@ -30,12 +33,16 @@ import org.matsim.contrib.common.zones.ZoneSystem; import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystem; import org.matsim.core.network.NetworkUtils; +import org.matsim.testcases.MatsimTestUtils; /** * @author Michal Maciejewski (michalm) */ public class FreeSpeedTravelTimeMatrixTest { + @RegisterExtension + MatsimTestUtils utils = new MatsimTestUtils(); + private final Network network = NetworkUtils.createNetwork(); private final Node nodeA = NetworkUtils.createAndAddNode(network, Id.createNodeId("A"), new Coord(0, 0)); private final Node nodeB = NetworkUtils.createAndAddNode(network, Id.createNodeId("B"), new Coord(150, 150)); @@ -66,6 +73,23 @@ void matrix() { assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(0); assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + + // write and read cache + File cachePath = new File(utils.getOutputDirectory(), "cache.bin"); + matrix.write(cachePath, network); + matrix = FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, null, 1, 1, cachePath); + + // distances between central nodes: A and B + assertThat(matrix.getTravelTime(nodeA, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeA, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeA, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeB, 0)).isEqualTo(0); + + // non-central node: C and A are in the same zone; A is the central node + assertThat(matrix.getTravelTime(nodeA, nodeC, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes } @Test @@ -87,5 +111,22 @@ void sparseMatrix() { assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(9 + 1); // 1 s for moving over nodes assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 11 + 2); // 2 s for moving over nodes assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 9 + 2); // 2 s for moving over nodes + + // write and read cache + File cachePath = new File(utils.getOutputDirectory(), "cache.bin"); + matrix.write(cachePath, network); + matrix = FreeSpeedTravelTimeMatrix.createFreeSpeedMatrixFromCache(network, zoneSystem, null, 1, 1, cachePath); + + // distances between central nodes: A and B + assertThat(matrix.getTravelTime(nodeA, nodeA, 0)).isEqualTo(0); + assertThat(matrix.getTravelTime(nodeA, nodeB, 0)).isEqualTo(10 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeA, 0)).isEqualTo(20 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeB, 0)).isEqualTo(0); + + // non-central node: C and A are in the same zone; A is the central node + assertThat(matrix.getTravelTime(nodeA, nodeC, 0)).isEqualTo(11 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeA, 0)).isEqualTo(9 + 1); // 1 s for moving over nodes + assertThat(matrix.getTravelTime(nodeB, nodeC, 0)).isEqualTo(20 + 11 + 2); // 2 s for moving over nodes + assertThat(matrix.getTravelTime(nodeC, nodeB, 0)).isEqualTo(10 + 9 + 2); // 2 s for moving over nodes } } diff --git a/contribs/emissions/pom.xml b/contribs/emissions/pom.xml index 16d87bc8cdb..98daccca22b 100644 --- a/contribs/emissions/pom.xml +++ b/contribs/emissions/pom.xml @@ -58,7 +58,7 @@ org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} com.fasterxml.jackson.core diff --git a/contribs/ev/pom.xml b/contribs/ev/pom.xml index e1c5144d706..120d63dfbe3 100644 --- a/contribs/ev/pom.xml +++ b/contribs/ev/pom.xml @@ -14,7 +14,7 @@ org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} org.apache.commons diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargeUpToMaxSocStrategy.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargeUpToMaxSocStrategy.java index 85760aabefc..3703a7b0794 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargeUpToMaxSocStrategy.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargeUpToMaxSocStrategy.java @@ -23,30 +23,65 @@ import org.matsim.contrib.ev.fleet.Battery; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.ChargerSpecification; +import org.matsim.vehicles.Vehicle; /** * @author Michal Maciejewski (michalm) + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public class ChargeUpToMaxSocStrategy implements ChargingStrategy { + static public final String MAXIMUM_SOC_VEHICLE_ATTRIBUTE = "maximumSoc"; + + private final ElectricVehicle ev; private final ChargerSpecification charger; private final double maxSoc; - public ChargeUpToMaxSocStrategy(ChargerSpecification charger, double maxSoc) { + public ChargeUpToMaxSocStrategy(ChargerSpecification charger, ElectricVehicle ev, double maxSoc) { if (maxSoc < 0 || maxSoc > 1) { throw new IllegalArgumentException(); } this.charger = charger; this.maxSoc = maxSoc; + this.ev = ev; } @Override - public double calcRemainingEnergyToCharge(ElectricVehicle ev) { + public double calcRemainingEnergyToCharge() { Battery battery = ev.getBattery(); return maxSoc * battery.getCapacity() - battery.getCharge(); } @Override - public double calcRemainingTimeToCharge(ElectricVehicle ev) { - return ((BatteryCharging)ev.getChargingPower()).calcChargingTime(charger, calcRemainingEnergyToCharge(ev)); + public double calcRemainingTimeToCharge() { + return ((BatteryCharging)ev.getChargingPower()).calcChargingTime(charger, calcRemainingEnergyToCharge()); + } + + @Override + public boolean isChargingCompleted() { + return calcRemainingEnergyToCharge() <= 0; + } + + static public class Factory implements ChargingStrategy.Factory { + private final double maxSoc; + + public Factory(double maxSoc) { + this.maxSoc = maxSoc; + } + + @Override + public ChargingStrategy createStrategy(ChargerSpecification charger, ElectricVehicle ev) { + double vehicleMaximumSoc = maxSoc; + + Vehicle vehicle = ev.getVehicleSpecification().getMatsimVehicle(); + if (vehicle != null) { + Double value = (Double) vehicle.getAttributes().getAttribute(MAXIMUM_SOC_VEHICLE_ATTRIBUTE); + + if (value != null) { + vehicleMaximumSoc = value; + } + } + + return new ChargeUpToMaxSocStrategy(charger, ev, vehicleMaximumSoc); + } } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingEstimations.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingEstimations.java index 5c0499f3bbf..502573d8bb2 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingEstimations.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingEstimations.java @@ -20,7 +20,7 @@ import java.util.stream.Stream; -import org.matsim.contrib.ev.fleet.ElectricVehicle; +import org.matsim.contrib.ev.charging.ChargingLogic.ChargingVehicle; import org.matsim.contrib.ev.infrastructure.Charger; /** @@ -38,20 +38,18 @@ public static double estimateMaxWaitTimeForNextVehicle(Charger charger) { } public static double estimateTotalTimeToCharge(ChargingLogic logic) { - return estimateTotalTimeToCharge(logic.getChargingStrategy(), - Stream.concat(logic.getPluggedVehicles().stream(), logic.getQueuedVehicles().stream())); + return estimateTotalTimeToCharge(Stream.concat(logic.getPluggedVehicles().stream(), logic.getQueuedVehicles().stream())); } public static double estimateTotalEnergyToCharge(ChargingLogic logic) { - return estimateTotalEnergyToCharge(logic.getChargingStrategy(), - Stream.concat(logic.getPluggedVehicles().stream(), logic.getQueuedVehicles().stream())); + return estimateTotalEnergyToCharge(Stream.concat(logic.getPluggedVehicles().stream(), logic.getQueuedVehicles().stream())); } - public static double estimateTotalTimeToCharge(ChargingStrategy strategy, Stream vehicles) { - return vehicles.mapToDouble(strategy::calcRemainingTimeToCharge).sum(); + public static double estimateTotalTimeToCharge(Stream vehicles) { + return vehicles.map(ChargingVehicle::strategy).mapToDouble(ChargingStrategy::calcRemainingTimeToCharge).sum(); } - public static double estimateTotalEnergyToCharge(ChargingStrategy strategy, Stream vehicles) { - return vehicles.mapToDouble(strategy::calcRemainingEnergyToCharge).sum(); + public static double estimateTotalEnergyToCharge(Stream vehicles) { + return vehicles.map(ChargingVehicle::strategy).mapToDouble(ChargingStrategy::calcRemainingEnergyToCharge).sum(); } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingLogic.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingLogic.java index 854947741e0..de274606326 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingLogic.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingLogic.java @@ -29,17 +29,17 @@ interface Factory { ChargingLogic create(ChargerSpecification charger); } - void addVehicle(ElectricVehicle ev, double now); + void addVehicle(ElectricVehicle ev, ChargingStrategy strategy, double now); - void addVehicle(ElectricVehicle ev, ChargingListener chargingListener, double now); + void addVehicle(ElectricVehicle ev, ChargingStrategy strategy, ChargingListener chargingListener, double now); void removeVehicle(ElectricVehicle ev, double now); void chargeVehicles(double chargePeriod, double now); - Collection getPluggedVehicles(); + Collection getPluggedVehicles(); - Collection getQueuedVehicles(); + Collection getQueuedVehicles(); - ChargingStrategy getChargingStrategy(); + record ChargingVehicle(ElectricVehicle ev, ChargingStrategy strategy) {} } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingModule.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingModule.java index 7b42877507d..1f81bac495c 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingModule.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingModule.java @@ -20,14 +20,13 @@ package org.matsim.contrib.ev.charging; -import com.google.inject.Singleton; import org.matsim.contrib.ev.EvModule; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.controler.AbstractModule; import org.matsim.core.mobsim.qsim.AbstractQSimModule; -import com.google.inject.Inject; -import com.google.inject.Provider; +import com.google.inject.Provides; +import com.google.inject.Singleton; /** * @author Michal Maciejewski (michalm) @@ -35,13 +34,11 @@ public class ChargingModule extends AbstractModule { @Override public void install() { - // The following returns a charging logic for a given charger specification. Needs to be a provider, since the eventsManager needs to be inserted. - bind(ChargingLogic.Factory.class).toProvider(new Provider<>() { - @Inject private EventsManager eventsManager; - @Override public ChargingLogic.Factory get() { - return charger -> new ChargingWithQueueingLogic(charger, new ChargeUpToMaxSocStrategy(charger, 1.), eventsManager); - } - }); + // By default, charging logic with queue is used + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingLogic.Factory.class); + + // By default, charging strategy that chargers to 100% is used + bind(ChargingStrategy.Factory.class).toInstance(new ChargeUpToMaxSocStrategy.Factory(1.0)); // The following returns the charging power/speed for a vehicle: bind(ChargingPower.Factory.class).toInstance(ev -> new FixedSpeedCharging(ev, 1)); @@ -57,5 +54,18 @@ public void install() { // this.addMobsimListenerBinding().to( ChargingHandler.class ).in( Singleton.class ); // does not work since ChargingInfrastructure is not available. + + // standard charging priority for all chargers + bind(ChargingPriority.Factory.class).toInstance(ChargingPriority.FIFO); + } + + @Provides @Singleton + ChargingWithQueueingLogic.Factory provideChargingWithQueueingLogicFactory(EventsManager eventsManager, ChargingPriority.Factory chargingPriorityFactory) { + return new ChargingWithQueueingLogic.Factory(eventsManager, chargingPriorityFactory); + } + + @Provides @Singleton + ChargingWithQueueingAndAssignmentLogic.Factory provideChargingWithQueueingAndAssignmentLogicFactory(EventsManager eventsManager, ChargingPriority.Factory chargingPriorityFactory) { + return new ChargingWithQueueingAndAssignmentLogic.Factory(eventsManager, chargingPriorityFactory); } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingPriority.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingPriority.java new file mode 100644 index 00000000000..83087a37f79 --- /dev/null +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingPriority.java @@ -0,0 +1,29 @@ +package org.matsim.contrib.ev.charging; + +import org.matsim.contrib.ev.charging.ChargingLogic.ChargingVehicle; +import org.matsim.contrib.ev.infrastructure.ChargerSpecification; + +/** + * This interface is supposed to decide if a vehicle can be plugged right now or + * if it needs to go to / remain in the queue. While the condition whether + * enough of empty plugs are available is *always* checked, the presented method + * allows to define a more complex logic beyond that. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public interface ChargingPriority { + /** + * The vehicle can start charging if the method returns true, otherwise it stays + * in the queue. + */ + boolean requestPlugNext(ChargingVehicle cv, double now); + + public interface Factory { + ChargingPriority create(ChargerSpecification charger); + } + + /** + * The default charging priority: first-in first-out. + */ + static public final Factory FIFO = charger -> (ev, now) -> true; +} \ No newline at end of file diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingStrategy.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingStrategy.java index 87b76bf1303..bb5717b3cc2 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingStrategy.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingStrategy.java @@ -19,17 +19,21 @@ package org.matsim.contrib.ev.charging; import org.matsim.contrib.ev.fleet.ElectricVehicle; +import org.matsim.contrib.ev.infrastructure.ChargerSpecification; /** * @author michalm + * @author Sebastian Hörl (sebhoerl), IRT SystemX */ public interface ChargingStrategy { - default boolean isChargingCompleted(ElectricVehicle ev) { - return calcRemainingEnergyToCharge(ev) <= 0; - } + boolean isChargingCompleted(); - double calcRemainingEnergyToCharge(ElectricVehicle ev); + double calcRemainingEnergyToCharge(); //XXX should include potentially longer charging if AUX remains turned on - double calcRemainingTimeToCharge(ElectricVehicle ev); + double calcRemainingTimeToCharge(); + + static public interface Factory { + ChargingStrategy createStrategy(ChargerSpecification charger, ElectricVehicle ev); + } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithAssignmentLogic.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithAssignmentLogic.java index ceaabad797e..cd7333d9411 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithAssignmentLogic.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithAssignmentLogic.java @@ -5,9 +5,11 @@ import java.util.Collection; public interface ChargingWithAssignmentLogic extends ChargingLogic { - void assignVehicle(ElectricVehicle ev); + void assignVehicle(ElectricVehicle ev, ChargingStrategy strategy); void unassignVehicle(ElectricVehicle ev); - Collection getAssignedVehicles(); + Collection getAssignedVehicles(); + + boolean isAssigned(ElectricVehicle ev); } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingAndAssignmentLogic.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingAndAssignmentLogic.java index 5fb5cc0ae6d..1a0aa853af0 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingAndAssignmentLogic.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingAndAssignmentLogic.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import java.util.function.Function; import org.matsim.api.core.v01.Id; import org.matsim.contrib.ev.fleet.ElectricVehicle; @@ -31,21 +30,18 @@ import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.vehicles.Vehicle; -import com.google.inject.Inject; -import com.google.inject.Provider; - public class ChargingWithQueueingAndAssignmentLogic extends ChargingWithQueueingLogic implements ChargingWithAssignmentLogic { - private final Map, ElectricVehicle> assignedVehicles = new LinkedHashMap<>(); + private final Map, ChargingVehicle> assignedVehicles = new LinkedHashMap<>(); - public ChargingWithQueueingAndAssignmentLogic(ChargerSpecification charger, ChargingStrategy chargingStrategy, - EventsManager eventsManager) { - super(charger, chargingStrategy, eventsManager); + public ChargingWithQueueingAndAssignmentLogic(ChargerSpecification charger, EventsManager eventsManager, ChargingPriority priority) { + super(charger, eventsManager, priority); } @Override - public void assignVehicle(ElectricVehicle ev) { - if (assignedVehicles.put(ev.getId(), ev) != null) { + public void assignVehicle(ElectricVehicle ev, ChargingStrategy strategy) { + ChargingVehicle cv = new ChargingVehicle(ev, strategy); + if (assignedVehicles.put(ev.getId(), cv) != null) { throw new IllegalArgumentException("Vehicle is already assigned: " + ev.getId()); } } @@ -57,28 +53,31 @@ public void unassignVehicle(ElectricVehicle ev) { } } - private final Collection unmodifiableAssignedVehicles = Collections.unmodifiableCollection( + @Override + public boolean isAssigned(ElectricVehicle ev) { + return assignedVehicles.containsKey(ev.getId()); + } + + private final Collection unmodifiableAssignedVehicles = Collections.unmodifiableCollection( assignedVehicles.values()); @Override - public Collection getAssignedVehicles() { + public Collection getAssignedVehicles() { return unmodifiableAssignedVehicles; } - public static class FactoryProvider implements Provider { - @Inject - private EventsManager eventsManager; - - private final Function chargingStrategyCreator; + static public class Factory implements ChargingLogic.Factory { + private final EventsManager eventsManager; + private final ChargingPriority.Factory priorityFactory; - public FactoryProvider(Function chargingStrategyCreator) { - this.chargingStrategyCreator = chargingStrategyCreator; + public Factory(EventsManager eventsManager, ChargingPriority.Factory priorityFactory) { + this.eventsManager = eventsManager; + this.priorityFactory = priorityFactory; } @Override - public ChargingLogic.Factory get() { - return charger -> new ChargingWithQueueingAndAssignmentLogic(charger, - chargingStrategyCreator.apply(charger), eventsManager); + public ChargingLogic create(ChargerSpecification charger) { + return new ChargingWithQueueingAndAssignmentLogic(charger, eventsManager, priorityFactory.create(charger)); } } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingLogic.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingLogic.java index 8cf57733532..0e0de973ffe 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingLogic.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingLogic.java @@ -19,78 +19,87 @@ package org.matsim.contrib.ev.charging; -import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; + import org.matsim.api.core.v01.Id; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.ChargerSpecification; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.vehicles.Vehicle; -import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; +import com.google.common.base.Preconditions; public class ChargingWithQueueingLogic implements ChargingLogic { protected final ChargerSpecification charger; - private final ChargingStrategy chargingStrategy; private final EventsManager eventsManager; + private final ChargingPriority priority; - private final Map, ElectricVehicle> pluggedVehicles = new LinkedHashMap<>(); - private final Queue queuedVehicles = new LinkedList<>(); - private final Queue arrivingVehicles = new LinkedBlockingQueue<>(); + private final Map, ChargingVehicle> pluggedVehicles = new LinkedHashMap<>(); + private final Queue queuedVehicles = new LinkedList<>(); + private final Queue arrivingVehicles = new LinkedBlockingQueue<>(); private final Map, ChargingListener> listeners = new LinkedHashMap<>(); - public ChargingWithQueueingLogic(ChargerSpecification charger, ChargingStrategy chargingStrategy, EventsManager eventsManager) { - this.chargingStrategy = Objects.requireNonNull(chargingStrategy); + public ChargingWithQueueingLogic(ChargerSpecification charger, EventsManager eventsManager, ChargingPriority priority) { this.charger = Objects.requireNonNull(charger); this.eventsManager = Objects.requireNonNull(eventsManager); + this.priority = priority; } @Override public void chargeVehicles(double chargePeriod, double now) { - Iterator evIter = pluggedVehicles.values().iterator(); - while (evIter.hasNext()) { - ElectricVehicle ev = evIter.next(); + Iterator cvIter = pluggedVehicles.values().iterator(); + while (cvIter.hasNext()) { + ChargingVehicle cv = cvIter.next(); // with fast charging, we charge around 4% of SOC per minute, // so when updating SOC every 10 seconds, SOC increases by less then 1% - double oldCharge = ev.getBattery().getCharge(); - double energy = ev.getChargingPower().calcChargingPower(charger) * chargePeriod; - double newCharge = Math.min(oldCharge + energy, ev.getBattery().getCapacity()); - ev.getBattery().setCharge(newCharge); - eventsManager.processEvent(new EnergyChargedEvent(now, charger.getId(), ev.getId(), newCharge - oldCharge, newCharge)); - - if (chargingStrategy.isChargingCompleted(ev)) { - evIter.remove(); - eventsManager.processEvent(new ChargingEndEvent(now, charger.getId(), ev.getId(), ev.getBattery().getCharge())); - listeners.remove(ev.getId()).notifyChargingEnded(ev, now); + double oldCharge = cv.ev().getBattery().getCharge(); + double energy = cv.ev().getChargingPower().calcChargingPower(charger) * chargePeriod; + double newCharge = Math.min(oldCharge + energy, cv.ev().getBattery().getCapacity()); + cv.ev().getBattery().setCharge(newCharge); + eventsManager.processEvent(new EnergyChargedEvent(now, charger.getId(), cv.ev().getId(), newCharge - oldCharge, newCharge)); + + if (cv.strategy().isChargingCompleted()) { + cvIter.remove(); + eventsManager.processEvent(new ChargingEndEvent(now, charger.getId(), cv.ev().getId(), cv.ev().getBattery().getCharge())); + listeners.remove(cv.ev().getId()).notifyChargingEnded(cv.ev(), now); } } - int queuedToPluggedCount = Math.min(queuedVehicles.size(), charger.getPlugCount() - pluggedVehicles.size()); - for (int i = 0; i < queuedToPluggedCount; i++) { - plugVehicle(queuedVehicles.poll(), now); + var queuedVehiclesIter = queuedVehicles.iterator(); + while (queuedVehiclesIter.hasNext() && pluggedVehicles.size() < charger.getPlugCount()) { + var cv = queuedVehiclesIter.next(); + if (plugVehicle(cv, now)) { + queuedVehiclesIter.remove(); + } } var arrivingVehiclesIter = arrivingVehicles.iterator(); while (arrivingVehiclesIter.hasNext()) { - var ev = arrivingVehiclesIter.next(); - if (pluggedVehicles.size() < charger.getPlugCount()) { - plugVehicle(ev, now); - } else { - queueVehicle(ev, now); + var cv = arrivingVehiclesIter.next(); + if (pluggedVehicles.size() >= charger.getPlugCount() || !plugVehicle(cv, now)) { + queueVehicle(cv, now); } - arrivingVehiclesIter.remove(); } + arrivingVehicles.clear(); } @Override - public void addVehicle(ElectricVehicle ev, double now) { - addVehicle(ev, new ChargingListener() { + public void addVehicle(ElectricVehicle ev, ChargingStrategy strategy, double now) { + addVehicle(ev, strategy, new ChargingListener() { }, now); } @Override - public void addVehicle(ElectricVehicle ev, ChargingListener chargingListener, double now) { - arrivingVehicles.add(ev); + public void addVehicle(ElectricVehicle ev, ChargingStrategy strategy, ChargingListener chargingListener, double now) { + arrivingVehicles.add(new ChargingVehicle(ev, strategy)); listeners.put(ev.getId(), chargingListener); } @@ -100,47 +109,79 @@ public void removeVehicle(ElectricVehicle ev, double now) { eventsManager.processEvent(new ChargingEndEvent(now, charger.getId(), ev.getId(), ev.getBattery().getCharge())); listeners.remove(ev.getId()).notifyChargingEnded(ev, now); - if (!queuedVehicles.isEmpty()) { - plugVehicle(queuedVehicles.poll(), now); + var queuedVehiclesIter = queuedVehicles.iterator(); + while (queuedVehiclesIter.hasNext()) { + var queuedVehicle = queuedVehiclesIter.next(); + if (plugVehicle(queuedVehicle, now)) { + queuedVehiclesIter.remove(); + break; + } } } else { - // make sure ev was in the queue - Preconditions.checkState(queuedVehicles.remove(ev), "Vehicle (%s) is neither queued nor plugged at charger (%s)", ev.getId(), - charger.getId()); - eventsManager.processEvent(new QuitQueueAtChargerEvent(now, charger.getId(), ev.getId())); + var queuedVehiclesIter = queuedVehicles.iterator(); + while (queuedVehiclesIter.hasNext()) { + var queuedVehicle = queuedVehiclesIter.next(); + + if (queuedVehicle.ev() == ev) { + queuedVehiclesIter.remove(); + eventsManager.processEvent(new QuitQueueAtChargerEvent(now, charger.getId(), ev.getId())); + return; // found the vehicle + } + } + + throw new IllegalStateException(String.format("Vehicle (%s) is neither queued nor plugged at charger (%s)", ev.getId(), + charger.getId())); } } - private void queueVehicle(ElectricVehicle ev, double now) { - queuedVehicles.add(ev); - eventsManager.processEvent(new QueuedAtChargerEvent(now, charger.getId(), ev.getId())); - listeners.get(ev.getId()).notifyVehicleQueued(ev, now); + private void queueVehicle(ChargingVehicle cv, double now) { + queuedVehicles.add(cv); + eventsManager.processEvent(new QueuedAtChargerEvent(now, charger.getId(), cv.ev().getId())); + listeners.get(cv.ev().getId()).notifyVehicleQueued(cv.ev(), now); } - private void plugVehicle(ElectricVehicle ev, double now) { - if (pluggedVehicles.put(ev.getId(), ev) != null) { + private boolean plugVehicle(ChargingVehicle cv, double now) { + assert pluggedVehicles.size() < charger.getPlugCount(); + + if (!priority.requestPlugNext(cv, now)) { + return false; + } + + if (pluggedVehicles.put(cv.ev().getId(), cv) != null) { throw new IllegalArgumentException(); } - eventsManager.processEvent(new ChargingStartEvent(now, charger.getId(), ev.getId(), ev.getBattery().getCharge())); - listeners.get(ev.getId()).notifyChargingStarted(ev, now); + eventsManager.processEvent(new ChargingStartEvent(now, charger.getId(), cv.ev().getId(), cv.ev().getBattery().getCharge())); + listeners.get(cv.ev().getId()).notifyChargingStarted(cv.ev(), now); + + return true; } - private final Collection unmodifiablePluggedVehicles = Collections.unmodifiableCollection(pluggedVehicles.values()); + private final Collection unmodifiablePluggedVehicles = Collections.unmodifiableCollection(pluggedVehicles.values()); @Override - public Collection getPluggedVehicles() { + public Collection getPluggedVehicles() { return unmodifiablePluggedVehicles; } - private final Collection unmodifiableQueuedVehicles = Collections.unmodifiableCollection(queuedVehicles); + private final Collection unmodifiableQueuedVehicles = Collections.unmodifiableCollection(queuedVehicles); @Override - public Collection getQueuedVehicles() { + public Collection getQueuedVehicles() { return unmodifiableQueuedVehicles; } - @Override - public ChargingStrategy getChargingStrategy() { - return chargingStrategy; + static public class Factory implements ChargingLogic.Factory { + private final EventsManager eventsManager; + private final ChargingPriority.Factory chargingPriorityFactory; + + public Factory(EventsManager eventsManager, ChargingPriority.Factory chargingPriorityFactory) { + this.eventsManager = eventsManager; + this.chargingPriorityFactory = chargingPriorityFactory; + } + + @Override + public ChargingLogic create(ChargerSpecification charger) { + return new ChargingWithQueueingLogic(charger, eventsManager, chargingPriorityFactory.create(charger)); + } } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/VehicleChargingHandler.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/VehicleChargingHandler.java index d206a50c875..15431cea1fe 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/VehicleChargingHandler.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/VehicleChargingHandler.java @@ -86,11 +86,14 @@ public class VehicleChargingHandler private final ImmutableListMultimap, Charger> chargersAtLinks; private final EvConfigGroup evCfg; + private final ChargingStrategy.Factory strategyFactory; + @Inject - VehicleChargingHandler(ChargingInfrastructure chargingInfrastructure, ElectricFleet electricFleet, EvConfigGroup evConfigGroup) { + VehicleChargingHandler(ChargingInfrastructure chargingInfrastructure, ElectricFleet electricFleet, EvConfigGroup evConfigGroup, ChargingStrategy.Factory strategyFactory) { this.chargingInfrastructure = chargingInfrastructure; this.electricFleet = electricFleet; this.evCfg = evConfigGroup; + this.strategyFactory = strategyFactory; chargersAtLinks = ChargingInfrastructureUtils.getChargersAtLinks(chargingInfrastructure ); } @@ -112,7 +115,7 @@ public void handleEvent(ActivityStartEvent event) { .filter(ch -> ev.getChargerTypes().contains(ch.getChargerType())) .findAny() .get(); - c.getLogic().addVehicle(ev, event.getTime()); + c.getLogic().addVehicle(ev, strategyFactory.createStrategy(c.getSpecification(), ev), event.getTime()); vehiclesAtChargers.put(evId, c.getId()); } } diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricFleetSpecificationDefaultImpl.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricFleetSpecificationDefaultImpl.java index b24583feb13..6b9b30e8cfd 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricFleetSpecificationDefaultImpl.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricFleetSpecificationDefaultImpl.java @@ -30,7 +30,7 @@ /** * @author Michal Maciejewski (michalm) */ -final class ElectricFleetSpecificationDefaultImpl implements ElectricFleetSpecification { +public final class ElectricFleetSpecificationDefaultImpl implements ElectricFleetSpecification { private final Map, ElectricVehicleSpecification> specifications = new LinkedHashMap<>(); @Override diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricVehicleSpecificationDefaultImpl.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricVehicleSpecificationDefaultImpl.java index ef18ae6cce6..e3a4caca03e 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricVehicleSpecificationDefaultImpl.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/fleet/ElectricVehicleSpecificationDefaultImpl.java @@ -33,7 +33,7 @@ /** * @author Michal Maciejewski (michalm) */ -final class ElectricVehicleSpecificationDefaultImpl implements ElectricVehicleSpecification { +public final class ElectricVehicleSpecificationDefaultImpl implements ElectricVehicleSpecification { private final Vehicle matsimVehicle; diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureSpecificationDefaultImpl.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureSpecificationDefaultImpl.java index 48a27563616..763a2cd70e1 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureSpecificationDefaultImpl.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/infrastructure/ChargingInfrastructureSpecificationDefaultImpl.java @@ -28,7 +28,7 @@ /** * @author Michal Maciejewski (michalm) */ -final class ChargingInfrastructureSpecificationDefaultImpl implements ChargingInfrastructureSpecification { +public final class ChargingInfrastructureSpecificationDefaultImpl implements ChargingInfrastructureSpecification { private final SpecificationContainer container = new SpecificationContainer<>(); @Override diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationManager.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationManager.java new file mode 100644 index 00000000000..6e6fa1e77c9 --- /dev/null +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationManager.java @@ -0,0 +1,106 @@ +package org.matsim.contrib.ev.reservation; + +import java.util.LinkedList; +import java.util.List; + +import org.matsim.api.core.v01.IdMap; +import org.matsim.contrib.ev.fleet.ElectricVehicle; +import org.matsim.contrib.ev.infrastructure.Charger; +import org.matsim.contrib.ev.infrastructure.ChargerSpecification; +import org.matsim.core.controler.events.IterationStartsEvent; +import org.matsim.core.controler.listener.IterationStartsListener; + +/** + * This class is a singleton service that keeps a list of reservations for + * chargers. It can be used in combination with the + * ReservationBasedChargingPriority to let vehicle pass on to charging only if + * they have a proper reservation. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class ChargerReservationManager implements IterationStartsListener { + private final IdMap> reservations = new IdMap<>(Charger.class); + + public boolean isAvailable(ChargerSpecification charger, ElectricVehicle vehicle, double startTile, + double endTime) { + if (charger.getPlugCount() == 0) { + return false; + } + + if (!reservations.containsKey(charger.getId())) { + return true; + } + + int remaining = charger.getPlugCount(); + for (Reservation reservation : reservations.get(charger.getId())) { + if (reservation.vehicle != vehicle && isOverlapping(reservation, startTile, endTime)) { + remaining--; + } + } + + return remaining > 0; + } + + private boolean isOverlapping(Reservation reservation, double startTime, double endTime) { + if (startTime >= reservation.startTime && startTime <= reservation.endTime) { + return true; // start time within existing range + } else if (endTime >= reservation.startTime && endTime <= reservation.endTime) { + return true; // end time within existing range + } else if (startTime <= reservation.startTime && endTime >= reservation.endTime) { + return true; // new range covers existing range + } else { + return false; + } + } + + public Reservation addReservation(ChargerSpecification charger, ElectricVehicle vehicle, double startTime, + double endTime) { + if (isAvailable(charger, vehicle, startTime, endTime)) { + List chargerReservations = reservations.get(charger.getId()); + + if (chargerReservations == null) { + chargerReservations = new LinkedList<>(); + reservations.put(charger.getId(), chargerReservations); + } + + Reservation reservation = new Reservation(charger, vehicle, startTime, endTime); + chargerReservations.add(reservation); + + return reservation; + } + + return null; + } + + public boolean removeReservation(Reservation reservation) { + List chargerReservations = reservations.get(reservation.charger.getId()); + + if (chargerReservations != null) { + return chargerReservations.remove(reservation); + } + + return false; + } + + public Reservation findReservation(ChargerSpecification charger, ElectricVehicle vehicle, double now) { + List chargerReservations = reservations.get(charger.getId()); + + if (chargerReservations != null) { + for (Reservation reservation : chargerReservations) { + if (reservation.vehicle == vehicle && now >= reservation.startTime && now <= reservation.endTime) { + return reservation; + } + } + } + + return null; + } + + public record Reservation(ChargerSpecification charger, ElectricVehicle vehicle, double startTime, double endTime) { + } + + @Override + public void notifyIterationStarts(IterationStartsEvent event) { + reservations.clear(); + } +} \ No newline at end of file diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationModule.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationModule.java new file mode 100644 index 00000000000..9a17f208055 --- /dev/null +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationModule.java @@ -0,0 +1,35 @@ +package org.matsim.contrib.ev.reservation; + +import org.matsim.contrib.ev.charging.ChargingPriority; +import org.matsim.core.controler.AbstractModule; + +import com.google.inject.Provides; +import com.google.inject.Singleton; + +/** + * This module enables the reservation-based charging logic that requires + * vehicles to have or make a reservation when attempting to charge at a + * charger. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class ChargerReservationModule extends AbstractModule { + @Override + public void install() { + addControlerListenerBinding().to(ChargerReservationManager.class); + bind(ChargingPriority.Factory.class).to(ReservationBasedChargingPriority.Factory.class); + } + + @Provides + @Singleton + ReservationBasedChargingPriority.Factory provideReservationBasedChargingPriorityFactory( + ChargerReservationManager reservationManager) { + return new ReservationBasedChargingPriority.Factory(reservationManager); + } + + @Provides + @Singleton + ChargerReservationManager provideChargerReservationManager() { + return new ChargerReservationManager(); + } +} \ No newline at end of file diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ReservationBasedChargingPriority.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ReservationBasedChargingPriority.java new file mode 100644 index 00000000000..8ac5a79a8ad --- /dev/null +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ReservationBasedChargingPriority.java @@ -0,0 +1,64 @@ +package org.matsim.contrib.ev.reservation; + +import org.matsim.contrib.ev.charging.ChargingLogic.ChargingVehicle; +import org.matsim.contrib.ev.charging.ChargingPriority; +import org.matsim.contrib.ev.infrastructure.ChargerSpecification; +import org.matsim.contrib.ev.reservation.ChargerReservationManager.Reservation; + +/** + * This is an implementation of a charging priority which is backed by the + * ReservationManager: When a vehicle arrives, it is checked whether a + * reservation for this vehicle exists for the respective charger and the + * current time. In that case, the vehicle can be plugged if it is on top of the + * queue. If not, the ChargingPriority will try to make a reservation and if it + * is successful, the vehicle can start charging. In all other cases, the + * vehicle will stay in the queue until it is removed manually or a successful + * reservation can be made at a future time. + * + * @author Sebastian Hörl (sebhoerl), IRT SystemX + */ +public class ReservationBasedChargingPriority implements ChargingPriority { + private final ChargerReservationManager manager; + private final ChargerSpecification charger; + + public ReservationBasedChargingPriority(ChargerReservationManager manager, ChargerSpecification charger) { + this.charger = charger; + this.manager = manager; + } + + @Override + public boolean requestPlugNext(ChargingVehicle cv, double now) { + Reservation reservation = manager.findReservation(charger, cv.ev(), now); + + if (reservation != null) { + // vehicle has a reservation, can be plugged right away, consume reservation + manager.removeReservation(reservation); + return true; + } + + double endTime = cv.strategy().calcRemainingTimeToCharge() + now; + reservation = manager.addReservation(charger, cv.ev(), now, endTime); + + if (reservation != null) { + // vehicle did not have a reservation, but managed to create one on the fly, + // consume it directly + manager.removeReservation(reservation); + return true; + } + + return false; + } + + static public class Factory implements ChargingPriority.Factory { + private final ChargerReservationManager reservationManager; + + public Factory(ChargerReservationManager reservationManager) { + this.reservationManager = reservationManager; + } + + @Override + public ChargingPriority create(ChargerSpecification charger) { + return new ReservationBasedChargingPriority(reservationManager, charger); + } + } +} \ No newline at end of file diff --git a/contribs/ev/src/main/java/org/matsim/contrib/ev/stats/ChargingProceduresCSVWriter.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/stats/ChargingProceduresCSVWriter.java index ae1c9d0c013..4cef65da81b 100644 --- a/contribs/ev/src/main/java/org/matsim/contrib/ev/stats/ChargingProceduresCSVWriter.java +++ b/contribs/ev/src/main/java/org/matsim/contrib/ev/stats/ChargingProceduresCSVWriter.java @@ -83,8 +83,12 @@ private void proccessChargingEventSequences(CSVPrinter csvPrinter, Collection() { - @Inject - private ChargerPowerTimeProfileCalculator calculator; - @Inject - private MatsimServices matsimServices; + }); + bind(ChargerPowerTimeProfileCalculator.class).asEagerSingleton(); + addEventHandlerBinding().to(ChargerPowerTimeProfileCalculator.class); + addControlerListenerBinding().toProvider(new Provider<>() { + @Inject + private ChargerPowerTimeProfileCalculator calculator; + @Inject + private MatsimServices matsimServices; - @Override - public ControlerListener get() { - var profileView = new ChargerPowerTimeProfileView(calculator); - return new ProfileWriter(matsimServices,"ev",profileView,"charger_power_time_profiles"); + @Override + public ControlerListener get() { + var profileView = new ChargerPowerTimeProfileView(calculator); + return new ProfileWriter(matsimServices, "ev", profileView, "charger_power_time_profiles"); - } - }); + } + }); + } } } 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/pom.xml b/contribs/freight/pom.xml index d6dd0d20b65..c1df7ab953a 100644 --- a/contribs/freight/pom.xml +++ b/contribs/freight/pom.xml @@ -55,13 +55,13 @@ org.matsim.contrib roadpricing - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} @@ -85,7 +85,7 @@ org.matsim matsim-examples - 2025.0-SNAPSHOT + ${project.parent.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/Carrier.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/Carrier.java index 8ee9e1812e5..e80fbb6c9fa 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/Carrier.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/Carrier.java @@ -21,13 +21,12 @@ package org.matsim.freight.carriers; +import java.util.List; +import java.util.Map; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.population.HasPlansAndId; import org.matsim.utils.objectattributes.attributable.Attributable; -import java.util.List; -import java.util.Map; - /** * A carrier. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierCapabilities.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierCapabilities.java index fa14ddfd9bb..879017be0f4 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierCapabilities.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierCapabilities.java @@ -21,12 +21,11 @@ package org.matsim.freight.carriers; +import java.util.*; import org.matsim.api.core.v01.Id; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; -import java.util.*; - /** * This contains the capabilities/resources a carrier has/can deploy. * @@ -65,7 +64,7 @@ public Builder setFleetSize(FleetSize fleetSize){ /** * @deprecated Since the vehicle type is in the {@link CarrierVehicleTypes} * container, it should not be duplicated here. It is also not written - * to file when writing {@link CarrierPlanXmlWriterV2}. + * to file when writing. */ @Deprecated public Builder addType( VehicleType type ){ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierImpl.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierImpl.java index 8dcc53adc75..54bebb6b9d2 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierImpl.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierImpl.java @@ -21,14 +21,13 @@ package org.matsim.freight.carriers; -import org.matsim.api.core.v01.Id; -import org.matsim.utils.objectattributes.attributable.Attributes; -import org.matsim.utils.objectattributes.attributable.AttributesImpl; - import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; /** * This is a carrier that has capabilities and resources, jobs and plans to fulfill its obligations. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierJob.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierJob.java new file mode 100644 index 00000000000..1dc1cd32f8d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierJob.java @@ -0,0 +1,19 @@ +package org.matsim.freight.carriers; + +import org.matsim.utils.objectattributes.attributable.Attributable; + +/** + * A job that a {@link Carrier} can do. + *

+ * In a first step this is more or less a marker interface. + *

+ * In the next steps it will be extended, as follows + * 1) existing common methods of {@link CarrierShipment} and {@link + * CarrierService} where moved up here + * 2) some similar, but differently named methods of {@link + * CarrierShipment} and {@link CarrierService} were renamed to the same name and moved up here + * ... + * future) It maybe gets generalized in way, that we only have one job definition with 1 or 2 + * location(s). This then defines, if jsprit takes the job as a service or as a shipment. + */ +public interface CarrierJob extends Attributable {} diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlan.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlan.java index 9c51aac159e..eed09f1b42b 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlan.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlan.java @@ -21,13 +21,12 @@ package org.matsim.freight.carriers; +import java.util.Collection; import org.matsim.api.core.v01.population.BasicPlan; import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; -import java.util.Collection; - /** * * A specific plan of a carrier, and its score. @@ -70,7 +69,6 @@ public Double getScore() { /** * In future (starting in May'23) this is the score from the MATSim scoring function. * The jsprit score is saved in attribute. Please use the method setJspritScore() to store it. - * @return the (MATSim) score */ @Override public void setScore(Double score) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanReaderV1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanReaderV1.java index 4e13ad599b6..4bb90047d86 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanReaderV1.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanReaderV1.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -34,8 +35,6 @@ import org.matsim.vehicles.VehicleType; import org.xml.sax.Attributes; -import java.util.*; - /** * A reader that reads carriers and their plans. * @@ -82,7 +81,7 @@ class CarrierPlanReaderV1 extends MatsimXmlParser { * Constructs a reader with an empty carriers-container for the carriers to be constructed. * * @param carriers which is a map that stores carriers - * @param carrierVehicleTypes + * @param carrierVehicleTypes which is a map that stores carrierVehicleTypes */ public CarrierPlanReaderV1( Carriers carriers, CarrierVehicleTypes carrierVehicleTypes ) { super(ValidationType.DTD_OR_XSD); @@ -188,7 +187,7 @@ public void startTag(String name, Attributes attributes, Stack context) { String vehicleId = attributes.getValue("vehicleId"); currentVehicle = vehicles.get(vehicleId); - currentTourBuilder = Tour.Builder.newInstance(); + currentTourBuilder = Tour.Builder.newInstance(Id.create("unknown", Tour.class)); break ; } case "leg": diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanWriter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanWriter.java index 3d7922d9489..888bfcf5289 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanWriter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanWriter.java @@ -22,9 +22,8 @@ package org.matsim.freight.carriers; import com.google.inject.Inject; -import org.matsim.utils.objectattributes.AttributeConverter; - import java.util.Map; +import org.matsim.utils.objectattributes.AttributeConverter; /** * @author mrieser / Simunto @@ -47,31 +46,6 @@ public void write(String filename) { this.writeV2_1(filename); } - /** - * @deprecated The underlining {@Link{CarrierPlanXmlWriterV1} is deprecated since April21 - */ - @Deprecated - public void writeV1(String filename) { - new CarrierPlanXmlWriterV1(this.carriers.getCarriers().values()).write(filename); - } - - - /** - * Writes out the Carriers file in version 2. - * Please use the method {@link #write(String)} instead to always ensure writing out to the newest format. - * - * @deprecated The underlining {@Link{CarrierPlanXmlWriterV2} is deprecated since Sep'22 - * - * @param filename Name of the file that should be written. - */ - @Deprecated public void writeV2(String filename) { - CarrierPlanXmlWriterV2 writer = new CarrierPlanXmlWriterV2(this.carriers); - if (this.attributeConverters != null) { - writer.putAttributeConverters(this.attributeConverters); - } - writer.write(filename); - } - /** * Writes out the Carriers file in version 2.1. * Please use the method {@link #write(String)} to always ensure writing out to the newest format. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2.java index a63697cfab4..271871b0970 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2.java @@ -21,7 +21,10 @@ package org.matsim.freight.carriers; +import static org.matsim.freight.carriers.CarrierConstants.*; + 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; @@ -40,10 +43,6 @@ import org.matsim.vehicles.VehicleType; import org.xml.sax.Attributes; -import java.util.*; - -import static org.matsim.freight.carriers.CarrierConstants.*; - class CarrierPlanXmlParserV2 extends MatsimXmlParser { public static final Logger logger = LogManager.getLogger(CarrierPlanXmlParserV2.class); @@ -78,7 +77,7 @@ class CarrierPlanXmlParserV2 extends MatsimXmlParser { * Constructs a reader with an empty carriers-container for the carriers to be constructed. * * @param carriers which is a map that stores carriers - * @param carrierVehicleTypes + * @param carrierVehicleTypes which is a map that stores vehicle types */ CarrierPlanXmlParserV2( Carriers carriers, CarrierVehicleTypes carrierVehicleTypes ) { super(ValidationType.XSD_ONLY); @@ -234,7 +233,7 @@ public void startTag(String name, Attributes atts, Stack context) { currentVehicle = vehicles.get(vehicleId); if (currentVehicle == null) throw new IllegalStateException("vehicle to vehicleId " + vehicleId + " is missing."); - currentTourBuilder = Tour.Builder.newInstance(); + currentTourBuilder = Tour.Builder.newInstance(Id.create("unknown", Tour.class)); break; case "leg": String depTime = atts.getValue("expected_dep_time"); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2_1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2_1.java index 8503eb4acad..9c3f2b7a1e6 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2_1.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlParserV2_1.java @@ -21,7 +21,10 @@ package org.matsim.freight.carriers; +import static org.matsim.freight.carriers.CarrierConstants.*; + 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; @@ -40,10 +43,6 @@ import org.matsim.vehicles.VehicleType; import org.xml.sax.Attributes; -import java.util.*; - -import static org.matsim.freight.carriers.CarrierConstants.*; - class CarrierPlanXmlParserV2_1 extends MatsimXmlParser { public static final Logger logger = LogManager.getLogger(CarrierPlanXmlParserV2_1.class); @@ -77,7 +76,7 @@ class CarrierPlanXmlParserV2_1 extends MatsimXmlParser { * Constructs a reader with an empty carriers-container for the carriers to be constructed. * * @param carriers which is a map that stores carriers - * @param carrierVehicleTypes + * @param carrierVehicleTypes which is a map that stores vehicle types */ CarrierPlanXmlParserV2_1(Carriers carriers, CarrierVehicleTypes carrierVehicleTypes ) { super(ValidationType.XSD_ONLY); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlReader.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlReader.java index 5155f5bdebc..4842ab434f9 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlReader.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlReader.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers; +import java.io.InputStream; +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; @@ -28,10 +31,6 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import java.io.InputStream; -import java.net.URL; -import java.util.Stack; - /** * A reader that reads carriers and their plans. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1.java deleted file mode 100644 index 510ea9b1ac3..00000000000 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * *********************************************************************** * - * 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.carriers; - -import com.graphhopper.jsprit.core.problem.job.Shipment; -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.population.routes.NetworkRoute; -import org.matsim.core.utils.io.MatsimXmlWriter; -import org.matsim.core.utils.misc.Time; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * A writer that writes carriers and their plans in a xml-file. - * - * @author sschroeder - * - * @deprecated Use {@link CarrierPlanWriter} instead which writes the newest format - */ -@Deprecated -public class CarrierPlanXmlWriterV1 extends MatsimXmlWriter { - - @SuppressWarnings("unused") - private static final Logger logger = LogManager.getLogger(CarrierPlanXmlWriterV1.class); - - private final Collection carriers; - private int idCounter = 0; - private final Map> registeredShipments = new HashMap<>(); - - /** - * Constructs the writer with the carriers to be written. - * - * @param carriers to be written - */ - public CarrierPlanXmlWriterV1(Collection carriers) { - super(); - this.carriers = carriers; - } - - /** - * Writes carriers and their plans into a xml-file. - * - * @param filename should be the target xml-file - */ - public void write(String filename) { - logger.info("write carrier plans"); - try { - openFile(filename); - writeXmlHead(); - startCarriers(this.writer); - for (Carrier carrier : carriers) { - startCarrier(carrier, this.writer); - writeVehicles(carrier, this.writer); - writeShipments(carrier, this.writer); - writePlans(carrier, this.writer); - endCarrier(this.writer); - } - endCarriers(this.writer); - close(); - logger.info("done"); - } catch (IOException e) { - e.printStackTrace(); - logger.error(e); - System.exit(1); - } - } - - private void startCarriers(BufferedWriter writer) throws IOException { - writer.write("\t\n"); - } - - private void startCarrier(Carrier carrier, BufferedWriter writer) - throws IOException { - writer.write("\t\t\n"); - } - - private void writeVehicles(Carrier carrier, BufferedWriter writer) - throws IOException { - writer.write("\t\t\t\n"); - for (CarrierVehicle v : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { - writer.write("\t\t\t\t\n"); - } - writer.write("\t\t\t\n\n"); - } - - private void writeShipments(Carrier carrier, BufferedWriter writer) - throws IOException { - writer.write("\t\t\t\n"); - for (CarrierShipment s : carrier.getShipments().values()) { - // CarrierShipment s = contract.getShipment(); - Id shipmentId = Id.create(++idCounter, Shipment.class); - registeredShipments.put(s, shipmentId); - writer.write("\t\t\t\t\n"); - } - writer.write("\t\t\t\n\n"); - } - - private String getTime(double time) { - return Time.writeTime(time); - } - - private void writePlans(Carrier carrier, BufferedWriter writer) - throws IOException { - if (carrier.getSelectedPlan() == null) { - return; - } - - for(CarrierPlan plan : carrier.getPlans()){ - writer.write("\t\t\t\n"); - - for (ScheduledTour tour : plan.getScheduledTours()) { - writer.write("\t\t\t\t\n"); - writer.write("\t\t\t\t\t\n"); - for (Tour.TourElement tourElement : tour.getTour().getTourElements()) { - if (tourElement instanceof Tour.Leg leg) { - writer.write("\t\t\t\t\t"); - if (leg.getRoute() != null) { - writer.write("\n"); - writer.write("\t\t\t\t\t\t"); - boolean firstLink = true; - for (Id id : ((NetworkRoute) leg.getRoute()).getLinkIds()) { - if (firstLink) { - writer.write(id.toString()); - firstLink = false; - } else { - writer.write(" " + id.toString()); - } - } - writer.write("\n"); - writer.write("\t\t\t\t\t\n"); - } else { - writer.write("\n"); - } - } - if (tourElement instanceof Tour.ShipmentBasedActivity act) { - writer.write("\t\t\t\t\t\n"); - } - - } - writer.write("\t\t\t\t\t\n"); - writer.write("\t\t\t\t\n"); - } - writer.write("\t\t\t\n\n"); - } - - } - - private void endCarrier(BufferedWriter writer) throws IOException { - writer.write("\t\t\n\n"); - registeredShipments.clear(); - } - - private void endCarriers(BufferedWriter writer) throws IOException { - writer.write("\t\n"); - - } -} diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2.java deleted file mode 100644 index b78af8aa3e6..00000000000 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * *********************************************************************** * - * 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.carriers; - -import com.google.inject.Inject; -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.population.routes.NetworkRoute; -import org.matsim.core.utils.collections.Tuple; -import org.matsim.core.utils.io.MatsimXmlWriter; -import org.matsim.core.utils.misc.Time; -import org.matsim.freight.carriers.Tour.Leg; -import org.matsim.freight.carriers.Tour.ServiceActivity; -import org.matsim.freight.carriers.Tour.ShipmentBasedActivity; -import org.matsim.freight.carriers.Tour.TourElement; -import org.matsim.utils.objectattributes.AttributeConverter; -import org.matsim.utils.objectattributes.attributable.AttributesXmlWriterDelegate; -import org.matsim.vehicles.VehicleType; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.*; - -/** - * A writer that writes carriers and their plans in a xml-file. - * - * @author sschroeder - * - * @deprecated Use {@link CarrierPlanWriter} instead which writes the newest format - */ -@Deprecated -public class CarrierPlanXmlWriterV2 extends MatsimXmlWriter { - - @SuppressWarnings("unused") - private static final Logger logger = LogManager.getLogger(CarrierPlanXmlWriterV2.class); - - private final Collection carriers; - - private final Map> registeredShipments = new HashMap<>(); - - private final Map> serviceMap = new HashMap<>(); - - private final AttributesXmlWriterDelegate attributesWriter = new AttributesXmlWriterDelegate(); - private final List> atts = new ArrayList<>(); - - - /** - * Constructs the writer with the carriers to be written. - * - * @param carriers to be written - */ - public CarrierPlanXmlWriterV2(Carriers carriers) { - super(); - this.carriers = carriers.getCarriers().values(); - } - - @Inject - public void putAttributeConverters( final Map, AttributeConverter> converters ) { - attributesWriter.putAttributeConverters( converters ); - } - - /** - * Writes carriers and their plans into a xml-file. - * - * @param filename should be the target xml-file - */ - public void write(String filename) { - logger.info("write carrier plans"); - try { - openFile(filename); - writeXmlHead(); - - startCarriers(this.writer); - for (Carrier carrier : carriers) { - startCarrier(carrier, this.writer); - writeVehiclesAndTheirTypes(carrier, this.writer); - writeShipments(carrier, this.writer); - writeServices(carrier,this.writer); - writePlans(carrier, this.writer); - endCarrier(this.writer); - } - endCarriers(this.writer); - close(); - logger.info("done"); - } catch (IOException e) { - e.printStackTrace(); - logger.error(e); - System.exit(1); - } - } - - private void startCarriers(BufferedWriter writer) throws IOException { - writer.write("\t\n"); - } - - private void startCarrier(Carrier carrier, BufferedWriter writer) - throws IOException { - writer.write("\t\t\n"); - attributesWriter.writeAttributes("\t\t\t", writer, carrier.getAttributes()); - } - - private void writeVehiclesAndTheirTypes(Carrier carrier, BufferedWriter writer)throws IOException { - writer.write("\t\t\t\n"); - //vehicles - writer.write("\t\t\t\t\n"); - for (CarrierVehicle v : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { - Id vehicleTypeId = v.getVehicleTypeId(); - if(vehicleTypeId == null) vehicleTypeId = v.getType() == null ? null : v.getType().getId(); - if(vehicleTypeId == null) throw new IllegalStateException("vehicleTypeId is missing."); - writer.write("\t\t\t\t\t\n"); - } - writer.write("\t\t\t\t\n\n"); - writer.write("\t\t\t\n\n"); - } - - private void writeShipments(Carrier carrier, BufferedWriter writer) throws IOException { - if(carrier.getShipments().isEmpty()) return; - writer.write("\t\t\t\n"); - for (CarrierShipment s : carrier.getShipments().values()) { - // CarrierShipment s = contract.getShipment(); - Id shipmentId = s.getId(); - registeredShipments.put(s, shipmentId); - writer.write("\t\t\t\t\n"); - } else { - writer.write("\">\n"); - this.attributesWriter.writeAttributes("\t\t\t\t\t", writer, s.getAttributes()); - writer.write("\t\t\t\t\n"); - } - } - writer.write("\t\t\t\n\n"); - } - - private void writeServices(Carrier carrier, BufferedWriter writer) throws IOException { - writer.write("\t\t\t\n"); - for (CarrierService s : carrier.getServices().values()) { - serviceMap.put(s, s.getId()); - writer.write("\t\t\t\t\n"); - } else { - writer.write("\">\n"); - this.attributesWriter.writeAttributes("\t\t\t\t\t", writer, s.getAttributes()); - writer.write("\t\t\t\t\n"); - } - - } - writer.write("\t\t\t\n\n"); - - } - - private String getTime(double time) { - return Time.writeTime(time); - } - - private void writePlans(Carrier carrier, BufferedWriter writer) - throws IOException { - if (carrier.getSelectedPlan() == null) { - return; - } - - for(CarrierPlan plan : carrier.getPlans()){ - writer.write("\t\t\t\n"); - - for (ScheduledTour tour : plan.getScheduledTours()) { - writer.write("\t\t\t\t\n"); - writer.write("\t\t\t\t\t\n"); - for (TourElement tourElement : tour.getTour().getTourElements()) { - if (tourElement instanceof Leg leg) { - writer.write("\t\t\t\t\t"); - if (leg.getRoute() != null) { - writer.write("\n"); - writer.write("\t\t\t\t\t\t"); - boolean firstLink = true; - for (Id id : ((NetworkRoute) leg.getRoute()) - .getLinkIds()) { - if (firstLink) { - writer.write(id.toString()); - firstLink = false; - } else { - writer.write(" " + id.toString()); - } - } - writer.write("\n"); - writer.write("\t\t\t\t\t\n"); - } else { - writer.write("\n"); - } - } - else if (tourElement instanceof ShipmentBasedActivity act) { - writer.write("\t\t\t\t\t\n"); - } - else if (tourElement instanceof ServiceActivity act){ - writer.write("\t\t\t\t\t\n"); - } - - } - writer.write("\t\t\t\t\t\n"); - writer.write("\t\t\t\t\n"); - } - writer.write("\t\t\t\n\n"); - } - - } - - private void endCarrier(BufferedWriter writer) throws IOException { - writer.write("\t\t\n\n"); - registeredShipments.clear(); - } - - private void endCarriers(BufferedWriter writer) throws IOException { - writer.write("\t\n"); - - } -} diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1.java index 92699982378..6195fb3834f 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1.java @@ -21,7 +21,16 @@ package org.matsim.freight.carriers; +import static org.matsim.freight.carriers.CarrierConstants.*; + import com.google.inject.Inject; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +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; @@ -34,16 +43,6 @@ import org.matsim.utils.objectattributes.attributable.AttributesXmlWriterDelegate; import org.matsim.vehicles.VehicleType; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static org.matsim.freight.carriers.CarrierConstants.*; - /** * A writer that writes carriers and their plans in a xml-file. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierService.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierService.java index b7106fa6de9..69a5ce75e42 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierService.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierService.java @@ -27,8 +27,7 @@ import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; - -public final class CarrierService implements Attributable { +public final class CarrierService implements CarrierJob { public static class Builder { @@ -56,10 +55,10 @@ public Builder setName(String name){ } /** - * By default it is [0.0,Integer.MaxValue]. + * By default, it is [0.0,Integer.MaxValue]. * - * @param serviceDuration - * @return + * @param serviceDuration duration of the service + * @return the builder */ public Builder setServiceDuration(double serviceDuration){ this.serviceTime = serviceDuration; @@ -72,8 +71,8 @@ public Builder setServiceDuration(double serviceDuration){ *

Note that the time-window restricts the start-time of the service (i.e. serviceActivity). If one works with hard time-windows (which means that * time-windows must be met) than the service is allowed to start between startTimeWindow.getStart() and startTimeWindow.getEnd(). * - * @param startTimeWindow - * @return + * @param startTimeWindow time-window for the service + * @return the builder */ public Builder setServiceStartTimeWindow(TimeWindow startTimeWindow){ this.timeWindow = startTimeWindow; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierShipment.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierShipment.java index 9472ffaac91..01c8b873e70 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierShipment.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierShipment.java @@ -36,7 +36,7 @@ * @author sschroeder * */ -public final class CarrierShipment implements Attributable { +public final class CarrierShipment implements CarrierJob { /** * A builder that builds shipments. @@ -47,17 +47,17 @@ public final class CarrierShipment implements Attributable { public static class Builder { /** - * @Deprecated Please use Builder newInstance(Id id, Id from, Id to, int size) instead. + * @deprecated Please use Builder newInstance(Id id, Id from, Id to, int size) instead. *

* Returns a new shipment builder. * *

The builder is init with the shipment's origin (from), destination (to) and with the shipment's size. * The default-value for serviceTime is 0.0. The default-value for a timeWindow is [start=0.0, end=Double.maxValue()]. * - * @param from - * @param to - * @param size - * @return the builder + * @param from the origin + * @param to the destination + * @param size size of the shipment + * @return the builder */ @Deprecated public static Builder newInstance(Id from, Id to, int size){ @@ -70,11 +70,11 @@ public static Builder newInstance(Id from, Id to, int size){ *

The builder is init with the shipment's origin (from), destination (to) and with the shipment's size. * The default-value for serviceTime is 0.0. The default-value for a timeWindow is [start=0.0, end=Double.maxValue()]. * - * @param id - * @param from - * @param to - * @param size - * @return the builder + * @param id the id of the shipment + * @param from the origin + * @param to the destination + * @param size size of the shipment + * @return the builder */ public static Builder newInstance(Id id, Id from, Id to, int size){ return new Builder(id, from,to,size); @@ -90,7 +90,7 @@ public static Builder newInstance(Id id, Id from, Id id, Id from, Id to, int size) instead. + * @deprecated Please use Builder (Id id, Id from, Id to, int size) instead. */ @Deprecated public Builder(Id from, Id to, int size) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicle.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicle.java index 917052a65fe..7d317af7d26 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicle.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicle.java @@ -46,8 +46,8 @@ public final class CarrierVehicle implements Vehicle { *

* The default values for other fields (being implicitly set) are [capacity=0][earliestStart=0.0][latestEnd=Integer.MaxValue()]. * - * @param vehicleId - * @param locationId + * @param vehicleId the vehicle id + * @param locationId the location id * @return CarrierVehicle * @see CarrierVehicle */ @@ -68,9 +68,9 @@ public static class Builder { *

* The default values for other fields (being implicitly set) are [capacity=0][earliestStart=0.0][latestEnd=Integer.MaxValue()]. * - * @param vehicleId - * @param locationId - * @param vehicleType + * @param vehicleId the vehicle id + * @param locationId the location id + * @param vehicleType the vehicle type * @return a new vehicle builder */ public static Builder newInstance( Id vehicleId, Id locationId, VehicleType vehicleType ){ @@ -91,29 +91,6 @@ public Builder( Id vehicleId, Id locationId, VehicleType vehicleT this.type = vehicleType; } - /** - * @param type - * @deprecated The vehicleType need now to be set in the constructor kai/kai jan'22 - */ - @Deprecated - public Builder setType( VehicleType type ){ - log.warn(".setType has no functionality anymore and is deprecated"); -// this.type=type; - return this; - } - - /** - * @param typeId - * @deprecated The vehicleTypeId is no longer needed and was confusing -> Use getType().getId kai/kai jan'22 - */ - @Deprecated - public Builder setTypeId(Id typeId ){ - log.warn(".setTypeId has no functionality anymore and is deprecated"); -// this.typeId = typeId; - return this; - } - - public Builder setEarliestStart(double earliestStart){ this.earliestStart=earliestStart; return this; @@ -151,10 +128,7 @@ private CarrierVehicle(Builder builder){ public Id getLinkId() { return locationId; } - /** - * @deprecated -- please inline. kai, jul'22 - */ - @Deprecated public Id getLocation() { return getLinkId(); } + @Override public Id getId() { return vehicleId; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleType.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleType.java index 16b7e92a03d..2983b859043 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleType.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleType.java @@ -28,7 +28,7 @@ /** * The carrier vehicle type. *

- * I decided to put vehicle cost information into the type (which is indeed not a physical attribute of the type). Thus physical and + * I decided to put vehicle cost information into the type (which is indeed not a physical attribute of the type). Thus, physical and * non-physical attributes are used. This is likely to be changed in the future. * * @author sschroeder @@ -57,30 +57,13 @@ public static class Builder { *

* The defaults are [fix=0.0][perDistanceUnit=1.0][perTimeUnit=0.0]. * - * @param typeId + * @param typeId the type id * @return a type builder */ public static Builder newInstance(Id typeId){ return new Builder(typeId); } - /** - * Returns a new instance of builder initialized with the typeId and the values the given from existing CarrierVehicleType. - *

- * Can be used for create a new, modified CarrierVehicleType basing on an existing one. - * Values can be changed within the builder afterwards. - * - * @param carrierVehicleType - * @param typeId - * @return a type builder - * - * @deprecated Use {@link #newInstance(Id)} instead - */ - @Deprecated(since = "sep'19", forRemoval = true) - public static Builder newInstance(Id typeId, CarrierVehicleType carrierVehicleType){ - throw new RuntimeException("not implemented") ; - } - private Builder(Id typeId){ this.delegate = VehicleUtils.getFactory().createVehicleType( typeId ) ; } @@ -88,9 +71,9 @@ private Builder(Id typeId){ /** * Sets fixed costs of vehicle. * - *

By default it is 0. - * @param fix - * @return + *

By default, it is 0. + * @param fix fixed costs + * @return this builder */ public Builder setFixCost(double fix){ this.delegate.getCostInformation().setFixedCost( fix ) ; @@ -100,10 +83,10 @@ public Builder setFixCost(double fix){ /** * Sets costs per distance-unit. * - *

By default it is 1. + *

By default, it is 1. * - * @param perDistanceUnit - * @return + * @param perDistanceUnit costs per distance-unit + * @return this builder */ public Builder setCostPerDistanceUnit(double perDistanceUnit){ this.delegate.getCostInformation().setCostsPerMeter( perDistanceUnit ) ; @@ -113,10 +96,10 @@ public Builder setCostPerDistanceUnit(double perDistanceUnit){ /** * Sets costs per time-unit. * - *

By default it is 0. + *

By default, it is 0. * - * @param perTimeUnit - * @return + * @param perTimeUnit costs per time-unit + * @return this builder */ public Builder setCostPerTimeUnit(double perTimeUnit){ this.delegate.getCostInformation().setCostsPerSecond( perTimeUnit ) ; @@ -126,8 +109,8 @@ public Builder setCostPerTimeUnit(double perTimeUnit){ /** * Sets description. * - * @param description - * @return this builder + * @param description the description + * @return this builder */ public Builder setDescription(String description){ this.delegate.setDescription( description ) ; @@ -139,8 +122,8 @@ public Builder setDescription(String description){ * *

By default, the capacity is 0. * - * @param capacity - * @return this builder + * @param capacity the capacity of the vehicle-type + * @return this builder */ public Builder setCapacity(int capacity){ this.delegate.getCapacity().setOther( capacity ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReader.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReader.java index f10e5fc9bd5..b96a224b20e 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReader.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReader.java @@ -21,6 +21,10 @@ package org.matsim.freight.carriers; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; +import java.util.Stack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -33,11 +37,6 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import java.io.InputStream; -import java.net.URL; -import java.util.Map; -import java.util.Stack; - /** * Reader reading carrierVehicleTypes from a xml-file. * @@ -79,7 +78,7 @@ public void readURL( URL url ){ reader.readURL(url); } catch (Exception e) { log.warn("### Exception: Message={}", e.getMessage()); - log.warn("### Exception: Cause={}", e.getCause()); + log.warn("### Exception: Cause={}", e.getCause().toString()); log.warn("### Exception: Class={}", e.getClass()); if (e.getCause().getMessage().contains("cvc-elt.1.a")) { // "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()); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java index 92e2bacc590..f1cb66dac45 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderV1.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers; +import java.util.Stack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -33,8 +34,6 @@ import org.matsim.vehicles.VehicleUtils; import org.xml.sax.Attributes; -import java.util.Stack; - class CarrierVehicleTypeReaderV1 extends MatsimXmlParser { private static final Logger log = LogManager.getLogger(CarrierVehicleTypeReaderV1.class) ; @@ -73,9 +72,8 @@ public void startTag( String name, Attributes attributes, Stack context } if(name.equals("engineInformation")){ EngineInformation engineInfo = this.currentType.getEngineInformation() ; - VehicleUtils.setFuelConsumption(this.currentType, Double.parseDouble(attributes.getValue( "gasConsumption" ))); - engineInfo.setFuelConsumption( Double.parseDouble( attributes.getValue( "gasConsumption" ) ) ); - engineInfo.setFuelType( EngineInformation.FuelType.valueOf( attributes.getValue( "fuelType" ) ) ); + VehicleUtils.setHbefaTechnology(engineInfo, attributes.getValue( "fuelType")); + VehicleUtils.setFuelConsumptionLitersPerMeter(engineInfo, Double.parseDouble(attributes.getValue( "gasConsumption" ))); } if(name.equals("costInformation")){ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriter.java index 4fbd8d68bbb..573f8441cae 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriter.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers; +import java.util.Map; import org.matsim.api.core.v01.Id; import org.matsim.core.api.internal.MatsimWriter; import org.matsim.vehicles.MatsimVehicleWriter; @@ -28,8 +29,6 @@ import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.Vehicles; -import java.util.Map; - /** * A writer that writes carriers and their plans in a xml-file. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterV1.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterV1.java deleted file mode 100644 index 823123e916a..00000000000 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterV1.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * *********************************************************************** * - * 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.carriers; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.matsim.core.utils.io.MatsimXmlWriter; -import org.matsim.vehicles.CostInformation; -import org.matsim.vehicles.EngineInformation; -import org.matsim.vehicles.VehicleType; - -import java.io.BufferedWriter; -import java.io.IOException; - -@Deprecated // only there if someone insists on writing V1 -public final class CarrierVehicleTypeWriterV1 extends MatsimXmlWriter { - - @SuppressWarnings("unused") - private static final Logger logger = LogManager.getLogger(CarrierVehicleTypeWriter.class ); - - private final CarrierVehicleTypes vehicleTypes; - - - public CarrierVehicleTypeWriterV1(CarrierVehicleTypes carrierVehicleTypes) { - super(); - this.vehicleTypes = carrierVehicleTypes; - } - - - public void write(String filename) { - logger.info("write vehicle-types"); - try { - openFile(filename); - writeXmlHead(); - writeTypes(this.writer); - close(); - logger.info("done"); - } catch ( IOException e) { - e.printStackTrace(); - logger.error(e); - System.exit(1); - } - } - - private void writeTypes( BufferedWriter writer )throws IOException { - writer.write("\t\n"); - for( VehicleType type : vehicleTypes.getVehicleTypes().values()){ - writer.write("\t\t\n"); - writer.write("\t\t\t" + type.getDescription() + "\n"); - EngineInformation engineInformation = type.getEngineInformation(); - if(engineInformation != null && !engineInformation.getAttributes().isEmpty()) { - writer.write("\t\t\t\n"); - } - writer.write("\t\t\t" + type.getCapacity().getWeightInTons() + "\n" ); - CostInformation vehicleCostInformation = type.getCostInformation(); - if(vehicleCostInformation == null) throw new IllegalStateException("vehicleCostInformation is missing."); - writer.write("\t\t\t\n"); - writer.write("\t\t\n"); - } - writer.write("\t\n\n"); - } - - - -} diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypes.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypes.java index e9900cdc6cb..0250412938a 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypes.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypes.java @@ -21,11 +21,10 @@ package org.matsim.freight.carriers; -import org.matsim.api.core.v01.Id; -import org.matsim.vehicles.VehicleType; - import java.util.HashMap; import java.util.Map; +import org.matsim.api.core.v01.Id; +import org.matsim.vehicles.VehicleType; /** * VehicleTypeContainer mapping all vehicleTypes. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/Carriers.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/Carriers.java index f13f0bc56ae..4512008b9e8 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/Carriers.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/Carriers.java @@ -21,13 +21,12 @@ package org.matsim.freight.carriers; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.matsim.api.core.v01.Id; - import java.util.Collection; 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; /** * A container that maps carriers. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarriersUtils.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarriersUtils.java index 7c8e7220e3e..1b6a270e65e 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarriersUtils.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarriersUtils.java @@ -28,6 +28,10 @@ import com.graphhopper.jsprit.core.problem.job.Shipment; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.util.Solutions; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import javax.management.InvalidAttributeValueException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -44,11 +48,6 @@ import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; -import javax.management.InvalidAttributeValueException; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - public class CarriersUtils { static final String CARRIER_VEHICLE = "carrierVehicle"; @@ -235,7 +234,7 @@ public static void runJsprit(Scenario scenario, CarrierSelectionForSolution carr continue; } } - case solveForAllCarriersAndAddPLans -> {carrier.setSelectedPlan(null);} // Keep existing plan(s), but make them not selected. + case solveForAllCarriersAndAddPLans -> carrier.setSelectedPlan(null); // Keep existing plan(s), but make them not selected. default -> throw new IllegalStateException("Unexpected value: " + carriersSolutionType); } carrierActivityCounterMap.put(carrier.getId(), carrierActivityCounterMap.getOrDefault(carrier.getId(), 0) + carrier.getServices().size()); @@ -338,7 +337,7 @@ public static Carriers getOrCreateCarriers(Scenario scenario) { public static Carriers addOrGetCarriers(Scenario scenario) { // I have separated getOrCreateCarriers and getCarriers, since when the - // controler is started, it is better to fail if the carriers are not found. + // controller is started, it is better to fail if the carriers are not found. // kai, oct'19 Carriers carriers = (Carriers) scenario.getScenarioElement(CARRIERS); if (carriers == null) { @@ -382,8 +381,6 @@ public static void loadCarriersAccordingToFreightConfig(Scenario scenario) { Carriers carriers = addOrGetCarriers(scenario); // also registers with scenario new CarrierPlanXmlReader(carriers, vehTypes).readURL( IOUtils.extendUrl(scenario.getConfig().getContext(), freightCarriersConfigGroup.getCarriersFile())); - -// new CarrierVehicleTypeLoader( carriers ).loadVehicleTypes( vehTypes ); } /** diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/FreightCarriersConfigGroup.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/FreightCarriersConfigGroup.java index 1aed1a936f2..2474df19550 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/FreightCarriersConfigGroup.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/FreightCarriersConfigGroup.java @@ -22,11 +22,10 @@ package org.matsim.freight.carriers; import jakarta.validation.constraints.Positive; -import org.matsim.core.config.ConfigGroup; -import org.matsim.core.config.ReflectiveConfigGroup; - import java.net.URL; import java.util.Map; +import org.matsim.core.config.ConfigGroup; +import org.matsim.core.config.ReflectiveConfigGroup; public class FreightCarriersConfigGroup extends ReflectiveConfigGroup { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/ScheduledTour.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/ScheduledTour.java index 6a133ebc71c..84eeb1907a1 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/ScheduledTour.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/ScheduledTour.java @@ -37,9 +37,9 @@ public class ScheduledTour { *

Look at the builder. It might be easier to build a scheduled tour. * You get the builder this way: ScheduledTour.Builder.newInstance(carrierVehicle). * - * @param tour - * @param vehicle - * @param departureTime + * @param tour The scheduled tour. + * @param vehicle The vehicle for the tour. + * @param departureTime The time when the vehicle starts the tour. * @return a scheduledTour * @see ScheduledTour */ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/TimeWindow.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/TimeWindow.java index 8c5e9fc0d25..1eadbe077c0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/TimeWindow.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/TimeWindow.java @@ -24,7 +24,6 @@ import org.matsim.core.utils.misc.Time; - /** * Q: What happens/should happen if the time window is not sufficient to unload, or * the vehicle arrives after the time window? diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/Tour.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/Tour.java index cb522e857fb..55f72325237 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/Tour.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/Tour.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -30,8 +31,6 @@ import org.matsim.core.population.routes.NetworkRoute; import org.matsim.core.population.routes.RouteUtils; -import java.util.*; - /** * This is a tour of a carrier which is a sequence of activities and legs. *

@@ -62,21 +61,6 @@ public static class Builder { private End end; - /** - * Returns a new tour builder. - * - * @deprecated - * Please use {@link #newInstance(Id)} instead. kmt sep'22 - *

- * - * - * @return the builder including "unknown" as tourId - */ - @Deprecated - public static Builder newInstance(){ - return new Builder(Id.create("unknown", Tour.class)); - } - /** * Returns a new tour builder. * This now also includes an Id for this tour. @@ -98,8 +82,8 @@ private Builder(Id tourId) { * *

Tour start should correspond to the locationId of the vehicle that runs the tour. * - * @param startLinkId - * @return the builder again + * @param startLinkId linkId of the start location + * @return the builder again */ public Builder scheduleStart(Id startLinkId) { scheduleStart(startLinkId, TimeWindow.newInstance(0.0, Double.MAX_VALUE)); @@ -121,7 +105,7 @@ public void scheduleEnd(Id endLinkId, TimeWindow timeWindow){ /** * Schedules the end of the tour (in terms of locationId). * - * @param endLinkId + * @param endLinkId linkId of the end location */ public void scheduleEnd(Id endLinkId) { scheduleEnd(endLinkId, TimeWindow.newInstance(0.0, Double.MAX_VALUE)); @@ -132,8 +116,8 @@ public void scheduleEnd(Id endLinkId) { * *

Consider that a leg follows an activity. Otherwise, an exception occurs. * - * @param leg - * @throws IllegalStateException if leg is null or if previous element is not an activity. + * @param leg the leg to be added + * @throws IllegalStateException if leg is null or if previous element is not an activity. */ public Builder addLeg(Leg leg) { Gbl.assertNotNull(leg); @@ -156,9 +140,9 @@ public Leg createLeg(Route route, double dep_time, double transportTime) { /** * Inserts leg at the beginning of a tour. * - * @param leg - * @return the builder - * @throws IllegalStateException if leg is null + * @param leg the leg to be inserted + * @return the builder + * @throws IllegalStateException if leg is null */ @Deprecated public Builder insertLegAtBeginning(Leg leg) { @@ -170,9 +154,9 @@ public Builder insertLegAtBeginning(Leg leg) { /** * Schedules a pickup of the shipment right at the beginning of the tour. * - * @param shipment - * @return the builder - * @throws IllegalStateException if shipment is null or shipment has already been picked up. + * @param shipment the shipment to be picked up + * @return the builder + * @throws IllegalStateException if shipment is null or shipment has already been picked up. */ @Deprecated public Builder schedulePickupAtBeginning(CarrierShipment shipment) { @@ -218,8 +202,8 @@ private void assertLastElementIsLeg() { /** * Schedules a delivery of a shipment, i.e. adds a delivery activity to current tour. * - * @param shipment - * @throws IllegalStateException if shipment is null or if shipment has not been picked up yet or if last element is not a leg. + * @param shipment the shipment to be delivered + * @throws IllegalStateException if shipment is null or if shipment has not been picked up yet or if last element is not a leg. */ public void scheduleDelivery(CarrierShipment shipment) { Gbl.assertNotNull(shipment); @@ -272,10 +256,10 @@ public Leg createLeg() { /** * Creates and returns a network route. * - * @param startLinkId - * @param linkIds - * @param endLinkId - * @return NetworkRoute + * @param startLinkId start link id + * @param linkIds list of link ids that form the route + * @param endLinkId end link id + * @return NetworkRoute * @see NetworkRoute */ public NetworkRoute createRoute(Id startLinkId, List> linkIds, Id endLinkId) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierLoadAnalysis.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierLoadAnalysis.java index 7de5125e51e..760ce513035 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierLoadAnalysis.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierLoadAnalysis.java @@ -21,6 +21,16 @@ package org.matsim.freight.carriers.analysis; +import static org.matsim.freight.carriers.events.CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -34,17 +44,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; - -import static org.matsim.freight.carriers.events.CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND; - /** * @author Kai Martins-Turner (kturner) */ @@ -52,7 +51,7 @@ public class CarrierLoadAnalysis implements CarrierShipmentPickupStartEventHandl private static final Logger log = LogManager.getLogger(CarrierLoadAnalysis.class); private final String delimiter; - Carriers carriers; + final Carriers carriers; private final Map, LinkedList> vehicle2Load = new LinkedHashMap<>(); @@ -96,6 +95,7 @@ void writeLoadPerVehicle(String analysisOutputDirectory, Scenario scenario) thro //Write headline: bw1.write(String.join(delimiter,"vehicleId", + "vehicleTypeId", "capacity", "maxLoad", "load state during tour")); @@ -104,12 +104,13 @@ void writeLoadPerVehicle(String analysisOutputDirectory, Scenario scenario) thro for (Id vehicleId : vehicle2Load.keySet()) { final LinkedList load = vehicle2Load.get(vehicleId); - final Integer maxLoad = load.stream().max(Comparator.naturalOrder()).get(); + final Integer maxLoad = load.stream().max(Comparator.naturalOrder()).orElseThrow(); final VehicleType vehicleType = VehicleUtils.findVehicle(vehicleId, scenario).getType(); final Double capacity = vehicleType.getCapacity().getOther(); bw1.write(vehicleId.toString()); + bw1.write(delimiter + vehicleType.getId().toString()); bw1.write(delimiter + capacity); bw1.write(delimiter + maxLoad); bw1.write(delimiter + load); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierPlanAnalysis.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierPlanAnalysis.java index aeec93fd605..362dfaf8793 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierPlanAnalysis.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/CarrierPlanAnalysis.java @@ -21,17 +21,16 @@ package org.matsim.freight.carriers.analysis; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.matsim.api.core.v01.Id; -import org.matsim.core.utils.misc.Time; -import org.matsim.freight.carriers.*; - import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Path; import java.util.TreeMap; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.core.utils.misc.Time; +import org.matsim.freight.carriers.*; /** * Some basic analysis / data collection for {@link Carriers}(files) @@ -55,7 +54,7 @@ public class CarrierPlanAnalysis { private static final Logger log = LogManager.getLogger(CarrierPlanAnalysis.class); public final String delimiter; - Carriers carriers; + final Carriers carriers; public CarrierPlanAnalysis(String delimiter, Carriers carriers) { this.delimiter = delimiter; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/FreightTimeAndDistanceAnalysisEventsHandler.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/FreightTimeAndDistanceAnalysisEventsHandler.java index c62863465d5..6302c0df803 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/FreightTimeAndDistanceAnalysisEventsHandler.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/FreightTimeAndDistanceAnalysisEventsHandler.java @@ -21,6 +21,13 @@ package org.matsim.freight.carriers.analysis; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -44,14 +51,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Path; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; - /** * @author Kai Martins-Turner (kturner) */ @@ -227,7 +226,7 @@ void writeTravelTimeAndDistancePerVehicle(String analysisOutputDirectory, Scenar void writeTravelTimeAndDistancePerVehicleType(String analysisOutputDirectory, Scenario scenario) throws IOException { log.info("Writing out Time & Distance & Costs ... perVehicleType"); - //----- All VehicleTypes in CarriervehicleTypes container. Used so that even unused vehTypes appear in the output + //----- All VehicleTypes in CarrierVehicleTypes container. Used so that even unused vehTypes appear in the output TreeMap, VehicleType> vehicleTypesMap = new TreeMap<>(CarriersUtils.getCarrierVehicleTypes(scenario).getVehicleTypes()); //For the case that there are additional vehicle types found in the events. for (VehicleType vehicleType : vehicleId2VehicleType.values()) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java index 7269a70ac7f..0502ae2e1c4 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/analysis/RunFreightAnalysisEventBased.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers.analysis; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Scenario; @@ -36,10 +39,6 @@ import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.freight.carriers.events.CarrierEventsReaders; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; - //import static org.matsim.application.ApplicationUtils.globFile; @@ -83,11 +82,12 @@ public RunFreightAnalysisEventBased(String simOutputPath, String analysisOutputP // the better version with the globFile method is not available since there is a circular dependency between the modules application and freight - this.EVENTS_PATH = Path.of(simOutputPath).resolve("output_events.xml.gz").toString(); - String vehiclesPath = Path.of(simOutputPath).resolve("output_allVehicles.xml.gz").toString(); - String networkPath = Path.of(simOutputPath).resolve("output_network.xml.gz").toString(); - String carriersPath = Path.of(simOutputPath).resolve("output_carriers.xml.gz").toString(); - String carriersVehicleTypesPath = Path.of(simOutputPath).resolve("output_carriersVehicleTypes.xml.gz").toString(); + final Path path = Path.of(simOutputPath); + this.EVENTS_PATH = path.resolve("output_events.xml.gz").toString(); + String vehiclesPath = path.resolve("output_allVehicles.xml.gz").toString(); + String networkPath = path.resolve("output_network.xml.gz").toString(); + String carriersPath = path.resolve("output_carriers.xml.gz").toString(); + String carriersVehicleTypesPath = path.resolve("output_carriersVehicleTypes.xml.gz").toString(); createScenarioForFreightAnalysis(vehiclesPath, networkPath, carriersPath, carriersVehicleTypesPath, globalCrs); } @@ -136,7 +136,7 @@ private void createScenarioForFreightAnalysis(String vehiclesPath, String networ //freight settings FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); freightCarriersConfigGroup.setCarriersFile(carriersPath); - freightCarriersConfigGroup.setCarriersVehicleTypesFile(carriersVehicleTypesPath.toString()); + freightCarriersConfigGroup.setCarriersVehicleTypesFile(carriersVehicleTypesPath); scenario = ScenarioUtils.loadScenario(config); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgent.java similarity index 99% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgent.java index da31ae5637d..1afe10da4d0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgent.java @@ -19,8 +19,9 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -38,8 +39,6 @@ import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleUtils; -import java.util.*; - /** * This keeps track of the carrier during simulation. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgentTracker.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgentTracker.java similarity index 99% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgentTracker.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgentTracker.java index 09c4036d92f..f2bd02a204e 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgentTracker.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierAgentTracker.java @@ -19,9 +19,10 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; 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; @@ -35,8 +36,6 @@ import org.matsim.freight.carriers.events.CarrierEventCreator; import org.matsim.freight.carriers.events.CarrierEventCreatorUtils; -import java.util.*; - /** * This keeps track of all carrierAgents during simulation. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerListener.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerListener.java similarity index 92% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerListener.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerListener.java index f8a103bcbe5..136fecf4725 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerListener.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerListener.java @@ -19,9 +19,10 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import jakarta.inject.Inject; +import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Scenario; @@ -31,8 +32,6 @@ import org.matsim.core.controler.listener.ScoringListener; import org.matsim.freight.carriers.CarriersUtils; -import javax.annotation.Nullable; - /** * Controls the workflow of the simulation. *

@@ -46,13 +45,13 @@ * // not sure if this _should_ be public, but current LSP design makes this necessary. kai, sep'20 */ -public class CarrierControlerListener implements ScoringListener, ReplanningListener { +public class CarrierControllerListener implements ScoringListener, ReplanningListener { // not sure if this _should_ be public, but current LSP design makes this necessary. // It is done analogue to CarrierAgentTracker. kmt oct'22 @SuppressWarnings("unused") - private static final Logger log = LogManager.getLogger( CarrierControlerListener.class ) ; + private static final Logger log = LogManager.getLogger( CarrierControllerListener.class ) ; private final CarrierStrategyManager strategyManager; private final CarrierAgentTracker carrierAgentTracker; @@ -62,7 +61,8 @@ public class CarrierControlerListener implements ScoringListener, ReplanningList /** * Constructs a controller with a set of carriers, re-planning capabilities and scoring-functions. */ - @Inject CarrierControlerListener( @Nullable CarrierStrategyManager strategyManager, CarrierAgentTracker carrierAgentTracker ) { + @Inject + CarrierControllerListener(@Nullable CarrierStrategyManager strategyManager, CarrierAgentTracker carrierAgentTracker ) { // The current default is bind( CarrierStrategyManager.class ).toProvider( () -> null ); this.strategyManager = strategyManager; this.carrierAgentTracker = carrierAgentTracker; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerUtils.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerUtils.java similarity index 94% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerUtils.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerUtils.java index fe19207bfcc..5d15a6821f0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierControlerUtils.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierControllerUtils.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; /** * Utils class for (package-private) content of freight.carriers.controler - package; @@ -27,7 +27,7 @@ * @author kturner * */ -public class CarrierControlerUtils { +public class CarrierControllerUtils { public static CarrierStrategyManager createDefaultCarrierStrategyManager() { return new CarrierStrategyManagerImpl(); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierDriverAgent.java similarity index 99% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierDriverAgent.java index c7f030f3457..50474242a92 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierDriverAgent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierDriverAgent.java @@ -19,8 +19,13 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -41,12 +46,6 @@ import org.matsim.freight.carriers.events.CarrierEventCreator; import org.matsim.vehicles.Vehicle; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * This keeps track of a scheduledTour during simulation and can thus be seen as the driver of the vehicle that runs the tour. * @@ -265,7 +264,7 @@ else if( index < elementsSize ){ * 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}. + * 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. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierModule.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierModule.java similarity index 97% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierModule.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierModule.java index e2b9e1d8354..d95e1e7ac18 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierModule.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierModule.java @@ -19,11 +19,12 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; +import java.util.List; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.events.Event; import org.matsim.api.core.v01.population.Activity; @@ -38,8 +39,6 @@ import org.matsim.core.scoring.ScoringFunction; import org.matsim.freight.carriers.*; -import java.util.List; - public final class CarrierModule extends AbstractModule { @@ -49,8 +48,8 @@ public final class CarrierModule extends AbstractModule { bind(Carriers.class).toProvider( new CarrierProvider() ).asEagerSingleton(); // needs to be eager since it is still scenario construction. kai, oct'19 // this is probably ok - bind(CarrierControlerListener.class).in( Singleton.class ); - addControlerListenerBinding().to(CarrierControlerListener.class); + bind(CarrierControllerListener.class).in( Singleton.class ); + addControlerListenerBinding().to(CarrierControllerListener.class); bind(CarrierAgentTracker.class).in( Singleton.class ); addEventHandlerBinding().to( CarrierAgentTracker.class ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierReRouteVehicles.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierReRouteVehicles.java similarity index 95% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierReRouteVehicles.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierReRouteVehicles.java index f59ba81c930..a2e32470a88 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierReRouteVehicles.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierReRouteVehicles.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -77,8 +77,8 @@ private CarrierReRouteVehicles( LeastCostPathCalculator router, Network network, /** * Routes the carrierPlan in time and space. * - * @param carrierPlan - * @throws IllegalStateException if carrierPlan is null. + * @param carrierPlan the carrierPlan to be routed. + * @throws IllegalStateException if carrierPlan is null. * @see CarrierTimeAndSpaceTourRouter */ @Override diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierScoringFunctionFactory.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierScoringFunctionFactory.java similarity index 96% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierScoringFunctionFactory.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierScoringFunctionFactory.java index c73a41b3008..79338a48884 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierScoringFunctionFactory.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierScoringFunctionFactory.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import org.matsim.core.scoring.ScoringFunction; import org.matsim.freight.carriers.Carrier; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManager.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManager.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManager.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManager.java index f1d6d06e84e..8a7a3cfa263 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManager.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManager.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import com.google.inject.Provider; import org.matsim.core.replanning.GenericStrategyManager; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManagerImpl.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManagerImpl.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManagerImpl.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManagerImpl.java index 5bcad45b183..8a673af527b 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierStrategyManagerImpl.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierStrategyManagerImpl.java @@ -19,8 +19,9 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; +import java.util.List; import org.matsim.api.core.v01.population.HasPlansAndId; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericStrategyManager; @@ -30,8 +31,6 @@ import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarrierPlan; -import java.util.List; - class CarrierStrategyManagerImpl implements CarrierStrategyManager{ final GenericStrategyManager delegate = new GenericStrategyManagerImpl<>(); @Override public void addStrategy( GenericPlanStrategy strategy, String subpopulation, double weight ){ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAllocationMutator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAllocationMutator.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAllocationMutator.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAllocationMutator.java index 3b7fc83af01..b38a96a8fd2 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAllocationMutator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAllocationMutator.java @@ -18,17 +18,16 @@ * *********************************************************************** * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; +import java.util.ArrayList; +import java.util.Collection; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; import org.matsim.freight.carriers.CarrierPlan; import org.matsim.freight.carriers.ScheduledTour; -import java.util.ArrayList; -import java.util.Collection; - /** * @author nagel * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAndSpaceTourRouter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAndSpaceTourRouter.java similarity index 96% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAndSpaceTourRouter.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAndSpaceTourRouter.java index 0a6a7399c9f..b02c5938e42 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierTimeAndSpaceTourRouter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierTimeAndSpaceTourRouter.java @@ -19,8 +19,10 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; +import java.util.ArrayList; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -41,9 +43,6 @@ import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; -import java.util.ArrayList; -import java.util.List; - /** * Router routing scheduledTours. * @@ -94,9 +93,9 @@ public Attributes getAttributes() { /** * Constructs the timeAndSpaceRouter with a leastCostPathCalculator, network and travelTime. - * @param router - * @param network - * @param travelTime + * @param router the leastCostPathCalculator + * @param network the network + * @param travelTime the travelTime * @see LeastCostPathCalculator, Network, TravelTime */ public CarrierTimeAndSpaceTourRouter( LeastCostPathCalculator router, Network network, TravelTime travelTime ) { @@ -111,7 +110,7 @@ public CarrierTimeAndSpaceTourRouter( LeastCostPathCalculator router, Network ne * *

Uses a leastCostPathCalculator to calculate a route/path from one activity to another. It starts at the departureTime of * the scheduledTour and determines activity arrival and departure times considering activities time-windows. - * @param tour + * @param tour the scheduledTour to be routed. */ public void route(ScheduledTour tour) { MatsimVehicleAdapter matsimVehicle = new MatsimVehicleAdapter(tour.getVehicle()); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierVehicleReRouter.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierVehicleReRouter.java index cd03cb5fd94..1d9a02d74d0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/CarrierVehicleReRouter.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; import com.graphhopper.jsprit.core.algorithm.state.StateManager; @@ -35,6 +35,7 @@ import com.graphhopper.jsprit.io.algorithm.AlgorithmConfig; import com.graphhopper.jsprit.io.algorithm.AlgorithmConfigXmlReader; import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms; +import java.util.Collection; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.roadpricing.RoadPricingScheme; import org.matsim.core.replanning.ReplanningContext; @@ -45,9 +46,6 @@ import org.matsim.freight.carriers.CarrierVehicleTypes; import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; -import org.matsim.freight.carriers.jsprit.VehicleTypeDependentRoadPricingCalculator; - -import java.util.Collection; class CarrierVehicleReRouter implements GenericPlanStrategyModule{ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightActivity.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightActivity.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightActivity.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightActivity.java index 42cd58ae587..ee3f0e65afc 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightActivity.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightActivity.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightAgentSource.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightAgentSource.java index f5613f1a961..c1550c49701 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/FreightAgentSource.java @@ -19,9 +19,11 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import com.google.inject.Inject; +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; @@ -35,8 +37,6 @@ import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleUtils; -import java.util.ArrayList; -import java.util.Collection; /** * Created by IntelliJ IDEA. User: zilske Date: 10/31/11 Time: 5:59 PM To change * this template use File | Settings | File Templates. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/WithinDayActivityReScheduling.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/WithinDayActivityReScheduling.java similarity index 98% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/controler/WithinDayActivityReScheduling.java rename to contribs/freight/src/main/java/org/matsim/freight/carriers/controller/WithinDayActivityReScheduling.java index 285939a7174..0e4cbebfa6d 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/WithinDayActivityReScheduling.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controller/WithinDayActivityReScheduling.java @@ -19,9 +19,12 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import com.google.inject.Inject; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -38,10 +41,6 @@ import org.matsim.freight.carriers.Tour.Start; import org.matsim.freight.carriers.Tour.TourActivity; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - /* * Physically enforces beginnings of time windows for freight activities, i.e. freight agents * wait before closed doors until they can deliver / pick up their goods. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/AbstractCarrierEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/AbstractCarrierEvent.java index 1380144b9b4..497bc3dca7e 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/AbstractCarrierEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/AbstractCarrierEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.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; @@ -29,8 +30,6 @@ import org.matsim.freight.carriers.Carrier; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * A general freight event contains the information (= {@link Id}) of the * - {@link Carrier} diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierEventsReaders.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierEventsReaders.java index 23c9176a0ff..ee06d87ba6d 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierEventsReaders.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierEventsReaders.java @@ -21,11 +21,10 @@ package org.matsim.freight.carriers.events; +import java.util.Map; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.events.MatsimEventsReader; -import java.util.Map; - /** * Creates an {@link MatsimEventsReader} that also handles the carrier specific events. *

diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceEndEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceEndEvent.java index bfd8ad7d68c..f806248471c 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceEndEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceEndEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +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; @@ -28,8 +29,6 @@ import org.matsim.freight.carriers.CarrierService; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * An event, that informs that a Freight {@link CarrierService} activity has ended. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceStartEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceStartEvent.java index 1b866d5ce5b..d1b4d816ace 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceStartEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierServiceStartEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +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; @@ -28,8 +29,6 @@ import org.matsim.freight.carriers.CarrierService; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * An event, that informs that a Freight {@link CarrierService} activity has started. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryEndEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryEndEvent.java index c02717031fa..8f60260a067 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryEndEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryEndEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +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; @@ -28,8 +29,6 @@ import org.matsim.freight.carriers.CarrierShipment; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * An event, that informs that a Freight {@link CarrierShipment} delivery-activity has ended. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryStartEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryStartEvent.java index 43cf21fc752..a30035968c0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryStartEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentDeliveryStartEvent.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers.events; +import static org.matsim.freight.carriers.events.CarrierEventAttributes.*; + +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; @@ -28,10 +31,6 @@ import org.matsim.freight.carriers.CarrierShipment; import org.matsim.vehicles.Vehicle; -import java.util.Map; - -import static org.matsim.freight.carriers.events.CarrierEventAttributes.*; - /** * An event, that informs that a Freight {@link CarrierShipment} delivery-activity has started. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupEndEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupEndEvent.java index 90e1fd137b7..4316e6f4dfe 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupEndEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupEndEvent.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers.events; +import static org.matsim.freight.carriers.events.CarrierEventAttributes.*; + +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; @@ -28,10 +31,6 @@ import org.matsim.freight.carriers.CarrierShipment; import org.matsim.vehicles.Vehicle; -import java.util.Map; - -import static org.matsim.freight.carriers.events.CarrierEventAttributes.*; - /** * An event, that informs that a Freight {@link CarrierShipment} pickup-activity has ended. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupStartEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupStartEvent.java index ab36e627190..fe851a10138 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupStartEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierShipmentPickupStartEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +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; @@ -28,8 +29,6 @@ import org.matsim.freight.carriers.CarrierShipment; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * An event, that informs that a Freight {@link CarrierShipment} pickup-activity has started. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourEndEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourEndEvent.java index 82e133f2166..1c0e3579312 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourEndEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourEndEvent.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +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; @@ -28,8 +29,6 @@ import org.matsim.freight.carriers.Tour; import org.matsim.vehicles.Vehicle; -import java.util.Map; - /** * An event, that informs when a Freight {@link Tour} has ended. * There are NO specific information of the tour given, because the {@link Tour} is determined by the {@link Vehicle} and its {@link Carrier}. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEvent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEvent.java index 9c64e8213b2..aa4ff9f1084 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEvent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEvent.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers.events; +import static org.matsim.freight.carriers.events.CarrierEventAttributes.ATTRIBUTE_TOUR_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; @@ -28,10 +31,6 @@ import org.matsim.freight.carriers.Tour; import org.matsim.vehicles.Vehicle; -import java.util.Map; - -import static org.matsim.freight.carriers.events.CarrierEventAttributes.ATTRIBUTE_TOUR_ID; - /** * An event, that informs when a Freight {@link Tour} has started. * There are NO specific information of the tour given, because the {@link Tour} is determined by the {@link Vehicle} and its {@link Carrier}. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEventCreator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEventCreator.java index aacf3e6ef12..6a29c022aae 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEventCreator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/CarrierTourStartEventCreator.java @@ -21,6 +21,7 @@ package org.matsim.freight.carriers.events; +import java.util.TreeMap; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.events.ActivityEndEvent; import org.matsim.api.core.v01.events.Event; @@ -32,8 +33,6 @@ import org.matsim.freight.carriers.ScheduledTour; import org.matsim.vehicles.Vehicle; -import java.util.TreeMap; - /*package-private*/ final class CarrierTourStartEventCreator implements CarrierEventCreator { final TreeMap, ActivityEndEvent> endEventMap = new TreeMap<>(); @@ -69,9 +68,9 @@ public Event createEvent(Event event, Carrier carrier, Activity activity, Schedu /** * Creating the FreightTourStartsEvent * - * @param personId - * @param carrier - * @param scheduledTour + * @param personId id of the driver (person) + * @param carrier the carrier + * @param scheduledTour the scheduledTour * @return CarrierTourStartEvent */ private CarrierTourStartEvent createFreightTourStartsEvent(Id personId, Carrier carrier, ScheduledTour scheduledTour) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierServiceStartEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierServiceStartEventHandler.java index a8ea55c13e8..362974eae3f 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierServiceStartEventHandler.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierServiceStartEventHandler.java @@ -24,7 +24,6 @@ import org.matsim.core.events.handler.EventHandler; import org.matsim.freight.carriers.events.CarrierServiceStartEvent; - public interface CarrierServiceStartEventHandler extends EventHandler { void handleEvent( CarrierServiceStartEvent event ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourEndEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourEndEventHandler.java index 2d30ce4d70c..d14a5d285cf 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourEndEventHandler.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourEndEventHandler.java @@ -24,7 +24,6 @@ import org.matsim.core.events.handler.EventHandler; import org.matsim.freight.carriers.events.CarrierTourEndEvent; - public interface CarrierTourEndEventHandler extends EventHandler { void handleEvent( CarrierTourEndEvent event ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourStartEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourStartEventHandler.java index 5f4b26ce4bb..3a7997cc9ef 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourStartEventHandler.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/CarrierTourStartEventHandler.java @@ -24,7 +24,6 @@ import org.matsim.core.events.handler.EventHandler; import org.matsim.freight.carriers.events.CarrierTourStartEvent; - public interface CarrierTourStartEventHandler extends EventHandler { void handleEvent( CarrierTourStartEvent event ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/Vehicle2CarrierEventHandler.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/Vehicle2CarrierEventHandler.java index bc9236decbf..0d5b9902f57 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/Vehicle2CarrierEventHandler.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/events/eventhandler/Vehicle2CarrierEventHandler.java @@ -20,15 +20,14 @@ */ package org.matsim.freight.carriers.events.eventhandler; +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.vehicles.Vehicle; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * Basic event handler that collects the relation between vehicles and carrier. * Necessary since link enter and leave events do not contain any information of the carrier. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/DistanceConstraint.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/DistanceConstraint.java index 068c70506cd..8615e0b3d75 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/DistanceConstraint.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/DistanceConstraint.java @@ -94,7 +94,7 @@ public ConstraintsStatus fulfilled(JobInsertionContext context, TourActivity pre consumptionPerMeter = VehicleUtils .getEnergyConsumptionKWhPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); else - consumptionPerMeter = VehicleUtils.getFuelConsumption(vehicleTypeOfNewVehicle); + consumptionPerMeter = VehicleUtils.getFuelConsumptionLitersPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); double routeDistance = calculateRouteDistance(context, newVehicle); double routeConsumption = routeDistance * (consumptionPerMeter); @@ -212,9 +212,9 @@ private double calculateRouteDistance(JobInsertionContext context, Vehicle newVe * directly behind the new pickup. This method gives back the minimal distance * of this three options. * - * @param context - * @param newInvestigatedPickup - * @param nextAct + * @param context the context of the job insertion + * @param newInvestigatedPickup the new pickup which should be added to the tour + * @param nextAct the next activity after the new pickup * @return minimal distance of the associated delivery */ private double findMinimalAdditionalDistance(JobInsertionContext context, TourActivity newInvestigatedPickup, @@ -283,8 +283,8 @@ private double findMinimalAdditionalDistance(JobInsertionContext context, TourAc /** * Checks if the find possible distance is the minimal one. * - * @param minimalAdditionalDistance - * @param possibleAdditionalDistance + * @param minimalAdditionalDistance the minimal additional distance + * @param possibleAdditionalDistance the possible additional distance * @return the minimal transport distance */ private double findMinimalDistance(double minimalAdditionalDistance, double possibleAdditionalDistance) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/MatsimJspritFactory.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/MatsimJspritFactory.java index 8710e50c7ba..00cf9347716 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/MatsimJspritFactory.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/MatsimJspritFactory.java @@ -45,6 +45,10 @@ import com.graphhopper.jsprit.io.algorithm.AlgorithmConfig; import com.graphhopper.jsprit.io.algorithm.AlgorithmConfigXmlReader; import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms; +import java.net.URL; +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.api.core.v01.Coord; @@ -57,11 +61,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * A factory that creates matsim-object from jsprit * (...) and vice versa. @@ -686,9 +685,6 @@ public static Carrier createCarrier(String carrierId, VehicleRoutingProblem vrp) capabilityBuilder.setFleetSize(CarrierCapabilities.FleetSize.FINITE); } else capabilityBuilder.setFleetSize(CarrierCapabilities.FleetSize.INFINITE); - for (com.graphhopper.jsprit.core.problem.vehicle.VehicleType type : vrp.getTypes()) { - capabilityBuilder.addType(createMatsimVehicleType(type)); - } for (Vehicle vehicle : vrp.getVehicles()) { capabilityBuilder.addVehicle(createCarrierVehicle(vehicle)); } diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java index e6d8e1a0e45..c97243d50fe 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java @@ -26,6 +26,8 @@ import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -45,9 +47,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - /** * This calculates transport-times, transport-costs and the distance to cover * the distance from one location to another. It calculates these values based @@ -57,7 +56,7 @@ * *

* It can be used with multiple threads. Note that each thread gets its own - * leastCostPathCalculator. It is created only once and cached afterwards. Thus, + * leastCostPathCalculator. It is created only once and cached afterward. Thus, * it requires a threadSafe leastCostPathCalculatorFactory (the calculator * itself does not need to be thread-safe). * @@ -85,8 +84,6 @@ */ public class NetworkBasedTransportCosts implements VRPTransportCosts { - private final RoadPricingScheme roadPricingScheme; - public interface InternalLeastCostPathCalculatorListener { void startCalculation(long routerId); @@ -497,7 +494,7 @@ public Builder setRoadPricingScheme( RoadPricingScheme roadPricingScheme) { *

* Comments: *
    - *
  • By default this will take free speed travel times. + *
  • By default, this will take free speed travel times. *
  • yyyy These free speed travel times do not take the time-dependent * network into account. kai, jan'14 *
  • Either can be changed with builder.setTravelTime(...) or with @@ -578,7 +575,6 @@ private NetworkBasedTransportCosts(Builder builder) { this.travelTime = builder.travelTime; this.network = builder.network; this.leastCostPathCalculatorFactory = builder.leastCostPathCalculatorFactory; - this.roadPricingScheme = builder.roadPricingScheme; this.timeSliceWidth = builder.timeSliceWidth; this.defaultTypeId = builder.defaultTypeId; this.ttMemorizedCounter = new Counter("#TransportCostValues cached "); @@ -658,12 +654,12 @@ private VehicleImpl getDefaultVehicle(Location fromId) { private void informEndCalc() { for (InternalLeastCostPathCalculatorListener l : listeners) - l.endCalculation(Thread.currentThread().getId()); + l.endCalculation(Thread.currentThread().threadId()); } private void informStartCalc() { for (InternalLeastCostPathCalculatorListener l : listeners) - l.startCalculation(Thread.currentThread().getId()); + l.startCalculation(Thread.currentThread().threadId()); } /** @@ -853,11 +849,11 @@ public LeastCostPathCalculator getRouter() { } private LeastCostPathCalculator createLeastCostPathCalculator() { - LeastCostPathCalculator router = routerCache.get(Thread.currentThread().getId()); + LeastCostPathCalculator router = routerCache.get(Thread.currentThread().threadId()); if (router == null) { LeastCostPathCalculator newRouter = leastCostPathCalculatorFactory.createPathCalculator(network, travelDisutility, travelTime); - router = routerCache.putIfAbsent(Thread.currentThread().getId(), newRouter); + router = routerCache.putIfAbsent(Thread.currentThread().threadId(), newRouter); if (router == null) { router = newRouter; } diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsFactory.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsFactory.java index 6a0be5414f0..558ec523a81 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsFactory.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsFactory.java @@ -21,19 +21,18 @@ package org.matsim.freight.carriers.jsprit; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.router.util.TravelTime; -import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.freight.carriers.Carriers; +import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.vehicles.VehicleType; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - /** * @author steffenaxer */ diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkRouter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkRouter.java index 7dac94a1c8c..2388801503b 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkRouter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkRouter.java @@ -22,7 +22,7 @@ import org.matsim.freight.carriers.CarrierPlan; import org.matsim.freight.carriers.ScheduledTour; -import org.matsim.freight.carriers.controler.CarrierTimeAndSpaceTourRouter; +import org.matsim.freight.carriers.controller.CarrierTimeAndSpaceTourRouter; /** * Router that routes {@link CarrierPlan}. diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VRPTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VRPTransportCosts.java index d831d329fc9..240c16adf7c 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VRPTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VRPTransportCosts.java @@ -27,7 +27,7 @@ import org.matsim.core.router.util.TravelTime; /** - * @author: Steffen Axer + * @author Steffen Axer */ public interface VRPTransportCosts extends VehicleRoutingTransportCosts { LeastCostPathCalculator getRouter(); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java index 6175780ab9a..7c9541f5777 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java @@ -21,14 +21,12 @@ package org.matsim.freight.carriers.jsprit; import com.graphhopper.jsprit.core.problem.vehicle.VehicleType; +import java.util.*; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.roadpricing.RoadPricingScheme; import org.matsim.contrib.roadpricing.RoadPricingSchemeImpl.Cost; -import java.util.*; - - /** * Calculator that manages and calculates vehicle type dependent road pricing schemas. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/CarrierScoreStats.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/CarrierScoreStats.java index 84556de1a14..8578c0a91b9 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/CarrierScoreStats.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/CarrierScoreStats.java @@ -21,6 +21,10 @@ package org.matsim.freight.carriers.usecases.analysis; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Locale; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.core.controler.events.IterationEndsEvent; @@ -35,11 +39,6 @@ import org.matsim.freight.carriers.CarrierPlan; import org.matsim.freight.carriers.Carriers; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.Locale; - /** * As you can see, it is basically a copy of {@link org.matsim.analysis.ScoreStatsControlerListener}. However, it is modified to score {@link Carrier}s * rather than Persons. (Oct'13, schroeder) @@ -81,7 +80,6 @@ public class CarrierScoreStats implements StartupListener, IterationEndsListener * * @param filename including the path, excluding the file type extension * @param createPNG true if in every iteration, the scorestats should be visualized in a graph and written to disk. - * @throws UncheckedIOException */ public CarrierScoreStats(Carriers carriers, final String filename, final boolean createPNG) throws UncheckedIOException { this.carriers = carriers; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/LegHistogram.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/LegHistogram.java index fff393eee93..2a1400a6564 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/LegHistogram.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/analysis/LegHistogram.java @@ -22,6 +22,14 @@ package org.matsim.freight.carriers.usecases.analysis; import jakarta.inject.Inject; +import java.awt.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartUtils; import org.jfree.chart.JFreeChart; @@ -42,15 +50,6 @@ import org.matsim.api.core.v01.population.Population; import org.matsim.core.utils.misc.Time; -import java.awt.*; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - /** * It is a copy of {@link org.matsim.analysis.LegHistogram}. It is modified to include or exclude persons. * @@ -392,8 +391,7 @@ private int getBinIndex(final double time) { private ModeData getDataForMode(final String legMode) { // +1 for all times out of our range - ModeData modeData = this.data.computeIfAbsent(legMode, k -> new ModeData(this.nofBins + 1)); - return modeData; + return this.data.computeIfAbsent(legMode, k -> new ModeData(this.nofBins + 1)); } private static class ModeData { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/CarrierScoringFunctionFactoryImpl.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/CarrierScoringFunctionFactoryImpl.java index 759b3da5890..8b61af1efdc 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/CarrierScoringFunctionFactoryImpl.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/CarrierScoringFunctionFactoryImpl.java @@ -22,6 +22,8 @@ package org.matsim.freight.carriers.usecases.chessboard; import com.google.inject.Inject; +import java.util.HashSet; +import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -36,14 +38,11 @@ import org.matsim.core.scoring.ScoringFunction; import org.matsim.core.scoring.SumScoringFunction; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; -import org.matsim.freight.carriers.controler.FreightActivity; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.FreightActivity; import org.matsim.freight.carriers.jsprit.VehicleTypeDependentRoadPricingCalculator; import org.matsim.vehicles.Vehicle; -import java.util.HashSet; -import java.util.Set; - /** * Defines example carrier scoring function (factory). * @@ -187,9 +186,7 @@ public void handleLeg(Leg leg) { Id vehicleId = nRoute.getVehicleId(); CarrierVehicle vehicle = CarriersUtils.getCarrierVehicle(carrier, vehicleId); Gbl.assertNotNull(vehicle); - if(!employedVehicles.contains(vehicle)){ - employedVehicles.add(vehicle); - } + employedVehicles.add(vehicle); double distance = 0.0; if(leg.getRoute() instanceof NetworkRoute){ Link startLink = network.getLinks().get(leg.getRoute().getStartLinkId()); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/FreightScenarioCreator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/FreightScenarioCreator.java index c258d01e703..3d291829b77 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/FreightScenarioCreator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/FreightScenarioCreator.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers.usecases.chessboard; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Link; @@ -34,10 +37,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - /** * Creates chessboard freight scenario. * diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InitialCarrierPlanCreator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InitialCarrierPlanCreator.java index fb2979e4be1..72c6d90df96 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InitialCarrierPlanCreator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InitialCarrierPlanCreator.java @@ -34,6 +34,7 @@ import com.graphhopper.jsprit.io.algorithm.AlgorithmConfig; import com.graphhopper.jsprit.io.algorithm.AlgorithmConfigXmlReader; import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms; +import java.util.Collection; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Network; import org.matsim.core.config.Config; @@ -44,8 +45,6 @@ import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; import org.matsim.freight.carriers.jsprit.NetworkRouter; -import java.util.Collection; - final class InitialCarrierPlanCreator { private final Network network; @@ -166,8 +165,6 @@ public static void main(String[] args) { Carriers carriers = new Carriers(); new CarrierPlanXmlReader(carriers, types ).readFile("input/usecases/chessboard/freight/carrierPlansWithoutRoutes_10minTW.xml" ); - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); - for(Carrier carrier : carriers.getCarriers().values()){ CarrierPlan plan = new InitialCarrierPlanCreator(scenario.getNetwork()).createPlan(carrier); carrier.addPlan(plan); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InnerOuterCityScenarioCreator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InnerOuterCityScenarioCreator.java index d5b48f1df69..789a5681a46 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InnerOuterCityScenarioCreator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/InnerOuterCityScenarioCreator.java @@ -21,12 +21,11 @@ package org.matsim.freight.carriers.usecases.chessboard; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.network.Link; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; final class InnerOuterCityScenarioCreator { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PassengerScenarioCreator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PassengerScenarioCreator.java index 3a742ced5e6..1060931835e 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PassengerScenarioCreator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PassengerScenarioCreator.java @@ -21,6 +21,8 @@ package org.matsim.freight.carriers.usecases.chessboard; +import java.util.ArrayList; +import java.util.List; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; @@ -36,9 +38,6 @@ import org.matsim.core.router.util.LeastCostPathCalculator.Path; import org.matsim.core.scenario.ScenarioUtils; -import java.util.ArrayList; -import java.util.List; - final class PassengerScenarioCreator { static int agentCounter = 1; diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PlotPlans.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PlotPlans.java index 838ac5463ae..9e615dda9f4 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PlotPlans.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/PlotPlans.java @@ -47,8 +47,6 @@ public static void main(String[] args) { // new CarrierPlanXmlReader(carriers).read("input/usecases/chessboard/freight/singleCarrierTwentyActivities.xml"); new CarrierPlanXmlReader(carriers, types ).readFile("output/ITERS/it.140/140.carrierPlans.xml" ); - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); - final Carrier carrier = carriers.getCarriers().get(Id.create("carrier1",Carrier.class)); VehicleRoutingProblem.Builder vrpBuilder = MatsimJspritFactory.createRoutingProblemBuilder(carrier, scenario.getNetwork()); VehicleRoutingProblem vrp = vrpBuilder.build(); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunChessboard.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunChessboard.java index e8f7887cfea..ff62264a468 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunChessboard.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunChessboard.java @@ -23,14 +23,13 @@ import com.google.inject.Provider; import jakarta.inject.Inject; +import java.util.Map; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Network; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.controler.AbstractModule; -import org.matsim.core.controler.Controler; -import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.*; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.listener.IterationEndsListener; import org.matsim.core.replanning.GenericPlanStrategyImpl; @@ -46,12 +45,10 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.*; +import org.matsim.freight.carriers.controller.*; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; import org.matsim.freight.carriers.usecases.analysis.LegHistogram; -import java.util.Map; - public final class RunChessboard { public static void main(String[] args){ @@ -74,11 +71,11 @@ public static void main(String[] args){ Carriers carriers = CarriersUtils.addOrGetCarriers( scenario ); CarrierVehicleTypes types = CarriersUtils.getCarrierVehicleTypes( scenario ); - Controler controler = new Controler( scenario); + Controller controller = ControllerUtils.createController( scenario ); - controler.addOverridingModule(new CarrierModule() ); + controller.addOverridingModule(new CarrierModule() ); - controler.addOverridingModule(new AbstractModule() { + controller.addOverridingModule(new AbstractModule() { @Override public void install() { @@ -113,7 +110,7 @@ public void install() { } }); - controler.run(); + controller.run(); } @@ -139,7 +136,7 @@ private static class MyCarrierPlanStrategyManagerProvider implements Provider strategy = new GenericPlanStrategyImpl<>( new ExpBetaPlanChanger.Factory().build() ); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunPassengerAlongWithCarriers.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunPassengerAlongWithCarriers.java index 40a49ecf40c..2561968e1f2 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunPassengerAlongWithCarriers.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/RunPassengerAlongWithCarriers.java @@ -23,16 +23,15 @@ import com.google.inject.Provider; import jakarta.inject.Inject; +import java.net.URL; +import java.util.Map; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Network; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.controler.AbstractModule; -import org.matsim.core.controler.Controler; -import org.matsim.core.controler.MatsimServices; -import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.controler.*; import org.matsim.core.controler.listener.IterationEndsListener; import org.matsim.core.gbl.Gbl; import org.matsim.core.replanning.GenericPlanStrategyImpl; @@ -47,13 +46,10 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.*; +import org.matsim.freight.carriers.controller.*; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; import org.matsim.freight.carriers.usecases.analysis.LegHistogram; -import java.net.URL; -import java.util.Map; - final class RunPassengerAlongWithCarriers { final static URL url = ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"); @@ -67,7 +63,7 @@ public void run() { Scenario scenario = prepareScenario(config); - Controler controler = new Controler(scenario); + Controller controller = ControllerUtils.createController(scenario); CarrierVehicleTypes types = new CarrierVehicleTypes(); new CarrierVehicleTypeReader(types).readURL( IOUtils.extendUrl(url, "vehicleTypes.xml" ) ); @@ -75,9 +71,9 @@ public void run() { final Carriers carriers = new Carriers(); new CarrierPlanXmlReader(carriers, types ).readURL( IOUtils.extendUrl(url, "carrierPlans.xml" ) ); - controler.addOverridingModule( new CarrierModule() ); + controller.addOverridingModule( new CarrierModule() ); - controler.addOverridingModule( new AbstractModule(){ + controller.addOverridingModule( new AbstractModule(){ @Override public void install(){ this.bind( CarrierStrategyManager.class ).toProvider( new MyCarrierPlanStrategyManagerFactory(types) ); this.bind( CarrierScoringFunctionFactory.class ).toInstance(carrier -> { @@ -91,9 +87,9 @@ public void run() { } ); - prepareFreightOutputDataAndStats(scenario, controler.getEvents(), controler, carriers); + prepareFreightOutputDataAndStats(scenario, controller.getEvents(), controller, carriers); - controler.run(); + controller.run(); } @@ -154,7 +150,7 @@ public MyCarrierPlanStrategyManagerFactory(CarrierVehicleTypes types) { final TravelDisutility travelDisutility = CarrierTravelDisutilities.createBaseDisutility(types, modeTravelTimes.get(TransportMode.car ) ); final LeastCostPathCalculator router = leastCostPathCalculatorFactory.createPathCalculator(network, travelDisutility, modeTravelTimes.get(TransportMode.car)); - final CarrierStrategyManager carrierStrategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + final CarrierStrategyManager carrierStrategyManager = CarrierControllerUtils.createDefaultCarrierStrategyManager(); carrierStrategyManager.setMaxPlansPerAgent(5); carrierStrategyManager.addStrategy(new GenericPlanStrategyImpl<>(new BestPlanSelector<>()), null, 0.95); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/SelectBestPlanAndOptimizeItsVehicleRouteFactory.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/SelectBestPlanAndOptimizeItsVehicleRouteFactory.java index 0051af3de81..a043c85d958 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/SelectBestPlanAndOptimizeItsVehicleRouteFactory.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/usecases/chessboard/SelectBestPlanAndOptimizeItsVehicleRouteFactory.java @@ -30,6 +30,8 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.util.Solutions; import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms; +import java.net.URL; +import java.util.Collection; import org.matsim.api.core.v01.network.Network; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericPlanStrategyImpl; @@ -46,9 +48,6 @@ import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; import org.matsim.freight.carriers.jsprit.NetworkRouter; -import java.net.URL; -import java.util.Collection; - final class SelectBestPlanAndOptimizeItsVehicleRouteFactory { final URL url = ExamplesUtils.getTestScenarioURL("freight-chessboard-9x9"); 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..ca222f462ab --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/FreightLogisticsConfigGroup.java @@ -0,0 +1,142 @@ +/* + *********************************************************************** * + * 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.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 straight 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..9d856aaa6cb --- /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 assignment 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/LSPControllerListener.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPControllerListener.java new file mode 100644 index 00000000000..0da2e144cbc --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPControllerListener.java @@ -0,0 +1,253 @@ +/* + * *********************************************************************** * + * * 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.controller.CarrierAgentTracker; +import org.matsim.freight.logistics.io.LSPPlanXmlWriter; +import org.matsim.freight.logistics.shipment.LspShipment; + +class LSPControllerListener + implements StartupListener, + BeforeMobsimListener, + AfterMobsimListener, + ScoringListener, + ReplanningListener, + IterationStartsListener, + IterationEndsListener, + ShutdownListener { + private static final Logger log = LogManager.getLogger(LSPControllerListener.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 + LSPControllerListener(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..d25cbfb043a --- /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 LSPControllerListener} 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..520aead053b --- /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.controller.*; +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(LSPControllerListener.class).in(Singleton.class); + addControlerListenerBinding().to(LSPControllerListener.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..7f7d3823866 --- /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(); + + void 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..84a698a5edd --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/LSPPlanImpl.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; + +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 void addShipmentPlan(LspShipmentPlan lspShipmentPlan) { + this.lspShipmentPlans.add(lspShipmentPlan); + } + + @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..4f0ae7a718d --- /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 createForwardLogisticChainScheduler() { + 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..55a1176330f --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/analysis/Driver2VehicleEventHandler.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.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; + +/** + * 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..438c34feaa2 --- /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 controlerShutdownEvent) { + 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..452ef06ff43 --- /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} 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/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java similarity index 50% rename from contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test.java rename to contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java index f4840b577ae..b5a0933fa7c 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test.java +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventCreator.java @@ -19,37 +19,18 @@ * */ -package org.matsim.freight.carriers; +package org.matsim.freight.logistics.events; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; -import org.matsim.freight.carriers.*; -import org.matsim.testcases.MatsimTestUtils; -import org.matsim.vehicles.VehicleType; -import org.matsim.vehicles.VehicleUtils; +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 class CarrierPlanXmlWriterV1Test { - - @RegisterExtension - private MatsimTestUtils testUtils = new MatsimTestUtils(); - - @Test - void testCarrierPlanWriterWrites() { - - CarrierVehicleTypes carrierVehicleTypes = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader( carrierVehicleTypes ).readFile( testUtils.getPackageInputDirectory() + "vehicleTypes_v2.xml" ); - VehicleType defaultVehicleType = VehicleUtils.getFactory().createVehicleType( Id.create("default", VehicleType.class ) ); - carrierVehicleTypes.getVehicleTypes().put( defaultVehicleType.getId(), defaultVehicleType ); - - Carriers carriers = new Carriers(); - CarrierPlanReaderV1 carrierPlanReaderV1 = new CarrierPlanReaderV1(carriers, carrierVehicleTypes ); - carrierPlanReaderV1.readFile(testUtils.getClassInputDirectory() + "carrierPlansEquils.xml"); - CarrierPlanXmlWriterV1 planWriter = new CarrierPlanXmlWriterV1(carriers.getCarriers().values()); - planWriter.write(testUtils.getOutputDirectory() + "carrierPlansEquilsWritten.xml"); - } - +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/carriers/CarrierVehicleTypeLoader.java b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java similarity index 51% rename from contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeLoader.java rename to contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java index c9fbe45d4ad..b65cf79b7c0 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierVehicleTypeLoader.java +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/events/LspEventsReader.java @@ -19,47 +19,35 @@ * */ -package org.matsim.freight.carriers; +package org.matsim.freight.logistics.events; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import java.util.Map; +import java.util.TreeMap; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.events.MatsimEventsReader; +import org.matsim.freight.carriers.events.CarrierEventsReaders; +import org.matsim.freight.logistics.LSP; /** - * @deprecated Functionality is removed. VehicleTypes must be set (and available) when creating the vehicle. kai/kai jan'22 - *

    - * Loader that loads/assigns vehicleTypes to their vehicles and carriers respectively. - * - * @author sschroeder + * Creates an {@link MatsimEventsReader} that also handles the {@link + * LSP} specific events. * + * @author kturner (Kai Martins-Turner) */ -@Deprecated -public class CarrierVehicleTypeLoader { - - @SuppressWarnings("unused") - private static final Logger logger = LogManager.getLogger(CarrierVehicleTypeLoader.class); - - /** - * Constructs the loader with the carriers the types should be assigned to. - * - * @param carriers - * - * * @deprecated Functionality is removed. VehicleTypes must be set (and available) when creating the vehicle. kai/kai jan'22 - */ - @Deprecated - public CarrierVehicleTypeLoader(Carriers carriers) { - super(); - } +public class LspEventsReader { - /** - * Assigns types to carriers and their vehicles. - * - * @param types - * - * @deprecated Functionality is removed. VehicleTypes must be set (and available) when creating the vehicle. kai/kai jan'22 - */ - @Deprecated - public void loadVehicleTypes(CarrierVehicleTypes types){ - logger.error("Functionality is removed. VehicleTypes must be set (and available) when creating the vehicle."); - } + 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..8715df32602 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfInitialPlan.java @@ -0,0 +1,209 @@ +/* + *********************************************************************** * + * 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.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("scenarios/2regions/2regions-network.xml"); + 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..eb01dda6b7e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChain.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.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.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("scenarios/2regions/2regions-network.xml"); + + // 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..59c36fde881 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleSchedulingOfTransportChainHubsVsDirect.java @@ -0,0 +1,620 @@ +/* + *********************************************************************** * + * 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.*; +import org.matsim.core.replanning.GenericPlanStrategyImpl; +import org.matsim.core.replanning.selectors.RandomPlanSelector; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + + 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 controller 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. + + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule(new LSPModule()); + controller.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 = + CarrierControllerUtils.createDefaultCarrierStrategyManager(); + strategyManager.addStrategy( + new GenericPlanStrategyImpl<>(new RandomPlanSelector<>()), null, 1); + return strategyManager; + }); + } + }); + + log.info("Run MATSim"); + + controller.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 sideeffects + // 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..7cfc3b4ca82 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTestOutput.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.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.Controller; +import org.matsim.core.controler.ControllerUtils; +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); + + Controller controller = ControllerUtils.createController(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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..b289d95c39a --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid.java @@ -0,0 +1,535 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + log.info("Some results ...."); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printScores(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printShipmentsOfLSP( + controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentPlan( + controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog( + controller.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..ffaf4c0aa48 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/initialPlans/ExampleTwoEchelonGrid_NR.java @@ -0,0 +1,544 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + // Ggf. muss der Ordner noch erstellt werden (?) + new LSPPlanXmlWriter(LSPUtils.getLSPs(controller.getScenario())) + .write(controller.getConfig().controller().getOutputDirectory() + "/lsps.xml"); + new LSPPlanXmlReader( + LSPUtils.getLSPs(controller.getScenario()), + CarriersUtils.getCarriers(controller.getScenario())); + new CarrierPlanWriter(CarriersUtils.getCarriers(controller.getScenario())) + .write(controller.getConfig().controller().getOutputDirectory() + "/carriers.xml"); + + log.info("Some results ...."); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printScores(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printShipmentsOfLSP( + controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentPlan( + controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog( + controller.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..83b1fa4dc3a --- /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.controller.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..ec67c2895f6 --- /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.controller.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(LinkBasedTollScoring.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..5d554e99a82 --- /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.examples.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..69f9cc76a59 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/lspScoring/ExampleLSPScoring.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.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.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.scenario.ScenarioUtils; +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); + + Controller controller = prepareController(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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp2 : LSPUtils.getLSPs(scenario).getLSPs().values()) { + System.out.println("The tip of all customers was: " + lsp2.getSelectedPlan().getScore()); + } + } + + static Controller prepareController(Scenario scenario) { + // Start the Mobsim one iteration is sufficient for scoring + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule(new LSPModule()); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + bind(LSPScorerFactory.class).toInstance(TipScorer::new); + } + }); + return controller; + } + + 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("scenarios/2regions/2regions-network.xml"); + + 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..59fb551c08b --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfSimpleLSP.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.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.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +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("scenarios/2regions/2regions-network.xml"); + + // 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 controller 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); + + Controller controller = ControllerUtils.createController(scenario); + controller.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..1853cc27331 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/mobsimExamples/ExampleMobsimOfTransportChain.java @@ -0,0 +1,420 @@ +/* + *********************************************************************** * + * 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.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +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("scenarios/2regions/2regions-network.xml"); + + // 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 controller and LSPModule + ArrayList lspList = new ArrayList<>(); + lspList.add(lsp); + LSPs lsps = new LSPs(lspList); + LSPUtils.addLSPs(scenario, lsps); + + Controller controller = ControllerUtils.createController(scenario); + controller.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("scenarios/2regions/2regions-network.xml"); + // 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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..9cd649ae127 --- /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.controller.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(LinkBasedTollScoring.class); + + private final double toll; + private final List vehicleTypesToBeTolled; + private double score; + private final 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..b45a151a19e --- /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.controller.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; + + 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..e2bb5db2bc0 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleGroceryDeliveryMultipleChains.java @@ -0,0 +1,343 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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 controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..fcf31169400 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleMixedEchelonChains.java @@ -0,0 +1,498 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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 controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..6e01b0e38ac --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChains.java @@ -0,0 +1,390 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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 controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..4012855405c --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleOneEchelonChainsReplanning.java @@ -0,0 +1,401 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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 controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..a0204e7fb36 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleMultipleTwoEchelonChainsReplanning.java @@ -0,0 +1,441 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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 controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + // @formatter:off + controller.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 = CarrierControllerUtils.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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..1ed5bcc050d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChains.java @@ -0,0 +1,455 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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)); + + Controller controller = prepareController(scenario); + + log.info("Run MATSim"); + + controller.run(); + + runCarrierAnalysis(controller.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 Controller prepareController(Scenario scenario) { + log.info("Prepare controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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 controller; + } + + 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..cd397b50937 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/ExampleTwoLspsGroceryDeliveryMultipleChainsWithToll.java @@ -0,0 +1,482 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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)); + + + Controller controller = prepareController(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 + controller + .getConfig() + .vspExperimental() + .setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + runCarrierAnalysis(controller.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 Controller prepareController(Scenario scenario, RoadPricingScheme rpScheme) { + log.info("Prepare controller"); + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule( + new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + install(new PersonMoneyEventsAnalysisModule()); + } + }); + + controller.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 = + CarrierControllerUtils.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(controller); + controller.addOverridingModule( new RoadPricingModule(rpScheme) ); + } + return controller; + } + + /* + * 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..6cd0c2389c6 --- /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.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 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..45ae711dcf1 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/multipleChains/RandomShiftingStrategyFactory.java @@ -0,0 +1,115 @@ +/* + *********************************************************************** * + * 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..a918de5f531 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/ExampleCheckRequirementsOfAssigner.java @@ -0,0 +1,262 @@ +/* + *********************************************************************** * + * 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.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("scenarios/2regions/2regions-network.xml"); + 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..0422427ab30 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/requirementsChecking/RedRequirement.java @@ -0,0 +1,59 @@ +/* + *********************************************************************** * + * 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..22572f86572 --- /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..26959c6081d --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/examples/simulationTrackers/ExampleSimulationTrackers.java @@ -0,0 +1,215 @@ +/* + *********************************************************************** * + * 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.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("scenarios/2regions/2regions-network.xml"); + 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("scenarios/2regions/2regions-network.xml"); + // 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..c997b5a35d2 --- /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) { + this.writeStartTag(LSP, List.of(createTuple(ID, lsp.getId().toString()))); + } + + private void writeResources(LSP lsp) { + 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) { + 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) { + 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..deb8e984b2e --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CarrierSchedulerUtils.java @@ -0,0 +1,145 @@ +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..d91bf1c94f5 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/CollectionCarrierScheduler.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.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 { + + private static final 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..90abf00ea67 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/DistributionCarrierScheduler.java @@ -0,0 +1,471 @@ +/* + *********************************************************************** * + * 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 { + + private static final 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 -> //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... + carrier.getShipments().putAll(auxiliaryCarrier.getShipments()); + 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..46a0ae0e709 --- /dev/null +++ b/contribs/freight/src/main/java/org/matsim/freight/logistics/resourceImplementations/LSPTourStartEventHandler.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.resourceImplementations; + +import java.util.Objects; +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; + +/*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..59307392ff6 --- /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 + * exogenous, 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..6c6081c81bf --- /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.LspShipment; +import org.matsim.freight.logistics.shipment.LspShipmentPlan; +import org.matsim.freight.logistics.shipment.LspShipmentPlanElement; +import org.matsim.freight.logistics.shipment.LspShipmentUtils; + +/*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/carriers/CarrierEventsReadersTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierEventsReadersTest.java index bf1cb7be9a6..933961095cb 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierEventsReadersTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierEventsReadersTest.java @@ -20,6 +20,10 @@ package org.matsim.freight.carriers; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -36,12 +40,6 @@ import org.matsim.testcases.utils.EventsCollector; import org.matsim.vehicles.Vehicle; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; -import java.util.List; - - /** * @author Kai Martins-Turner (kturner) * @author Niclas Richter (nixlaos) @@ -195,7 +193,7 @@ void testReader() { handledEvents.addAll(eventHandlerServices.handledEvents); handledEvents.addAll(eventHandlerShipments.handledEvents); - //Please note: This test is sensitive to the order of events as they are added in carrierEvents (input) and the resukts of the handler... + //Please note: This test is sensitive to the order of events as they are added in carrierEvents (input) and the results of the handler... Assertions.assertArrayEquals(carrierEvents.toArray(), handledEvents.toArray()); } diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java index 49dc173dd05..e80f24075be 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierModuleTest.java @@ -33,11 +33,9 @@ import org.matsim.core.controler.Controler; import org.matsim.core.controler.OutputDirectoryHierarchy; import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.freight.carriers.CarriersUtils; -import org.matsim.freight.carriers.FreightCarriersConfigGroup; -import org.matsim.freight.carriers.controler.CarrierModule; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; -import org.matsim.freight.carriers.controler.CarrierStrategyManager; +import org.matsim.freight.carriers.controller.CarrierModule; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.CarrierStrategyManager; import org.matsim.freight.carriers.mobsim.DistanceScoringFunctionFactoryForTests; import org.matsim.freight.carriers.mobsim.StrategyManagerFactoryForTests; import org.matsim.testcases.MatsimTestUtils; @@ -69,10 +67,10 @@ public void setUp(){ config.plans().setInputFile( testUtils.getClassInputDirectory() + "plans100.xml" ); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.overwriteExistingFiles); config.controller().setWritePlansInterval(1); - config.controller().setCreateGraphs(false); + config.controller().setCreateGraphsInterval(0); freightCarriersConfigGroup = ConfigUtils.addOrGetModule( config, FreightCarriersConfigGroup.class ) ; freightCarriersConfigGroup.setCarriersFile( testUtils.getClassInputDirectory() + "carrierPlansEquils.xml"); - freightCarriersConfigGroup.setCarriersVehicleTypesFile( testUtils.getClassInputDirectory() + "vehicleTypes.xml"); + freightCarriersConfigGroup.setCarriersVehicleTypesFile( testUtils.getPackageInputDirectory() + "vehicleTypes_v2.xml"); Scenario scenario = ScenarioUtils.loadScenario( config ); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanReaderV1Test.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanReaderV1Test.java index 38749fbabdf..8092ccfd02d 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanReaderV1Test.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanReaderV1Test.java @@ -26,7 +26,6 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; import org.matsim.core.population.routes.NetworkRoute; -import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.Tour.Leg; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.VehicleType; diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2Test.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2Test.java index 0deffa73889..07b0a547f3e 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2Test.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2Test.java @@ -21,8 +21,12 @@ package org.matsim.freight.carriers; -import org.junit.jupiter.api.BeforeEach; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; import org.junit.jupiter.api.Assertions; +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; @@ -32,16 +36,10 @@ import org.matsim.core.config.ConfigUtils; import org.matsim.core.gbl.Gbl; import org.matsim.core.scenario.ScenarioUtils; -import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.*; - public class CarrierPlanXmlReaderV2Test { @RegisterExtension @@ -192,7 +190,7 @@ void test_readStream() { - + diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2WithDtdTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2WithDtdTest.java index fb12a37ff82..db3141cf8cb 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2WithDtdTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlReaderV2WithDtdTest.java @@ -21,20 +21,18 @@ package org.matsim.freight.carriers; +import java.util.*; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; import org.matsim.core.gbl.Gbl; -import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; -import java.util.*; - public class CarrierPlanXmlReaderV2WithDtdTest { @RegisterExtension diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test.java deleted file mode 100644 index 46444ed07d3..00000000000 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * *********************************************************************** * - * 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.carriers; - -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.TransportMode; -import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; -import org.matsim.testcases.MatsimTestUtils; -import org.matsim.vehicles.Vehicle; - -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; - -public class CarrierPlanXmlWriterV2Test { - - @RegisterExtension - private MatsimTestUtils testUtils = new MatsimTestUtils(); - - private Carrier testCarrier; - - @BeforeEach - public void setUp() { - - CarrierVehicleTypes carrierVehicleTypes = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader( carrierVehicleTypes ).readFile( this.testUtils.getPackageInputDirectory() + "vehicleTypes_v2.xml" ); - - Carriers carriers = new Carriers(); - new CarrierPlanXmlReader(carriers, carrierVehicleTypes ).readFile(this.testUtils.getClassInputDirectory() + "carrierPlansEquils.xml" ); - new CarrierPlanXmlWriterV2(carriers).write(this.testUtils.getClassInputDirectory() + "carrierPlansEquilsWritten.xml"); - carriers.getCarriers().clear(); - new CarrierPlanXmlReader(carriers, carrierVehicleTypes ).readFile(this.testUtils.getClassInputDirectory() + "carrierPlansEquilsWritten.xml" ); - testCarrier = carriers.getCarriers().get(Id.create("testCarrier", Carrier.class)); - } - - @Test - void test_whenReadingServices_nuOfServicesIsCorrect(){ - assertEquals(3,testCarrier.getServices().size()); - } - - @Test - void test_whenReadingCarrier_itReadsTypeIdsCorrectly(){ - - CarrierVehicle light = CarriersUtils.getCarrierVehicle(testCarrier, Id.createVehicleId("lightVehicle")); - assertEquals("light",light.getVehicleTypeId().toString()); - - CarrierVehicle medium = CarriersUtils.getCarrierVehicle(testCarrier, Id.createVehicleId("mediumVehicle")); - assertEquals("medium",medium.getVehicleTypeId().toString()); - - CarrierVehicle heavy = CarriersUtils.getCarrierVehicle(testCarrier, Id.createVehicleId("heavyVehicle")); - assertEquals("heavy",heavy.getVehicleTypeId().toString()); - } - - @Test - void test_whenReadingCarrier_itReadsVehiclesCorrectly(){ - Map, CarrierVehicle> carrierVehicles = testCarrier.getCarrierCapabilities().getCarrierVehicles(); - assertEquals(3,carrierVehicles.size()); - assertTrue(exactlyTheseVehiclesAreInVehicleCollection(Arrays.asList(Id.create("lightVehicle", Vehicle.class), - Id.create("mediumVehicle", Vehicle.class),Id.create("heavyVehicle", Vehicle.class)),carrierVehicles.values())); - } - - @Test - void test_whenReadingCarrier_itReadsFleetSizeCorrectly(){ - assertEquals(FleetSize.INFINITE, testCarrier.getCarrierCapabilities().getFleetSize()); - } - - @Test - void test_whenReadingCarrier_itReadsShipmentsCorrectly(){ - assertEquals(2, testCarrier.getShipments().size()); - } - - @Test - void test_whenReadingCarrier_itReadsPlansCorrectly(){ - assertEquals(3, testCarrier.getPlans().size()); - } - - @Test - void test_whenReadingCarrier_itSelectsPlansCorrectly(){ - assertNotNull(testCarrier.getSelectedPlan()); - } - - @Test - void test_whenReadingPlans_nuOfToursIsCorrect(){ - List plans = new ArrayList<>(testCarrier.getPlans()); - assertEquals(1, plans.get(0).getScheduledTours().size()); - assertEquals(1, plans.get(1).getScheduledTours().size()); - assertEquals(1, plans.get(2).getScheduledTours().size()); - } - - @Test - void test_whenReadingToursOfPlan1_nuOfActivitiesIsCorrect(){ - List plans = new ArrayList<>(testCarrier.getPlans()); - CarrierPlan plan1 = plans.getFirst(); - ScheduledTour tour1 = plan1.getScheduledTours().iterator().next(); - assertEquals(5,tour1.getTour().getTourElements().size()); - } - - @Test - void test_whenReadingToursOfPlan2_nuOfActivitiesIsCorrect(){ - List plans = new ArrayList<>(testCarrier.getPlans()); - CarrierPlan plan2 = plans.get(1); - ScheduledTour tour1 = plan2.getScheduledTours().iterator().next(); - assertEquals(9,tour1.getTour().getTourElements().size()); - } - - @Test - void test_whenReadingToursOfPlan3_nuOfActivitiesIsCorrect(){ - List plans = new ArrayList<>(testCarrier.getPlans()); - CarrierPlan plan3 = plans.get(2); - ScheduledTour tour1 = plan3.getScheduledTours().iterator().next(); - assertEquals(9,tour1.getTour().getTourElements().size()); - } - - - private boolean exactlyTheseVehiclesAreInVehicleCollection(List> asList, Collection carrierVehicles) { - List vehicles = new ArrayList<>(carrierVehicles); - for(CarrierVehicle type : carrierVehicles) if(asList.contains(type.getId() )) vehicles.remove(type ); - return vehicles.isEmpty(); - } - - @Test - void test_CarrierHasAttributes(){ - assertEquals((TransportMode.drt), CarriersUtils.getCarrierMode(testCarrier)); - assertEquals(50, CarriersUtils.getJspritIterations(testCarrier)); - } - - @Test - void test_ServicesAndShipmentsHaveAttributes(){ - Object serviceCustomerAtt = testCarrier.getServices().get(Id.create("serv1",CarrierService.class)).getAttributes().getAttribute("customer"); - assertNotNull(serviceCustomerAtt); - assertEquals("someRandomCustomer", serviceCustomerAtt); - Object shipmentCustomerAtt = testCarrier.getShipments().get(Id.create("s1",CarrierShipment.class)).getAttributes().getAttribute("customer"); - assertNotNull(shipmentCustomerAtt); - assertEquals("someRandomCustomer", shipmentCustomerAtt); - } - -} diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1Test.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1Test.java index b3a12fdb60f..f331ff0b671 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1Test.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierPlanXmlWriterV2_1Test.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -30,10 +33,6 @@ import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; - public class CarrierPlanXmlWriterV2_1Test { @RegisterExtension diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierReadWriteV2_1Test.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierReadWriteV2_1Test.java index 71d69e6d216..5da6137dcd8 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierReadWriteV2_1Test.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierReadWriteV2_1Test.java @@ -21,13 +21,11 @@ package org.matsim.freight.carriers; +import java.util.Collections; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.freight.carriers.*; import org.matsim.testcases.MatsimTestUtils; -import java.util.Collections; - public class CarrierReadWriteV2_1Test { @RegisterExtension @@ -43,7 +41,7 @@ void readWriteTest() { String outputFilename = utils.getOutputDirectory() + "outputCarriers.xml"; CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(carrierVehicleTypes); - vehicleTypeReader.readFile(utils.getClassInputDirectory() + "vehicles.xml"); + vehicleTypeReader.readFile(utils.getPackageInputDirectory() + "vehicleTypes_v2.xml"); CarrierPlanXmlReader carrierReader = new CarrierPlanXmlReader(carriers, carrierVehicleTypes); carrierReader.readFile(inputFilename); @@ -65,7 +63,7 @@ void readWriteReadTest() { String outputFilename2 = utils.getOutputDirectory() + "/outputCarriers2.xml"; CarrierVehicleTypeReader vehicleTypeReader = new CarrierVehicleTypeReader(carrierVehicleTypes); - vehicleTypeReader.readFile(utils.getClassInputDirectory() + "vehicles.xml"); + vehicleTypeReader.readFile(utils.getPackageInputDirectory() + "vehicleTypes_v2.xml"); CarrierPlanXmlReader reader1 = new CarrierPlanXmlReader(carriers, carrierVehicleTypes); reader1.readFile(utils.getClassInputDirectory() + "carriers.xml"); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest.java index 97954bb151d..8a8b30b9a0a 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest.java @@ -21,38 +21,39 @@ package org.matsim.freight.carriers; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Assertions; +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.freight.carriers.*; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; +import java.nio.file.Path; + public class CarrierVehicleTypeLoaderTest { @RegisterExtension public final MatsimTestUtils utils = new MatsimTestUtils(); - private CarrierVehicleTypes types; private Carriers carriers; @BeforeEach public void setUp() { - types = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader(types).readFile(utils.getClassInputDirectory() + "vehicleTypes.xml"); + CarrierVehicleTypes types = new CarrierVehicleTypes(); + new CarrierVehicleTypeReader(types).readFile(Path.of(utils.getClassInputDirectory()).getParent().resolve("vehicleTypes_v2.xml").toString()); carriers = new Carriers(); - new CarrierPlanXmlReader(carriers, types ).readFile(utils.getClassInputDirectory() + "carrierPlansEquils.xml" ); + new CarrierPlanXmlReader(carriers, types).readFile(utils.getClassInputDirectory() + "carrierPlansEquils.xml" ); } @Test void test_whenLoadingTypes_allAssignmentsInLightVehicleAreCorrectly(){ - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); +// new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); Carrier testCarrier = carriers.getCarriers().get(Id.create("testCarrier", Carrier.class)); CarrierVehicle v = CarriersUtils.getCarrierVehicle(testCarrier,Id.createVehicleId("lightVehicle")); + assert v != null; VehicleType vehicleTypeLoaded = v.getType(); Assertions.assertNotNull(vehicleTypeLoaded); @@ -62,16 +63,17 @@ void test_whenLoadingTypes_allAssignmentsInLightVehicleAreCorrectly(){ Assertions.assertEquals(0.35, vehicleTypeLoaded.getCostInformation().getCostsPerMeter(), MatsimTestUtils.EPSILON); Assertions.assertEquals(30, vehicleTypeLoaded.getCostInformation().getCostsPerSecond(), MatsimTestUtils.EPSILON); - Assertions.assertEquals("gasoline", vehicleTypeLoaded.getEngineInformation().getFuelType().toString()); - Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumption(vehicleTypeLoaded), MatsimTestUtils.EPSILON); + Assertions.assertEquals("gasoline", VehicleUtils.getHbefaTechnology(vehicleTypeLoaded.getEngineInformation())); + Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumptionLitersPerMeter(vehicleTypeLoaded.getEngineInformation()), MatsimTestUtils.EPSILON); } @Test void test_whenLoadingTypes_allAssignmentsInMediumVehicleAreCorrectly(){ - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); +// new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(types); Carrier testCarrier = carriers.getCarriers().get(Id.create("testCarrier", Carrier.class)); CarrierVehicle v = CarriersUtils.getCarrierVehicle(testCarrier,Id.createVehicleId("mediumVehicle")); + assert v != null; VehicleType vehicleTypeLoaded = v.getType(); Assertions.assertNotNull(vehicleTypeLoaded); @@ -81,8 +83,8 @@ void test_whenLoadingTypes_allAssignmentsInMediumVehicleAreCorrectly(){ Assertions.assertEquals(0.4, vehicleTypeLoaded.getCostInformation().getCostsPerMeter(), MatsimTestUtils.EPSILON); Assertions.assertEquals(30, vehicleTypeLoaded.getCostInformation().getCostsPerSecond(), MatsimTestUtils.EPSILON); - Assertions.assertEquals("gasoline", vehicleTypeLoaded.getEngineInformation().getFuelType().toString()); - Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumption(vehicleTypeLoaded), MatsimTestUtils.EPSILON); + Assertions.assertEquals("gasoline", VehicleUtils.getHbefaTechnology(vehicleTypeLoaded.getEngineInformation())); + Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumptionLitersPerMeter(vehicleTypeLoaded.getEngineInformation()), MatsimTestUtils.EPSILON); } diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest.java index 3a2f5a5648e..47e8f2b8a95 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest.java @@ -21,6 +21,9 @@ package org.matsim.freight.carriers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.BeforeEach; @@ -29,9 +32,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.VehicleType; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.matsim.vehicles.VehicleUtils; public class CarrierVehicleTypeReaderTest { @RegisterExtension private MatsimTestUtils utils = new MatsimTestUtils() ; @@ -39,25 +40,25 @@ public class CarrierVehicleTypeReaderTest { private static final Logger log = LogManager.getLogger(CarrierVehicleTypeReaderTest.class) ; private CarrierVehicleTypes types; - private String inFilename; @BeforeEach public void setUp() { types = new CarrierVehicleTypes(); - inFilename = utils.getClassInputDirectory() + "vehicleTypes.xml"; - new CarrierVehicleTypeReader(types).readFile( inFilename ); + String inFilename = utils.getClassInputDirectory() + "vehicleTypes_deprecated_v1.xml"; + new CarrierVehicleTypeReader(types).readFile(inFilename); } @Test void test_whenReadingTypes_nuOfTypesIsReadCorrectly(){ - assertEquals(2, types.getVehicleTypes().size()); + assertEquals(3, types.getVehicleTypes().size()); } @Test void test_whenReadingTypes_itReadyExactlyTheTypesFromFile(){ assertTrue(types.getVehicleTypes().containsKey(Id.create("medium", org.matsim.vehicles.VehicleType.class ) ) ); assertTrue(types.getVehicleTypes().containsKey(Id.create("light", org.matsim.vehicles.VehicleType.class ) ) ); - assertEquals(2, types.getVehicleTypes().size()); + assertTrue(types.getVehicleTypes().containsKey(Id.create("heavy", org.matsim.vehicles.VehicleType.class ) ) ); + assertEquals(3, types.getVehicleTypes().size()); } @Test @@ -83,15 +84,15 @@ void test_whenReadingTypeMedium_itReadsCostInfoCorrectly(){ @Test void test_whenReadingTypeMedium_itReadsEngineInfoCorrectly(){ VehicleType medium = types.getVehicleTypes().get(Id.create("medium", org.matsim.vehicles.VehicleType.class ) ); - assertEquals(0.02, medium.getEngineInformation().getFuelConsumption(),0.01); - assertEquals("gasoline", medium.getEngineInformation().getFuelType().toString()); + assertEquals(0.02, VehicleUtils.getFuelConsumptionLitersPerMeter(medium.getEngineInformation()), 0.01); + assertEquals("gasoline", VehicleUtils.getHbefaTechnology(medium.getEngineInformation())); } @Test void readV1andWriteV2(){ final String outFilename = utils.getOutputDirectory() + "/vehicleTypes_v2.xml"; new CarrierVehicleTypeWriter( types ).write( outFilename ) ; - final String referenceFilename = utils.getClassInputDirectory() + "/vehicleTypes_v2.xml" ; + final String referenceFilename = utils.getPackageInputDirectory() + "/vehicleTypes_v2.xml" ; MatsimTestUtils.assertEqualFilesLineByLine( referenceFilename, outFilename ); } @@ -104,7 +105,7 @@ void readV2andWriteV2() { log.info("") ; log.info("now starting for real") ; log.info("") ; - String inFilename1 = utils.getClassInputDirectory() + "vehicleTypes_v2.xml"; + String inFilename1 = utils.getPackageInputDirectory() + "vehicleTypes_v2.xml"; CarrierVehicleTypes types1 = new CarrierVehicleTypes(); new CarrierVehicleTypeReader( types1 ).readFile( inFilename1 ); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java index a95fac8d1ec..653c3972aad 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeTest.java @@ -21,13 +21,12 @@ package org.matsim.freight.carriers; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Assertions; +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.TransportMode; -import org.matsim.freight.carriers.CarrierVehicleTypes; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.*; import org.matsim.vehicles.EngineInformation.FuelType; @@ -49,8 +48,8 @@ public void setUp() { costInformation1.setCostsPerMeter( 1.0 ); costInformation1.setCostsPerSecond( 0.5 ); EngineInformation engineInformation1 = mediumType.getEngineInformation(); - engineInformation1.setFuelType( FuelType.diesel ); - engineInformation1.setFuelConsumption( 0.02 ); + VehicleUtils.setHbefaTechnology( engineInformation1, "diesel" ); + VehicleUtils.setFuelConsumptionLitersPerMeter( engineInformation1, 0.02 ); VehicleCapacity vehicleCapacity = mediumType.getCapacity(); vehicleCapacity.setWeightInTons( 30 ); mediumType.setDescription( "Medium Vehicle" ).setMaximumVelocity( 13.89 ); @@ -73,8 +72,8 @@ public void setUp() { costInformation.setCostsPerMeter( 0.75 ); costInformation.setCostsPerSecond( 0.25 ); EngineInformation engineInformation = smallType.getEngineInformation() ; - engineInformation.setFuelType( FuelType.gasoline ); - engineInformation.setFuelConsumption( 0.015 ); + VehicleUtils.setHbefaTechnology( engineInformation, "gasoline" ); + VehicleUtils.setFuelConsumptionLitersPerMeter( engineInformation, 0.015 ); VehicleCapacity capacity = smallType.getCapacity() ; capacity.setWeightInTons( 16 ) ; // VehicleType smallType = CarriersUtils.CarrierVehicleTypeBuilder.newInstance( smallTypeId, mediumType ) @@ -107,8 +106,8 @@ void test_whenCreatingTypeMedium_itCreatesCostInfoCorrectly(){ @Test void test_whenCreatingTypeMedium_itCreatesEngineInfoCorrectly(){ VehicleType medium = types.getVehicleTypes().get(Id.create("medium", org.matsim.vehicles.VehicleType.class ) ); - Assertions.assertEquals(0.02, medium.getEngineInformation().getFuelConsumption(),0.001); - Assertions.assertEquals(FuelType.diesel, medium.getEngineInformation().getFuelType()); + Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumptionLitersPerMeter(medium.getEngineInformation())); + Assertions.assertEquals("diesel", VehicleUtils.getHbefaTechnology(medium.getEngineInformation())); } @Test @@ -141,8 +140,8 @@ void test_whenCopyingTypeMedium_itCopiesCostInfoCorrectly(){ @Test void test_whenCopyingTypeMedium_itCopiesEngineInfoCorrectly(){ VehicleType medium2 = types.getVehicleTypes().get(Id.create("medium2", org.matsim.vehicles.VehicleType.class ) ); - Assertions.assertEquals(0.02, medium2.getEngineInformation().getFuelConsumption(),0.001); - Assertions.assertEquals(FuelType.diesel, medium2.getEngineInformation().getFuelType()); + Assertions.assertEquals(0.02, VehicleUtils.getFuelConsumptionLitersPerMeter(medium2.getEngineInformation())); + Assertions.assertEquals("diesel", VehicleUtils.getHbefaTechnology(medium2.getEngineInformation())); } @Test @@ -175,8 +174,8 @@ void test_whenModifyingTypeSmall_itModifiesCostInfoCorrectly(){ @Test void test_whenModifyingTypeSmall_itModifiesEngineInfoCorrectly(){ VehicleType small = types.getVehicleTypes().get(Id.create("small", org.matsim.vehicles.VehicleType.class ) ); - Assertions.assertEquals(0.015, small.getEngineInformation().getFuelConsumption(),0.001); - Assertions.assertEquals(FuelType.gasoline, small.getEngineInformation().getFuelType()); + Assertions.assertEquals(0.015, VehicleUtils.getFuelConsumptionLitersPerMeter(small.getEngineInformation())); + Assertions.assertEquals("gasoline", VehicleUtils.getHbefaTechnology(small.getEngineInformation())); } @Test diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest.java index 307408885a6..89228f26c4e 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest.java @@ -23,9 +23,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.freight.carriers.CarrierVehicleTypeReader; -import org.matsim.freight.carriers.CarrierVehicleTypeWriter; -import org.matsim.freight.carriers.CarrierVehicleTypes; import org.matsim.testcases.MatsimTestUtils; public class CarrierVehicleTypeWriterTest { @@ -36,7 +33,7 @@ public class CarrierVehicleTypeWriterTest { @Test void testTypeWriter(){ CarrierVehicleTypes types = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader(types).readFile(utils.getClassInputDirectory()+ "vehicleTypes.xml"); + new CarrierVehicleTypeReader(types).readFile(utils.getPackageInputDirectory()+ "vehicleTypes_v2.xml"); final String outputVehTypeFile = utils.getOutputDirectory()+ "vehicleTypesWritten.xml"; new CarrierVehicleTypeWriter(types).write(outputVehTypeFile); types.getVehicleTypes().clear(); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarriersUtilsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarriersUtilsTest.java index 04772ee65a2..fe0428621e0 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/CarriersUtilsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/CarriersUtilsTest.java @@ -21,18 +21,17 @@ package org.matsim.freight.carriers; +import static org.matsim.testcases.MatsimTestUtils.EPSILON; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; -import org.matsim.freight.carriers.*; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import static org.matsim.testcases.MatsimTestUtils.EPSILON; - /** */ public class CarriersUtilsTest { @@ -43,7 +42,7 @@ public class CarriersUtilsTest { @Test void testAddAndGetVehicleToCarrier() { VehicleType vehicleType = VehicleUtils.createDefaultVehicleType(); - + Carrier carrier = new CarrierImpl(Id.create("carrier", Carrier.class)); Id testVehicleId = Id.createVehicleId("testVehicle"); CarrierVehicle carrierVehicle = CarrierVehicle.newInstance(testVehicleId, Id.createLinkId("link0"),vehicleType); @@ -58,6 +57,7 @@ void testAddAndGetVehicleToCarrier() { //get Vehicle CarrierVehicle carrierVehicle1 = CarriersUtils.getCarrierVehicle(carrier, testVehicleId ); + assert carrierVehicle1 != null; Assertions.assertEquals(testVehicleId, carrierVehicle1.getId()); Assertions.assertEquals(vehicleType, carrierVehicle1.getType()); Assertions.assertEquals(Id.createLinkId("link0"), carrierVehicle1.getLinkId() ); @@ -79,6 +79,7 @@ void testAddAndGetServiceToCarrier() { //get Service CarrierService cs1b = CarriersUtils.getService(carrier, serviceId ); + assert cs1b != null; Assertions.assertEquals(serviceId, cs1b.getId()); Assertions.assertEquals(service1.getId(), cs1b.getId()); Assertions.assertEquals(Id.createLinkId("link0"), cs1b.getLocationLinkId()); @@ -100,6 +101,7 @@ void testAddAndGetShipmentToCarrier() { //get Shipment CarrierShipment carrierShipment1b = CarriersUtils.getShipment(carrier, shipmentId ); + assert carrierShipment1b != null; Assertions.assertEquals(shipmentId, carrierShipment1b.getId()); Assertions.assertEquals(service1.getId(), carrierShipment1b.getId()); Assertions.assertEquals(Id.createLinkId("link0"), carrierShipment1b.getFrom()); @@ -109,7 +111,7 @@ void testAddAndGetShipmentToCarrier() { @Test void testGetSetJspritIteration(){ Carrier carrier = new CarrierImpl(Id.create("carrier", Carrier.class)); - //jspirtIterations is not set. should return Integer.Min_Value (null is not possible because returning (int) + //jspritIterations is not set. should return Integer.Min_Value (null is not possible because returning (int) Assertions.assertEquals(Integer.MIN_VALUE, CarriersUtils.getJspritIterations(carrier) ); CarriersUtils.setJspritIterations(carrier, 125); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/FreightCarriersConfigGroupTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/FreightCarriersConfigGroupTest.java index 33a4d6736e8..5c3d053190b 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/FreightCarriersConfigGroupTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/FreightCarriersConfigGroupTest.java @@ -21,6 +21,10 @@ package org.matsim.freight.carriers; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.core.config.Config; @@ -28,11 +32,6 @@ import org.matsim.core.config.ConfigUtils; import org.matsim.freight.carriers.FreightCarriersConfigGroup.UseDistanceConstraintForTourPlanning; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; - /** * @author mrieser / Simunto */ diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest.java index c7fc851bf24..58587ab5248 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest.java @@ -21,15 +21,14 @@ package org.matsim.freight.carriers.analysis; +import java.io.IOException; +import java.net.URL; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; -import java.io.IOException; -import java.net.URL; - public class FreightAnalysisEventBasedTest { @RegisterExtension diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT.java similarity index 95% rename from contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java rename to contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT.java index 75800bfd34d..d18c15840a4 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT.java @@ -19,10 +19,10 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Assertions; +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; @@ -40,6 +40,8 @@ import org.matsim.freight.carriers.mobsim.StrategyManagerFactoryForTests; import org.matsim.testcases.MatsimTestUtils; +import java.nio.file.Path; + public class EquilWithCarrierWithPersonsIT { private Controler controler; @@ -81,7 +83,7 @@ static Scenario commonScenario( Config config, MatsimTestUtils testUtils ){ Scenario scenario = ScenarioUtils.loadScenario( config ); CarrierVehicleTypes carrierVehicleTypes = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader( carrierVehicleTypes ).readFile( testUtils.getPackageInputDirectory() + "vehicleTypes_v2.xml" ); + new CarrierVehicleTypeReader( carrierVehicleTypes ).readFile(Path.of(testUtils.getPackageInputDirectory()).getParent().resolve("vehicleTypes_v2.xml").toString()); Carriers carriers = CarriersUtils.addOrGetCarriers(scenario ); new CarrierPlanXmlReader( carriers, carrierVehicleTypes ).readFile( testUtils.getClassInputDirectory() + "carrierPlansEquils.xml" ); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT.java similarity index 99% rename from contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java rename to contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT.java index 70b01111b10..1df5a1a5b22 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT.java @@ -19,7 +19,7 @@ * */ -package org.matsim.freight.carriers.controler; +package org.matsim.freight.carriers.controller; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -33,9 +33,9 @@ import org.matsim.core.config.groups.RoutingConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; -import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.FreightCarriersConfigGroup; import org.matsim.freight.carriers.ScheduledTour; import org.matsim.freight.carriers.Tour; import org.matsim.freight.carriers.mobsim.DistanceScoringFunctionFactoryForTests; @@ -203,7 +203,7 @@ public void install() { } @Test - void testEventFilessAreEqual(){ + void testEventFilesAreEqual(){ setUp(); controler.addOverridingModule(new CarrierModule()); controler.addOverridingModule(new AbstractModule() { diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintFromVehiclesFileTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintFromVehiclesFileTest.java index 43abc654497..43557b37a2a 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintFromVehiclesFileTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintFromVehiclesFileTest.java @@ -21,6 +21,10 @@ package org.matsim.freight.carriers.jsprit; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Assertions; @@ -39,22 +43,17 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.FreightCarriersConfigGroup.UseDistanceConstraintForTourPlanning; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.FreightCarriersConfigGroup.UseDistanceConstraintForTourPlanning; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - /** * * @author rewert, kturner - * + *

    * Test for the distance constraint. 4 different setups are used to control the * correct working of the constraint * @@ -113,13 +112,13 @@ final void CarrierSmallBatteryTest_Version1() throws ExecutionException, Interru Assertions.assertEquals(1, carrierV1.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); VehicleType vehicleType_SmallV1 = vehicleTypes.getVehicleTypes().get(Id.create("SmallBattery_V1", VehicleType.class)); VehicleType vehicleType_LargeV1 = vehicleTypes.getVehicleTypes().get(Id.create("LargeBattery_V1", VehicleType.class)); - Assertions.assertEquals(vehicleType_SmallV1.getId(), ((Vehicle) carrierV1.getSelectedPlan().getScheduledTours().iterator().next() - .getVehicle()).getType().getId()); + Assertions.assertEquals(vehicleType_SmallV1.getId(), carrierV1.getSelectedPlan().getScheduledTours().iterator().next() + .getVehicle().getType().getId()); double maxDistance_vehicleType_LargeV1 = VehicleUtils.getEnergyCapacity(vehicleType_LargeV1.getEngineInformation()) / VehicleUtils.getEnergyConsumptionKWhPerMeter(vehicleType_LargeV1.getEngineInformation()); double maxDistance_vehicleType_SmallV1 = VehicleUtils.getEnergyCapacity(vehicleType_SmallV1.getEngineInformation()) @@ -144,12 +143,12 @@ final void CarrierSmallBatteryTest_Version1() throws ExecutionException, Interru } Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } /** - * Option 2: Tour is not possible with the vehicle with the small battery. Thats - * why one vehicle with a large battery is used. + * Option 2: Tour is not possible with the vehicle with the small battery. + * That's why one vehicle with a large battery is used. * */ @Test @@ -190,7 +189,7 @@ final void CarrierLargeBatteryTest_Version2() throws ExecutionException, Interru Assertions.assertEquals(1, carrierV2.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); VehicleType vehicleType_SmallV2 = vehicleTypes.getVehicleTypes().get(Id.create("SmallBattery_V2", VehicleType.class)); VehicleType vehicleType_LargeV2 = vehicleTypes.getVehicleTypes().get(Id.create("LargeBattery_V2", VehicleType.class)); @@ -221,7 +220,7 @@ final void CarrierLargeBatteryTest_Version2() throws ExecutionException, Interru } Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } @@ -267,7 +266,7 @@ final void Carrier2SmallBatteryTest_Version3() throws ExecutionException, Interr Assertions.assertEquals(2, carrierV3.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); VehicleType vehicleType_SmallV3 = vehicleTypes.getVehicleTypes().get(Id.create("SmallBattery_V3", VehicleType.class)); VehicleType vehicleType_LargeV3 = vehicleTypes.getVehicleTypes().get(Id.create("LargeBattery_V3", VehicleType.class)); @@ -301,17 +300,17 @@ final void Carrier2SmallBatteryTest_Version3() throws ExecutionException, Interr if (distanceTour == 12000) Assertions.assertEquals(12000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else Assertions.assertEquals(20000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } } /** - * Option 4: An additional shipment outside the range of both BEVtypes. - * Therefore one diesel vehicle must be used and one vehicle with a small + * Option 4: An additional shipment outside the range of both BEV types. + * Therefore, one diesel vehicle must be used and one vehicle with a small * battery. * */ @@ -386,11 +385,11 @@ final void CarrierWithAdditionalDieselVehicleTest_Version4() throws ExecutionExc if (thisTypeId.equals("SmallBattery_V4")) Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else if (thisTypeId.equals("DieselVehicle")) Assertions.assertEquals(36000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else Assertions.fail("Wrong vehicleType used"); } @@ -453,8 +452,6 @@ private static Carrier addThreeServicesToCarrier(Carrier carrier) { /** * Creates the vehicle at the depot, ads this vehicle to the carriers and sets * the capabilities. Sets TimeWindow for the carriers. - * - * @param */ private static void createCarriers(Carriers carriers, FleetSize fleetSize, Carrier singleCarrier, CarrierVehicleTypes vehicleTypes) { @@ -474,8 +471,6 @@ private static void createCarriers(Carriers carriers, FleetSize fleetSize, Carri /** * Method for creating a new carrierVehicle * - * @param - * * @return new carrierVehicle at the depot */ static CarrierVehicle createGarbageTruck(String vehicleName, double earliestStartingTime, @@ -488,9 +483,6 @@ static CarrierVehicle createGarbageTruck(String vehicleName, double earliestStar /** * Defines and sets the Capabilities of the Carrier, including the vehicleTypes * for the carriers - * - * @param - * */ private static void defineCarriers(Carriers carriers, FleetSize fleetSize, Carrier singleCarrier, List vehicles, CarrierVehicleTypes vehicleTypes) { diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintTest.java index 50b8505cb70..a375cceac46 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/DistanceConstraintTest.java @@ -21,6 +21,10 @@ package org.matsim.freight.carriers.jsprit; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Assertions; @@ -39,25 +43,20 @@ import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.FreightCarriersConfigGroup.UseDistanceConstraintForTourPlanning; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.FreightCarriersConfigGroup.UseDistanceConstraintForTourPlanning; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - /** * * @author rewert, kturner - * + *

    * Test for the distance constraint. 4 different setups are used to control the * correct working of the constraint for services - * + *

    * 2 additional setups are defined when using shipments instead of service. * Shipments allow reloading of good during the tour. * @@ -123,10 +122,10 @@ final void CarrierSmallBatteryTest_Version1() throws ExecutionException, Interru Assertions.assertEquals(1, carrierV1.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); - Assertions.assertEquals(vehicleType_SmallV1.getId(), ((Vehicle) carrierV1.getSelectedPlan().getScheduledTours().iterator().next() - .getVehicle()).getType().getId()); + Assertions.assertEquals(vehicleType_SmallV1.getId(), carrierV1.getSelectedPlan().getScheduledTours().iterator().next() + .getVehicle().getType().getId()); double maxDistance_vehicleType_LargeV1 = VehicleUtils.getEnergyCapacity(vehicleType_LargeV1.getEngineInformation()) / VehicleUtils.getEnergyConsumptionKWhPerMeter(vehicleType_LargeV1.getEngineInformation()); double maxDistance_vehicleType_SmallV1 = VehicleUtils.getEnergyCapacity(vehicleType_SmallV1.getEngineInformation()) @@ -151,12 +150,12 @@ final void CarrierSmallBatteryTest_Version1() throws ExecutionException, Interru } Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } /** - * Option 2: Tour is not possible with the vehicle with the small battery. Thats - * why one vehicle with a large battery is used. + * Option 2: Tour is not possible with the vehicle with the small battery. + * That's why one vehicle with a large battery is used. * */ @Test @@ -206,7 +205,7 @@ final void CarrierLargeBatteryTest_Version2() throws ExecutionException, Interru Assertions.assertEquals(1, carrierV2.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); Assertions.assertEquals(vehicleType_LargeV2.getId(), carrierV2.getSelectedPlan().getScheduledTours().iterator().next() .getVehicle().getType().getId()); @@ -234,7 +233,7 @@ final void CarrierLargeBatteryTest_Version2() throws ExecutionException, Interru } Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } @@ -292,7 +291,7 @@ final void Carrier2SmallBatteryTest_Version3() throws ExecutionException, Interr Assertions.assertEquals(2, carrierV3.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); double maxDistance_vehicleType_LargeV3 = VehicleUtils.getEnergyCapacity(vehicleType_LargeV3.getEngineInformation()) / VehicleUtils.getEnergyConsumptionKWhPerMeter(vehicleType_LargeV3.getEngineInformation()); @@ -323,17 +322,17 @@ final void Carrier2SmallBatteryTest_Version3() throws ExecutionException, Interr if (distanceTour == 12000) Assertions.assertEquals(12000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else Assertions.assertEquals(20000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); } } /** * Option 4: An additional service outside the range of both BEV types. - * Therefore one diesel vehicle must be used and one vehicle with a small + * Therefore, one diesel vehicle must be used and one vehicle with a small * battery. * */ @@ -372,7 +371,7 @@ final void CarrierWithAdditionalDieselVehicleTest_Version4() throws ExecutionExc VehicleType vehicleType_Diesel = VehicleUtils.createVehicleType(Id.create("DieselVehicle", VehicleType.class)); vehicleType_Diesel.getCostInformation().setCostsPerMeter(0.00055).setCostsPerSecond(0.008).setFixedCost(400.); VehicleUtils.setHbefaTechnology(vehicleType_Diesel.getEngineInformation(), "diesel"); - VehicleUtils.setFuelConsumption(vehicleType_Diesel, 0.0001625); + VehicleUtils.setFuelConsumptionLitersPerMeter(vehicleType_Diesel.getEngineInformation(), 0.0001625); vehicleType_Diesel.setDescription("Carrier_Version4"); vehicleType_Diesel.getCapacity().setOther(40.); @@ -391,7 +390,7 @@ final void CarrierWithAdditionalDieselVehicleTest_Version4() throws ExecutionExc Assertions.assertEquals(2, carrierV4.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); double maxDistance_vehicleType_Large4 = VehicleUtils.getEnergyCapacity(vehicleType_LargeV4.getEngineInformation()) / VehicleUtils.getEnergyConsumptionKWhPerMeter(vehicleType_LargeV4.getEngineInformation()); @@ -421,11 +420,11 @@ final void CarrierWithAdditionalDieselVehicleTest_Version4() throws ExecutionExc if (thisTypeId.equals("SmallBattery_V4")) Assertions.assertEquals(24000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else if (thisTypeId.equals("DieselVehicle")) Assertions.assertEquals(36000, distanceTour, MatsimTestUtils.EPSILON, - "The schedulded tour has a non expected distance"); + "The scheduled tour has a non expected distance"); else Assertions.fail("Wrong vehicleType used"); } @@ -436,7 +435,7 @@ else if (thisTypeId.equals("DieselVehicle")) * This test uses shipments instead of service . * As a consequence the vehicles can return to the depot, load more goods and run another subtour. * Distance is set to a value that, due to distance restrictions, two tours are necessary. - * + *

    * This option (5) is designed similar to option 2 * */ @@ -479,7 +478,7 @@ final void CarrierWithShipmentsMidSizeBatteryTest_Version5() throws ExecutionExc //We need two tours, due to reloading both shipments must be transported one after the other Assertions.assertEquals(2, carrierV5.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); Assertions.assertEquals(vehicleType_MidSizeV5.getId(), carrierV5.getSelectedPlan().getScheduledTours().iterator().next() .getVehicle().getType().getId()); @@ -506,9 +505,9 @@ final void CarrierWithShipmentsMidSizeBatteryTest_Version5() throws ExecutionExc Assertions.assertEquals(2, distancesOfTours.size(), "There must be two entry for tour distances"); //One tour has distance of 12000m - Assertions.assertTrue(distancesOfTours.contains(12000.0), "The schedulded tour has a non expected distance"); + Assertions.assertTrue(distancesOfTours.contains(12000.0), "The scheduled tour has a non expected distance"); //The other tour has distance of 20000m - Assertions.assertTrue(distancesOfTours.contains(20000.0), "The schedulded tour has a non expected distance"); + Assertions.assertTrue(distancesOfTours.contains(20000.0), "The scheduled tour has a non expected distance"); } /** @@ -516,7 +515,7 @@ final void CarrierWithShipmentsMidSizeBatteryTest_Version5() throws ExecutionExc * This test uses shipments instead of service . * As a consequence the vehicles can return to the depot, load more goods and run another subtour. * Distance is set to a value that one tour can be run with loading once. - * + *

    * This option (6) is designed similar to option 5 * */ @@ -560,7 +559,7 @@ final void CarrierWithShipmentsLargeBatteryTest_Version6() throws ExecutionExcep //We need two tours, due to reloading both shipments must be transported one after the other Assertions.assertEquals(1, carrierV5.getSelectedPlan().getScheduledTours().size(), - "Not the correct amout of scheduled tours"); + "Not the correct amount of scheduled tours"); Assertions.assertEquals(vehicleType_LargeV5.getId(), carrierV5.getSelectedPlan().getScheduledTours().iterator().next() .getVehicle().getType().getId()); @@ -587,7 +586,7 @@ final void CarrierWithShipmentsLargeBatteryTest_Version6() throws ExecutionExcep Assertions.assertEquals(1, distancesOfTours.size(), "There must be one entry for tour distances"); //This tour has distance of 24000m - Assertions.assertTrue(distancesOfTours.contains(24000.0), "The schedulded tour has a non expected distance"); + Assertions.assertTrue(distancesOfTours.contains(24000.0), "The scheduled tour has a non expected distance"); } /** @@ -664,8 +663,6 @@ private static Carrier addThreeServicesToCarrier(Carrier carrier) { /** * Creates the vehicle at the depot, ads this vehicle to the carriers and sets * the capabilities. Sets TimeWindow for the carriers. - * - * @param */ private static void createCarriers(Carriers carriers, FleetSize fleetSize, Carrier singleCarrier, CarrierVehicleTypes vehicleTypes) { @@ -684,9 +681,6 @@ private static void createCarriers(Carriers carriers, FleetSize fleetSize, Carri /** * Method for creating a new carrierVehicle - * - * @param - * * @return new carrierVehicle at the depot */ static CarrierVehicle createCarrierVehicle(String vehicleName, double earliestStartingTime, @@ -699,9 +693,6 @@ static CarrierVehicle createCarrierVehicle(String vehicleName, double earliestSt /** * Defines and sets the Capabilities of the Carrier, including the vehicleTypes * for the carriers - * - * @param - * */ private static void defineCarriers(Carriers carriers, FleetSize fleetSize, Carrier singleCarrier, List vehicles, CarrierVehicleTypes vehicleTypes) { @@ -711,7 +702,5 @@ private static void defineCarriers(Carriers carriers, FleetSize fleetSize, Carri CarriersUtils.addCarrierVehicle(singleCarrier, carrierVehicle); } singleCarrier.getCarrierCapabilities().getVehicleTypes().addAll(vehicleTypes.getVehicleTypes().values()); - - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(vehicleTypes); } } diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/FixedCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/FixedCostsTest.java index 7e0e4bbe12e..cf5060bf772 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/FixedCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/FixedCostsTest.java @@ -27,10 +27,12 @@ import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.util.Solutions; +import java.net.URL; +import java.util.Collection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Assertions; +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; @@ -46,10 +48,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.net.URL; -import java.util.Collection; - - /** * @author kturner * @@ -91,8 +89,8 @@ public void setUp() { VehicleType carrierVehType_A = VehicleUtils.getFactory().createVehicleType( vehicleTypeId ); { EngineInformation engineInformation1 = carrierVehType_A.getEngineInformation(); - engineInformation1.setFuelType( EngineInformation.FuelType.diesel ); - engineInformation1.setFuelConsumption( 0.015 ); + VehicleUtils.setFuelConsumptionLitersPerMeter(carrierVehType_A.getEngineInformation(), 0.015); + VehicleUtils.setHbefaTechnology(engineInformation1, "diesel"); carrierVehType_A.getCapacity().setOther( 1. ); carrierVehType_A.getCostInformation().setFixedCost( 0. ).setCostsPerMeter( 0.001 ).setCostsPerSecond( 0.0 ); carrierVehType_A.setMaximumVelocity( 10 ); @@ -106,8 +104,8 @@ public void setUp() { VehicleType carrierVehType_B = VehicleUtils.getFactory().createVehicleType( vehicleTypeId1 ); { EngineInformation engineInformation = carrierVehType_B.getEngineInformation(); - engineInformation.setFuelType( EngineInformation.FuelType.diesel ); - engineInformation.setFuelConsumption( 0.015 ); + VehicleUtils.setFuelConsumptionLitersPerMeter(carrierVehType_A.getEngineInformation(), 0.015); + VehicleUtils.setHbefaTechnology(engineInformation, "diesel"); carrierVehType_B.getCapacity().setOther( 1. ); carrierVehType_B.getCostInformation().setFixedCost( 10. ).setCostsPerMeter( 0.00001 ).setCostsPerSecond( 0. ) ; carrierVehType_B.setMaximumVelocity( 10. ); @@ -118,7 +116,6 @@ public void setUp() { //carrier1: only vehicles of Type A (no fixed costs, variable costs: 1 EUR/km) CarrierCapabilities cc1 = CarrierCapabilities.Builder.newInstance() - .addType(carrierVehType_A) .addVehicle(carrierVehicle_A) .setFleetSize(CarrierCapabilities.FleetSize.INFINITE) .build(); @@ -127,7 +124,6 @@ public void setUp() { //carrier2: only vehicles of Type B (fixed costs of 10 EUR/vehicle, no variable costs) CarrierCapabilities cc2 = CarrierCapabilities.Builder.newInstance() - .addType(carrierVehType_B) .addVehicle(carrierVehicle_B) .setFleetSize(CarrierCapabilities.FleetSize.INFINITE) .build(); @@ -136,8 +132,6 @@ public void setUp() { //carrier3: has both vehicles of Type A (no fixed costs, variable costs: 1 EUR/km) and Type B (fixed costs of 10 EUR/vehicle, no variable costs) CarrierCapabilities cc3 = CarrierCapabilities.Builder.newInstance() - .addType(carrierVehType_A) - .addType(carrierVehType_B) .addVehicle(carrierVehicle_A) .addVehicle(carrierVehicle_B) .setFleetSize(CarrierCapabilities.FleetSize.INFINITE) @@ -145,10 +139,6 @@ public void setUp() { carrier3.setCarrierCapabilities(cc3); carriers.addCarrier(carrier3); - - // assign vehicle types to the carriers - new CarrierVehicleTypeLoader(carriers).loadVehicleTypes(vehicleTypes) ; - //load Network and build netbasedCosts for jsprit URL context = org.matsim.examples.ExamplesUtils.getTestScenarioURL( "freight-chessboard-9x9" ); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/IntegrationIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/IntegrationIT.java index 762a2efe08a..6c61511a480 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/IntegrationIT.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/IntegrationIT.java @@ -27,6 +27,8 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.reporting.SolutionPrinter; import com.graphhopper.jsprit.core.util.Solutions; +import java.nio.file.Path; +import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -41,8 +43,6 @@ import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts.Builder; import org.matsim.testcases.MatsimTestUtils; -import java.util.concurrent.ExecutionException; - public class IntegrationIT { @RegisterExtension @@ -51,7 +51,7 @@ public class IntegrationIT { @Test void testJsprit() throws ExecutionException, InterruptedException { final String networkFilename = utils.getClassInputDirectory() + "/merged-network-simplified.xml.gz"; - final String vehicleTypeFilename = utils.getClassInputDirectory() + "/vehicleTypes.xml"; + final String vehicleTypeFilename = Path.of(utils.getPackageInputDirectory()).getParent().resolve("vehicleTypes_v2.xml").toString(); final String carrierFilename = utils.getClassInputDirectory() + "/carrier.xml"; Config config = ConfigUtils.createConfig(); @@ -99,7 +99,7 @@ void testJsprit() throws ExecutionException, InterruptedException { @Test void testJspritWithDefaultSolutionOption() throws ExecutionException, InterruptedException { final String networkFilename = utils.getClassInputDirectory() + "/merged-network-simplified.xml.gz"; - final String vehicleTypeFilename = utils.getClassInputDirectory() + "/vehicleTypes.xml"; + final String vehicleTypeFilename = Path.of(utils.getPackageInputDirectory()).getParent().resolve("vehicleTypes_v2.xml").toString(); final String carrierFilename = utils.getClassInputDirectory() + "/carrier.xml"; Config config = ConfigUtils.createConfig(); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/MatsimTransformerTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/MatsimTransformerTest.java index 15f7a1a7c86..5025334cc5e 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/MatsimTransformerTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/MatsimTransformerTest.java @@ -21,6 +21,8 @@ package org.matsim.freight.carriers.jsprit; +import static org.junit.jupiter.api.Assertions.*; + import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.job.Job; @@ -31,6 +33,9 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; @@ -44,12 +49,6 @@ import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - public class MatsimTransformerTest { @RegisterExtension @@ -340,7 +339,7 @@ private ScheduledTour getMatsimServiceTour() { .setCapacityDemand(10).build(); CarrierVehicle matsimVehicle = getMatsimVehicle("matsimVehicle", "loc", getMatsimVehicleType()); double startTime = 15.0; - Tour.Builder sTourBuilder = Tour.Builder.newInstance(); + Tour.Builder sTourBuilder = Tour.Builder.newInstance(Id.create("testTour", Tour.class)); sTourBuilder.scheduleStart(matsimVehicle.getLinkId() ); sTourBuilder.addLeg(sTourBuilder.createLeg(null, 15.0, 0.0)); sTourBuilder.scheduleService(s1); @@ -356,7 +355,7 @@ private ScheduledTour getMatsimTour(String vehicleId) { CarrierShipment s2 = getMatsimShipment("s2", "from", "to2", 20); CarrierVehicle matsimVehicle = getMatsimVehicle(vehicleId, "loc", getMatsimVehicleType()); double startTime = 15.0; - Tour.Builder sTourBuilder = Tour.Builder.newInstance(); + Tour.Builder sTourBuilder = Tour.Builder.newInstance(Id.create("testTour", Tour.class)); sTourBuilder.scheduleStart(matsimVehicle.getLinkId() ); sTourBuilder.addLeg(sTourBuilder.createLeg(null, 15.0, 0.0)); sTourBuilder.schedulePickup(s1); @@ -378,18 +377,13 @@ private CarrierVehicle getMatsimVehicle(String VehicleId, String locationId, Veh } private VehicleType getMatsimVehicleType() { -// EngineInformation engineInformation = new EngineInformation(); -// engineInformation.setFuelType( FuelType.diesel ); -// engineInformation.setFuelConsumption( (double) 15 ); -// CarriersUtils.CarrierVehicleTypeBuilder builder = CarriersUtils.CarrierVehicleTypeBuilder.newInstance( Id.create( "matsimType", VehicleType.class ) ) VehicleType vehicleType = VehicleUtils.getFactory() .createVehicleType(Id.create("matsimType", VehicleType.class)).setMaximumVelocity(13.8); vehicleType.getCapacity().setOther(50); vehicleType.getCostInformation().setCostsPerMeter(10.0).setCostsPerSecond(5.0).setFixedCost(100.); VehicleUtils.setHbefaTechnology(vehicleType.getEngineInformation(), "diesel"); - VehicleUtils.setFuelConsumption(vehicleType, 15.); -// vehicleType.getEngineInformation().setFuelType( FuelType.diesel ) ; -// vehicleType.getEngineInformation().setFuelConsumption( 15. ); + VehicleUtils.setFuelConsumptionLitersPerMeter(vehicleType.getEngineInformation(), 0.015); + return vehicleType; } @@ -422,8 +416,8 @@ void createVehicleRoutingProblemBuilderWithServices_isMadeCorrectly() { assertEquals(10.0, vehicle.getType().getVehicleCostParams().perDistanceUnit, 0.0); assertEquals(5.0, vehicle.getType().getVehicleCostParams().perTransportTimeUnit, 0.0); assertEquals(100.0, vehicle.getType().getVehicleCostParams().fix, 0.0); - // assertEquals(FuelType.diesel, vehicle. ...); //TODO - // assertEquals(15, FuelConsumption ...); //TODO + assertEquals("diesel", VehicleUtils.getHbefaTechnology(((VehicleType)vehicle.getType().getUserData()).getEngineInformation())); + assertEquals(0.015, VehicleUtils.getFuelConsumptionLitersPerMeter(((VehicleType)vehicle.getType().getUserData()).getEngineInformation())); assertEquals(13.8, vehicle.getType().getMaxVelocity(), 0.0); // check service data diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 64e7eeba641..d58cadf388a 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -21,9 +21,13 @@ package org.matsim.freight.carriers.jsprit; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; +import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -43,12 +47,6 @@ import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.VehiclesFactory; -import java.util.Arrays; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - - public class NetworkBasedTransportCostsTest { diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/SkillsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/SkillsIT.java index 8886010e74b..7da556872c2 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/SkillsIT.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/SkillsIT.java @@ -127,7 +127,6 @@ private Scenario setupTestScenario() { // typeOne.setCapacity(vehicleCapacity); typeOne.getCapacity().setOther( 2.0 ); CarriersUtils.addSkill(typeOne, "skill 1"); - capabilitiesBuilder.addType(typeOne); CarrierVehicle vehicleOne = CarrierVehicle.Builder.newInstance(Id.createVehicleId("1"), carrierLocation, typeOne ) .setEarliestStart(0.0) .setLatestEnd(Time.parseTime("24:00:00")) @@ -141,7 +140,6 @@ private Scenario setupTestScenario() { // typeTwo.setCapacity(vehicleCapacity); typeTwo.getCapacity().setOther( 2.0 ); CarriersUtils.addSkill(typeTwo, "skill 2"); - capabilitiesBuilder.addType(typeTwo); CarrierVehicle vehicleTwo = CarrierVehicle.Builder.newInstance(Id.createVehicleId("2"), carrierLocation, typeTwo ) .setEarliestStart(0.0) .setLatestEnd(Time.parseTime("24:00:00")) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/DistanceScoringFunctionFactoryForTests.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/DistanceScoringFunctionFactoryForTests.java index 81ad7c6e577..6fc9b085bf1 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/DistanceScoringFunctionFactoryForTests.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/DistanceScoringFunctionFactoryForTests.java @@ -22,6 +22,8 @@ package org.matsim.freight.carriers.mobsim; import jakarta.inject.Inject; +import java.util.HashSet; +import java.util.Set; import org.junit.jupiter.api.Disabled; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -38,14 +40,11 @@ import org.matsim.deprecated.scoring.ScoringFunctionAccumulator.LegScoring; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarrierConstants; -import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.CarrierVehicle; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; import org.matsim.vehicles.Vehicle; -import java.util.HashSet; -import java.util.Set; - @Disabled public class DistanceScoringFunctionFactoryForTests implements CarrierScoringFunctionFactory{ @@ -140,7 +139,7 @@ private double getTimeParameter(CarrierVehicle vehicle, Person driver) { // if(carrier.getCarrierCapabilities().getCarrierVehicles().containsKey(vehicleId)){ // return carrier.getCarrierCapabilities().getCarrierVehicles().get(vehicleId); // } -// log.error("Vehicle with Id does not exists", new IllegalStateException("vehicle with id " + vehicleId + " is missing")); +// log.error("Vehicle with Id does not exist", new IllegalStateException("vehicle with id " + vehicleId + " is missing")); // return null; // } } diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/ScoringFunctionFactoryForTests.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/ScoringFunctionFactoryForTests.java index 68dbf0bc7ab..e529b690fd4 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/ScoringFunctionFactoryForTests.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/ScoringFunctionFactoryForTests.java @@ -21,6 +21,8 @@ package org.matsim.freight.carriers.mobsim; +import java.util.HashSet; +import java.util.Set; import org.junit.jupiter.api.Disabled; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -37,14 +39,11 @@ import org.matsim.deprecated.scoring.ScoringFunctionAccumulator.LegScoring; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarrierConstants; -import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.CarrierVehicle; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; import org.matsim.vehicles.Vehicle; -import java.util.HashSet; -import java.util.Set; - @Disabled public class ScoringFunctionFactoryForTests implements CarrierScoringFunctionFactory{ @@ -55,9 +54,8 @@ static class DriverLegScoring implements BasicScoring, LegScoring{ private final Carrier carrier; private final Set employedVehicles; private Leg currentLeg = null; - private double currentLegStartTime; - public DriverLegScoring(Carrier carrier, Network network) { + public DriverLegScoring(Carrier carrier, Network network) { super(); this.network = network; this.carrier = carrier; @@ -66,9 +64,7 @@ public DriverLegScoring(Carrier carrier, Network network) { @Override - public void finish() { - - } + public void finish() {} @Override @@ -87,7 +83,6 @@ public void reset() { @Override public void startLeg(double time, Leg leg) { currentLeg = leg; - currentLegStartTime = time; } @@ -97,9 +92,7 @@ public void endLeg(double time) { Id vehicleId = nRoute.getVehicleId(); CarrierVehicle vehicle = CarriersUtils.getCarrierVehicle(carrier, vehicleId); Gbl.assertNotNull(vehicle); - if(!employedVehicles.contains(vehicle)){ - employedVehicles.add(vehicle); - } + employedVehicles.add(vehicle); double distance = 0.0; if(currentLeg.getRoute() instanceof NetworkRoute){ distance += network.getLinks().get(currentLeg.getRoute().getStartLinkId()).getLength(); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/StrategyManagerFactoryForTests.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/StrategyManagerFactoryForTests.java index 680ef4e1953..c61519ea613 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/StrategyManagerFactoryForTests.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/StrategyManagerFactoryForTests.java @@ -23,6 +23,7 @@ import com.google.inject.Provider; import jakarta.inject.Inject; +import java.util.Map; import org.junit.jupiter.api.Disabled; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; @@ -36,13 +37,11 @@ import org.matsim.core.router.util.TravelTime; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarrierPlan; -import org.matsim.freight.carriers.controler.CarrierReRouteVehicles; -import org.matsim.freight.carriers.controler.CarrierStrategyManager; -import org.matsim.freight.carriers.controler.CarrierControlerUtils; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierReRouteVehicles; +import org.matsim.freight.carriers.controller.CarrierStrategyManager; import org.matsim.vehicles.Vehicle; -import java.util.Map; - @Disabled public class StrategyManagerFactoryForTests implements Provider{ @@ -83,7 +82,7 @@ public CarrierStrategyManager get() { GenericPlanStrategyImpl planStrat_reRoutePlan = new GenericPlanStrategyImpl<>( new BestPlanSelector<>() ); planStrat_reRoutePlan.addStrategyModule(new CarrierReRouteVehicles.Factory(router, network, travelTimes.get(TransportMode.car )).build() ); - CarrierStrategyManager stratManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + CarrierStrategyManager stratManager = CarrierControllerUtils.createDefaultCarrierStrategyManager(); stratManager.addStrategy(planStrat_reRoutePlan, null, 1.0); diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/TimeScoringFunctionFactoryForTests.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/TimeScoringFunctionFactoryForTests.java index a8cc127ba93..3b3f8965acf 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/TimeScoringFunctionFactoryForTests.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/mobsim/TimeScoringFunctionFactoryForTests.java @@ -22,6 +22,8 @@ package org.matsim.freight.carriers.mobsim; import jakarta.inject.Inject; +import java.util.HashSet; +import java.util.Set; import org.junit.jupiter.api.Disabled; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -38,14 +40,11 @@ import org.matsim.deprecated.scoring.ScoringFunctionAccumulator.LegScoring; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarrierConstants; -import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.CarrierVehicle; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.CarriersUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; import org.matsim.vehicles.Vehicle; -import java.util.HashSet; -import java.util.Set; - @Disabled public class TimeScoringFunctionFactoryForTests implements CarrierScoringFunctionFactory{ diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsIT.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsIT.java index 76738a411a9..d7127bc80bf 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsIT.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsIT.java @@ -26,8 +26,9 @@ import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.util.Solutions; -import org.junit.jupiter.api.BeforeEach; +import java.util.Collection; import org.junit.jupiter.api.Assertions; +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; @@ -45,9 +46,6 @@ import org.matsim.vehicles.*; import org.matsim.vehicles.EngineInformation.FuelType; -import java.util.Collection; - - //TODO: length of routes (legs) AND end time of route are missing. /** * @author kturner @@ -71,7 +69,7 @@ public class CarrierControllerUtilsIT{ public void setUp() { //Create carrier with services and shipments - Carriers carriersWithServicesAndShpiments = new Carriers(); + Carriers carriersWithServicesAndShipments = new Carriers(); carrierWServices = CarriersUtils.createCarrier(CARRIER_SERVICES_ID ); CarrierService service1 = createMatsimService("Service1", "i(3,9)", 2); CarriersUtils.addService(carrierWServices, service1); @@ -89,8 +87,8 @@ public void setUp() { final Id vehTypeId = Id.create( "gridType", VehicleType.class ); VehicleType carrierVehType = VehicleUtils.getFactory().createVehicleType( vehTypeId ); EngineInformation engineInformation = carrierVehType.getEngineInformation() ; - engineInformation.setFuelType( FuelType.diesel ); - engineInformation.setFuelConsumption( 0.015 ); + VehicleUtils.setHbefaTechnology(engineInformation, "diesel"); + VehicleUtils.setFuelConsumptionLitersPerMeter(engineInformation, 0.015); VehicleCapacity capacity = carrierVehType.getCapacity() ; capacity.setOther( 3. ) ; CostInformation costInfo = carrierVehType.getCostInformation(); @@ -106,18 +104,14 @@ public void setUp() { CarrierVehicle carrierVehicle = CarrierVehicle.Builder.newInstance(Id.create("gridVehicle", org.matsim.vehicles.Vehicle.class), Id.createLinkId("i(6,0)"), carrierVehType ).setEarliestStart(0.0 ).setLatestEnd(36000.0 ).build(); CarrierCapabilities.Builder ccBuilder = CarrierCapabilities.Builder.newInstance() - .addType(carrierVehType) .addVehicle(carrierVehicle) .setFleetSize(FleetSize.INFINITE); carrierWServices.setCarrierCapabilities(ccBuilder.build()); carrierWShipments.setCarrierCapabilities(ccBuilder.build()); // Add both carriers - carriersWithServicesAndShpiments.addCarrier(carrierWServices); - carriersWithServicesAndShpiments.addCarrier(carrierWShipments); - - // assign vehicle types to the carriers - new CarrierVehicleTypeLoader(carriersWithServicesAndShpiments).loadVehicleTypes(vehicleTypes) ; + carriersWithServicesAndShipments.addCarrier(carrierWServices); + carriersWithServicesAndShipments.addCarrier(carrierWShipments); //load Network and build netbasedCosts for jsprit Network network = NetworkUtils.createNetwork(); @@ -126,7 +120,7 @@ public void setUp() { final NetworkBasedTransportCosts netBasedCosts = netBuilder.build() ; netBuilder.setTimeSliceWidth(1800) ; // !!!!, otherwise it will not do anything. - for (Carrier carrier : carriersWithServicesAndShpiments.getCarriers().values()) { + for (Carrier carrier : carriersWithServicesAndShipments.getCarriers().values()) { //Build VRP VehicleRoutingProblem.Builder vrpBuilder = MatsimJspritFactory.createRoutingProblemBuilder(carrier, network); vrpBuilder.setRoutingCost(netBasedCosts) ; @@ -144,15 +138,12 @@ public void setUp() { } /* - * Now convert it to a only shipment-based VRP. + * Now convert it to an only shipment-based VRP. */ //Convert to jsprit VRP Carriers carriersWithShipmentsOnly = CarriersUtils.createShipmentVRPCarrierFromServiceVRPSolution( - carriersWithServicesAndShpiments ); - - // assign vehicle types to the carriers - new CarrierVehicleTypeLoader(carriersWithShipmentsOnly).loadVehicleTypes(vehicleTypes) ; + carriersWithServicesAndShipments ); for (Carrier carrier : carriersWithShipmentsOnly.getCarriers().values()) { //Build VRP diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsTest.java index 87ac86ec9b3..1896021e805 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/utils/CarrierControllerUtilsTest.java @@ -28,10 +28,12 @@ import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.util.Solutions; +import java.net.URL; +import java.util.Collection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Assertions; +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; @@ -41,7 +43,8 @@ import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.PlansConfigGroup; -import org.matsim.core.controler.Controler; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; import org.matsim.core.network.NetworkUtils; import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.scenario.ScenarioUtils; @@ -56,9 +59,6 @@ import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.*; -import java.net.URL; -import java.util.Collection; - public class CarrierControllerUtilsTest{ @RegisterExtension @@ -82,7 +82,7 @@ public class CarrierControllerUtilsTest{ public void setUp() { //Create carrier with services and shipments - Carriers carriersWithServicesAndShpiments = new Carriers(); + Carriers carriersWithServicesAndShipments = new Carriers(); carrierWServices = CarriersUtils.createCarrier(CARRIER_SERVICES_ID ); CarrierService service1 = createMatsimService("Service1", "i(3,9)", 2); CarriersUtils.addService(carrierWServices, service1); @@ -100,7 +100,7 @@ public void setUp() { final Id vehicleTypeId = Id.create( "gridType", VehicleType.class ); VehicleType carrierVehType = VehicleUtils.getFactory().createVehicleType( vehicleTypeId ); VehicleUtils.setHbefaTechnology(carrierVehType.getEngineInformation(), "diesel"); - VehicleUtils.setFuelConsumption(carrierVehType, 0.015); + VehicleUtils.setFuelConsumptionLitersPerMeter(carrierVehType.getEngineInformation(), 0.015); VehicleCapacity vehicleCapacity = carrierVehType.getCapacity(); vehicleCapacity.setOther( 3 ); CostInformation costInfo = carrierVehType.getCostInformation(); @@ -115,18 +115,14 @@ public void setUp() { CarrierVehicle carrierVehicle = CarrierVehicle.Builder.newInstance(Id.create("gridVehicle", org.matsim.vehicles.Vehicle.class), Id.createLinkId("i(6,0)"), carrierVehType ).setEarliestStart(0.0 ).setLatestEnd(36000.0 ).build(); CarrierCapabilities.Builder ccBuilder = CarrierCapabilities.Builder.newInstance() - .addType(carrierVehType) .addVehicle(carrierVehicle) .setFleetSize(FleetSize.INFINITE); carrierWServices.setCarrierCapabilities(ccBuilder.build()); carrierWShipments.setCarrierCapabilities(ccBuilder.build()); // Add both carriers - carriersWithServicesAndShpiments.addCarrier(carrierWServices); - carriersWithServicesAndShpiments.addCarrier(carrierWShipments); - - // assign vehicle types to the carriers - new CarrierVehicleTypeLoader(carriersWithServicesAndShpiments).loadVehicleTypes(vehicleTypes) ; + carriersWithServicesAndShipments.addCarrier(carrierWServices); + carriersWithServicesAndShipments.addCarrier(carrierWShipments); //load Network and build netbasedCosts for jsprit Network network = NetworkUtils.createNetwork(); @@ -152,22 +148,19 @@ public void setUp() { carrierWServices.addPlan(carrierPlanServicesAndShipments) ; /* - * Now convert it to a only shipment-based VRP. + * Now convert it to an only shipment-based VRP. */ //Convert to jsprit VRP - Carriers carriersWithShipmentsOnly = CarriersUtils.createShipmentVRPCarrierFromServiceVRPSolution(carriersWithServicesAndShpiments); + Carriers carriersWithShipmentsOnly = CarriersUtils.createShipmentVRPCarrierFromServiceVRPSolution(carriersWithServicesAndShipments); carrierWShipmentsOnlyFromCarrierWServices = carriersWithShipmentsOnly.getCarriers().get(CARRIER_SERVICES_ID); //with converted Service carrierWShipmentsOnlyFromCarrierWShipments = carriersWithShipmentsOnly.getCarriers().get(CARRIER_SHIPMENTS_ID); //with copied Shipments - - // assign vehicle types to the carriers - new CarrierVehicleTypeLoader(carriersWithShipmentsOnly).loadVehicleTypes(vehicleTypes) ; } //Should only have Services @Test - void numberOfInitalServicesIsCorrect() { + void numberOfInitialServicesIsCorrect() { Assertions.assertEquals(2, carrierWServices.getServices().size()); int demandServices = 0; @@ -227,7 +220,7 @@ void fleetAvailableAfterConvertingIsCorrect() { Assertions.assertEquals(0.001, carrierVehicleType.getCostInformation().getCostsPerSecond(), 0.0 ); Assertions.assertEquals(10, carrierVehicleType.getMaximumVelocity(), 0.0); Assertions.assertEquals("diesel", VehicleUtils.getHbefaTechnology(carrierVehicleType.getEngineInformation())); - Assertions.assertEquals(0.015, VehicleUtils.getFuelConsumption(carrierVehicleType), 0.0); + Assertions.assertEquals(0.015, VehicleUtils.getFuelConsumptionLitersPerMeter(carrierVehicleType.getEngineInformation()), 0.0); } Assertions.assertEquals(FleetSize.INFINITE, carrierWShipmentsOnlyFromCarrierWShipments.getCarrierCapabilities().getFleetSize()); @@ -239,11 +232,11 @@ void fleetAvailableAfterConvertingIsCorrect() { Assertions.assertEquals(0.001, carrierVehicleType.getCostInformation().getCostsPerSecond(), 0.0 ); Assertions.assertEquals(10, carrierVehicleType.getMaximumVelocity(), 0.0); Assertions.assertEquals("diesel", VehicleUtils.getHbefaTechnology(carrierVehicleType.getEngineInformation())); - Assertions.assertEquals(0.015, VehicleUtils.getFuelConsumption(carrierVehicleType), 0.0); } + Assertions.assertEquals(0.015, VehicleUtils.getFuelConsumptionLitersPerMeter(carrierVehicleType.getEngineInformation()), 0.0); } } @Test - void copiingOfShipmentsIsDoneCorrectly() { + void copyingOfShipmentsIsDoneCorrectly() { boolean foundShipment1 = false; boolean foundShipment2 = false; CarrierShipment carrierShipment1 = CarriersUtils.getShipment(carrierWShipmentsOnlyFromCarrierWShipments, Id.create("shipment1", CarrierShipment.class)); @@ -276,19 +269,19 @@ void copiingOfShipmentsIsDoneCorrectly() { Assertions.assertEquals(0.0, carrierShipment2.getPickupTimeWindow().getStart(), 0); Assertions.assertEquals(7200.0, carrierShipment2.getPickupTimeWindow().getEnd(), 0); } - Assertions.assertTrue(foundShipment1, "Not found Shipment1 after copiing"); - Assertions.assertTrue(foundShipment2, "Not found Shipment2 after copiing"); + Assertions.assertTrue(foundShipment1, "Not found Shipment1 after copying"); + Assertions.assertTrue(foundShipment2, "Not found Shipment2 after copying"); } @Test void convertionOfServicesIsDoneCorrectly() { - boolean foundSercice1 = false; + boolean foundService1 = false; boolean foundService2 = false; CarrierShipment carrierShipment1 = CarriersUtils.getShipment(carrierWShipmentsOnlyFromCarrierWServices, Id.create("Service1", CarrierShipment.class)); assert carrierShipment1 != null; if (carrierShipment1.getId() == Id.create("Service1", CarrierShipment.class)) { - foundSercice1 = true; + foundService1 = true; Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment1.getFrom()); Assertions.assertEquals(Id.createLinkId("i(3,9)"), carrierShipment1.getTo()); Assertions.assertEquals(2, carrierShipment1.getSize()); @@ -313,12 +306,12 @@ void convertionOfServicesIsDoneCorrectly() { Assertions.assertEquals(0.0, carrierShipment2.getPickupTimeWindow().getStart(), 0); Assertions.assertEquals(36001.0, carrierShipment2.getPickupTimeWindow().getEnd(), 0); } - Assertions.assertTrue(foundSercice1, "Not found converted Service1 after converting"); + Assertions.assertTrue(foundService1, "Not found converted Service1 after converting"); Assertions.assertTrue(foundService2, "Not found converted Service2 after converting"); } /*Note: This test can be removed / modified when jsprit works properly with a combined Service and Shipment VRP. - * Currently the capacity of the vehicle seems to be "ignored" in a way that the load within the tour is larger than the capacity; + * Currently, the capacity of the vehicle seems to be "ignored" in a way that the load within the tour is larger than the capacity; * Maybe it is because of the misunderstanding, that a Service is modeled as "Pickup" and not as thought before as "Delivery". KMT sep18 */ @Test @@ -426,7 +419,7 @@ void testRunJsprit_allInformationGiven(){ Scenario scenario = ScenarioUtils.loadScenario(config); CarriersUtils.loadCarriersAccordingToFreightConfig(scenario ); - Controler controler = new Controler(scenario); + Controller controller = ControllerUtils.createController(scenario); try { CarriersUtils.runJsprit(scenario); @@ -435,7 +428,7 @@ void testRunJsprit_allInformationGiven(){ Assertions.fail(); } - Assertions.assertEquals(vraFile, ConfigUtils.addOrGetModule( controler.getConfig(), FreightCarriersConfigGroup.class ).getVehicleRoutingAlgorithmFile()); + Assertions.assertEquals(vraFile, ConfigUtils.addOrGetModule( controller.getConfig(), FreightCarriersConfigGroup.class ).getVehicleRoutingAlgorithmFile()); } /** @@ -461,10 +454,10 @@ void testRunJsprit_NoOfJspritIterationsMissing() { } /** - * Don't crash even if there is no algortihm file specified. + * Don't crash even if there is no algorithm file specified. */ @Test - void testRunJsprit_NoAlgortihmFileGiven(){ + void testRunJsprit_NoAlgorithmFileGiven(){ Config config = prepareConfig(); config.controller().setOutputDirectory(utils.getOutputDirectory()); Scenario scenario = ScenarioUtils.loadScenario(config); @@ -483,7 +476,7 @@ private Config prepareConfig(){ Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(scenarioUrl, "config.xml" ) ); config.controller().setLastIteration(0); config.plans().setActivityDurationInterpretation(PlansConfigGroup.ActivityDurationInterpretation.tryEndTimeThenDuration ); - //freight configstuff + //freight config stuff FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class); freightCarriersConfigGroup.setCarriersFile(IOUtils.extendUrl(scenarioUrl, "singleCarrierFiveActivitiesWithoutRoutes.xml" ).toString() ); freightCarriersConfigGroup.setCarriersVehicleTypesFile(IOUtils.extendUrl(scenarioUrl, "vehicleTypes.xml" ).toString() ); 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("scenarios/2regions/2regions-network.xml"); + 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))); + + Controller controller = ControllerUtils.createController(scenario); + + controller.addOverridingModule(new LSPModule() ); + + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..acfb73567df --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/CollectionLSPScoringTest.java @@ -0,0 +1,198 @@ +/* + *********************************************************************** * + * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.scenario.ScenarioUtils; +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("scenarios/2regions/2regions-network.xml"); + + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.addOverridingModule( new LSPModule() ); + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..c6634e58239 --- /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.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +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.Controller; +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); + + Controller controller = ExampleLSPScoring.prepareController(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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..e18204c2f99 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/lspScoring/MultipleIterationsCollectionLSPScoringTest.java @@ -0,0 +1,210 @@ +/* + *********************************************************************** * + * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule( new LSPModule() ); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..8c50a3b20b3 --- /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.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +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" ); + } + +} 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..b98dd24e4ca --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/MultipleChainsReplanningTest.java @@ -0,0 +1,310 @@ +/* + *********************************************************************** * + * 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.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.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.VspExperimentalConfigGroup; +import org.matsim.core.controler.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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); + + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = CarrierControllerUtils.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; + }); + } + }); + + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + + LSP lsp = LSPUtils.getLSPs(controller.getScenario()).getLSPs().values().iterator().next(); + + initialPlanCount = lsp.getPlans().size(); + initialPlanShipmentPlanCount = lsp.getPlans().getFirst().getShipmentPlans().size(); + + controller.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..7556c24f8c6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/multipleChains/WorstPlanSelectorTest.java @@ -0,0 +1,317 @@ +/* + *********************************************************************** * + * 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.*; +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.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.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); + + Controller controller = ControllerUtils.createController(scenario); + controller.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + + controller.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 = CarrierControllerUtils.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; + }); + } + }); + + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + this.lsp = LSPUtils.getLSPs(controller.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..37588adb752 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/requirementsChecking/AssignerRequirementsTest.java @@ -0,0 +1,195 @@ +/* + *********************************************************************** * + * 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.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("scenarios/2regions/2regions-network.xml"); + 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..e72394b24ea --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/examples/simulationTrackers/CollectionTrackerTest.java @@ -0,0 +1,324 @@ +/* + *********************************************************************** * + * 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 static org.junit.jupiter.api.Assertions.*; + +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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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; + +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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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("scenarios/2regions/2regions-network.xml"); + 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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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 += 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() * 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() * 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() * 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() * scheduledTour.getVehicle().getType().getCostInformation().getCostsPerMeter(); + } + } + if (element instanceof ServiceActivity activity) { + scheduledDistanceCosts += network.getLinks().get(activity.getLocation()).getLength() * 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..82a2d86a835 --- /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.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +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..40ab28dbce5 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/CollectionElementTest.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.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.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("scenarios/2regions/2regions-network.xml"); + 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..ca387a1056b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/DistributionElementTest.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.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.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("scenarios/2regions/2regions-network.xml"); + 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..26694caceb0 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainElementTests/MainRunElementTest.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.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.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("scenarios/2regions/2regions-network.xml"); + 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..2d0a981f7d5 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CollectionChainTest.java @@ -0,0 +1,118 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..a3f61d2f872 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/logisticChainTests/CompleteLogisticChainTest.java @@ -0,0 +1,246 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..7272fa366fa --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CollectionLSPCreationTest.java @@ -0,0 +1,124 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..9b347e5055b --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspCreationTests/CompleteLSPCreationTest.java @@ -0,0 +1,232 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..df196d86233 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CollectionLSPMobsimTest.java @@ -0,0 +1,245 @@ +/* + * *********************************************************************** * + * * 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.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.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.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.events.handler.BasicEventHandler; +import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.scenario.ScenarioUtils; +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("scenarios/2regions/2regions-network.xml"); + 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); + } + Controller controller = ControllerUtils.createController(scenario); + controller.getEvents().addHandler((BasicEventHandler) event -> log.warn(event)); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..4a17e1dbc4d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/CompleteLSPMobsimTest.java @@ -0,0 +1,332 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.scenario.ScenarioUtils; +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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..3294ed1b7c2 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstAndSecondReloadLSPMobsimTest.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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..d5ba96be6d0 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/FirstReloadLSPMobsimTest.java @@ -0,0 +1,249 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..aac62ebf43a --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunLSPMobsimTest.java @@ -0,0 +1,279 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..57a4886fba3 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MainRunOnlyLSPMobsimTest.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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..910cd4ce3ea --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCollectionLSPMobsimTest.java @@ -0,0 +1,226 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new LSPModule()); + } + }); + controller.addOverridingModule( new AbstractModule(){ + @Override public void install(){ + bind( LSPStrategyManager.class ).toInstance( new LSPModule.LSPStrategyManagerEmptyImpl() ); + bind( CarrierStrategyManager.class ).toProvider(() -> { + CarrierStrategyManager strategyManager = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..8b2a05157c6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsCompleteLSPMobsimTest.java @@ -0,0 +1,359 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controller.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..14d2f7a263f --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstAndSecondReloadLSPMobsimTest.java @@ -0,0 +1,318 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..fb6fb93f516 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsFirstReloadLSPMobsimTest.java @@ -0,0 +1,262 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..8dac1d91417 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleIterationsMainRunLSPMobsimTest.java @@ -0,0 +1,302 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controller.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..6a6c4aafdb6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCollectionLSPMobsimTest.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.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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..984027f50d9 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsCompleteLSPMobsimTest.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.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controller.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..37d260c2f28 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstAndSecondReloadLSPMobsimTest.java @@ -0,0 +1,316 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.freight.carriers.*; +import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; +import org.matsim.freight.carriers.controller.CarrierControllerUtils; +import org.matsim.freight.carriers.controller.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.addOverridingModule(new LSPModule()); + controller.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 = CarrierControllerUtils.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..7b75f3a8fd7 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsFirstReloadLSPMobsimTest.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.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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controller.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..d0119ec03a2 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/MultipleShipmentsMainRunLSPMobsimTest.java @@ -0,0 +1,287 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.run(); + + for (LSP lsp : LSPUtils.getLSPs(controller.getScenario()).getLSPs().values()) { + ResourceImplementationUtils.printResults_shipmentPlan(controller.getControlerIO().getOutputPath(), lsp); + ResourceImplementationUtils.printResults_shipmentLog(controller.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..f14a75d3802 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspMobsimTests/RepeatedMultipleShipmentsCompleteLSPMobsimTest.java @@ -0,0 +1,353 @@ +/* + * *********************************************************************** * + * * 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.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.VspExperimentalConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +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.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("scenarios/2regions/2regions-network.xml"); + 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); + + Controller controller = ControllerUtils.createController(scenario); + + LSPUtils.addLSPs(scenario, lsps); + controller.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 + controller.getConfig().vspExperimental().setVspDefaultsCheckingLevel(VspExperimentalConfigGroup.VspDefaultsCheckingLevel.warn); + controller.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..06e9f39b5d1 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CollectionLSPPlanTest.java @@ -0,0 +1,107 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..58f82a24ebb --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspPlanTests/CompleteLSPPlanTest.java @@ -0,0 +1,216 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..c7f627638bb --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CollectionLspShipmentAssigmentTest.java @@ -0,0 +1,165 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..5e2348ae67e --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentAssignmentTests/CompleteLspShipmentAssignerTest.java @@ -0,0 +1,287 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..11957dbfac6 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CollectionShipmentBuilderTest.java @@ -0,0 +1,117 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..cb3ea748e39 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/CompleteShipmentBuilderTest.java @@ -0,0 +1,132 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..380a86b98a4 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/lspShipmentTest/DistributionShipmentBuilderTest.java @@ -0,0 +1,118 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..5e071b894d4 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CollectionLSPSchedulingTest.java @@ -0,0 +1,240 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..c4fd34c0fd3 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/CompleteLSPSchedulingTest.java @@ -0,0 +1,608 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..3cead4c873c --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/FirstReloadLSPSchedulingTest.java @@ -0,0 +1,324 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..b98bb40a884 --- /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(hubLinkId, transshipmentHubResource.getEndLinkId()); + assertSame(hubLinkId, transshipmentHubResource.getStartLinkId()); + 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..4a39f6c6170 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MainRunLSPSchedulingTest.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.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("scenarios/2regions/2regions-network.xml"); + 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..d30d608f985 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCollectionLSPSchedulingTest.java @@ -0,0 +1,237 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..f27a1e08219 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsCompleteLSPSchedulingTest.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.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("scenarios/2regions/2regions-network.xml"); + 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..e1661887039 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsFirstReloadLSPSchedulingTest.java @@ -0,0 +1,321 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..c9811f9e03d --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsMainRunLSPSchedulingTest.java @@ -0,0 +1,434 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..23ee9f61e86 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/MultipleShipmentsSecondReloadLSPSchedulingTest.java @@ -0,0 +1,518 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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..6a37cd65697 --- /dev/null +++ b/contribs/freight/src/test/java/org/matsim/freight/logistics/resourceImplementations/SecondReloadLSPSchedulingTest.java @@ -0,0 +1,525 @@ +/* + * *********************************************************************** * + * * 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.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("scenarios/2regions/2regions-network.xml"); + 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/carriers/CarrierModuleTest/vehicleTypes.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierModuleTest/vehicleTypes.xml deleted file mode 100644 index 1ad295354d8..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierModuleTest/vehicleTypes.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - Light Vehicle - - - - - - - - - - - - - - - - Medium Vehicle - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test/carrierPlansEquils.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test/carrierPlansEquils.xml deleted file mode 100644 index 9c6165af57d..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV1Test/carrierPlansEquils.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquils.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquils.xml deleted file mode 100644 index 68337d77b88..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquils.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - drt - 50 - - - - - - - - - - - - - - someRandomCustomer - - - - - - - - - someRandomCustomer - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquilsWritten.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquilsWritten.xml deleted file mode 100644 index 5c122507f56..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierPlanXmlWriterV2Test/carrierPlansEquilsWritten.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - drt - 50 - - - - - - - - - - - - - - someRandomCustomer - - - - - - - - - someRandomCustomer - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - - - 2 3 4 - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/carriers.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/carriers.xml index 88124972eec..3d2ae8952c2 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/carriers.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/carriers.xml @@ -8,8 +8,8 @@ - - + + @@ -115,8 +115,8 @@ - - + + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes.xml deleted file mode 100644 index f4087007a6d..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Medium Vehicle - - 30 - - - - - Light Vehicle - 15 - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest/vehicleTypes.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_deprecated_v1.xml similarity index 76% rename from contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest/vehicleTypes.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_deprecated_v1.xml index 4913dba6c79..703e60cd498 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeLoaderTest/vehicleTypes.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_deprecated_v1.xml @@ -14,9 +14,9 @@ - Heavy Vehicle - 15 - - + Medium Vehicle + 30 + + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_v2.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_v2.xml deleted file mode 100644 index 8568206c736..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderTest/vehicleTypes_v2.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - Light Vehicle - - - - - - - - 0.02 - gasoline - - - - - - - - - - - - - Medium Vehicle - - - - - - - - 0.02 - gasoline - - - - - - - - - - - - - \ No newline at end of file diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderWithDtdV1Test/carrierVehicleTypes_v2.xsd b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderWithDtdV1Test/carrierVehicleTypes_v2.xsd index 043b44666d5..e35fcb0c615 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderWithDtdV1Test/carrierVehicleTypes_v2.xsd +++ b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeReaderWithDtdV1Test/carrierVehicleTypes_v2.xsd @@ -4,85 +4,86 @@ elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest/vehicleTypes.xml b/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest/vehicleTypes.xml deleted file mode 100644 index 9ac37fd0dfe..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierVehicleTypeWriterTest/vehicleTypes.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Medium Vehicle - - 30 - - - - - Light Vehicle - 15 - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runServiceEventTest/Load_perVehicle.tsv b/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runServiceEventTest/Load_perVehicle.tsv index 67fb0e5f002..a1e0058ce5b 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runServiceEventTest/Load_perVehicle.tsv +++ b/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runServiceEventTest/Load_perVehicle.tsv @@ -1 +1 @@ -vehicleId capacity maxLoad load state during tour +vehicleId vehicleTypeId capacity maxLoad load state during tour diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runShipmentEventTest/Load_perVehicle.tsv b/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runShipmentEventTest/Load_perVehicle.tsv index cf7f4992d37..d61ddd36308 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runShipmentEventTest/Load_perVehicle.tsv +++ b/contribs/freight/test/input/org/matsim/freight/carriers/analysis/FreightAnalysisEventBasedTest/runShipmentEventTest/Load_perVehicle.tsv @@ -1,2 +1,2 @@ -vehicleId capacity maxLoad load state during tour -freight_carrier1_veh_freight_carrier1_veh_heavyVehicle_1_1 50.0 26 [3, 8, 18, 25, 26, 23, 13, 12, 7, 0] +vehicleId vehicleTypeId capacity maxLoad load state during tour +freight_carrier1_veh_freight_carrier1_veh_heavyVehicle_1_1 heavy 50.0 26 [3, 8, 18, 25, 26, 23, 13, 12, 7, 0] diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/vehicleTypes_v2.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controler/vehicleTypes_v2.xml deleted file mode 100644 index d29386a7a2a..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/controler/vehicleTypes_v2.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - Light Vehicle - - - - - - - - 0.02 - gasoline - - - - - - - - - - - - - Medium Vehicle - - - - - - - - 0.02 - gasoline - - - - - - - - - - - - - Medium Vehicle - - - - - - - - 0.03 - gasoline - - - - - - - - - - - - - Medium Vehicle - - - - - - - - 0.03 - gasoline - - - - - - - - - - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml similarity index 91% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml index 1a7369f8abf..0971f759480 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/carrierPlansEquils.xml @@ -31,17 +31,17 @@ - - + + - + - + @@ -58,7 +58,7 @@ - + @@ -76,18 +76,18 @@ - + - + - + - + @@ -106,18 +106,18 @@ - + - + - + - + @@ -136,7 +136,6 @@ - + - - \ No newline at end of file + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/network.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/network.xml old mode 100755 new mode 100644 similarity index 100% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/network.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/network.xml diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/plans100.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/plans100.xml similarity index 100% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithPersonsIT/plans100.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithPersonsIT/plans100.xml diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml similarity index 91% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml index 4fd1e13d09d..e7374870fc3 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/carrierPlansEquils.xml @@ -31,17 +31,17 @@ - - + + - + - + @@ -58,7 +58,7 @@ - + @@ -76,18 +76,18 @@ - + - + - + - + @@ -106,18 +106,18 @@ - + - + - + - + @@ -136,6 +136,6 @@ - + - + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/network.xml b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/network.xml old mode 100755 new mode 100644 similarity index 100% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/network.xml rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/network.xml diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/output_events.xml.gz similarity index 100% rename from contribs/freight/test/input/org/matsim/freight/carriers/controler/EquilWithCarrierWithoutPersonsIT/output_events.xml.gz rename to contribs/freight/test/input/org/matsim/freight/carriers/controller/EquilWithCarrierWithoutPersonsIT/output_events.xml.gz diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/carrier.xml b/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/carrier.xml index e14845dfaff..3f7eaf626e1 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/carrier.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/carrier.xml @@ -3,19 +3,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -197,8 +197,8 @@ - - + + diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/vehicleTypes.xml b/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/vehicleTypes.xml deleted file mode 100644 index 5f3ad64ff22..00000000000 --- a/contribs/freight/test/input/org/matsim/freight/carriers/jsprit/IntegrationIT/vehicleTypes.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - null - 6000 - - - - null - 7000 - - - - null - 12000 - - - - null - 3000 - - - - null - 15000 - - - - diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/usecases/chessboard/RunChessboardIT/runChessboard/output_events.xml.gz b/contribs/freight/test/input/org/matsim/freight/carriers/usecases/chessboard/RunChessboardIT/runChessboard/output_events.xml.gz index 8057a55fbcc..bf5ebee32b8 100644 Binary files a/contribs/freight/test/input/org/matsim/freight/carriers/usecases/chessboard/RunChessboardIT/runChessboard/output_events.xml.gz and b/contribs/freight/test/input/org/matsim/freight/carriers/usecases/chessboard/RunChessboardIT/runChessboard/output_events.xml.gz differ diff --git a/contribs/freight/test/input/org/matsim/freight/carriers/vehicleTypes_v2.xml b/contribs/freight/test/input/org/matsim/freight/carriers/vehicleTypes_v2.xml index c9b487b48b9..f78dccd883c 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/vehicleTypes_v2.xml +++ b/contribs/freight/test/input/org/matsim/freight/carriers/vehicleTypes_v2.xml @@ -2,29 +2,7 @@ - - - Light Vehicle - - - - - - - - 0.02 - gasoline - - - - - - - - - - - + Medium Vehicle @@ -34,11 +12,11 @@ - 0.02 - gasoline + gasoline + 0.03 - + @@ -46,21 +24,21 @@ - + - Medium Vehicle - + Light Vehicle + - 0.03 - gasoline + gasoline + 0.02 - + @@ -68,7 +46,7 @@ - + Medium Vehicle @@ -78,11 +56,11 @@ - 0.03 - gasoline + gasoline + 0.02 - + 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/carriers/CarrierReadWriteV2_1Test/vehicles.xml b/contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml similarity index 71% rename from contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/vehicles.xml rename to contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml index 3ff84f751a1..a98419ac59d 100644 --- a/contribs/freight/test/input/org/matsim/freight/carriers/CarrierReadWriteV2_1Test/vehicles.xml +++ b/contribs/freight/test/input/org/matsim/freight/logistics/io/vehicles.xml @@ -17,22 +17,6 @@ - - - - - - - - - - - - - - - - @@ -48,6 +32,6 @@ + - - + \ 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 diff --git a/contribs/freightreceiver/pom.xml b/contribs/freightreceiver/pom.xml index 9b9a8fdc2c9..1e69c51d40d 100644 --- a/contribs/freightreceiver/pom.xml +++ b/contribs/freightreceiver/pom.xml @@ -28,13 +28,13 @@ org.matsim.contrib freight - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim matsim-examples - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java index 6060e7ba4ee..d2cd76201eb 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Order.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Order.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java index 4589cd7b3b9..6c7b6f84f97 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ProductType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ProductType.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Identifiable; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java index 631130ba87a..3faee4fc53b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receiver.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receiver.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java index df29bc43a71..df4c6d6f948 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverAgent.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverAgent.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java index dfbc6cbe4a5..e42150f9b8f 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverConfigGroup.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverConfigGroup.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java index 10fe1be6bdd..852452663a6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverControlerListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.apache.logging.log4j.LogManager; @@ -29,8 +29,8 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.ScheduledTour; import org.matsim.freight.carriers.Tour; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; -import org.matsim.contrib.freightreceiver.replanning.ReceiverStrategyManager; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.replanning.ReceiverStrategyManager; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.*; import org.matsim.core.controler.listener.*; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java index 72ccdeb68fa..c01f7425f9b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocation.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocation.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.Carrier; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java index 6f85efcd2f1..ae79d2db6c5 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationEqualProportion.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationEqualProportion.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.matsim.api.core.v01.Id; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java index 5f3a6a2dea2..fed9d76f609 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixed.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationFixed.java @@ -17,7 +17,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.matsim.freight.carriers.Carrier; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java index 9ad1862b9c9..c4b110f8266 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverCostAllocationType.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; /** * The supported ways in which the carrier's cost is spread among the receivers. diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java index 1f29889a0a6..59b70767176 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverImpl.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverImpl.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java index aac11b5e7b2..a108dbf87f4 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverModule.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverModule.java @@ -16,14 +16,15 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.replanning.*; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.AbstractModule; +import org.matsim.freight.receiver.replanning.ReceiverReplanningUtils; +import org.matsim.freight.receiver.replanning.ReceiverStrategyManager; public final class ReceiverModule extends AbstractModule { final private static Logger LOG = LogManager.getLogger(ReceiverModule.class); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java index 081004dcb71..cad5c103842 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverOrder.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverOrder.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java index 0497d364b3d..88a8fe76268 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverPlan.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverPlan.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -25,7 +25,7 @@ import org.matsim.api.core.v01.population.Person; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java index 40489f44c23..5e734d77247 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverProduct.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverProduct.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; /** * Returns a new instance of a receiver product with associated information, diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java similarity index 96% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java index d8bd5df43dc..f1845f3d2cb 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverReplanningType.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverReplanningType.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; public enum ReceiverReplanningType { serviceTime, timeWindow, orderFrequency, afterHoursTimeWindow diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java index a9a63491a07..a6b260fc449 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoreStats.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoreStats.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.google.inject.Inject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Scenario; import org.matsim.freight.carriers.CarriersUtils; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.controler.events.ShutdownEvent; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java index 81e60676e02..ade37d5354e 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactory.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.core.scoring.ScoringFunction; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java index 57357050ebb..e937074d616 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverScoringFunctionFactoryMoneyOnly.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverScoringFunctionFactoryMoneyOnly.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.matsim.core.scoring.ScoringFunction; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java index a03dc19cf06..e1fd6bc7ef5 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTracker.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTracker.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java index 62a2a507aa2..2b8c4a6dfb9 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverTriggersCarrierReplanningListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java @@ -15,7 +15,7 @@ * See also COPYING, LICENSE and WARRANTY file * * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; @@ -29,7 +29,7 @@ import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; import org.matsim.freight.carriers.jsprit.NetworkBasedTransportCosts; import org.matsim.freight.carriers.jsprit.NetworkRouter; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.events.IterationStartsEvent; import org.matsim.core.controler.listener.IterationStartsListener; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java index dcd2861daed..e9b1b293368 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiverUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java index 3d042480928..640aa31d6b8 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/Receivers.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/Receivers.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java index 63afdf1c4cd..1c68dd3dbfe 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReader.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReader.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.core.utils.io.MatsimXmlParser; import org.xml.sax.Attributes; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java index 2036326c078..b886be795f8 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversReaderV2.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversReaderV2.java @@ -18,13 +18,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; 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.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.api.internal.MatsimReader; import org.matsim.core.utils.io.MatsimXmlParser; import org.matsim.core.utils.misc.Counter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java index cd9e2f33a06..68b37813398 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriter.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriter.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java index 09172159e06..1ceacde5d4b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandler.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandler.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import java.io.BufferedWriter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java index ecc7b58f43e..4e5a4b2e262 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV1.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV1.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java similarity index 99% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java index c2b8fe50f1b..b9091c62111 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReceiversWriterHandlerImplV2.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiversWriterHandlerImplV2.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.freight.carriers.TimeWindow; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java index e04152e5e30..9447bb3b8bc 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/ReorderPolicy.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReorderPolicy.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.utils.objectattributes.attributable.Attributable; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java index 9928bbc6191..f9620ef58b2 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/SSReorderPolicy.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/SSReorderPolicy.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java index 5cc872f2b50..ba49d350c14 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/UsecasesCarrierScoringFunctionFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/UsecasesCarrierScoringFunctionFactory.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @@ -8,8 +8,8 @@ import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Leg; import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.controler.CarrierScoringFunctionFactory; -import org.matsim.freight.carriers.controler.FreightActivity; +import org.matsim.freight.carriers.controller.CarrierScoringFunctionFactory; +import org.matsim.freight.carriers.controller.FreightActivity; import org.matsim.core.population.routes.NetworkRoute; import org.matsim.core.scoring.ScoringFunction; import org.matsim.core.scoring.SumScoringFunction; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java similarity index 86% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java index 9afea8cdc9e..77e28d853e6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/Coalition.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/Coalition.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.Receiver; +import org.matsim.freight.receiver.Receiver; import org.matsim.utils.objectattributes.attributable.Attributable; import java.util.Collection; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java index 25e73445613..3775eec413b 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -7,7 +7,7 @@ import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; -import org.matsim.contrib.freightreceiver.*; +import org.matsim.freight.receiver.*; public class CollaborationUtils{ private CollaborationUtils(){} // do not instantiate diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java similarity index 70% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java index c3c3d3d544e..68576dc0ea3 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/CollaborationUtilsNew.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/CollaborationUtilsNew.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carriers; -import org.matsim.contrib.freightreceiver.*; +import org.matsim.freight.receiver.Receivers; /** * Class with utilities to handle the collaboration between {@link Carriers} diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java index 4799f493912..c6597ff695d 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/MutableCoalition.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/MutableCoalition.java @@ -1,8 +1,8 @@ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.Carrier; -import org.matsim.contrib.freightreceiver.Receiver; +import org.matsim.freight.receiver.Receiver; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java index 99b91c04395..118f6ed3b84 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/OrderSizeMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/OrderSizeMutator.java @@ -16,11 +16,11 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; -import org.matsim.contrib.freightreceiver.Order; -import org.matsim.contrib.freightreceiver.ReceiverOrder; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Order; +import org.matsim.freight.receiver.ReceiverOrder; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java index bf972b057fe..abd734db026 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/collaboration/TimeWindowMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/collaboration/TimeWindowMutator.java @@ -19,10 +19,10 @@ /** * */ -package org.matsim.contrib.freightreceiver.collaboration; +package org.matsim.freight.receiver.collaboration; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java similarity index 89% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java index 46fad091944..b5aad6ea53a 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/multiday/MultidayUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/multiday/MultidayUtils.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver.multiday; +package org.matsim.freight.receiver.multiday; import org.matsim.core.utils.misc.OptionalTime; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java similarity index 88% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java index 018a8f64c87..caa840d48c1 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/CollaborationStatusMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/CollaborationStatusMutator.java @@ -1,9 +1,9 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.matsim.contrib.freightreceiver.ReceiverPlan; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.ReceiverPlan; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java similarity index 91% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java index f74750d9924..eb14b8eeb22 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/OrderFrequencyStrategyManager.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/OrderFrequencyStrategyManager.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; -import org.matsim.contrib.freightreceiver.collaboration.OrderSizeMutator; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; +import org.matsim.freight.receiver.collaboration.OrderSizeMutator; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java similarity index 81% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java index 2bdc4eadbb7..71309261c26 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverReplanningUtils.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverReplanningUtils.java @@ -1,7 +1,7 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Provider; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverReplanningType; /** * A single entry point for receiver replanning. diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java similarity index 83% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java index 0ef128e441a..f697154a305 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManager.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManager.java @@ -18,11 +18,11 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; -import org.matsim.freight.carriers.controler.CarrierStrategyManager; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.carriers.controller.CarrierStrategyManager; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericStrategyManager; /** diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java similarity index 94% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java index 4b56bee4470..c164c64a039 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ReceiverStrategyManagerImpl.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ReceiverStrategyManagerImpl.java @@ -18,11 +18,11 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.matsim.api.core.v01.population.HasPlansAndId; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericStrategyManager; import org.matsim.core.replanning.GenericStrategyManagerImpl; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java index 842ad6c5584..7488cc3e748 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeMutator.java @@ -16,13 +16,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.matsim.contrib.freightreceiver.Order; -import org.matsim.contrib.freightreceiver.ReceiverOrder; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Order; +import org.matsim.freight.receiver.ReceiverOrder; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java similarity index 95% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java index 6271e402b57..c88b09a261d 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/ServiceTimeStrategyManagerProvider.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/ServiceTimeStrategyManagerProvider.java @@ -1,10 +1,10 @@ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategy; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java similarity index 92% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java index e19d1437dc0..87926d796a2 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowStrategyManagerFactory.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowStrategyManagerFactory.java @@ -1,13 +1,13 @@ /** * */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import com.google.inject.Inject; import com.google.inject.Provider; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.Receiver; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.Receiver; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.replanning.GenericPlanStrategyImpl; import org.matsim.core.replanning.selectors.ExpBetaPlanChanger; import org.matsim.core.utils.misc.Time; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java similarity index 97% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java index 97ea20b2e20..553504a7862 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/replanning/TimeWindowUpperBoundMutator.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/replanning/TimeWindowUpperBoundMutator.java @@ -16,10 +16,10 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.replanning; +package org.matsim.freight.receiver.replanning; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.ReceiverPlan; +import org.matsim.freight.receiver.ReceiverPlan; import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java similarity index 94% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java index b5b946942b0..327c65716d6 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardParameters.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardParameters.java @@ -16,9 +16,9 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverReplanningType; /** * Class to help with setting experimental parameters. These parameters are diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java similarity index 98% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java index b5b2f535b45..fd036695370 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/ReceiverChessboardScenario.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,8 +29,8 @@ import org.matsim.api.core.v01.network.NetworkWriter; import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; -import org.matsim.contrib.freightreceiver.*; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.*; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.ConfigWriter; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java index 469f45574ee..4e7b9b2607a 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithEqualProportionCost.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,9 +26,9 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; -import org.matsim.contrib.freightreceiver.ReceiverModule; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; -import org.matsim.contrib.freightreceiver.ReceiverUtils; +import org.matsim.freight.receiver.ReceiverModule; +import org.matsim.freight.receiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverUtils; import org.matsim.core.controler.Controler; import org.matsim.core.controler.MatsimServices; diff --git a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java similarity index 93% rename from contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java rename to contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java index 112785c45b8..2570eb80c16 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/contrib/freightreceiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/RunReceiverChessboardWithFixedCarrierCost.java @@ -18,7 +18,7 @@ * *********************************************************************** */ -package org.matsim.contrib.freightreceiver.run.chessboard; +package org.matsim.freight.receiver.run.chessboard; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,9 +26,9 @@ import org.matsim.freight.carriers.CarriersUtils; import org.matsim.freight.carriers.Carriers; import org.matsim.freight.carriers.usecases.analysis.CarrierScoreStats; -import org.matsim.contrib.freightreceiver.ReceiverModule; -import org.matsim.contrib.freightreceiver.ReceiverReplanningType; -import org.matsim.contrib.freightreceiver.ReceiverUtils; +import org.matsim.freight.receiver.ReceiverModule; +import org.matsim.freight.receiver.ReceiverReplanningType; +import org.matsim.freight.receiver.ReceiverUtils; import org.matsim.core.controler.Controler; import org.matsim.core.controler.MatsimServices; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java similarity index 88% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java index 8faf02fd1c0..4189a6e9779 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverCostAllocationFixedTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverCostAllocationFixedTest.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java index 9933bda39d7..ea784499f81 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiverPlanTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiverPlanTest.java @@ -16,7 +16,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java similarity index 98% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java index 970641df24e..6a893a9409f 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversReaderTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversReaderTest.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.freight.carriers.Carrier; import org.matsim.freight.carriers.TimeWindow; -import org.matsim.contrib.freightreceiver.collaboration.CollaborationUtils; +import org.matsim.freight.receiver.collaboration.CollaborationUtils; import org.matsim.core.utils.misc.Time; import org.matsim.testcases.MatsimTestUtils; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java index 35dbed33c31..8ca84ad87f8 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversTest.java @@ -1,11 +1,11 @@ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; 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.contrib.freightreceiver.run.chessboard.ReceiverChessboardScenario; +import org.matsim.freight.receiver.run.chessboard.ReceiverChessboardScenario; import org.matsim.testcases.MatsimTestUtils; import java.util.Collection; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java similarity index 96% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java index 34a66898d68..1f9a453ce08 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/ReceiversWriterTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/ReceiversWriterTest.java @@ -18,13 +18,13 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Scenario; -import org.matsim.contrib.freightreceiver.run.chessboard.ReceiverChessboardScenario; +import org.matsim.freight.receiver.run.chessboard.ReceiverChessboardScenario; import org.matsim.testcases.MatsimTestUtils; import java.io.File; diff --git a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java similarity index 97% rename from contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java rename to contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java index 1841ae963fc..c22aea6a54b 100644 --- a/contribs/freightreceiver/src/test/java/org/matsim/contrib/freightreceiver/SSReorderPolicyTest.java +++ b/contribs/freightreceiver/src/test/java/org/matsim/freight/receiver/SSReorderPolicyTest.java @@ -18,7 +18,7 @@ * * * *********************************************************************** */ -package org.matsim.contrib.freightreceiver; +package org.matsim.freight.receiver; import org.junit.jupiter.api.Assertions; diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_basic.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_basic.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_basic.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_basic.xml diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_full.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_full.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversReaderTest/receivers_v2_full.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversReaderTest/receivers_v2_full.xml diff --git a/contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversTest/receivers_v2.xml b/contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversTest/receivers_v2.xml similarity index 100% rename from contribs/freightreceiver/test/input/org/matsim/contrib/freightreceiver/ReceiversTest/receivers_v2.xml rename to contribs/freightreceiver/test/input/org/matsim/freight/receiver/ReceiversTest/receivers_v2.xml diff --git a/contribs/hybridsim/pom.xml b/contribs/hybridsim/pom.xml index d8f69b28046..7bb94a4feff 100644 --- a/contribs/hybridsim/pom.xml +++ b/contribs/hybridsim/pom.xml @@ -11,7 +11,7 @@ 4.28.3 - 1.66.0 + 1.68.1 diff --git a/contribs/informed-mode-choice/pom.xml b/contribs/informed-mode-choice/pom.xml index 04b54d402cb..d28005db983 100644 --- a/contribs/informed-mode-choice/pom.xml +++ b/contribs/informed-mode-choice/pom.xml @@ -16,7 +16,7 @@ org.matsim.contrib application - 2025.0-SNAPSHOT + ${project.parent.version} xerces diff --git a/contribs/integration/pom.xml b/contribs/integration/pom.xml index 05bc09e61a9..95a7a2dfd5c 100644 --- a/contribs/integration/pom.xml +++ b/contribs/integration/pom.xml @@ -80,7 +80,7 @@ org.matsim.contrib accessibility - 2025.0-SNAPSHOT + ${project.parent.version} org.geotools.jdbc @@ -90,18 +90,18 @@ org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} test org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} test diff --git a/contribs/locationchoice/pom.xml b/contribs/locationchoice/pom.xml index 955d0dd364c..33de35d8866 100644 --- a/contribs/locationchoice/pom.xml +++ b/contribs/locationchoice/pom.xml @@ -24,12 +24,12 @@ org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} test diff --git a/contribs/minibus/pom.xml b/contribs/minibus/pom.xml index c9b6f4eb0fb..374288785e9 100644 --- a/contribs/minibus/pom.xml +++ b/contribs/minibus/pom.xml @@ -45,7 +45,7 @@ org.matsim matsim - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/noise/pom.xml b/contribs/noise/pom.xml index ac1c5fbd32b..920c9b58606 100644 --- a/contribs/noise/pom.xml +++ b/contribs/noise/pom.xml @@ -13,7 +13,7 @@ org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/parking/README.md b/contribs/parking/README.md index a9e090515c3..1285c0d5f86 100644 --- a/contribs/parking/README.md +++ b/contribs/parking/README.md @@ -12,4 +12,34 @@ approaches as to how parking can be handled in MATSim, depending on the use case . This was designed for large scenarios where it's not feasable to fully simulate parking agents. Rather, the additional time needed for parking is estimated - Parking Costs, developed by Marcel Rieser and Joschka Bischoff at SBB. This modules allows the integration of parking - costs based on link attribute data. \ No newline at end of file + costs based on link attribute data. + +## Implementations + +### Parking Search + +Model parking search, including walking segments and parking search traffic. + +Different Parking Search Logics: + +1. **Random:** + 1. Drive to the destination. + 2. The next link is chosen randomly. +2. **DistanceMemoryParkingSearch:** + 1. Drive to the destination. + 2. Select the next link: + 1. Choose an unknown link with the shortest straight-line distance to the destination. + 2. If all links are known, choose randomly. +3. **NearestParkingSpotSearchLogic:** + 1. Drive to the destination (??). + 2. Search for the facility with the shortest distance to the current location, considering the expected driving time and parking duration (and + possibly parking time restrictions). + 3. If no suitable facility is found ? +4. **BenensonParkingSearchLogic:** A more sophisticated strategy based on the Benenson + model: https://www.sciencedirect.com/science/article/pii/S0198971508000689 + +### Parking Proxy + +### Parking Costs + +### Parking Choice diff --git a/contribs/parking/pom.xml b/contribs/parking/pom.xml index f6d4bbf3c76..8dd4d6c1af9 100644 --- a/contribs/parking/pom.xml +++ b/contribs/parking/pom.xml @@ -12,17 +12,17 @@ org.matsim.contrib multimodal - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/BenensonDynLeg.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/BenensonDynLeg.java index 5bd6ca248bb..c7b041ba21a 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/BenensonDynLeg.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/BenensonDynLeg.java @@ -21,30 +21,30 @@ /** * @author schlenther *

    - * Benenson et al defined 3 phases of parking search + * Benenson et al. defined 3 phases of parking search * OBSERVING: observation of parking situation while driving towards destination * SEARCH_WHILE_APPROACH: estimating the amount of free parking lots on the way to destination * and if applicable parking before arriving * SEARCH_FOR_NEXT: taking the next free parking space if it isn't too far away from destination */ enum ParkingMode { - DRIVING, OBSERVING, SEARCH_WHILE_APPROACH, SEARCH_FOR_NEXT + DRIVING, OBSERVING, SEARCH_WHILE_APPROACH, SEARCH_FOR_NEXT } -public class BenensonDynLeg extends ParkingDynLeg{ +public class BenensonDynLeg extends ParkingDynLeg { private static final Logger logger = LogManager.getLogger(BenensonDynLeg.class); private static final boolean logForDebug = false; private double totalObservedParkingSpaces = 0.0; private double observedFreeParkingSpaces = 0.0; - private double firstDestinationLinkEnterTime = 0; - private ParkingMode legStage = ParkingMode.DRIVING; + private double firstDestinationLinkEnterTime = 0; + private ParkingMode legStage = ParkingMode.DRIVING; public BenensonDynLeg(String mode, NetworkRoute route, ParkingSearchLogic logic, - ParkingSearchManager parkingManager, Id vehicleId, MobsimTimer timer, EventsManager events) { + ParkingSearchManager parkingManager, Id vehicleId, MobsimTimer timer, EventsManager events) { super(mode, route, logic, parkingManager, vehicleId, timer, events); - if (!(logic instanceof BenensonParkingSearchLogic)){ + if (!(logic instanceof BenensonParkingSearchLogic)) { throw new RuntimeException(); } } @@ -55,56 +55,68 @@ public void movedOverNode(Id newLinkId) { currentLinkId = newLinkId; if (this.legStage == ParkingMode.DRIVING) { - if (((BenensonParkingSearchLogic) this.logic).transitionToObservingBehaviour(currentLinkId, this.route.getEndLinkId())) { - this.legStage = ParkingMode.OBSERVING; + if (((BenensonParkingSearchLogic) this.logic).transitionToObservingBehaviour(currentLinkId, this.route.getEndLinkId())) { + this.legStage = ParkingMode.OBSERVING; this.events.processEvent(new StartParkingSearchEvent(timer.getTimeOfDay(), vehicleId, currentLinkId)); - if(logForDebug)logger.error("vehicle " + this.vehicleId + " goes into observing on link " + this.currentLinkId); + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " goes into observing on link " + this.currentLinkId); + } } } - if(this.legStage == ParkingMode.OBSERVING ){ + if (this.legStage == ParkingMode.OBSERVING) { memorizeParkingSituationAndIsSomethingFree(); - if (((BenensonParkingSearchLogic) this.logic).transitionToParkingBehaviour(currentLinkId, this.route.getEndLinkId())) { - this.legStage = ParkingMode.SEARCH_WHILE_APPROACH; - if(logForDebug)logger.error("vehicle " + this.vehicleId + " goes into parking on link " + this.currentLinkId); + if (((BenensonParkingSearchLogic) this.logic).transitionToParkingBehaviour(currentLinkId, this.route.getEndLinkId())) { + this.legStage = ParkingMode.SEARCH_WHILE_APPROACH; + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " goes into parking on link " + this.currentLinkId); + } } } - if(this.legStage == ParkingMode.SEARCH_WHILE_APPROACH){ - if(currentLinkId.equals(route.getEndLinkId())){ + if (this.legStage == ParkingMode.SEARCH_WHILE_APPROACH) { + if (currentLinkId.equals(route.getEndLinkId())) { this.legStage = ParkingMode.SEARCH_FOR_NEXT; - this.firstDestinationLinkEnterTime = timer.getTimeOfDay(); - } - else{ - if(memorizeParkingSituationAndIsSomethingFree()){ + this.firstDestinationLinkEnterTime = timer.getTimeOfDay(); + } else { + if (memorizeParkingSituationAndIsSomethingFree()) { double pUnoccupied = 0; - if(this.totalObservedParkingSpaces > 0){ + if (this.totalObservedParkingSpaces > 0) { pUnoccupied = this.observedFreeParkingSpaces / this.totalObservedParkingSpaces; } - if ( ((BenensonParkingSearchLogic)this.logic).wantToParkHere(pUnoccupied, currentLinkId, route.getEndLinkId())){ - if (logForDebug) logger.error("vehicle " + this.vehicleId + " would like to park on link" + currentLinkId - + "\n \t pUnoccupied = " + pUnoccupied + "\n\t totalObservedParkingSpaces = " + totalObservedParkingSpaces + "\n\t observedFreeSpaces = " + this.observedFreeParkingSpaces); - hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId); - } - } - else{ - if(logForDebug)logger.error("nothing free for vehicle " + vehicleId + " on link " + currentLinkId); + if (((BenensonParkingSearchLogic) this.logic).wantToParkHere(pUnoccupied, currentLinkId, route.getEndLinkId())) { + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " would like to park on link" + currentLinkId + + "\n \t pUnoccupied = " + pUnoccupied + "\n\t totalObservedParkingSpaces = " + totalObservedParkingSpaces + "\n\t " + + "observedFreeSpaces = " + this.observedFreeParkingSpaces); + } + hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId); + } + } else { + if (logForDebug) { + logger.error("nothing free for vehicle " + vehicleId + " on link " + currentLinkId); + } } } } - if (this.legStage == ParkingMode.SEARCH_FOR_NEXT){ - if (logForDebug) logger.error("vehicle " + this.vehicleId + " is in PHASE3 on link " + this.currentLinkId); - //if( ((BenensonParkingSearchLogic)this.logic).isDriverInAcceptableDistance(currentLinkId, route.getEndLinkId(), this.firstDestLinkEnterTimer, timer.getTimeOfDay()) ){ + if (this.legStage == ParkingMode.SEARCH_FOR_NEXT) { + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " is in PHASE3 on link " + this.currentLinkId); + } + //if( ((BenensonParkingSearchLogic)this.logic).isDriverInAcceptableDistance(currentLinkId, route.getEndLinkId(), this + // .firstDestLinkEnterTimer, timer.getTimeOfDay()) ){ - hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId); + hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId); - if (logForDebug) logger.error("vehicle " + this.vehicleId + " tries in PHASE3 to park on link " + this.currentLinkId + ", " + - (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) / 60 + ":" + (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) % 60 - + " min after passing destination. Result: " + hasFoundParking); - //} - } - } + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " tries in PHASE3 to park on link " + this.currentLinkId + ", " + + (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) / 60 + ":" + (int) (timer.getTimeOfDay() - this.firstDestinationLinkEnterTime) % 60 + + " min after passing destination. Result: " + hasFoundParking); + } + //} + } + } - /** + /** * returns true if there is at least one empty slot on the current link */ private boolean memorizeParkingSituationAndIsSomethingFree() { @@ -124,13 +136,14 @@ public Id getNextLinkId() { return route.getEndLinkId(); } return linkIds.get(currentLinkIdx + 1); - } - else { + } else { if (hasFoundParking) { - if(logForDebug)logger.error("vehicle " + this.vehicleId + " has found a parking on link " + this.currentLinkId + " after passing " + Math.abs((this.route.getLinkIds().size() - this.currentLinkIdx - 3)) + " links"); + if (logForDebug) { + logger.error("vehicle " + this.vehicleId + " has found a parking on link " + this.currentLinkId + " after passing " + Math.abs((this.route.getLinkIds() + .size() - this.currentLinkIdx - 3)) + " links"); + } return null; - } - else { + } else { if (this.currentAndNextParkLink != null) { if (currentAndNextParkLink.getFirst().equals(currentLinkId)) { // we already calculated this @@ -139,15 +152,15 @@ public Id getNextLinkId() { } Id nextLinkId; - if(this.legStage == ParkingMode.SEARCH_FOR_NEXT){ - nextLinkId = ((BenensonParkingSearchLogic) this.logic).getNextLinkRandomInAcceptableDistance(currentLinkId, this.route.getEndLinkId(), - vehicleId, firstDestinationLinkEnterTime, this.timer.getTimeOfDay(), mode); - } - else{ + if (this.legStage == ParkingMode.SEARCH_FOR_NEXT) { + nextLinkId = ((BenensonParkingSearchLogic) this.logic).getNextLinkRandomInAcceptableDistance(currentLinkId, + this.route.getEndLinkId(), + vehicleId, firstDestinationLinkEnterTime, this.timer.getTimeOfDay(), mode); + } else { nextLinkId = ((BenensonParkingSearchLogic) (this.logic)).getNextLinkBenensonRouting(currentLinkId, route.getEndLinkId(), mode); - } - currentAndNextParkLink = new Tuple<>(currentLinkId, nextLinkId); - return nextLinkId; + } + currentAndNextParkLink = new Tuple<>(currentLinkId, nextLinkId); + return nextLinkId; } } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/NearestParkingDynLeg.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/NearestParkingDynLeg.java index a5f4cdcf143..ba81ede9c1d 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/NearestParkingDynLeg.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/NearestParkingDynLeg.java @@ -45,10 +45,12 @@ public NearestParkingDynLeg(Leg currentPlannedLeg, NetworkRoute route, Plan plan this.currentPlannedLeg = currentPlannedLeg; this.plan = plan; this.planIndexNextActivity = planIndexNextActivity; - if (ParkingUtils.checkIfActivityHasNoParking(followingActivity)) + if (ParkingUtils.checkIfActivityHasNoParking(followingActivity)) { parkingAtEndOfLeg = false; - if (ParkingUtils.checkIfActivityHasPassengerInteraction(followingActivity)) + } + if (ParkingUtils.checkIfActivityHasPassengerInteraction(followingActivity)) { passangerInteractionAtParkingFacilityAtEndOfLeg = true; + } } @Override @@ -67,20 +69,22 @@ public void movedOverNode(Id newLinkId) { if (hasFoundParking) { this.events.processEvent(new ReserveParkingLocationEvent(timer.getTimeOfDay(), vehicleId, currentLinkId, currentLinkId)); nextSelectedParkingLink = currentLinkId; - } else + } else { ((FacilityBasedParkingManager) parkingManager).registerRejectedReservation(timer.getTimeOfDay()); + } } } } else if (followingActivity.getLinkId().equals(newLinkId)) { - if (alreadyReservedParking) + if (alreadyReservedParking) { hasFoundParking = true; - else { + } else { hasFoundParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, currentLinkId); if (hasFoundParking) { this.events.processEvent(new ReserveParkingLocationEvent(timer.getTimeOfDay(), vehicleId, currentLinkId, currentLinkId)); nextSelectedParkingLink = currentLinkId; - } else + } else { ((FacilityBasedParkingManager) parkingManager).registerRejectedReservation(timer.getTimeOfDay()); + } } } } @@ -138,11 +142,10 @@ public Id getNextLinkId() { // need to find the next link double nextPickupTime; double maxParkingDuration; - if (passangerInteractionAtParkingFacilityAtEndOfLeg){ + if (passangerInteractionAtParkingFacilityAtEndOfLeg) { nextPickupTime = 0.; maxParkingDuration = followingActivity.getMaximumDuration().seconds(); - } - else { + } else { nextPickupTime = currentPlannedLeg.getDepartureTime().seconds() + followingActivity.getMaximumDuration().seconds(); maxParkingDuration = nextPickupTime - timer.getTimeOfDay(); } @@ -163,11 +166,12 @@ public Id getNextLinkId() { nextSelectedParkingLink = nextPlanedParkingLink; if (((NearestParkingSpotSearchLogic) this.logic).canReserveParkingSlot()) { alreadyReservedParking = parkingManager.reserveSpaceIfVehicleCanParkHere(vehicleId, nextSelectedParkingLink); - if (alreadyReservedParking) + if (alreadyReservedParking) { this.events.processEvent( new ReserveParkingLocationEvent(timer.getTimeOfDay(), vehicleId, currentLinkId, nextSelectedParkingLink)); - else + } else { ((FacilityBasedParkingManager) parkingManager).registerRejectedReservation(timer.getTimeOfDay()); + } } else { this.events.processEvent( new SelectNewParkingLocationEvent(timer.getTimeOfDay(), vehicleId, currentLinkId, nextSelectedParkingLink)); @@ -176,13 +180,16 @@ public Id getNextLinkId() { } } currentAndNextParkLink = new Tuple<>(currentLinkId, nextLinkId); - if (((NearestParkingSpotSearchLogic) this.logic).getNextRoute() != null) + if (((NearestParkingSpotSearchLogic) this.logic).getNextRoute() != null) { currentPlannedLeg.setRoute(((NearestParkingSpotSearchLogic) this.logic).getNextRoute()); + } return nextLinkId; } } } + //yyyy I assume, the vehicle is removed from the link's queue and thus waiting for parking does not influence the behaviour of the mobsim? + // Does this make sense? paul, nov'24 private void createWaitingActivityUntilPassengerInteractionIsPossible(Id newLinkId, Id vehicleId, double now) { Activity waitingActivity = PopulationUtils.createActivityFromLinkId(ParkingUtils.WaitingForParkingActivityType, newLinkId); ParkingUtils.setNoParkingForActivity(waitingActivity); @@ -195,7 +202,8 @@ private void removeNextActivityAndFollowingLeg() { plan.getPlanElements().remove(planIndexNextActivity); plan.getPlanElements().remove(planIndexNextActivity); // log.info( -// plan.getPerson().getId().toString() + ": Parking activity after getOff point '" + ((Activity)plan.getPlanElements().get(planIndexNextActivity - 2)).getType() + "' is removed, because no parking facility was found."); +// plan.getPerson().getId().toString() + ": Parking activity after getOff point '" + ((Activity)plan.getPlanElements().get +// (planIndexNextActivity - 2)).getType() + "' is removed, because no parking facility was found."); } public boolean driveToBaseWithoutParking() { diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/NearestParkingSpotAgentLogic.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/NearestParkingSpotAgentLogic.java index f3a7e671b14..b0095eb5cf7 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/NearestParkingSpotAgentLogic.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/NearestParkingSpotAgentLogic.java @@ -52,19 +52,20 @@ public DynAction computeNextAction(DynAction oldAction, double now) { // unpark activity: find the way to the next route & start leg //if a parking activity was skipped we need no change the nexParkActionState - if (lastParkActionState.equals(LastParkActionState.CARTRIP) && ((NearestParkingDynLeg) oldAction).driveToBaseWithoutParking()) + if (lastParkActionState.equals(LastParkActionState.CARTRIP) && ((NearestParkingDynLeg) oldAction).driveToBaseWithoutParking()) { this.lastParkActionState = LastParkActionState.WALKFROMPARK; + } - return switch (lastParkActionState) { - case ACTIVITY -> nextStateAfterActivity(oldAction, now); - case CARTRIP -> nextStateAfterCarTrip(oldAction, now); - case NONCARTRIP -> nextStateAfterNonCarTrip(oldAction, now); - case PARKACTIVITY -> nextStateAfterParkActivity(oldAction, now); - case UNPARKACTIVITY -> nextStateAfterUnParkActivity(oldAction, now); - case WALKFROMPARK -> nextStateAfterWalkFromPark(oldAction, now); - case WALKTOPARK -> nextStateAfterWalkToPark(oldAction, now); - }; - } + return switch (lastParkActionState) { + case ACTIVITY -> nextStateAfterActivity(oldAction, now); + case CARTRIP -> nextStateAfterCarTrip(oldAction, now); + case NONCARTRIP -> nextStateAfterNonCarTrip(oldAction, now); + case PARKACTIVITY -> nextStateAfterParkActivity(oldAction, now); + case UNPARKACTIVITY -> nextStateAfterUnParkActivity(oldAction, now); + case WALKFROMPARK -> nextStateAfterWalkFromPark(oldAction, now); + case WALKTOPARK -> nextStateAfterWalkToPark(oldAction, now); + }; + } @Override protected DynAction nextStateAfterUnParkActivity(DynAction oldAction, double now) { @@ -75,20 +76,24 @@ protected DynAction nextStateAfterUnParkActivity(DynAction oldAction, double now Route plannedRoute = currentPlannedLeg.getRoute(); NetworkRoute actualRoute = this.parkingRouter.getRouteFromParkingToDestination(plannedRoute.getEndLinkId(), now, agent.getCurrentLinkId()); actualRoute.setVehicleId(currentlyAssignedVehicleId); - if (!plannedRoute.getStartLinkId().equals(actualRoute.getStartLinkId())) + if (!plannedRoute.getStartLinkId().equals(actualRoute.getStartLinkId())) { currentPlannedLeg.setRoute(actualRoute); + } if ((this.parkingManager.unParkVehicleHere(currentlyAssignedVehicleId, agent.getCurrentLinkId(), now)) || (isInitialLocation)) { this.lastParkActionState = LastParkActionState.CARTRIP; isInitialLocation = false; // Leg currentLeg = (Leg) this.currentPlanElement; int planIndexNextActivity = planIndex + 1; Activity nextPlanElement = (Activity) plan.getPlanElements().get(planIndexNextActivity); - if (ParkingUtils.checkIfActivityHasNoParking(nextPlanElement)) + if (ParkingUtils.checkIfActivityHasNoParking(nextPlanElement)) { this.lastParkActionState = LastParkActionState.WALKFROMPARK; + } //this could be Car, Carsharing, Motorcylce, or whatever else mode we have, so we want our leg to reflect this. return new NearestParkingDynLeg(currentPlannedLeg, actualRoute, plan, planIndexNextActivity, parkingLogic, parkingManager, currentlyAssignedVehicleId, timer, events); - } else throw new RuntimeException("parking location mismatch"); + } else { + throw new RuntimeException("parking location mismatch"); + } } @@ -101,17 +106,19 @@ protected DynAction nextStateAfterParkActivity(DynAction oldAction, double now) List walkTrip = walkRouter.calcRoute( DefaultRoutingRequest.withoutAttributes(fromFacility, toFacility, now, plan.getPerson())); if (walkTrip.size() != 1 || !(walkTrip.get(0) instanceof Leg)) { - String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to access the network. Not implemented in parking yet!"; + String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to " + + "access the network. Not implemented in parking yet!"; log.error(message); throw new RuntimeException(message); } Leg walkLeg = (Leg) walkTrip.get(0); this.lastParkActionState = LastParkActionState.WALKFROMPARK; this.stageInteractionType = null; - if (!walkLeg.getTravelTime().equals(OptionalTime.defined(0.))) + if (!walkLeg.getTravelTime().equals(OptionalTime.defined(0.))) { return new StaticPassengerDynLeg(walkLeg.getRoute(), walkLeg.getMode()); - else + } else { return nextStateAfterWalkFromPark(oldAction, now); + } } @Override @@ -125,15 +132,20 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { this.parkingManager.parkVehicleHere(Id.create(this.agent.getId(), Vehicle.class), agent.getCurrentLinkId(), now); return nextStateAfterNonCarTrip(oldAction, now); } - if (plan.getPlanElements().get(planIndex + 1) instanceof Activity) + if (plan.getPlanElements().get(planIndex + 1) instanceof Activity) { return nextStateAfterNonCarTrip(oldAction, now); - if (plan.getPlanElements().get(planIndex) instanceof Activity && ((Activity) plan.getPlanElements().get(planIndex)).getType().contains("_GetOff")) { + } + if (plan.getPlanElements().get(planIndex) instanceof Activity && ((Activity) plan.getPlanElements().get(planIndex)).getType() + .contains("_GetOff")) { ((Activity) plan.getPlanElements().get(planIndex)).setEndTime(now); - ((Activity) plan.getPlanElements().get(planIndex + 4)).setStartTime(now + ((Activity) plan.getPlanElements().get(planIndex + 2)).getMaximumDuration().seconds()); + ((Activity) plan.getPlanElements().get(planIndex + 4)).setStartTime(now + ((Activity) plan.getPlanElements() + .get(planIndex + 2)).getMaximumDuration() + .seconds()); // checks if it is possible to stay from getOff until getIn - boolean possibleToStay = checkIfParkingIsPossibleUntilNextActivities(this.planIndex,this.planIndex + 2); - if (possibleToStay) + boolean possibleToStay = checkIfParkingIsPossibleUntilNextActivities(this.planIndex, this.planIndex + 2); + if (possibleToStay) { return nextStateAfterNonCarTrip(oldAction, now); + } } planIndex++; this.currentPlanElement = plan.getPlanElements().get(planIndex); @@ -143,7 +155,8 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { Id parkLink = this.parkingManager.getVehicleParkingLocation(vehicleId); if (parkLink == null) { - //this is the first activity of a day and our parking manager does not provide information about initial stages. We suppose the car is parked where we are + //this is the first activity of a day and our parking manager does not provide information about initial stages. We suppose the + // car is parked where we are parkLink = agent.getCurrentLinkId(); } @@ -154,7 +167,8 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { List walkTrip = walkRouter.calcRoute( DefaultRoutingRequest.withoutAttributes(fromFacility, toFacility, now, plan.getPerson())); if (walkTrip.size() != 1 || !(walkTrip.get(0) instanceof Leg walkLeg)) { - String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to access the network. Not implemented in parking yet!"; + String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk" + + " to access the network. Not implemented in parking yet!"; log.error(message); throw new RuntimeException(message); } @@ -180,9 +194,12 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { return new StaticPassengerDynLeg(currentLeg.getRoute(), currentLeg.getMode()); } - } else throw new RuntimeException( - "no more leg to follow but activity is ending\nLastPlanElement: " + currentPlanElement.toString() + "\n Agent " + this.agent.getId() + "\nTime: " + Time.writeTime( - now)); + } else { + throw new RuntimeException( + "no more leg to follow but activity is ending\nLastPlanElement: " + currentPlanElement.toString() + "\n Agent " + this.agent.getId() + + "\nTime: " + Time.writeTime( + now)); + } } @Override @@ -190,8 +207,9 @@ protected DynAction nextStateAfterWalkToPark(DynAction oldAction, double now) { //walk2park is complete, we can unpark. this.lastParkActionState = LastParkActionState.UNPARKACTIVITY; Activity beforePlanElement = (Activity) plan.getPlanElements().get(planIndex - 1); - if (ParkingUtils.checkIfActivityHasNoParking(beforePlanElement)) + if (ParkingUtils.checkIfActivityHasNoParking(beforePlanElement)) { return nextStateAfterUnParkActivity(oldAction, now); // wenn kein Parken dann einfach weiter + } return new IdleDynActivity(this.stageInteractionType, now + configGroup.getUnparkduration()); } @@ -211,7 +229,9 @@ protected DynAction nextStateAfterCarTrip(DynAction oldAction, double now) { this.currentlyAssignedVehicleId = null; this.parkingLogic.reset(); return new IdleDynActivity(this.stageInteractionType, now + configGroup.getParkduration()); - } else throw new RuntimeException("No parking possible"); + } else { + throw new RuntimeException("No parking possible"); + } } @Override @@ -221,7 +241,7 @@ protected DynAction nextStateAfterNonCarTrip(DynAction oldAction, double now) { Activity nextPlannedActivity = (Activity) this.currentPlanElement; // checks if you can extend parking here until getIn if (nextPlannedActivity.getType().equals(ParkingUtils.ParkingActivityType) && plan.getPlanElements().get(planIndex + 2) instanceof Leg) { - checkIfParkingIsPossibleUntilNextActivities(planIndex + 1,planIndex + 1); + checkIfParkingIsPossibleUntilNextActivities(planIndex + 1, planIndex + 1); } // switch back to activity planIndex++; @@ -249,11 +269,11 @@ private boolean checkIfParkingIsPossibleUntilNextActivities(int indexOfCurrentAc Activity currentActivity = ((Activity) plan.getPlanElements().get(this.planIndex)); Activity activityAfterFollowing = ((Activity) plan.getPlanElements().get(this.planIndex + 4)); if (agent.getCurrentLinkId().equals(activityAfterFollowing.getLinkId()) && !ParkingUtils.checkIfActivityHasNoParking( - (Activity) currentPlanElement)) { + (Activity) currentPlanElement)) { boolean canParkAtFacilityUntilGetIn = ((FacilityBasedParkingManager) parkingManager).canParkAtThisFacilityUntilEnd( agent.getCurrentLinkId(), - followingActivity.getMaximumDuration().seconds(), currentActivity.getMaximumDuration().seconds(), - activityAfterFollowing.getMaximumDuration().seconds(), timer.getTimeOfDay()); + timer.getTimeOfDay(), currentActivity.getMaximumDuration().seconds(), followingActivity.getMaximumDuration().seconds(), + activityAfterFollowing.getMaximumDuration().seconds()); if (canParkAtFacilityUntilGetIn) { plan.getPlanElements().remove(this.planIndex + 3); plan.getPlanElements().remove(this.planIndex + 1); @@ -269,8 +289,8 @@ else if (indexOfCurrentActivity == indexOfParkingActivity) { followingActivity)) { boolean canParkAtFacilityUntilGetIn = ((FacilityBasedParkingManager) parkingManager).canParkAtThisFacilityUntilEnd( agent.getCurrentLinkId(), - currentActivity.getMaximumDuration().seconds(), 0., - followingActivity.getMaximumDuration().seconds(), timer.getTimeOfDay()); + timer.getTimeOfDay(), 0., currentActivity.getMaximumDuration().seconds(), + followingActivity.getMaximumDuration().seconds()); if (canParkAtFacilityUntilGetIn) { plan.getPlanElements().remove(indexOfParkingActivity + 1); currentActivity.setEndTime(followingActivity.getStartTime().seconds()); diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/ParkingAgentLogic.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/ParkingAgentLogic.java index dd2fb4fa74b..31e175a3d30 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/ParkingAgentLogic.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/DynAgent/agentLogic/ParkingAgentLogic.java @@ -19,25 +19,14 @@ package org.matsim.contrib.parking.parkingsearch.DynAgent.agentLogic; -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.TransportMode; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.population.Activity; -import org.matsim.api.core.v01.population.Leg; -import org.matsim.api.core.v01.population.Plan; -import org.matsim.api.core.v01.population.PlanElement; -import org.matsim.api.core.v01.population.Route; -import org.matsim.contrib.dynagent.DynAction; -import org.matsim.contrib.dynagent.DynActivity; -import org.matsim.contrib.dynagent.DynAgent; -import org.matsim.contrib.dynagent.DynAgentLogic; -import org.matsim.contrib.dynagent.IdleDynActivity; -import org.matsim.contrib.dynagent.StaticPassengerDynLeg; +import org.matsim.api.core.v01.population.*; +import org.matsim.contrib.dynagent.*; import org.matsim.contrib.parking.parkingsearch.DynAgent.ParkingDynLeg; import org.matsim.contrib.parking.parkingsearch.ParkingUtils; import org.matsim.contrib.parking.parkingsearch.manager.ParkingSearchManager; @@ -56,8 +45,12 @@ import org.matsim.pt.routes.TransitPassengerRoute; import org.matsim.vehicles.Vehicle; +import java.util.List; + /** + * This class represents the logic for a {@link DynAgent}. It can only handle car legs for parking. + * * @author jbischoff */ public class ParkingAgentLogic implements DynAgentLogic { @@ -139,17 +132,17 @@ public DynAction computeNextAction(DynAction oldAction, double now) { // ordinary activity: get next Leg, if car: go to car, otherwise add ordinary leg by other mode // walk-leg to car: add unpark activity // unpark activity: find the way to the next route & start leg - return switch (lastParkActionState) { - case ACTIVITY -> nextStateAfterActivity(oldAction, now); - case CARTRIP -> nextStateAfterCarTrip(oldAction, now); - case NONCARTRIP -> nextStateAfterNonCarTrip(oldAction, now); - case PARKACTIVITY -> nextStateAfterParkActivity(oldAction, now); - case UNPARKACTIVITY -> nextStateAfterUnParkActivity(oldAction, now); - case WALKFROMPARK -> nextStateAfterWalkFromPark(oldAction, now); - case WALKTOPARK -> nextStateAfterWalkToPark(oldAction, now); - }; + return switch (lastParkActionState) { + case ACTIVITY -> nextStateAfterActivity(oldAction, now); + case CARTRIP -> nextStateAfterCarTrip(oldAction, now); + case NONCARTRIP -> nextStateAfterNonCarTrip(oldAction, now); + case PARKACTIVITY -> nextStateAfterParkActivity(oldAction, now); + case UNPARKACTIVITY -> nextStateAfterUnParkActivity(oldAction, now); + case WALKFROMPARK -> nextStateAfterWalkFromPark(oldAction, now); + case WALKTOPARK -> nextStateAfterWalkToPark(oldAction, now); + }; - } + } protected DynAction nextStateAfterUnParkActivity(DynAction oldAction, double now) { // we have unparked, now we need to get going by car again. @@ -164,7 +157,9 @@ protected DynAction nextStateAfterUnParkActivity(DynAction oldAction, double now //this could be Car, Carsharing, Motorcylce, or whatever else mode we have, so we want our leg to reflect this. return new ParkingDynLeg(currentLeg.getMode(), actualRoute, parkingLogic, parkingManager, currentlyAssignedVehicleId, timer, events); - } else throw new RuntimeException("parking location mismatch"); + } else { + throw new RuntimeException("parking location mismatch"); + } } @@ -175,19 +170,25 @@ protected DynAction nextStateAfterWalkToPark(DynAction oldAction, double now) { } protected DynAction nextStateAfterWalkFromPark(DynAction oldAction, double now) { - //walkleg complete, time to get the next activity from the plan Elements and start it, this is basically the same as arriving on any other mode + //walkleg complete, time to get the next activity from the plan Elements and start it, this is basically the same as arriving on any other + // mode return nextStateAfterNonCarTrip(oldAction, now); } protected DynAction nextStateAfterParkActivity(DynAction oldAction, double now) { // add a walk leg after parking Leg currentPlannedLeg = (Leg) currentPlanElement; + + // yyyy I think we don't want LinkWrapperFacilities but the actual facilities. Right now, only calculates the teleportation from link to + // link, but if the parking happens on the same link as the activity, then it does not consider the coordinates. Thus, it produces a + // degenerated (0m and 0s) walk leg. paul, nov'24 Facility fromFacility = new LinkWrapperFacility(network.getLinks().get(agent.getCurrentLinkId())); Facility toFacility = new LinkWrapperFacility(network.getLinks().get(currentPlannedLeg.getRoute().getEndLinkId())); List walkTrip = walkRouter.calcRoute( DefaultRoutingRequest.withoutAttributes(fromFacility, toFacility, now, plan.getPerson())); if (walkTrip.size() != 1 || !(walkTrip.get(0) instanceof Leg walkLeg)) { - String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to access the network. Not implemented in parking yet!"; + String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to " + + "access the network. Not implemented in parking yet!"; log.error(message); throw new RuntimeException(message); } @@ -224,7 +225,9 @@ protected DynAction nextStateAfterCarTrip(DynAction oldAction, double now) { this.currentlyAssignedVehicleId = null; this.parkingLogic.reset(); return new IdleDynActivity(this.stageInteractionType, now + configGroup.getParkduration()); - } else throw new RuntimeException("No parking possible"); + } else { + throw new RuntimeException("No parking possible"); + } } protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { @@ -233,15 +236,22 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { planIndex++; this.currentPlanElement = plan.getPlanElements().get(planIndex); Leg currentLeg = (Leg) currentPlanElement; + + // yyyy can only handle car legs for parking :-( paul, nov'24 if (currentLeg.getMode().equals(TransportMode.car)) { Id vehicleId = Id.create(this.agent.getId(), Vehicle.class); Id parkLink = this.parkingManager.getVehicleParkingLocation(vehicleId); if (parkLink == null) { - //this is the first activity of a day and our parking manager does not provide informations about initial stages. We suppose the car is parked where we are + //this is the first activity of a day and our parking manager does not provide information about initial stages. We suppose the + // car is parked where we are parkLink = agent.getCurrentLinkId(); } + // yyyy I think we don't want LinkWrapperFacilities but the actual facilities. Right now, only calculates the teleportation from + // link to + // link, but if the parking happens on the same link as the activity, then it does not consider the coordinates. Thus, it produces a + // degenerated (0m and 0s) walk leg. paul, nov'24 Facility fromFacility = new LinkWrapperFacility(network.getLinks().get(agent.getCurrentLinkId())); Id teleportedParkLink = this.teleportationLogic.getVehicleLocation(agent.getCurrentLinkId(), vehicleId, parkLink, now, currentLeg.getMode()); @@ -249,7 +259,8 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { List walkTrip = walkRouter.calcRoute( DefaultRoutingRequest.withoutAttributes(fromFacility, toFacility, now, plan.getPerson())); if (walkTrip.size() != 1 || !(walkTrip.get(0) instanceof Leg walkLeg)) { - String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with non_network_walk to access the network. Not implemented in parking yet!"; + String message = "walkRouter returned something else than a single Leg, e.g. it routes walk on the network with " + + "non_network_walk to access the network. Not implemented in parking yet!"; log.error(message); throw new RuntimeException(message); } @@ -271,9 +282,11 @@ protected DynAction nextStateAfterActivity(DynAction oldAction, double now) { return new StaticPassengerDynLeg(currentLeg.getRoute(), currentLeg.getMode()); } - } else throw new RuntimeException( - "no more leg to follow but activity is ending\nLastPlanElement: " + currentPlanElement.toString() + "\n Agent " + this.agent.getId() + "\nTime: " + Time.writeTime( - now)); + } else { + throw new RuntimeException( + "no more leg to follow but activity is ending\nLastPlanElement: " + currentPlanElement.toString() + "\n Agent " + this.agent.getId() + + "\nTime: " + Time.writeTime(now)); + } } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/evaluation/ParkingListener.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/evaluation/ParkingListener.java deleted file mode 100644 index 41e370c8065..00000000000 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/evaluation/ParkingListener.java +++ /dev/null @@ -1,117 +0,0 @@ -/* *********************************************************************** * - * project: org.matsim.* - * * - * *********************************************************************** * - * * - * copyright : (C) 2016 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.contrib.parking.parkingsearch.evaluation; - - -import com.google.inject.Inject; -import org.matsim.contrib.parking.parkingsearch.manager.FacilityBasedParkingManager; -import org.matsim.contrib.parking.parkingsearch.manager.ParkingSearchManager; -import org.matsim.core.controler.OutputDirectoryHierarchy; -import org.matsim.core.controler.events.IterationEndsEvent; -import org.matsim.core.controler.listener.IterationEndsListener; -import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent; -import org.matsim.core.mobsim.framework.events.MobsimInitializedEvent; -import org.matsim.core.mobsim.framework.listeners.MobsimBeforeSimStepListener; -import org.matsim.core.mobsim.framework.listeners.MobsimInitializedListener; -import org.matsim.core.mobsim.qsim.QSim; -import org.matsim.core.utils.io.IOUtils; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.List; - -/** - * @author jbischoff - * - */ - -public class ParkingListener implements IterationEndsListener, MobsimBeforeSimStepListener, MobsimInitializedListener { - - @Inject - ParkingSearchManager manager; - @Inject - OutputDirectoryHierarchy output; - - /* (non-Javadoc) - * @see org.matsim.core.controler.listener.IterationEndsListener#notifyIterationEnds(org.matsim.core.controler.events.IterationEndsEvent) - */ - @Override - public void notifyIterationEnds(IterationEndsEvent event) { - writeStats(manager.produceStatistics(), event.getIteration()); - writeStatsByTimesteps(((FacilityBasedParkingManager)manager).produceTimestepsStatistics(), event.getIteration()); - manager.reset(event.getIteration()); - } - - private void writeStatsByTimesteps(List produceBeneStatistics, int iteration) { - BufferedWriter bw = IOUtils.getBufferedWriter(output.getIterationFilename(iteration, "parkingStatsPerTimeSteps.csv")); - try { - - String header = "time;rejectedParkingRequest;foundParking;unpark"; - bw.write(header); - bw.newLine(); - for (String s : produceBeneStatistics){ - bw.write(s); - bw.newLine(); - } - bw.flush(); - bw.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - /** - * @param produceStatistics - */ - private void writeStats(List produceStatistics, int iteration) { - BufferedWriter bw = IOUtils.getBufferedWriter(output.getIterationFilename(iteration, "parkingStats.csv")); - try { - - String header = "linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn"; - bw.write(header); - bw.newLine(); - for (String s : produceStatistics){ - bw.write(s); - bw.newLine(); - } - bw.flush(); - bw.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - - } - - @Override - public void notifyMobsimBeforeSimStep(MobsimBeforeSimStepEvent event) { - ((FacilityBasedParkingManager) manager).checkFreeCapacitiesForWaitingVehicles((QSim) event.getQueueSimulation(), event.getSimulationTime()); - } - - @Override - public void notifyMobsimInitialized(final MobsimInitializedEvent e) { - QSim qSim = (QSim) e.getQueueSimulation(); - ((FacilityBasedParkingManager) manager).setQSim(qSim); - - } -} diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java index 9b3b8eff107..8c8491381c3 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java @@ -22,231 +22,232 @@ import com.google.inject.Inject; import org.apache.commons.lang3.mutable.MutableLong; 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.api.core.v01.network.Network; import org.matsim.contrib.dynagent.DynAgent; import org.matsim.contrib.parking.parkingsearch.ParkingUtils; import org.matsim.contrib.parking.parkingsearch.sim.ParkingSearchConfigGroup; +import org.matsim.core.controler.events.IterationEndsEvent; +import org.matsim.core.gbl.Gbl; +import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent; +import org.matsim.core.mobsim.framework.events.MobsimInitializedEvent; import org.matsim.core.mobsim.qsim.QSim; import org.matsim.core.utils.misc.Time; import org.matsim.facilities.ActivityFacility; import org.matsim.facilities.ActivityOption; +import org.matsim.facilities.OpeningTime; import org.matsim.vehicles.Vehicle; import java.util.*; import java.util.Map.Entry; /** + * Manages vehicles parking actions at facilities or freely on the street. I.e. keeps track of the capacity of the facilities. This class has + * additional functionality: + * - It can handle parking reservations. + * - It triggers reporting of parking statistics. + * - It can handle vehicles waiting for a parking space. * + * * @author jbischoff, schlenther, Ricardo Ewert */ public class FacilityBasedParkingManager implements ParkingSearchManager { + private static final Logger logger = LogManager.getLogger(FacilityBasedParkingManager.class); + private static final int REPORTING_TIME_BIN_SIZE = 15 * 60; + + protected Map, ParkingFacilityInfo> infoByFacilityId = new HashMap<>(); + + protected Map, TreeMap>> waitingVehiclesByLinkId = new HashMap<>(); + protected Map, ActivityFacility> parkingFacilitiesById; + protected Map, Id> parkingFacilityLocationByVehicleId = new HashMap<>(); + protected Map, Id> parkingReservationByVehicleId = new HashMap<>(); + //stores the parking location of vehicles that are parked outside of facilities (e.g. at the side of a link. therefore, there are no capacity + // checks) + protected Map, Id> freeParkingLinkByVehicleId = new HashMap<>(); + protected Map, Set>> parkingFacilitiesByLink = new HashMap<>(); + protected ParkingSearchConfigGroup psConfigGroup; + private QSim qsim; - protected Map, Integer> capacity = new HashMap<>(); - protected Map, MutableLong> occupation = new HashMap<>(); - protected Map, MutableLong> reservationsRequests = new HashMap<>(); - protected Map, MutableLong> rejectedParkingRequest = new HashMap<>(); - protected Map, MutableLong> numberOfParkedVehicles = new HashMap<>(); - protected Map, MutableLong> numberOfWaitingActivities = new HashMap<>(); - protected Map, MutableLong> numberOfStaysFromGetOffUntilGetIn = new HashMap<>(); - protected Map, MutableLong> numberOfParkingBeforeGetIn = new HashMap<>(); - protected Map, TreeMap>> waitingVehicles = new HashMap<>(); + //The following maps are used for reporting + @Inject + private ParkingStatsWriter writer; protected TreeMap rejectedReservationsByTime = new TreeMap<>(); protected TreeMap foundParkingByTime = new TreeMap<>(); protected TreeMap unparkByTime = new TreeMap<>(); - protected Map, ActivityFacility> parkingFacilities; - protected Map, Id> parkingLocations = new HashMap<>(); - protected Map, Id> parkingReservation = new HashMap<>(); - protected Map, Id> parkingLocationsOutsideFacilities = new HashMap<>(); - protected Map, Set>> facilitiesPerLink = new HashMap<>(); - protected Network network; - protected ParkingSearchConfigGroup psConfigGroup; - protected boolean canParkOnlyAtFacilities; - private QSim qsim; - private final int maxSlotIndex; - private final int maxTime; - private final int timeBinSize; - private final int startTime; + private int reportingMaxSlotIndex; + private int reportingMaxTime; @Inject public FacilityBasedParkingManager(Scenario scenario) { - psConfigGroup = (ParkingSearchConfigGroup) scenario.getConfig().getModules().get( - ParkingSearchConfigGroup.GROUP_NAME); - canParkOnlyAtFacilities = psConfigGroup.getCanParkOnlyAtFacilities(); - this.network = scenario.getNetwork(); - parkingFacilities = scenario.getActivityFacilities() - .getFacilitiesForActivityType(ParkingUtils.ParkingStageInteractionType); - LogManager.getLogger(getClass()).info(parkingFacilities.toString()); - this.timeBinSize = 15 * 60; - this.maxTime = 24 * 3600 - 1; - this.maxSlotIndex = (this.maxTime / this.timeBinSize) + 1; - this.startTime = 9 * 3600; - - for (ActivityFacility fac : this.parkingFacilities.values()) { - Id linkId = fac.getLinkId(); - Set> parkingOnLink = new HashSet<>(); - if (this.facilitiesPerLink.containsKey(linkId)) { - parkingOnLink = this.facilitiesPerLink.get(linkId); - } - parkingOnLink.add(fac.getId()); - this.facilitiesPerLink.put(linkId, parkingOnLink); - this.waitingVehicles.computeIfAbsent(linkId, (k) -> new TreeMap<>()); - this.occupation.put(fac.getId(), new MutableLong(0)); - this.reservationsRequests.put(fac.getId(), new MutableLong(0)); - this.rejectedParkingRequest.put(fac.getId(), new MutableLong(0)); - this.numberOfParkedVehicles.put(fac.getId(), new MutableLong(0)); - this.numberOfWaitingActivities.put(fac.getId(), new MutableLong(0)); - this.numberOfStaysFromGetOffUntilGetIn.put(fac.getId(), new MutableLong(0)); - this.numberOfParkingBeforeGetIn.put(fac.getId(), new MutableLong(0)); - } - int slotIndex = getTimeSlotIndex(startTime); - while (slotIndex <= maxSlotIndex) { - rejectedReservationsByTime.put(slotIndex * timeBinSize, new MutableLong(0)); - foundParkingByTime.put(slotIndex * timeBinSize, new MutableLong(0)); - unparkByTime.put(slotIndex * timeBinSize, new MutableLong(0)); - slotIndex++; + psConfigGroup = (ParkingSearchConfigGroup) scenario.getConfig().getModules().get(ParkingSearchConfigGroup.GROUP_NAME); + parkingFacilitiesById = scenario.getActivityFacilities().getFacilitiesForActivityType(ParkingUtils.ParkingStageInteractionType); + + logger.info(parkingFacilitiesById.toString()); + + for (ActivityFacility fac : this.parkingFacilitiesById.values()) { + initParkingFacility(fac); } + + initReporting(scenario); } - @Override - public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId) { - boolean canPark = false; + private void initReporting(Scenario scenario) { + this.reportingMaxTime = (int) scenario.getConfig().qsim().getEndTime().seconds(); + this.reportingMaxSlotIndex = (this.reportingMaxTime / REPORTING_TIME_BIN_SIZE) + 1; + } - if (linkIdHasAvailableParkingForVehicle(linkId, vehicleId)) { - canPark = true; - // LogManager.getLogger(getClass()).info("veh: "+vehicleId+" link - // "+linkId + " can park "+canPark); - } + private void initParkingFacility(ActivityFacility fac) { + Id linkId = fac.getLinkId(); + Set> parkingOnLink = parkingFacilitiesByLink.getOrDefault(linkId, new HashSet<>()); + parkingOnLink.add(fac.getId()); + this.parkingFacilitiesByLink.put(linkId, parkingOnLink); + this.waitingVehiclesByLinkId.put(linkId, new TreeMap<>()); - return canPark; + ActivityOption activityOption = fac.getActivityOptions().get(ParkingUtils.ParkingStageInteractionType); + this.infoByFacilityId.put(fac.getId(), new ParkingFacilityInfo(activityOption)); + } + + @Override + public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId) { + return linkIdHasAvailableParkingForVehicle(linkId, vehicleId); } /** * Checks if it is possible if you can park at this link for the complete time. - * - * @param linkId - * @param stopDuration - * @param getOffDuration - * @param pickUpDuration - * @param now - * @return */ - public boolean canParkAtThisFacilityUntilEnd(Id linkId, double stopDuration, double getOffDuration, double pickUpDuration, double now) { - Set> facilities = this.facilitiesPerLink.get(linkId); - if (facilities != null) { - double totalNeededParkingDuration = getOffDuration + stopDuration + pickUpDuration; - for (Id facility : facilities) { - double maxParkingDurationAtFacilityInHours = Double.MAX_VALUE; - if (this.parkingFacilities.get(facility).getAttributes().getAsMap().containsKey("maxParkingDurationInHours")) - maxParkingDurationAtFacilityInHours = 3600 * (double) this.parkingFacilities.get(facility).getAttributes().getAsMap().get( - "maxParkingDurationInHours"); - if (maxParkingDurationAtFacilityInHours > totalNeededParkingDuration) { - ActivityOption parkingOptions = this.parkingFacilities.get(facility).getActivityOptions().get("parking"); - if (!parkingOptions.getOpeningTimes().isEmpty()) { - if ((parkingOptions.getOpeningTimes().first().getStartTime() == 0 && parkingOptions.getOpeningTimes().first().getEndTime() == 24 * 3600)) - if (parkingOptions.getOpeningTimes().first().getStartTime() <= now && parkingOptions.getOpeningTimes().first().getEndTime() >= now + totalNeededParkingDuration) - return true; - } else - return true; + public boolean canParkAtThisFacilityUntilEnd(Id linkId, double now, double getOffDuration, double stopDuration, double pickUpDuration) { + Set> facilities = this.parkingFacilitiesByLink.get(linkId); + if (facilities == null) { + //TODO really? if there is no facility we assume free parking with no time constraint. + return false; + } + double totalDuration = getOffDuration + stopDuration + pickUpDuration; + for (Id facility : facilities) { + double maxParkingDurationAtFacilityInSeconds = + Optional.ofNullable(this.parkingFacilitiesById.get(facility).getAttributes().getAsMap().get("maxParkingDurationInHours")) + .map(attribute -> 3600 * (double) attribute).orElse(Double.MAX_VALUE); + + if (maxParkingDurationAtFacilityInSeconds < totalDuration) { + //Parking duration is limited, so we can't park here. + return false; + } + + ActivityOption parkingOptions = this.infoByFacilityId.get(facility).activityOption; + if (parkingOptions.getOpeningTimes().isEmpty()) { + //No opening times defined, so we can park here. + return true; + } + + OpeningTime firstOpeningTimes = parkingOptions.getOpeningTimes().first(); + //TODO do we really want this constraint? if parking facility has other opening times than 0-24, we can't park here. + if ((firstOpeningTimes.getStartTime() == 0 && firstOpeningTimes.getEndTime() == 24 * 3600)) { + if (firstOpeningTimes.getStartTime() <= now && firstOpeningTimes.getEndTime() >= now + totalDuration) { + //Parking facility is open for the complete duration, so we can park here. + return true; } } + } + //No parking facility is open for the complete duration, so we can't park here. return false; } + /** + * Either parks the vehicle at a link freely (no capacity constraint) or at a facility (capacity constraint). + */ private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id vid) { - // LogManager.getLogger(getClass()).info("link "+linkId+" vehicle "+vid); - if (!this.facilitiesPerLink.containsKey(linkId) && !canParkOnlyAtFacilities) { - // this implies: If no parking facility is present, we suppose that - // we can park freely (i.e. the matsim standard approach) - // it also means: a link without any parking spaces should have a - // parking facility with 0 capacity. - // LogManager.getLogger(getClass()).info("link not listed as parking - // space, we will say yes "+linkId); - - return true; - } else if (!this.facilitiesPerLink.containsKey(linkId)) { - return false; + if (!this.parkingFacilitiesByLink.containsKey(linkId)) { + // No parking facility at this link. Either parking is allowed only at facilities or not. + // If not, we can park freely, so link has available parking. (MATSim standard approach) + // If yes, we can't park here. + return !psConfigGroup.getCanParkOnlyAtFacilities(); } - Set> parkingFacilitiesAtLink = this.facilitiesPerLink.get(linkId); + Set> parkingFacilitiesAtLink = this.parkingFacilitiesByLink.get(linkId); for (Id fac : parkingFacilitiesAtLink) { - double cap = this.parkingFacilities.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) - .getCapacity(); - this.reservationsRequests.get(fac).increment(); - if (this.occupation.get(fac).doubleValue() < cap) { - // LogManager.getLogger(getClass()).info("occ: - // "+this.occupation.get(fac).toString()+" cap: "+cap); - this.occupation.get(fac).increment(); - this.parkingReservation.put(vid, fac); - + if (this.infoByFacilityId.get(fac).park()) { + this.parkingReservationByVehicleId.put(vid, fac); return true; } - this.rejectedParkingRequest.get(fac).increment(); } return false; } @Override public Id getVehicleParkingLocation(Id vehicleId) { - if (this.parkingLocations.containsKey(vehicleId)) { - return this.parkingFacilities.get(this.parkingLocations.get(vehicleId)).getLinkId(); - } else return this.parkingLocationsOutsideFacilities.getOrDefault(vehicleId, null); + if (this.parkingFacilityLocationByVehicleId.containsKey(vehicleId)) { + //parked at facility + return this.parkingFacilitiesById.get(this.parkingFacilityLocationByVehicleId.get(vehicleId)).getLinkId(); + } else { + //parked freely + return this.freeParkingLinkByVehicleId.getOrDefault(vehicleId, null); + } } + /** + * Parks a vehicle at a link. Either freely outside a facility or at a facility. + */ @Override public boolean parkVehicleHere(Id vehicleId, Id linkId, double time) { return parkVehicleAtLink(vehicleId, linkId, time); } protected boolean parkVehicleAtLink(Id vehicleId, Id linkId, double time) { - Set> parkingFacilitiesAtLink = this.facilitiesPerLink.get(linkId); + Set> parkingFacilitiesAtLink = this.parkingFacilitiesByLink.get(linkId); if (parkingFacilitiesAtLink == null) { - this.parkingLocationsOutsideFacilities.put(vehicleId, linkId); + //park freely + this.freeParkingLinkByVehicleId.put(vehicleId, linkId); return true; - } else { - Id fac = this.parkingReservation.remove(vehicleId); - if (fac != null) { - this.parkingLocations.put(vehicleId, fac); - this.numberOfParkedVehicles.get(fac).increment(); - foundParkingByTime.get(getTimeSlotIndex(time) * timeBinSize).increment(); - return true; - } else { - throw new RuntimeException("no parking reservation found for vehicle " + vehicleId.toString() - + " arrival on link " + linkId + " with parking restriction"); - } } + //park at facility + return parkVehicleInReservedFacility(vehicleId, linkId, time); + } + + private boolean parkVehicleInReservedFacility(Id vehicleId, Id linkId, double time) { + Id fac = this.parkingReservationByVehicleId.remove(vehicleId); + if (fac == null) { + throw new RuntimeException("no parking reservation found for vehicle " + vehicleId.toString() + + " arrival on link " + linkId + " with parking restriction"); + } + + Gbl.assertIf(parkingFacilitiesById.get(fac).getLinkId().equals(linkId)); + + this.parkingFacilityLocationByVehicleId.put(vehicleId, fac); + reportParking(time, fac); + return true; } + /** + * Unparks vehicle from a link. Either freely outside a facility or at a facility. + */ @Override public boolean unParkVehicleHere(Id vehicleId, Id linkId, double time) { - if (!this.parkingLocations.containsKey(vehicleId)) { - this.parkingLocationsOutsideFacilities.remove(vehicleId); - return true; - - // we assume the person parks somewhere else + if (!this.parkingFacilityLocationByVehicleId.containsKey(vehicleId)) { + //unpark freely + this.freeParkingLinkByVehicleId.remove(vehicleId); } else { - Id fac = this.parkingLocations.remove(vehicleId); - this.occupation.get(fac).decrement(); - unparkByTime.get(getTimeSlotIndex(time) * timeBinSize).increment(); - return true; + //unpark at facility + Id fac = this.parkingFacilityLocationByVehicleId.remove(vehicleId); + reportUnParking(time, fac); } + return true; } - @Override - public List produceStatistics() { + private List produceStatistics() { List stats = new ArrayList<>(); - for (Entry, MutableLong> e : this.occupation.entrySet()) { - Id linkId = this.parkingFacilities.get(e.getKey()).getLinkId(); - double capacity = this.parkingFacilities.get(e.getKey()).getActivityOptions() - .get(ParkingUtils.ParkingStageInteractionType).getCapacity(); - double x = this.parkingFacilities.get(e.getKey()).getCoord().getX(); - double y = this.parkingFacilities.get(e.getKey()).getCoord().getY(); - - String s = linkId.toString() + ";" + x + ";" + y + ";" + e.getKey().toString() + ";" + capacity + ";" + e.getValue().toString() + ";" + this.reservationsRequests.get( - e.getKey()).toString() + ";" + this.numberOfParkedVehicles.get(e.getKey()).toString() + ";" + this.rejectedParkingRequest.get( - e.getKey()).toString() + ";" + this.numberOfWaitingActivities.get( - e.getKey()).toString() + ";" + this.numberOfStaysFromGetOffUntilGetIn.get(e.getKey()).intValue() + ";" + this.numberOfParkingBeforeGetIn.get(e.getKey()).intValue(); + for (Entry, ParkingFacilityInfo> e : this.infoByFacilityId.entrySet()) { + Id linkId = this.parkingFacilitiesById.get(e.getKey()).getLinkId(); + double capacity = this.parkingFacilitiesById.get(e.getKey()).getActivityOptions() + .get(ParkingUtils.ParkingStageInteractionType).getCapacity(); + double x = this.parkingFacilitiesById.get(e.getKey()).getCoord().getX(); + double y = this.parkingFacilitiesById.get(e.getKey()).getCoord().getY(); + + String facilityId = e.getKey().toString(); + ParkingFacilityInfo info = e.getValue(); + String s = + linkId.toString() + ";" + x + ";" + y + ";" + facilityId + ";" + capacity + ";" + info.occupation + ";" + info.reservationRequests + + ";" + info.parkedVehiclesCount + ";" + info.rejectedParkingRequests + ";" + info.waitingActivitiesCount + ";" + + info.staysFromGetOffUntilGetIn + ";" + info.parkingBeforeGetInCount; stats.add(s); } return stats; @@ -266,10 +267,10 @@ public List produceTimestepsStatistics() { public double getNrOfAllParkingSpacesOnLink(Id linkId) { double allSpaces = 0; - Set> parkingFacilitiesAtLink = this.facilitiesPerLink.get(linkId); + Set> parkingFacilitiesAtLink = this.parkingFacilitiesByLink.get(linkId); if (!(parkingFacilitiesAtLink == null)) { for (Id fac : parkingFacilitiesAtLink) { - allSpaces += this.parkingFacilities.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType).getCapacity(); + allSpaces += this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType).getCapacity(); } } return allSpaces; @@ -277,97 +278,89 @@ public double getNrOfAllParkingSpacesOnLink(Id linkId) { public double getNrOfFreeParkingSpacesOnLink(Id linkId) { double allFreeSpaces = 0; - Set> parkingFacilitiesAtLink = this.facilitiesPerLink.get(linkId); + Set> parkingFacilitiesAtLink = this.parkingFacilitiesByLink.get(linkId); if (parkingFacilitiesAtLink == null) { return 0; } else { for (Id fac : parkingFacilitiesAtLink) { - int cap = (int) this.parkingFacilities.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType).getCapacity(); - allFreeSpaces += (cap - this.occupation.get(fac).intValue()); + int cap = (int) this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType).getCapacity(); + allFreeSpaces += (cap - this.infoByFacilityId.get(fac).occupation); } } return allFreeSpaces; } - public Map, ActivityFacility> getParkingFacilities() { - return this.parkingFacilities; + public Map, ActivityFacility> getParkingFacilitiesById() { + return this.parkingFacilitiesById; } public void registerRejectedReservation(double now) { - rejectedReservationsByTime.get(getTimeSlotIndex(now) * timeBinSize).increment(); - } - - public TreeSet getTimeSteps() { - TreeSet timeSteps = new TreeSet<>(); - int slotIndex = 0; - while (slotIndex <= maxSlotIndex) { - timeSteps.add(slotIndex * timeBinSize); - slotIndex++; - } - return timeSteps; + rejectedReservationsByTime.putIfAbsent(getTimeSlotIndex(now) * REPORTING_TIME_BIN_SIZE, new MutableLong(0)); + rejectedReservationsByTime.get(getTimeSlotIndex(now) * REPORTING_TIME_BIN_SIZE).increment(); } private int getTimeSlotIndex(final double time) { - if (time > this.maxTime) { - return this.maxSlotIndex; + if (time > this.reportingMaxTime) { + return this.reportingMaxSlotIndex; } - return ((int) time / this.timeBinSize); + return ((int) time / REPORTING_TIME_BIN_SIZE); } /** - * Gives the duration of the staging activity of parking - * - * @return + * Returns the duration of the staging activity of parking */ public double getParkStageActivityDuration() { return psConfigGroup.getParkduration(); } - /** - * Gives the duration of the staging activity of unparking - * - * @return - */ - public double getUnParkStageActivityDuration() { - return psConfigGroup.getUnparkduration(); - } - @Override public void reset(int iteration) { - for (Id fac : this.rejectedParkingRequest.keySet()) { - this.rejectedParkingRequest.get(fac).setValue(0); - this.reservationsRequests.get(fac).setValue(0); - this.numberOfParkedVehicles.get(fac).setValue(0); - this.numberOfWaitingActivities.get(fac).setValue(0); - } - waitingVehicles.clear(); + infoByFacilityId.replaceAll((k, v) -> new ParkingFacilityInfo(v.activityOption)); + waitingVehiclesByLinkId.clear(); } public void addVehicleForWaitingForParking(Id linkId, Id vehicleId, double now) { // System.out.println(now + ": vehicle " +vehicleId.toString() + " starts waiting here: " + linkId.toString()); - waitingVehicles.get(linkId).put(now + getParkStageActivityDuration() + 1, vehicleId); - for (Id fac : this.facilitiesPerLink.get(linkId)) { - this.numberOfWaitingActivities.get(fac).increment(); + waitingVehiclesByLinkId.get(linkId).put(now + getParkStageActivityDuration() + 1, vehicleId); + for (Id fac : this.parkingFacilitiesByLink.get(linkId)) { + this.infoByFacilityId.get(fac).waitingActivitiesCount++; break; } } + //@formatter:off + /** + * For all links l with waiting vehicles: + * For all facilities f located at l: + * While there is a free capacity at f and there are waiting vehicles: + * Remove the first waiting vehicle from the list of waiting vehicles. + * Reserve a parking space for this vehicle. + * End the activity of the vehicle. + * Reschedule the activity end of the vehicle. + * + */ + //@formatter:on public void checkFreeCapacitiesForWaitingVehicles(QSim qSim, double now) { - for (Id linkId : waitingVehicles.keySet()) { - if (!waitingVehicles.get(linkId).isEmpty()) { - for (Id fac : this.facilitiesPerLink.get(linkId)) { - int cap = (int) this.parkingFacilities.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType).getCapacity(); - while (this.occupation.get(fac).intValue() < cap && !waitingVehicles.get(linkId).isEmpty()) { - double startWaitingTime = waitingVehicles.get(linkId).firstKey(); - if (startWaitingTime > now) - break; - Id vehcileId = waitingVehicles.get(linkId).remove(startWaitingTime); - DynAgent agent = (DynAgent) qSim.getAgents().get(Id.createPersonId(vehcileId.toString())); - reserveSpaceIfVehicleCanParkHere(vehcileId, linkId); - agent.endActivityAndComputeNextState(now); - qsim.rescheduleActivityEnd(agent); + for (Id linkId : waitingVehiclesByLinkId.keySet()) { + TreeMap> vehicleIdByTime = waitingVehiclesByLinkId.get(linkId); + if (vehicleIdByTime.isEmpty()) { + break; + } + for (Id fac : this.parkingFacilitiesByLink.get(linkId)) { + int capacity = (int) this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) + .getCapacity(); + + while (this.infoByFacilityId.get(fac).occupation < capacity && !vehicleIdByTime.isEmpty()) { + double startWaitingTime = vehicleIdByTime.firstKey(); + if (startWaitingTime > now) { + break; } + Id vehcileId = vehicleIdByTime.remove(startWaitingTime); + DynAgent agent = (DynAgent) qSim.getAgents().get(Id.createPersonId(vehcileId.toString())); + reserveSpaceIfVehicleCanParkHere(vehcileId, linkId); + agent.endActivityAndComputeNextState(now); + qsim.rescheduleActivityEnd(agent); } } } @@ -378,10 +371,69 @@ public void setQSim(QSim qSim) { } public void registerStayFromGetOffUntilGetIn(Id vehcileId) { - this.numberOfStaysFromGetOffUntilGetIn.get(parkingLocations.get(vehcileId)).increment(); + infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).staysFromGetOffUntilGetIn++; } public void registerParkingBeforeGetIn(Id vehcileId) { - this.numberOfParkingBeforeGetIn.get(parkingLocations.get(vehcileId)).increment(); + this.infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).parkingBeforeGetInCount++; + } + + private void reportParking(double time, Id fac) { + this.infoByFacilityId.get(fac).parkedVehiclesCount++; + int timeSlot = getTimeSlotIndex(time) * REPORTING_TIME_BIN_SIZE; + foundParkingByTime.putIfAbsent(timeSlot, new MutableLong(0)); + foundParkingByTime.get(timeSlot).increment(); + } + + private void reportUnParking(double time, Id fac) { + this.infoByFacilityId.get(fac).occupation--; + int timeSlot = getTimeSlotIndex(time) * REPORTING_TIME_BIN_SIZE; + unparkByTime.putIfAbsent(timeSlot, new MutableLong(0)); + unparkByTime.get(timeSlot).increment(); + } + + @Override + public void notifyIterationEnds(IterationEndsEvent event) { + writer.writeStatsByFacility(produceStatistics(), event.getIteration()); + writer.writeStatsByTimesteps(produceTimestepsStatistics(), event.getIteration()); + reset(event.getIteration()); + } + + + @Override + public void notifyMobsimBeforeSimStep(MobsimBeforeSimStepEvent event) { + checkFreeCapacitiesForWaitingVehicles((QSim) event.getQueueSimulation(), event.getSimulationTime()); + } + + @Override + public void notifyMobsimInitialized(final MobsimInitializedEvent e) { + QSim qSim = (QSim) e.getQueueSimulation(); + setQSim(qSim); + } + + protected static class ParkingFacilityInfo { + protected long occupation = 0; + protected final ActivityOption activityOption; + protected long reservationRequests = 0; + protected long rejectedParkingRequests = 0; + protected long parkedVehiclesCount = 0; + protected long waitingActivitiesCount = 0; + protected long staysFromGetOffUntilGetIn = 0; + protected long parkingBeforeGetInCount = 0; + + ParkingFacilityInfo(ActivityOption activityOption) { + this.activityOption = activityOption; + } + + protected boolean park() { + reservationRequests++; + //TODO check double vs long + if (occupation >= activityOption.getCapacity()) { + rejectedParkingRequests++; + return false; + } + occupation++; + return true; + } } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/LinkLengthBasedParkingManagerWithRandomInitialUtilisation.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/LinkLengthBasedParkingManagerWithRandomInitialUtilisation.java index 5600260ec7a..56f75d97d14 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/LinkLengthBasedParkingManagerWithRandomInitialUtilisation.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/LinkLengthBasedParkingManagerWithRandomInitialUtilisation.java @@ -19,42 +19,43 @@ package org.matsim.contrib.parking.parkingsearch.manager; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - import jakarta.inject.Inject; - import org.apache.commons.lang3.mutable.MutableLong; 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.Config; +import org.matsim.core.controler.events.IterationEndsEvent; import org.matsim.core.gbl.MatsimRandom; +import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent; +import org.matsim.core.mobsim.framework.events.MobsimInitializedEvent; import org.matsim.vehicles.Vehicle; +import java.util.*; + /** - * @author jbischoff - * + * @author jbischoff */ public class LinkLengthBasedParkingManagerWithRandomInitialUtilisation implements ParkingSearchManager { - Map,Integer> capacity = new HashMap<>(); - Map,MutableLong> occupation = new HashMap<>(); - Map,Id> parkingPosition = new HashMap<>(); + Map, Integer> capacity = new HashMap<>(); + Map, MutableLong> occupation = new HashMap<>(); + Map, Id> parkingPosition = new HashMap<>(); Random rand = MatsimRandom.getLocalInstance(); int parkedVehicles = 0; int unparkedVehicles = 0; + + @Inject + private ParkingStatsWriter writer; + @Inject public LinkLengthBasedParkingManagerWithRandomInitialUtilisation(Network network, Config config) { - double assumedParkedVehicleLength = 4.0; - double shareOfLinkLengthUsedForParking = 0.7; + double assumedParkedVehicleLength = 4.0; + double shareOfLinkLengthUsedForParking = 0.7; - //TODO: Make this configurable - for (Link link : network.getLinks().values()){ - int maxCapacity = (int) (link.getLength()*shareOfLinkLengthUsedForParking / assumedParkedVehicleLength); + //TODO: Make this configurable + for (Link link : network.getLinks().values()) { + int maxCapacity = (int) (link.getLength() * shareOfLinkLengthUsedForParking / assumedParkedVehicleLength); this.capacity.put(link.getId(), maxCapacity); this.occupation.put(link.getId(), new MutableLong(rand.nextInt(maxCapacity))); @@ -63,7 +64,7 @@ public LinkLengthBasedParkingManagerWithRandomInitialUtilisation(Network network @Override public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId) { - return (this.occupation.get(linkId).intValue() getVehicleParkingLocation(Id vehicleId) { @Override public boolean parkVehicleHere(Id vehicleId, Id linkId, double time) { - if (this.occupation.get(linkId).intValue() vehicleId, Id linkId, double time) { - if (!linkId.equals(this.parkingPosition.get(vehicleId))) return false; - else { + if (!linkId.equals(this.parkingPosition.get(vehicleId))) { + return false; + } else { this.parkingPosition.remove(vehicleId); this.occupation.get(linkId).decrement(); unparkedVehicles++; @@ -95,11 +99,10 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double } - @Override public List produceStatistics() { List stats = new ArrayList<>(); - stats.add("parking occurences: "+ parkedVehicles); - stats.add("unparking occurences: "+ unparkedVehicles); + stats.add("parking occurences: " + parkedVehicles); + stats.add("unparking occurences: " + unparkedVehicles); return stats; } @@ -107,6 +110,18 @@ public List produceStatistics() { public void reset(int iteration) { } + @Override + public void notifyIterationEnds(IterationEndsEvent event) { + writer.writePlainStats(produceStatistics(), event.getIteration()); + } + + @Override + public void notifyMobsimBeforeSimStep(MobsimBeforeSimStepEvent e) { + } + + @Override + public void notifyMobsimInitialized(MobsimInitializedEvent e) { + } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingSearchManager.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingSearchManager.java index 7bdd6fb37c2..3cb029157f8 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingSearchManager.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingSearchManager.java @@ -19,25 +19,27 @@ package org.matsim.contrib.parking.parkingsearch.manager; -import java.util.List; - import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; +import org.matsim.core.controler.listener.IterationEndsListener; +import org.matsim.core.mobsim.framework.listeners.MobsimBeforeSimStepListener; +import org.matsim.core.mobsim.framework.listeners.MobsimInitializedListener; import org.matsim.vehicles.Vehicle; /** - * @author jbischoff - * + * @author jbischoff */ -public interface ParkingSearchManager { +public interface ParkingSearchManager extends IterationEndsListener, MobsimBeforeSimStepListener, MobsimInitializedListener { boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId); + Id getVehicleParkingLocation(Id vehicleId); + boolean parkVehicleHere(Id vehicleId, Id linkId, double time); + boolean unParkVehicleHere(Id vehicleId, Id linkId, double time); - - List produceStatistics(); + void reset(int iteration); - - + + } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingStatsWriter.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingStatsWriter.java new file mode 100644 index 00000000000..9b929dc53c3 --- /dev/null +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingStatsWriter.java @@ -0,0 +1,74 @@ +package org.matsim.contrib.parking.parkingsearch.manager; + +import com.google.inject.Inject; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.utils.io.IOUtils; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; + +//the functionality of this class is mainly copied from old ParkingListener and could be improved +public class ParkingStatsWriter { + @Inject + OutputDirectoryHierarchy output; + + public void writeStatsByTimesteps(List produceBeneStatistics, int iteration) { + BufferedWriter bw = IOUtils.getBufferedWriter(output.getIterationFilename(iteration, "parkingStatsPerTimeSteps.csv")); + try { + + String header = "time;rejectedParkingRequest;foundParking;unpark"; + bw.write(header); + bw.newLine(); + for (String s : produceBeneStatistics) { + bw.write(s); + bw.newLine(); + } + bw.flush(); + bw.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + /** + * @param produceStatistics + */ + public void writeStatsByFacility(List produceStatistics, int iteration) { + BufferedWriter bw = IOUtils.getBufferedWriter(output.getIterationFilename(iteration, "parkingStats.csv")); + try { + + String header = "linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;" + + "numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn"; + bw.write(header); + bw.newLine(); + for (String s : produceStatistics) { + bw.write(s); + bw.newLine(); + } + bw.flush(); + bw.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void writePlainStats(List produceStatistics, int iteration) { + BufferedWriter bw = IOUtils.getBufferedWriter(output.getIterationFilename(iteration, "parkingStats.txt")); + try { + for (String s : produceStatistics) { + bw.write(s); + bw.newLine(); + } + bw.flush(); + bw.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ZoneParkingManager.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ZoneParkingManager.java index b9fbebe4699..5dc503ac08a 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ZoneParkingManager.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ZoneParkingManager.java @@ -19,13 +19,16 @@ import java.util.Set; /** + * Extends the facility based manager, thus parks vehicles at facilities but also keeps track of the occupancy of zones. A zone is defined by a set + * of links. + * * @author tschlenther */ public class ZoneParkingManager extends FacilityBasedParkingManager { - private HashMap>> linksOfZone; - private HashMap totalCapOfZone; - private HashMap occupationOfZone; + private final HashMap>> linksByZone; + private final HashMap totalCapByZone; + private final HashMap occupationByZone; /** * @param scenario @@ -34,17 +37,17 @@ public class ZoneParkingManager extends FacilityBasedParkingManager { public ZoneParkingManager(Scenario scenario, String[] pathToZoneTxtFiles) { super(scenario); - this.linksOfZone = new HashMap>>(); - this.totalCapOfZone = new HashMap(); - this.occupationOfZone = new HashMap(); + this.linksByZone = new HashMap>>(); + this.totalCapByZone = new HashMap(); + this.occupationByZone = new HashMap(); for (String zone : pathToZoneTxtFiles) { readZone(zone); } - for (String zone : this.linksOfZone.keySet()) { + for (String zone : this.linksByZone.keySet()) { calculateTotalZoneParkCapacity(zone); - this.occupationOfZone.put(zone, 0.0); + this.occupationByZone.put(zone, 0.0); } } @@ -52,6 +55,7 @@ public ZoneParkingManager(Scenario scenario, String[] pathToZoneTxtFiles) { /** * reads in a tabular file that declares which link id's are in the monitored zone * the part between the last '/' and the file type extension in the given path is considered to be the zone name + * * @param pathToZoneFile */ void readZone(String pathToZoneFile) { @@ -72,61 +76,64 @@ public void startRow(String[] row) { }); - this.linksOfZone.put(zone, links); + this.linksByZone.put(zone, links); } private void calculateTotalZoneParkCapacity(String zoneName) { double cap = 0.0; - for (Id link : this.linksOfZone.get(zoneName)) { + for (Id link : this.linksByZone.get(zoneName)) { cap += getNrOfAllParkingSpacesOnLink(link); } - this.totalCapOfZone.put(zoneName, cap); + this.totalCapByZone.put(zoneName, cap); } @Override public boolean parkVehicleHere(Id vehicleId, Id linkId, double time) { if (parkVehicleAtLink(vehicleId, linkId, time)) { - for (String zone : this.linksOfZone.keySet()) { - if (linksOfZone.get(zone).contains(linkId) && this.facilitiesPerLink.containsKey(linkId)) { - double newOcc = this.occupationOfZone.get(zone) + 1; - if (this.totalCapOfZone.get(zone) < newOcc) { - String s = "FacilityID: " + this.parkingLocations.get(vehicleId); - String t = "Occupied: " + this.occupation.get(this.parkingLocations.get(vehicleId)); - String u = "Capacity: " + this.parkingFacilities.get(this.parkingLocations.get(vehicleId)).getActivityOptions().get( - ParkingUtils.ParkingStageInteractionType).getCapacity(); + for (String zone : this.linksByZone.keySet()) { + if (linksByZone.get(zone).contains(linkId) && this.parkingFacilitiesByLink.containsKey(linkId)) { + double newOcc = this.occupationByZone.get(zone) + 1; + if (this.totalCapByZone.get(zone) < newOcc) { + String s = "FacilityID: " + this.parkingFacilityLocationByVehicleId.get(vehicleId); + String t = "Occupied: " + this.infoByFacilityId.get(this.parkingFacilityLocationByVehicleId.get(vehicleId)).occupation; + String u = + "Capacity: " + this.parkingFacilitiesById.get(this.parkingFacilityLocationByVehicleId.get(vehicleId)).getActivityOptions() + .get( + ParkingUtils.ParkingStageInteractionType).getCapacity(); String v = "TotalCapacityOnLink: " + getNrOfAllParkingSpacesOnLink(linkId); - throw new RuntimeException("occupancy of zone " + zone + " is higher than 100%. Capacity= " + this.totalCapOfZone.get( + throw new RuntimeException("occupancy of zone " + zone + " is higher than 100%. Capacity= " + this.totalCapByZone.get( zone) + " occupancy=" + newOcc + "time = " + time + "\n" + s + "\n" + t + "\n" + u + "\n" + v); } - this.occupationOfZone.put(zone, newOcc); + this.occupationByZone.put(zone, newOcc); return true; // assumes: link is only part of exactly 1 zone } } return true; - } else + } else { return false; + } } @Override public boolean unParkVehicleHere(Id vehicleId, Id linkId, double time) { - if (!this.parkingLocations.containsKey(vehicleId)) { + if (!this.parkingFacilityLocationByVehicleId.containsKey(vehicleId)) { return true; // we assume the person parks somewhere else } else { - Id fac = this.parkingLocations.remove(vehicleId); - this.occupation.get(fac).decrement(); + Id fac = this.parkingFacilityLocationByVehicleId.remove(vehicleId); + this.infoByFacilityId.get(fac).occupation--; - Id parkingLink = this.parkingFacilities.get(fac).getLinkId(); - for (String zone : this.linksOfZone.keySet()) { - if (linksOfZone.get(zone).contains(parkingLink)) { - double newOcc = this.occupationOfZone.get(zone) - 1; + Id parkingLink = this.parkingFacilitiesById.get(fac).getLinkId(); + for (String zone : this.linksByZone.keySet()) { + if (linksByZone.get(zone).contains(parkingLink)) { + double newOcc = this.occupationByZone.get(zone) - 1; if (newOcc < 0) { //in iteration 0 agents can "leave parking spaces" (get into traffic), but the manager didn't record them to be parked newOcc = 0; } - this.occupationOfZone.put(zone, newOcc); + this.occupationByZone.put(zone, newOcc); } } return true; @@ -135,18 +142,19 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double public double getOccupancyRatioOfZone(String zone) { - if (!(this.linksOfZone.keySet().contains(zone))) + if (!(this.linksByZone.keySet().contains(zone))) { throw new RuntimeException("zone " + zone + " was not defined. thus, could'nt calculate occupancy ratio."); + } - return (this.occupationOfZone.get(zone) / this.totalCapOfZone.get(zone)); + return (this.occupationByZone.get(zone) / this.totalCapByZone.get(zone)); } public Set getZones() { - return this.linksOfZone.keySet(); + return this.linksByZone.keySet(); } public double getTotalCapacityOfZone(String zone) { - return this.totalCapOfZone.get(zone); + return this.totalCapByZone.get(zone); } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/BenensonParkingSearchLogic.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/BenensonParkingSearchLogic.java index 6b8d1f7bcff..adb5ee1dbb8 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/BenensonParkingSearchLogic.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/BenensonParkingSearchLogic.java @@ -19,58 +19,57 @@ /** * @author schlenther - * - *the matsim version of the parking strategy used in PARKAGENT. see the following paper for more information: - *doi: 10.1016/j.compenvurbsys.2008.09.011 - * + *

    + * the matsim version of the parking strategy used in PARKAGENT. see the following paper for more information: + * doi: 10.1016/j.compenvurbsys.2008.09.011 */ public class BenensonParkingSearchLogic implements ParkingSearchLogic { private static final Logger logger = LogManager.getLogger(BenensonDynLeg.class); private static final boolean logForDebug = false; - + private Network network; private static final double MIN_THRESHOLD_PROB_FUNCTION = 2; private static final double MAX_THRESHOLD_PROB_FUNCTION = 4; - //thresholds for phase transitions: 1->2 and 2->3 + //thresholds for phase transitions: 1->2 and 2->3 private static final double THRESHOLD_OBSERVING_METER = 1000; private static final double THRESHOLD_PARKING_METER = 500; - + private static final double ACCEPTED_DISTANCE_START = 100; private static final double ACCEPTED_DISTANCE_INCREASING_RATE_PER_MIN = 100; private static final double ACCEPTED_DISTANCE_MAX = 600; - + private final Random random = MatsimRandom.getLocalInstance(); - + private ParkingSearchConfigGroup configGroup; - + public BenensonParkingSearchLogic(Network network, ParkingSearchConfigGroup cfgGroup) { this.network = network; this.configGroup = cfgGroup; } - + @Override public void reset() { } - //----------------------------------------------------phase transitions---------------------------------------------------------------------------- + //----------------------------------------------------phase + // transitions---------------------------------------------------------------------------- - public boolean transitionToObservingBehaviour(Id currLinkId, Id endLinkId) { + public boolean transitionToObservingBehaviour(Id currLinkId, Id endLinkId) { double distToDest = NetworkUtils.getEuclideanDistance( - network.getLinks().get(currLinkId).getCoord(), network.getLinks().get(endLinkId).getCoord()); - return distToDest < THRESHOLD_OBSERVING_METER ; + network.getLinks().get(currLinkId).getCoord(), network.getLinks().get(endLinkId).getCoord()); + return distToDest < THRESHOLD_OBSERVING_METER; } - public boolean transitionToParkingBehaviour(Id currLinkId, Id endLinkId) { + public boolean transitionToParkingBehaviour(Id currLinkId, Id endLinkId) { double distToDest = NetworkUtils.getEuclideanDistance( - network.getLinks().get(currLinkId).getCoord(), network.getLinks().get(endLinkId).getCoord()); - return distToDest < THRESHOLD_PARKING_METER ; + network.getLinks().get(currLinkId).getCoord(), network.getLinks().get(endLinkId).getCoord()); + return distToDest < THRESHOLD_PARKING_METER; } - + //-------------------------------------------------------routing--------------------------------------------------------------------------- - + /** - * * @param currentLinkId * @param destinationLinkId * @return @@ -78,9 +77,9 @@ public boolean transitionToParkingBehaviour(Id currLinkId, Id endLin public Id getNextLinkBenensonRouting(Id currentLinkId, Id destinationLinkId, String mode) { Link currentLink = network.getLinks().get(currentLinkId); - //calculate the distance to fromNode of destination link instead of distance to activity + //calculate the distance to fromNode of destination link instead of distance to activity Node destination = network.getLinks().get(destinationLinkId).getFromNode(); - + double distanceToDest = Double.MAX_VALUE; Node nextNode; Id nextLinkId = null; @@ -91,13 +90,12 @@ public Id getNextLinkBenensonRouting(Id currentLinkId, Id dest return outLinkId; } nextNode = outLink.getToNode(); - double dd = NetworkUtils.getEuclideanDistance(destination.getCoord(),nextNode.getCoord()); - if( dd < distanceToDest){ + double dd = NetworkUtils.getEuclideanDistance(destination.getCoord(), nextNode.getCoord()); + if (dd < distanceToDest) { nextLinkId = outLinkId; distanceToDest = dd; - } - else if(dd == distanceToDest){ - if (Math.random() > 0.5){ + } else if (dd == distanceToDest) { + if (random.nextBoolean()) { nextLinkId = outLinkId; } } @@ -105,7 +103,8 @@ else if(dd == distanceToDest){ return nextLinkId; } - public Id getNextLinkRandomInAcceptableDistance(Id currentLinkId, Id endLinkId, Id vehicleId, double firstDestLinkEnterTime, double timeOfDay, String mode) { + public Id getNextLinkRandomInAcceptableDistance(Id currentLinkId, Id endLinkId, Id vehicleId, + double firstDestLinkEnterTime, double timeOfDay, String mode) { Link nextLink; Link currentLink = network.getLinks().get(currentLinkId); @@ -114,10 +113,14 @@ public Id getNextLinkRandomInAcceptableDistance(Id currentLinkId, Id int nrOfOutGoingLinks = outGoingLinks.size(); for (int i = 1; i <= nrOfOutGoingLinks; i++) { nextLink = outGoingLinks.get(random.nextInt(outGoingLinks.size())); - if (isDriverInAcceptableDistance(nextLink.getId(), endLinkId, firstDestLinkEnterTime, timeOfDay)) return nextLink.getId(); + if (isDriverInAcceptableDistance(nextLink.getId(), endLinkId, firstDestLinkEnterTime, timeOfDay)) { + return nextLink.getId(); + } outGoingLinks.remove(nextLink); - } - logger.error("vehicle " + vehicleId + " finds no outlink in acceptable distance going out from link " + currentLinkId + ". it just takes a random next link"); + } + logger.error("vehicle " + vehicleId + " finds no outlink in acceptable distance going out from link " + currentLinkId + ". it just takes a" + + " " + + "random next link"); return outGoingLinksCopy.get(random.nextInt(outGoingLinksCopy.size())).getId(); } @@ -125,63 +128,70 @@ public Id getNextLinkRandomInAcceptableDistance(Id currentLinkId, Id //---------------------------------------------------park decision----------------------------------------------------------------------- /** - * * estimate amount of free parking spaces on the way to destination Link and decide whether to park on currentLink - * + * * @param pUnoccupied * @param currentLinkId * @param endLinkId - * @return whether vehicle should be parked here + * @return whether vehicle should be parked here */ - public boolean wantToParkHere (double pUnoccupied, Id currentLinkId, Id endLinkId) { - - //if pUnoccupied = 0, no free slot has been detected, so it is realistic to accept the very next free slot + public boolean wantToParkHere(double pUnoccupied, Id currentLinkId, Id endLinkId) { + + //if pUnoccupied = 0, no free slot has been detected, so it is realistic to accept the very next free slot double distToDest = NetworkUtils.getEuclideanDistance( - network.getLinks().get(currentLinkId).getToNode().getCoord(), network.getLinks().get(endLinkId).getToNode().getCoord()); - double expectedFreeSlots = (pUnoccupied*distToDest/configGroup.getAvgparkingslotlength()); - double rnd = Math.random(); - if (logForDebug) - logger.error("\n current link: " + currentLinkId + "\n expected slots: " + expectedFreeSlots + "\n probabilty to continue driving: " + getProbabilityOfContinuingToDrive(expectedFreeSlots) + "\n rnd: " + rnd); - return rnd >= getProbabilityOfContinuingToDrive(expectedFreeSlots); + network.getLinks().get(currentLinkId).getToNode().getCoord(), network.getLinks().get(endLinkId).getToNode().getCoord()); + double expectedFreeSlots = (pUnoccupied * distToDest / configGroup.getAvgparkingslotlength()); + double rnd = random.nextDouble(); + if (logForDebug) { + logger.error("\n current link: " + currentLinkId + "\n expected slots: " + expectedFreeSlots + "\n probabilty to continue driving: " + getProbabilityOfContinuingToDrive(expectedFreeSlots) + "\n rnd: " + rnd); + } + return rnd >= getProbabilityOfContinuingToDrive(expectedFreeSlots); } - + /** - * linear probability function, depending on maximum and minimum threshold + * linear probability function, depending on maximum and minimum threshold */ - private double getProbabilityOfContinuingToDrive(double expectedFreeSlots) { - - if (expectedFreeSlots < MIN_THRESHOLD_PROB_FUNCTION) return 0.0; - else if(expectedFreeSlots > MAX_THRESHOLD_PROB_FUNCTION) return 1.0; - - return (expectedFreeSlots-MIN_THRESHOLD_PROB_FUNCTION)/(MAX_THRESHOLD_PROB_FUNCTION-MIN_THRESHOLD_PROB_FUNCTION); + private double getProbabilityOfContinuingToDrive(double expectedFreeSlots) { + + if (expectedFreeSlots < MIN_THRESHOLD_PROB_FUNCTION) { + return 0.0; + } else if (expectedFreeSlots > MAX_THRESHOLD_PROB_FUNCTION) { + return 1.0; + } + + return (expectedFreeSlots - MIN_THRESHOLD_PROB_FUNCTION) / (MAX_THRESHOLD_PROB_FUNCTION - MIN_THRESHOLD_PROB_FUNCTION); } /** - * * @param currentLinkId * @param endLinkId - * @param firstDestLinkEnterTime + * @param firstDestLinkEnterTime * @param timeOfDay * @return */ - private boolean isDriverInAcceptableDistance(Id currentLinkId, Id endLinkId, double firstDestLinkEnterTime, double timeOfDay) { + private boolean isDriverInAcceptableDistance(Id currentLinkId, Id endLinkId, double firstDestLinkEnterTime, double timeOfDay) { // if we're on the destinationLink, we always want to park - if(currentLinkId.equals(endLinkId)) return true; - - double distToDest = NetworkUtils.getEuclideanDistance(network.getLinks().get(currentLinkId).getCoord(), network.getLinks().get(endLinkId).getCoord()); + if (currentLinkId.equals(endLinkId)) { + return true; + } + + double distToDest = NetworkUtils.getEuclideanDistance(network.getLinks().get(currentLinkId).getCoord(), network.getLinks().get(endLinkId) + .getCoord()); double timeSpent = timeOfDay - firstDestLinkEnterTime; double acceptedDistance = ACCEPTED_DISTANCE_START + ACCEPTED_DISTANCE_INCREASING_RATE_PER_MIN * (timeSpent / 60); - - if (acceptedDistance > ACCEPTED_DISTANCE_MAX) acceptedDistance = ACCEPTED_DISTANCE_MAX; - - if (distToDest <= acceptedDistance){ - if(logForDebug){ + + if (acceptedDistance > ACCEPTED_DISTANCE_MAX) { + acceptedDistance = ACCEPTED_DISTANCE_MAX; + } + + if (distToDest <= acceptedDistance) { + if (logForDebug) { logger.error(" distance between link " + currentLinkId + " and destLink " + endLinkId + ": " + distToDest); logger.error("accepted : " + acceptedDistance); logger.error("time spent: " + timeSpent); } - return true; + return true; } return false; } @@ -190,5 +200,5 @@ private boolean isDriverInAcceptableDistance(Id currentLinkId, Id en public Id getNextLink(Id currentLinkId, Id vehicleId, String mode) { throw new RuntimeException("this should not happen!"); } - + } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/DistanceMemoryParkingSearchLogic.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/DistanceMemoryParkingSearchLogic.java index c4616c7df1e..5529e5b3c0a 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/DistanceMemoryParkingSearchLogic.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/DistanceMemoryParkingSearchLogic.java @@ -1,5 +1,5 @@ /** - * + * */ package org.matsim.contrib.parking.parkingsearch.search; @@ -19,24 +19,24 @@ /** * @author tschlenther - * - *Agents drive to destination first. Knowledge about surrounding streets is assumed. If no parking slot is available, they always look - *for a slot on the one outgoing link that has the shortest distance to their destination and is unknown to them so far. If every outlink - *is known they choose the next link to search on randomly. - * + *

    + * Agents drive to destination first. Knowledge about surrounding streets is assumed. If no parking slot is available, they always look + * for a slot on the one outgoing link that has the shortest distance to their destination and is unknown to them so far. If every outlink + * is known they choose the next link to search on randomly. */ public class DistanceMemoryParkingSearchLogic implements ParkingSearchLogic { private static final Logger logger = LogManager.getLogger(DistanceMemoryParkingSearchLogic.class); - private static final boolean doLogging = false; - +// static { +// Configurator.setRootLevel(org.apache.logging.log4j.Level.DEBUG); +// } + private Network network; - private HashSet> knownLinks; - + private HashSet> knownLinks; + /** - * @param network - * + * @param network */ public DistanceMemoryParkingSearchLogic(Network network) { this.network = network; @@ -49,49 +49,50 @@ public Id getNextLink(Id currentLinkId, Id destLinkId, Id nextLink = null; - - if(doLogging) logger.info("number of outlinks of link " + currentLinkId + ": " + outLinks.size()); + + logger.debug("number of outlinks of link {}: {}", currentLinkId, outLinks.size()); for (Link outLink : outLinks) { Id outLinkId = outLink.getId(); - if (this.knownLinks.contains(outLinkId)) nrKnownLinks++; - else{ + if (this.knownLinks.contains(outLinkId)) { + nrKnownLinks++; + } else { double distToDest = NetworkUtils.getEuclideanDistance(outLink.getCoord(), network.getLinks().get(destLinkId).getCoord()); - if (distToDest < shortestDistance){ + if (distToDest < shortestDistance) { nextLink = outLinkId; shortestDistance = distToDest; - if(doLogging) logger.info("currently chosen link: " + nextLink + " distToDest: " + shortestDistance); - } - else if(distToDest == shortestDistance){ + logger.debug("currently chosen link: {} distToDest: {}", nextLink, shortestDistance); + } else if (distToDest == shortestDistance) { String message = "link " + nextLink + " and link " + outLinkId + " both are " + distToDest + "m away from destination."; - if (Math.random() > 0.5) - nextLink = outLinkId; - if(doLogging) logger.info(message + " link " + nextLink + " is chosen."); - } - else{ - if (doLogging){ - logger.info("link " + outLinkId + " was not chosen because it is " + distToDest + "m away whereas shortest distance is " + shortestDistance); + if (MatsimRandom.getRandom().nextBoolean()) { + nextLink = outLinkId; } + logger.debug("{} link {} is chosen.", message, nextLink); + } else { + logger.debug("link {} was not chosen because it is {}m away whereas shortest distance is {}", outLinkId, distToDest, + shortestDistance); } } } - if(doLogging)logger.error("vehicle " + vehicleId + " knew " + nrKnownLinks + " out of " + outLinks.size() + " outlinks of link " + currentLinkId); - if(outLinks.size() == nrKnownLinks ){ - if(doLogging)logger.error("vehicle " + vehicleId + " knows all outlinks of link " + currentLinkId); - + logger.debug("vehicle {} knew {} out of {} outlinks of link {}", vehicleId, nrKnownLinks, outLinks.size(), currentLinkId); + if (outLinks.size() == nrKnownLinks) { + logger.debug("vehicle {} knows all outlinks of link {}", vehicleId, currentLinkId); + //return random Link int index = MatsimRandom.getRandom().nextInt(outLinks.size()); Iterator iter = outLinks.iterator(); for (int i = 0; i < index; i++) { - iter.next(); + iter.next(); } nextLink = iter.next().getId(); - } - - if(nextLink == null){ - throw new RuntimeException("the next Link Id for vehicle " + vehicleId + " on current link " + currentLinkId + " couldn't be calculated."); } - if(doLogging)logger.error("vehicle " + vehicleId + " takes link " + nextLink + " as next link"); + + if (nextLink == null) { + throw new RuntimeException("the next Link Id for vehicle " + vehicleId + " on current link " + currentLinkId + " couldn't be " + + "calculated" + + "."); + } + logger.debug("vehicle {} takes link {} as next link", vehicleId, nextLink); this.knownLinks.add(nextLink); return nextLink; } @@ -105,8 +106,8 @@ public Id getNextLink(Id currentLinkId, Id vehicleId, Strin throw new RuntimeException("shouldn't happen - method not implemented"); } - public void addToKnownLinks(Id linkId){ + public void addToKnownLinks(Id linkId) { this.knownLinks.add(linkId); } - + } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/NearestParkingSpotSearchLogic.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/NearestParkingSpotSearchLogic.java index d87bf0408fe..de4be67c97f 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/NearestParkingSpotSearchLogic.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/search/NearestParkingSpotSearchLogic.java @@ -69,7 +69,7 @@ public NearestParkingSpotSearchLogic(Network network, ParkingRouter parkingRoute this.parkingManager = parkingManager; this.canReserveParkingSlot = canReserveParkingSlot; this.canCheckParkingCapacitiesInAdvanced = canCheckParkingCapacitiesInAdvanced; - activityFacilities = ((FacilityBasedParkingManager) parkingManager).getParkingFacilities(); + activityFacilities = ((FacilityBasedParkingManager) parkingManager).getParkingFacilitiesById(); currentLinkIdx = 0; triedParking = new HashSet<>(); nextLink = null; @@ -83,26 +83,30 @@ public Id getNextLink(Id currentLinkId, Id baseLinkId, Id getNextLink(Id currentLinkId, Id baseLinkId, Id baseLinkId, Coord coordOfAttraction) { for (ActivityFacility activityFacility : activityFacilities.values()) { - if (activityFacility.getLinkId().equals(baseLinkId)) + if (activityFacility.getLinkId().equals(baseLinkId)) { distanceFromBaseToAttraction = NetworkUtils.getEuclideanDistance(activityFacility.getCoord(), coordOfAttraction); + } } } /** - * Checks if it is possible to drive to the new parking facility and to drive back to the base without extending the startTime of the following activity. + * Checks if it is possible to drive to the new parking facility and to drive back to the base without extending the startTime of the following + * activity. * If the resulting parking time at the new facility is less then 5 minutes the vehicle will drive directly to the next activity location. * * @param currentLinkId @@ -148,17 +154,20 @@ private void findDistanceBetweenBaseLinkAndAttraction(Id baseLinkId, Coord private void checkIfDrivingToNextParkingLocationIsPossible(Id currentLinkId, Id baseLinkId, double now, double nextPickupTime) { double expectedTravelTimeFromParkingToBase; - if (actualRoute == null) + if (actualRoute == null) { expectedTravelTimeFromParkingToBase = this.parkingRouter.getRouteFromParkingToDestination(baseLinkId, now, currentLinkId).getTravelTime().seconds(); //TODO better: use the nextLink for the check - else + } else { expectedTravelTimeFromParkingToBase = this.parkingRouter.getRouteFromParkingToDestination(baseLinkId, now, actualRoute.getEndLinkId()).getTravelTime().seconds(); + } double minimumExpectedParkingDuration = 5 * 60; double travelTimeNextPart; - if (actualRoute == null) + if (actualRoute == null) { travelTimeNextPart = 0.; - else travelTimeNextPart = actualRoute.getTravelTime().seconds(); + } else { + travelTimeNextPart = actualRoute.getTravelTime().seconds(); + } if ((nextPickupTime - now - travelTimeNextPart - expectedTravelTimeFromParkingToBase) < minimumExpectedParkingDuration) { actualRoute = this.parkingRouter.getRouteFromParkingToDestination(baseLinkId, now, @@ -168,8 +177,9 @@ private void checkIfDrivingToNextParkingLocationIsPossible(Id currentLinkI } public Id getNextParkingLocation() { - if (actualRoute == null) + if (actualRoute == null) { return null; + } return actualRoute.getEndLinkId(); } @@ -208,34 +218,42 @@ private NetworkRoute findRouteToNearestParkingFacility(Id baseLinkId, Id now && parkingOptions.getOpeningTimes().first().getEndTime() < latestEndOfParking) + if (parkingOptions.getOpeningTimes().first().getStartTime() > now && parkingOptions.getOpeningTimes().first() + .getEndTime() < latestEndOfParking) { continue; + } } //check if approx. the max parking time at facility will not exceed, assumption: "parking duration - 30 minutes" is parking Time. if (activityFacility.getAttributes().getAsMap().containsKey("maxParkingDurationInHours")) { //TODO vielleicht etwas sparsamer machen double maxParkingDurationAtFacility = 3600 * (double) activityFacility.getAttributes().getAsMap().get("maxParkingDurationInHours"); - if (maxParkingDuration - 30*60 > maxParkingDurationAtFacility) + if (maxParkingDuration - 30 * 60 > maxParkingDurationAtFacility) { continue; + } } //TODO beschreiben was passiert if (passangerInteractionAtParkingFacilityAtEndOfLeg) { double distanceBetweenThisParkingFacilityAndTheAttraction = NetworkUtils.getEuclideanDistance(activityFacility.getCoord(), coordOfAttraction); - if (distanceBetweenThisParkingFacilityAndTheAttraction - distanceFromBaseToAttraction > maxDistanceFromBase) + if (distanceBetweenThisParkingFacilityAndTheAttraction - distanceFromBaseToAttraction > maxDistanceFromBase) { continue; + } } // create Euclidean distances to the parking activities to find routes only to the nearest facilities in the next step Coord coordBaseLink = network.getLinks().get(baseLinkId).getCoord(); @@ -243,10 +261,11 @@ private NetworkRoute findRouteToNearestParkingFacility(Id baseLinkId, Id baseLinkId, Id maxParkingDurationAtFacility) + if (expectedParkingTime > maxParkingDurationAtFacility) { continue; + } } counter++; - if (passangerInteractionAtParkingFacilityAtEndOfLeg && euclideanDistanceToParkingFacilities.size() > triedParking.size()) - if (triedParking.contains(activityFacility.getId())) + if (passangerInteractionAtParkingFacilityAtEndOfLeg && euclideanDistanceToParkingFacilities.size() > triedParking.size()) { + if (triedParking.contains(activityFacility.getId())) { continue; - if (passangerInteractionAtParkingFacilityAtEndOfLeg && euclideanDistanceToParkingFacilities.size() == triedParking.size()) + } + } + if (passangerInteractionAtParkingFacilityAtEndOfLeg && euclideanDistanceToParkingFacilities.size() == triedParking.size()) { triedParking.clear(); + } NetworkRoute possibleRoute = this.parkingRouter.getRouteFromParkingToDestination(activityFacility.getLinkId(), now, currentLinkId); // reason is that we expect that the driver will always take the nearest possible getOff point to reduce the walk distance for the guests - if (passangerInteractionAtParkingFacilityAtEndOfLeg){ + if (passangerInteractionAtParkingFacilityAtEndOfLeg) { selectedRoute = possibleRoute; nearstActivityFacility = activityFacility; break; @@ -292,8 +315,9 @@ private NetworkRoute findRouteToNearestParkingFacility(Id baseLinkId, Id getComments() { - Map map = super.getComments(); + Map map = super.getComments(); map.put(UNPARKDURATION, "Duration to unpark a vehicle"); map.put(PARKDURATION, "Duration to park a vehicle"); - map.put(PARKINGSEARCH_STRATEGY, "The strategy to find a parking slot. Possible strategies: " + Arrays.toString(ParkingSearchStrategy.values())); + map.put(PARKINGSEARCH_STRATEGY, + "The strategy to find a parking slot. Possible strategies: " + Arrays.toString(ParkingSearchStrategy.values())); map.put(PARKINGSEARCH_MANAGER, "The type of the ParkingManager, may have the values: " + Arrays.toString(ParkingSearchManagerType.values())); - map.put(FRACTION_CAN_CHECK_FREE_CAPACITIES_IN_ADVANCED, "Fraction of agents who can check free capacities in advanced. This is currently developed for the FacilityBasedParkingManager"); - map.put(FRACTION_CAN_RESERVE_PARKING_IN_ADVANCED, "Fraction of agents who can reserve free capacities in advanced. This is currently developed for the FacilityBasedParkingManager\""); - map.put(CAN_PARK_ONLY_AT_FACILITIES, "Set if a vehicle can park only at given parking facilities or it can park freely at a link without a facility."); + map.put(FRACTION_CAN_CHECK_FREE_CAPACITIES_IN_ADVANCED, "Fraction of agents who can check free capacities in advanced. This is currently " + + "developed for the FacilityBasedParkingManager"); + map.put(FRACTION_CAN_RESERVE_PARKING_IN_ADVANCED, "Fraction of agents who can reserve free capacities in advanced. This is currently " + + "developed for the FacilityBasedParkingManager\""); + map.put(CAN_PARK_ONLY_AT_FACILITIES, "Set if a vehicle can park only at given parking facilities or it can park freely at a link without a" + + " " + + "facility."); return map; } @@ -162,11 +170,16 @@ protected void checkConsistency(Config config) { super.checkConsistency(config); - if (getFractionCanCheckFreeCapacitiesInAdvanced() != 0. && !getParkingSearchManagerType().equals(ParkingSearchManagerType.FacilityBasedParkingManager)) - log.warn("Fraction of agents who can check free capacities in advanced has no impact on your selected ParkingSearchManagerType, because it is only implemented for the FacilityBasedParkingManager."); + if (getFractionCanCheckFreeCapacitiesInAdvanced() != 0. && !getParkingSearchManagerType().equals(ParkingSearchManagerType.FacilityBasedParkingManager)) { + log.warn("Fraction of agents who can check free capacities in advanced has no impact on your selected ParkingSearchManagerType, " + + "because" + + " " + + "it is only implemented for the FacilityBasedParkingManager."); + } - if (getFractionCanCheckFreeCapacitiesInAdvanced() + getFractionCanReserveParkingInAdvanced() > 1.0) - throw new RuntimeException( "The sum of " + FRACTION_CAN_RESERVE_PARKING_IN_ADVANCED + " and " + FRACTION_CAN_CHECK_FREE_CAPACITIES_IN_ADVANCED + " is > 1.0. This should not happen."); + if (getFractionCanCheckFreeCapacitiesInAdvanced() + getFractionCanReserveParkingInAdvanced() > 1.0) { + throw new RuntimeException("The sum of " + FRACTION_CAN_RESERVE_PARKING_IN_ADVANCED + " and " + FRACTION_CAN_CHECK_FREE_CAPACITIES_IN_ADVANCED + " is > 1.0. This should not happen."); + } } diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/SetupParking.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/SetupParking.java index 5d8c657d9bb..288434518b1 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/SetupParking.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/SetupParking.java @@ -22,6 +22,8 @@ */ package org.matsim.contrib.parking.parkingsearch.sim; +import com.google.inject.Key; +import com.google.inject.name.Names; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.dvrp.router.DvrpGlobalRoutingNetworkProvider; @@ -30,15 +32,15 @@ import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.dvrp.trafficmonitoring.DvrpTravelTimeModule; -import org.matsim.contrib.parking.parkingsearch.evaluation.ParkingListener; import org.matsim.contrib.parking.parkingsearch.manager.FacilityBasedParkingManager; import org.matsim.contrib.parking.parkingsearch.manager.ParkingSearchManager; +import org.matsim.contrib.parking.parkingsearch.manager.ParkingStatsWriter; import org.matsim.contrib.parking.parkingsearch.manager.vehicleteleportationlogic.VehicleTeleportationLogic; import org.matsim.contrib.parking.parkingsearch.manager.vehicleteleportationlogic.VehicleTeleportationToNearbyParking; import org.matsim.contrib.parking.parkingsearch.routing.ParkingRouter; import org.matsim.contrib.parking.parkingsearch.routing.WithinDayParkingRouter; import org.matsim.core.controler.AbstractModule; -import org.matsim.core.controler.Controler; +import org.matsim.core.controler.Controller; import org.matsim.core.mobsim.qsim.PopulationModule; import org.matsim.core.mobsim.qsim.components.QSimComponentsConfig; import org.matsim.core.mobsim.qsim.components.StandardQSimComponentConfigurator; @@ -46,9 +48,6 @@ import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.TravelTime; -import com.google.inject.Key; -import com.google.inject.name.Names; - /** * @author jbischoff */ @@ -56,41 +55,42 @@ public class SetupParking { // TODO: create config group and make this all configurable? - static public void installParkingModules(Controler controler) { + static public void installParkingModules(Controller controller) { // No need to route car routes in Routing module in advance, as they are // calculated on the fly - if (!controler.getConfig().getModules().containsKey(DvrpConfigGroup.GROUP_NAME)) { - controler.getConfig().addModule(new DvrpConfigGroup()); + if (!controller.getConfig().getModules().containsKey(DvrpConfigGroup.GROUP_NAME)) { + controller.getConfig().addModule(new DvrpConfigGroup()); } - controler.addOverridingModule(new DvrpTravelTimeModule()); - controler.addOverridingModule(new AbstractModule() { + controller.addOverridingModule(new DvrpTravelTimeModule()); + controller.addOverridingModule(new AbstractModule() { @Override public void install() { bind(TravelTime.class).annotatedWith(DvrpModes.mode(TransportMode.car)) - .to(Key.get(TravelTime.class, Names.named(DvrpTravelTimeModule.DVRP_ESTIMATED))); + .to(Key.get(TravelTime.class, Names.named(DvrpTravelTimeModule.DVRP_ESTIMATED))); bind(TravelDisutilityFactory.class).annotatedWith(DvrpModes.mode(TransportMode.car)) - .toInstance(TimeAsTravelDisutility::new); + .toInstance(TimeAsTravelDisutility::new); bind(Network.class).annotatedWith(DvrpModes.mode(TransportMode.car)) - .to(Key.get(Network.class, Names.named(DvrpGlobalRoutingNetworkProvider.DVRP_ROUTING))); + .to(Key.get(Network.class, Names.named(DvrpGlobalRoutingNetworkProvider.DVRP_ROUTING))); install(new DvrpModeRoutingModule(TransportMode.car, new SpeedyALTFactory())); bind(Network.class).annotatedWith(Names.named(DvrpGlobalRoutingNetworkProvider.DVRP_ROUTING)) - .to(Network.class) - .asEagerSingleton(); + .to(Network.class) + .asEagerSingleton(); bind(ParkingSearchManager.class).to(FacilityBasedParkingManager.class).asEagerSingleton(); + bind(ParkingStatsWriter.class); this.install(new ParkingSearchQSimModule()); - addControlerListenerBinding().to(ParkingListener.class); + addControlerListenerBinding().to(ParkingSearchManager.class); bind(ParkingRouter.class).to(WithinDayParkingRouter.class); bind(VehicleTeleportationLogic.class).to(VehicleTeleportationToNearbyParking.class); } }); - controler.addOverridingModule(new AbstractModule() { + controller.addOverridingModule(new AbstractModule() { @Override public void install() { QSimComponentsConfig components = new QSimComponentsConfig(); - new StandardQSimComponentConfigurator(controler.getConfig()).configure(components); + new StandardQSimComponentConfigurator(controller.getConfig()).configure(components); components.removeNamedComponent(PopulationModule.COMPONENT_NAME); components.addNamedComponent(ParkingSearchPopulationModule.COMPONENT_NAME); diff --git a/contribs/parking/src/main/resources/parkingsearch/parkingFacilities.xml b/contribs/parking/src/main/resources/parkingsearch/parkingFacilities.xml index 95ecbfd1cc2..8f2228dcb5b 100644 --- a/contribs/parking/src/main/resources/parkingsearch/parkingFacilities.xml +++ b/contribs/parking/src/main/resources/parkingsearch/parkingFacilities.xml @@ -2,36 +2,36 @@ - + - - + + - - + + - + - - + + - - + + - + diff --git a/contribs/parking/src/main/resources/parkingsearch/population1.xml b/contribs/parking/src/main/resources/parkingsearch/population1.xml new file mode 100644 index 00000000000..4bace31f8e2 --- /dev/null +++ b/contribs/parking/src/main/resources/parkingsearch/population1.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/parking/src/main/resources/parkingsearch/population10.xml b/contribs/parking/src/main/resources/parkingsearch/population10.xml new file mode 100644 index 00000000000..059d8165658 --- /dev/null +++ b/contribs/parking/src/main/resources/parkingsearch/population10.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT.java deleted file mode 100644 index e3959961195..00000000000 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT.java +++ /dev/null @@ -1,157 +0,0 @@ -/* *********************************************************************** * - * project: org.matsim.* - * * - * *********************************************************************** * - * * - * copyright : (C) 2017 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.contrib.parking.parkingchoice.run; - -import org.junit.jupiter.api.Assertions; -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.population.Person; -import org.matsim.api.core.v01.population.Population; -import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; -import org.matsim.contrib.parking.parkingsearch.RunParkingSearchExample; -import org.matsim.contrib.parking.parkingsearch.sim.ParkingSearchConfigGroup; -import org.matsim.core.config.Config; -import org.matsim.core.config.ConfigUtils; -import org.matsim.core.events.EventsUtils; -import org.matsim.core.population.PopulationUtils; -import org.matsim.testcases.MatsimTestUtils; -import org.matsim.utils.eventsfilecomparison.ComparisonResult; - -/** - * @author jbischoff - */ -public class RunParkingSearchScenarioIT { - @RegisterExtension - private MatsimTestUtils utils = new MatsimTestUtils(); - - @Test - void testRunParkingBenesonStrategy() { - try { - String configFile = "./src/main/resources/parkingsearch/config.xml"; - Config config = ConfigUtils.loadConfig(configFile, new ParkingSearchConfigGroup()); - config.controller().setLastIteration(0); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - - ParkingSearchConfigGroup configGroup = (ParkingSearchConfigGroup) config.getModules().get(ParkingSearchConfigGroup.GROUP_NAME); - configGroup.setParkingSearchStrategy(ParkingSearchStrategy.Benenson); - - new RunParkingSearchExample().run(config, false); - - } catch (Exception e) { - e.printStackTrace(); - Assertions.fail("something went wrong"); - } - } - - @Test - void testRunParkingRandomStrategy() { - String configFile = "./src/main/resources/parkingsearch/config.xml"; - Config config = ConfigUtils.loadConfig(configFile, new ParkingSearchConfigGroup()); - config.controller().setLastIteration(0); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - - ParkingSearchConfigGroup configGroup = (ParkingSearchConfigGroup) config.getModules().get(ParkingSearchConfigGroup.GROUP_NAME); - configGroup.setParkingSearchStrategy(ParkingSearchStrategy.Random); - - try { - new RunParkingSearchExample().run(config, false); - } catch (Exception e) { - e.printStackTrace(); - Assertions.fail("something went wrong"); - } - } - - @Test - void testRunParkingDistanceMemoryStrategy() { - try { - String configFile = "./src/main/resources/parkingsearch/config.xml"; - Config config = ConfigUtils.loadConfig(configFile, new ParkingSearchConfigGroup()); - config.controller().setLastIteration(0); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - - ParkingSearchConfigGroup configGroup = (ParkingSearchConfigGroup) config.getModules().get(ParkingSearchConfigGroup.GROUP_NAME); - configGroup.setParkingSearchStrategy(ParkingSearchStrategy.DistanceMemory); - - new RunParkingSearchExample().run(config, false); - { - Population expected = PopulationUtils.createPopulation(ConfigUtils.createConfig()); - PopulationUtils.readPopulation(expected, utils.getInputDirectory() + "/output_plans.xml.gz"); - - Population actual = PopulationUtils.createPopulation(ConfigUtils.createConfig()); - PopulationUtils.readPopulation(actual, utils.getOutputDirectory() + "/output_plans.xml.gz"); - - for (Id personId : expected.getPersons().keySet()) { - double scoreReference = expected.getPersons().get(personId).getSelectedPlan().getScore(); - double scoreCurrent = actual.getPersons().get(personId).getSelectedPlan().getScore(); - Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are different"); - } - - } - { - String expected = utils.getInputDirectory() + "/output_events.xml.gz"; - String actual = utils.getOutputDirectory() + "/output_events.xml.gz"; - ComparisonResult result = EventsUtils.compareEventsFiles(expected, actual); - Assertions.assertEquals(ComparisonResult.FILES_ARE_EQUAL, result); - } - } catch (Exception e) { - e.printStackTrace(); - Assertions.fail("something went wrong"); - } - } - - @Test - void testRunParkingNearestParkingSpotStrategy() { - try { - String configFile = "./src/main/resources/parkingsearch/config.xml"; - Config config = ConfigUtils.loadConfig(configFile, new ParkingSearchConfigGroup()); - config.controller().setLastIteration(0); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - - ParkingSearchConfigGroup configGroup = (ParkingSearchConfigGroup) config.getModules().get(ParkingSearchConfigGroup.GROUP_NAME); - configGroup.setParkingSearchStrategy(ParkingSearchStrategy.NearestParkingSpot); - - new RunParkingSearchExample().run(config, false); - { - Population expected = PopulationUtils.createPopulation(ConfigUtils.createConfig()); - PopulationUtils.readPopulation(expected, utils.getInputDirectory() + "/output_plans.xml.gz"); - - Population actual = PopulationUtils.createPopulation(ConfigUtils.createConfig()); - PopulationUtils.readPopulation(actual, utils.getOutputDirectory() + "/output_plans.xml.gz"); - - for (Id personId : expected.getPersons().keySet()) { - double scoreReference = expected.getPersons().get(personId).getSelectedPlan().getScore(); - double scoreCurrent = actual.getPersons().get(personId).getSelectedPlan().getScore(); - Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are different"); - } - - } - { - String expected = utils.getInputDirectory() + "/output_events.xml.gz"; - String actual = utils.getOutputDirectory() + "/output_events.xml.gz"; - ComparisonResult result = EventsUtils.compareEventsFiles(expected, actual); - Assertions.assertEquals(ComparisonResult.FILES_ARE_EQUAL, result); - } - } catch (Exception e) { - e.printStackTrace(); - Assertions.fail("something went wrong"); - } - } -} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java new file mode 100644 index 00000000000..fee02ad587f --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java @@ -0,0 +1,130 @@ +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.junit.jupiter.api.Assertions; +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.population.Person; +import org.matsim.api.core.v01.population.Population; +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; +import org.matsim.contrib.parking.parkingsearch.sim.ParkingSearchConfigGroup; +import org.matsim.contrib.parking.parkingsearch.sim.SetupParking; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.Controller; +import org.matsim.core.controler.ControllerUtils; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.utils.eventsfilecomparison.ComparisonResult; + +public abstract class AbstractParkingTest { + @RegisterExtension + MatsimTestUtils utils = new MatsimTestUtils(); + + abstract ParkingSearchStrategy getParkingSearchStrategy(); + + @Test + void testParking1() { + Config config = getConfig(getParkingConfig()); + config.plans().setInputFile("population1.xml"); + run(config); + validate(); + } + + @Test + void testParking10() { + Config config = getConfig(getParkingConfig()); + config.plans().setInputFile("population10.xml"); + run(config); + validate(); + } + + @Test + void testParking100() { + Config config = getConfig(getParkingConfig()); + run(config); + validate(); + } + + @Test + void testParking1_onlyFacilityParking() { + ParkingSearchConfigGroup parkingConfig = getParkingConfig(); + parkingConfig.setCanParkOnlyAtFacilities(true); + Config config = getConfig(parkingConfig); + config.plans().setInputFile("population1.xml"); + run(config); + validate(); + } + + /** + * Tests the behaviour of the parking search when only parking at facilities is allowed. + * Result: Agents are trying to park at facilities and are searching so long for a parking space until they found one. + */ + @Test + void testParking10_onlyFacilityParking() { + ParkingSearchConfigGroup parkingConfig = getParkingConfig(); + parkingConfig.setCanParkOnlyAtFacilities(true); + Config config = getConfig(parkingConfig); + config.plans().setInputFile("population10.xml"); + run(config); + validate(); + } + + private ParkingSearchConfigGroup getParkingConfig() { + ParkingSearchConfigGroup parkingSearchConfigGroup = new ParkingSearchConfigGroup(); + parkingSearchConfigGroup.setParkingSearchStrategy(getParkingSearchStrategy()); + return parkingSearchConfigGroup; + } + + private Config getConfig(ParkingSearchConfigGroup parkingSearchConfigGroup) { + Config config = ConfigUtils.loadConfig("parkingsearch/config.xml", parkingSearchConfigGroup); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); + return config; + } + + private void run(Config config) { + Scenario scenario = ScenarioUtils.loadScenario(config); + + Controller controller = ControllerUtils.createController(scenario); + SetupParking.installParkingModules(controller); + controller.run(); + } + + private void validate() { + comparePopulation(); + compareEvents(); + compareCsv("0.parkingStats.csv"); + compareCsv("0.parkingStatsPerTimeSteps.csv"); + } + + private void compareCsv(String fileName) { + String parkingStatsOut = utils.getOutputDirectory() + "/ITERS/it.0/" + fileName; + String parkingStatsIn = utils.getInputDirectory() + "/" + fileName; + MatsimTestUtils.assertEqualFilesLineByLine(parkingStatsIn, parkingStatsOut); + } + + private void compareEvents() { + String expectedEventsFile = utils.getInputDirectory() + "/output_events.xml.gz"; + String actualEventsFile = utils.getOutputDirectory() + "/output_events.xml.gz"; + ComparisonResult result = EventsUtils.compareEventsFiles(expectedEventsFile, actualEventsFile); + Assertions.assertEquals(ComparisonResult.FILES_ARE_EQUAL, result); + } + + private void comparePopulation() { + Population expected = PopulationUtils.createPopulation(ConfigUtils.createConfig()); + PopulationUtils.readPopulation(expected, utils.getInputDirectory() + "/output_plans.xml.gz"); + + Population actual = PopulationUtils.createPopulation(ConfigUtils.createConfig()); + PopulationUtils.readPopulation(actual, utils.getOutputDirectory() + "/output_plans.xml.gz"); + + for (Id personId : expected.getPersons().keySet()) { + double scoreReference = expected.getPersons().get(personId).getSelectedPlan().getScore(); + double scoreCurrent = actual.getPersons().get(personId).getSelectedPlan().getScore(); + Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are different"); + } + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java new file mode 100644 index 00000000000..fe21aa68bbe --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; + +public class BenensonParkingTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.Benenson; + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java new file mode 100644 index 00000000000..9822c5a68d5 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; + +public class DistanceMemoryParkingTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.DistanceMemory; + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java new file mode 100644 index 00000000000..0403332ec60 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java @@ -0,0 +1,12 @@ +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; + +public class NearestParkingSpotTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.NearestParkingSpot; + } + + //TODO something is wrong with this strategy. Even for 100 vehicles, all of them are parking in the same parking spot. +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java new file mode 100644 index 00000000000..c473a821ea7 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; + +public class RandomParkingTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.Random; + } +} diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_events.xml.gz deleted file mode 100644 index e80c449a03b..00000000000 Binary files a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_events.xml.gz and /dev/null differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_plans.xml.gz deleted file mode 100644 index e2a50e6fa9a..00000000000 Binary files a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy/output_plans.xml.gz and /dev/null differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_events.xml.gz new file mode 100644 index 00000000000..36d8ae41c21 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 00000000000..cf995fee841 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..7bd305e83eb --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;10;5;5;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;10;5;5;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 00000000000..fd76d129a1b Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_plans.xml.gz new file mode 100644 index 00000000000..b49179b7c90 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..ee6192c5425 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;104;5;99;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;26;10;16;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;107;10;97;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;30;5;25;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..716c4f390f1 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;3 +09:15;0;0;1 +09:30;0;0;2 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_events.xml.gz new file mode 100644 index 00000000000..3300cf6fc43 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_plans.xml.gz new file mode 100644 index 00000000000..d18738479e9 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..dcdd85c0325 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;12;5;7;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;3;3;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;15;7;8;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;5;5;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..983cb03d56a Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..63644bd8eb6 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..dcdd85c0325 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;12;5;7;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;3;3;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;15;7;8;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;5;5;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..983cb03d56a Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..63644bd8eb6 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..36d8ae41c21 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..cf995fee841 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..36d8ae41c21 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..cf995fee841 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_events.xml.gz new file mode 100644 index 00000000000..2bc7be4d53f Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 00000000000..26b51e95fff Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..2ee1656326c --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;10;5;5;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;5;5;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;10;5;5;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;5;5;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 00000000000..a216a012aef Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz new file mode 100644 index 00000000000..a8ff7a8b2bd Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..804d206d189 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;100;5;95;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;90;10;80;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;100;10;90;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;95;5;90;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..12979cdbad0 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;7 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_events.xml.gz new file mode 100644 index 00000000000..1bb01ce6e46 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz new file mode 100644 index 00000000000..4c78de8075a Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..2ee1656326c --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;10;5;5;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;5;5;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;10;5;5;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;5;5;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..a216a012aef Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..a8ff7a8b2bd Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..2bc7be4d53f Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..26b51e95fff Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;0;0;0;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;0;0;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_events.xml.gz new file mode 100644 index 00000000000..8e1a8f4a86a Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_plans.xml.gz new file mode 100644 index 00000000000..c3d3666b97e Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;0;0;0;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;0;0;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_events.xml.gz new file mode 100644 index 00000000000..cadcc82dcbc Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_plans.xml.gz new file mode 100644 index 00000000000..40f4eaec10e Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;0;0;0;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;0;0;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;0;0;0;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;0;0;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..cadcc82dcbc Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..40f4eaec10e Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;0;0;0;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;0;0;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..8e1a8f4a86a Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..c3d3666b97e Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_events.xml.gz new file mode 100644 index 00000000000..2bc7be4d53f Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 00000000000..26b51e95fff Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..f3c91e1630b --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;10;5;5;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;10;5;5;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;1;1;1;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;0 +09:15;0;0;0 +09:30;0;0;0 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 00000000000..fa9a7b934f2 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_plans.xml.gz new file mode 100644 index 00000000000..4c36398342c Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..ddfea464dac --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;106;5;101;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;24;10;14;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;102;10;92;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;5;22;5;17;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..89a94f7925f --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1,62 @@ +time;rejectedParkingRequest;foundParking;unpark +09:00;0;0;2 +09:15;0;0;3 +09:30;0;0;2 +09:45;0;0;0 +10:00;0;0;0 +10:15;0;0;0 +10:30;0;0;0 +10:45;0;0;0 +11:00;0;0;0 +11:15;0;0;0 +11:30;0;0;0 +11:45;0;0;0 +12:00;0;0;0 +12:15;0;0;0 +12:30;0;0;0 +12:45;0;0;0 +13:00;0;0;0 +13:15;0;0;0 +13:30;0;0;0 +13:45;0;0;0 +14:00;0;0;0 +14:15;0;0;0 +14:30;0;0;0 +14:45;0;0;0 +15:00;0;0;0 +15:15;0;0;0 +15:30;0;0;0 +15:45;0;0;0 +16:00;0;0;0 +16:15;0;0;0 +16:30;0;0;0 +16:45;0;0;0 +17:00;0;0;0 +17:15;0;0;0 +17:30;0;0;0 +17:45;0;0;0 +18:00;0;0;0 +18:15;0;0;0 +18:30;0;0;0 +18:45;0;0;0 +19:00;0;0;0 +19:15;0;0;0 +19:30;0;0;0 +19:45;0;0;0 +20:00;0;0;0 +20:15;0;0;0 +20:30;0;0;0 +20:45;0;0;0 +21:00;0;0;0 +21:15;0;0;0 +21:30;0;0;0 +21:45;0;0;0 +22:00;0;0;0 +22:15;0;0;0 +22:30;0;0;0 +22:45;0;0;0 +23:00;0;0;0 +23:15;0;0;0 +23:30;0;0;0 +23:45;0;0;0 +24:00;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_events.xml.gz new file mode 100644 index 00000000000..1ba46f218f0 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_plans.xml.gz new file mode 100644 index 00000000000..f7d3b5d44ea Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..8704e2ee490 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;5;11;6;5;0;0;0 +149;300.0;-190.0;149_curbside;5.0;1;3;3;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;2;13;8;5;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;2;3;3;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..998560e4410 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..c9e8cf0c736 Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv @@ -0,0 +1,5 @@ +linkId;X;Y;parkingFacility;capacity;EndOccupation;reservationsRequests;numberOfParkedVehicles;rejectedParkingRequest;numberOfWaitingActivities;numberOfStaysFromGetOffUntilGetIn;numberOfParkingBeforeGetIn +114;-300.0;-790.0;114_curbside;5.0;1;1;1;0;0;0;0 +149;300.0;-190.0;149_curbside;5.0;0;0;0;0;0;0;0 +349;300.0;-210.0;349_curbside;5.0;0;1;1;0;0;0;0 +314;-300.0;-810.0;314_curbside;5.0;0;0;0;0;0;0;0 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 00000000000..2bc7be4d53f Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz differ diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 00000000000..26b51e95fff Binary files /dev/null and b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz differ diff --git a/contribs/pom.xml b/contribs/pom.xml index c8b2dd3620c..ae36adaea70 100644 --- a/contribs/pom.xml +++ b/contribs/pom.xml @@ -115,14 +115,14 @@ org.matsim matsim - ${project.version} + ${project.parent.version} jar compile org.matsim matsim - ${project.version} + ${project.parent.version} test-jar test @@ -133,7 +133,7 @@ org.matsim matsim-examples test - ${project.version} + ${project.parent.version} diff --git a/contribs/pseudosimulation/pom.xml b/contribs/pseudosimulation/pom.xml index 9d9ec4449f2..dbb6f00a75e 100644 --- a/contribs/pseudosimulation/pom.xml +++ b/contribs/pseudosimulation/pom.xml @@ -13,7 +13,7 @@ org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} commons-cli diff --git a/contribs/shared_mobility/pom.xml b/contribs/shared_mobility/pom.xml index d97630a3c64..24edfc4a3ce 100644 --- a/contribs/shared_mobility/pom.xml +++ b/contribs/shared_mobility/pom.xml @@ -16,12 +16,12 @@ org.matsim matsim-examples - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/signals/pom.xml b/contribs/signals/pom.xml index 15dc9962de4..23d03270960 100644 --- a/contribs/signals/pom.xml +++ b/contribs/signals/pom.xml @@ -22,12 +22,12 @@ org.matsim matsim-examples - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} compile diff --git a/contribs/simulatedannealing/pom.xml b/contribs/simulatedannealing/pom.xml index fbe7ed06b54..a3a2688d16e 100644 --- a/contribs/simulatedannealing/pom.xml +++ b/contribs/simulatedannealing/pom.xml @@ -16,7 +16,7 @@ org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/simwrapper/pom.xml b/contribs/simwrapper/pom.xml index 499bf95af87..cf59db1d70d 100644 --- a/contribs/simwrapper/pom.xml +++ b/contribs/simwrapper/pom.xml @@ -16,7 +16,7 @@ org.matsim.contrib application - 2025.0-SNAPSHOT + ${project.parent.version} @@ -55,7 +55,7 @@ org.matsim.contrib vsp - 2025.0-SNAPSHOT + ${project.parent.version} test diff --git a/contribs/small-scale-traffic-generation/pom.xml b/contribs/small-scale-traffic-generation/pom.xml index 46ea6a80936..07314d16da1 100644 --- a/contribs/small-scale-traffic-generation/pom.xml +++ b/contribs/small-scale-traffic-generation/pom.xml @@ -15,13 +15,13 @@ org.matsim.contrib application - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib freight - 2025.0-SNAPSHOT + ${project.parent.version} diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java index 094c2f753f4..c3aa017dc39 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/GenerateSmallScaleCommercialTrafficDemand.java @@ -70,7 +70,7 @@ import org.matsim.facilities.ActivityFacility; import org.matsim.freight.carriers.*; import org.matsim.freight.carriers.analysis.RunFreightAnalysisEventBased; -import org.matsim.freight.carriers.controler.*; +import org.matsim.freight.carriers.controller.*; import org.matsim.freight.carriers.usecases.chessboard.CarrierTravelDisutilities; import org.matsim.smallScaleCommercialTrafficGeneration.data.CommercialTourSpecifications; import org.matsim.smallScaleCommercialTrafficGeneration.data.DefaultTourSpecificationsByUsingKID2002; @@ -1063,7 +1063,7 @@ public CarrierStrategyManager get() { travelDisutility, modeTravelTimes.get(TransportMode.car)); // final GenericStrategyManager strategyManager = new GenericStrategyManager<>(); - final CarrierStrategyManager strategyManager = CarrierControlerUtils.createDefaultCarrierStrategyManager(); + final CarrierStrategyManager strategyManager = CarrierControllerUtils.createDefaultCarrierStrategyManager(); strategyManager.setMaxPlansPerAgent(5); { GenericPlanStrategyImpl strategy = new GenericPlanStrategyImpl<>( diff --git a/contribs/sumo/pom.xml b/contribs/sumo/pom.xml index da11bdf4865..fb52edc379c 100644 --- a/contribs/sumo/pom.xml +++ b/contribs/sumo/pom.xml @@ -16,7 +16,7 @@ org.matsim.contrib osm - ${project.version} + ${project.parent.version} diff --git a/contribs/taxi/pom.xml b/contribs/taxi/pom.xml index 33a2ceb4c42..b94a6ed2d99 100644 --- a/contribs/taxi/pom.xml +++ b/contribs/taxi/pom.xml @@ -28,17 +28,17 @@ org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib ev - 2025.0-SNAPSHOT + ${project.parent.version} org.assertj diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiChargingTask.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiChargingTask.java index 8f7f9b018ca..afb1b839bd5 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiChargingTask.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiChargingTask.java @@ -20,6 +20,7 @@ package org.matsim.contrib.etaxi; import org.matsim.contrib.evrp.ChargingTaskImpl; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; import org.matsim.contrib.taxi.schedule.TaxiTaskType; @@ -28,7 +29,7 @@ public class ETaxiChargingTask extends ChargingTaskImpl { public static final TaxiTaskType TYPE = new TaxiTaskType("CHARGING"); public ETaxiChargingTask(double beginTime, double endTime, Charger charger, ElectricVehicle ev, - double totalEnergy) { - super(TYPE, beginTime, endTime, charger, ev, totalEnergy); + double totalEnergy, ChargingStrategy chargingStrategy) { + super(TYPE, beginTime, endTime, charger, ev, totalEnergy, chargingStrategy); } } diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiScheduler.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiScheduler.java index 79999d4b140..16850cf1004 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiScheduler.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/ETaxiScheduler.java @@ -34,6 +34,7 @@ import org.matsim.contrib.dvrp.schedule.Schedules; import org.matsim.contrib.dvrp.schedule.Task; import org.matsim.contrib.ev.charging.ChargingEstimations; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithAssignmentLogic; import org.matsim.contrib.ev.fleet.ElectricVehicle; import org.matsim.contrib.ev.infrastructure.Charger; @@ -50,10 +51,13 @@ public class ETaxiScheduler extends TaxiScheduler { public static final TaxiTaskType DRIVE_TO_CHARGER = new TaxiTaskType("DRIVE_TO_CHARGER", EMPTY_DRIVE); + private final ChargingStrategy.Factory chargingStrategyFactory; + public ETaxiScheduler(TaxiConfigGroup taxiCfg, Fleet fleet, TaxiScheduleInquiry taxiScheduleInquiry, TravelTime travelTime, Supplier routerCreator, EventsManager eventsManager, - MobsimTimer mobsimTimer) { + MobsimTimer mobsimTimer, ChargingStrategy.Factory chargingStrategyFactory) { super(taxiCfg, fleet, taxiScheduleInquiry, travelTime, routerCreator, eventsManager, mobsimTimer); + this.chargingStrategyFactory = chargingStrategyFactory; } // FIXME underestimated due to the ongoing AUX/drive consumption @@ -65,12 +69,13 @@ public void scheduleCharging(DvrpVehicle vehicle, ElectricVehicle ev, Charger ch divertOrAppendDrive(schedule, vrpPath, DRIVE_TO_CHARGER); ChargingWithAssignmentLogic logic = (ChargingWithAssignmentLogic)charger.getLogic(); + ChargingStrategy strategy = chargingStrategyFactory.createStrategy(charger.getSpecification(), ev); double chargingEndTime = vrpPath.getArrivalTime() + ChargingEstimations.estimateMaxWaitTimeForNextVehicle( charger)// TODO not precise!!! - + logic.getChargingStrategy().calcRemainingTimeToCharge(ev);// TODO not precise !!! (SOC will be lower) + + strategy.calcRemainingTimeToCharge();// TODO not precise !!! (SOC will be lower) schedule.addTask(new ETaxiChargingTask(vrpPath.getArrivalTime(), chargingEndTime, charger, ev, - -logic.getChargingStrategy().calcRemainingEnergyToCharge(ev)));// TODO not precise !!! (ditto) - logic.assignVehicle(ev); + -strategy.calcRemainingEnergyToCharge(), strategy));// TODO not precise !!! (ditto) + logic.assignVehicle(ev, strategy); appendStayTask(vehicle); } diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/ETaxiModeOptimizerQSimModule.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/ETaxiModeOptimizerQSimModule.java index 5860bea3890..a713f20796c 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/ETaxiModeOptimizerQSimModule.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/ETaxiModeOptimizerQSimModule.java @@ -34,6 +34,7 @@ import org.matsim.contrib.etaxi.ETaxiActionCreator; import org.matsim.contrib.etaxi.ETaxiScheduler; import org.matsim.contrib.etaxi.util.ETaxiStayTaskEndTimeCalculator; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.infrastructure.ChargingInfrastructure; import org.matsim.contrib.ev.infrastructure.ChargingInfrastructureUtils; import org.matsim.contrib.taxi.analysis.TaxiEventSequenceCollector; @@ -113,8 +114,9 @@ public ETaxiScheduler get() { var speedyALTFactory = new SpeedyALTFactory(); Supplier routerCreator = () -> speedyALTFactory.createPathCalculator( network, travelDisutility, travelTime); + ChargingStrategy.Factory chargingStrategyFactory = getModalInstance(ChargingStrategy.Factory.class); return new ETaxiScheduler(taxiCfg, fleet, taxiScheduleInquiry, travelTime, routerCreator, - events, timer); + events, timer, chargingStrategyFactory); } }); diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/assignment/AssignmentChargerPlugData.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/assignment/AssignmentChargerPlugData.java index 6f3a1105fc3..3d3e4b720e8 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/assignment/AssignmentChargerPlugData.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/optimizer/assignment/AssignmentChargerPlugData.java @@ -71,7 +71,7 @@ static AssignmentDestinationData create(double currentTime, Iterabl } // does not include AUX+driving for assigned vehs - double assignedWorkload = ChargingEstimations.estimateTotalTimeToCharge(logic.getChargingStrategy(), + double assignedWorkload = ChargingEstimations.estimateTotalTimeToCharge( Streams.concat(logic.getPluggedVehicles().stream(), logic.getQueuedVehicles().stream(), logic.getAssignedVehicles().stream())); diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiBenchmark.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiBenchmark.java index 5e67a5e2105..68d20b5263b 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiBenchmark.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiBenchmark.java @@ -27,6 +27,7 @@ import org.matsim.contrib.dvrp.fleet.FleetSpecification; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.dvrp.run.DvrpQSimComponents; import org.matsim.contrib.ev.EvConfigGroup; import org.matsim.contrib.ev.EvModule; @@ -34,6 +35,7 @@ import org.matsim.contrib.ev.charging.ChargingEventSequenceCollector; import org.matsim.contrib.ev.charging.ChargingLogic; import org.matsim.contrib.ev.charging.ChargingPower; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithQueueingAndAssignmentLogic; import org.matsim.contrib.ev.charging.FixedSpeedCharging; import org.matsim.contrib.ev.discharging.IdleDischargingHandler; @@ -53,6 +55,8 @@ import org.matsim.core.mobsim.qsim.AbstractQSimModule; import org.matsim.core.scenario.ScenarioUtils; +import com.google.inject.Key; + /** * For a fair and consistent benchmarking of taxi dispatching algorithms we assume that link travel times are * deterministic. To simulate this property, we remove (1) all other traffic, and (2) link capacity constraints (e.g. by @@ -111,8 +115,8 @@ protected void configureQSim() { controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bind(ChargingLogic.Factory.class).toProvider(new ChargingWithQueueingAndAssignmentLogic.FactoryProvider( - charger -> new ChargeUpToMaxSocStrategy(charger, MAX_SOC))); + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingAndAssignmentLogic.Factory.class); + bind(Key.get(ChargingStrategy.Factory.class, DvrpModes.mode(mode))).toInstance(new ChargeUpToMaxSocStrategy.Factory(MAX_SOC)); //TODO switch to VariableSpeedCharging for Nissan bind(ChargingPower.Factory.class).toInstance(ev -> new FixedSpeedCharging(ev, CHARGING_SPEED_FACTOR)); bind(TemperatureService.class).toInstance(linkId -> TEMPERATURE); diff --git a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiScenario.java b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiScenario.java index f5598174103..bd266b4b0f2 100644 --- a/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiScenario.java +++ b/contribs/taxi/src/main/java/org/matsim/contrib/etaxi/run/RunETaxiScenario.java @@ -23,6 +23,7 @@ import org.matsim.api.core.v01.Scenario; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.contrib.dvrp.run.DvrpModule; import org.matsim.contrib.dvrp.run.DvrpQSimComponents; import org.matsim.contrib.ev.EvConfigGroup; @@ -30,12 +31,13 @@ import org.matsim.contrib.ev.charging.ChargeUpToMaxSocStrategy; import org.matsim.contrib.ev.charging.ChargingLogic; import org.matsim.contrib.ev.charging.ChargingPower; +import org.matsim.contrib.ev.charging.ChargingStrategy; import org.matsim.contrib.ev.charging.ChargingWithQueueingAndAssignmentLogic; import org.matsim.contrib.ev.charging.FixedSpeedCharging; import org.matsim.contrib.ev.discharging.IdleDischargingHandler; +import org.matsim.contrib.ev.temperature.TemperatureService; import org.matsim.contrib.evrp.EvDvrpFleetQSimModule; import org.matsim.contrib.evrp.OperatingVehicleProvider; -import org.matsim.contrib.ev.temperature.TemperatureService; import org.matsim.contrib.otfvis.OTFVisLiveModule; import org.matsim.contrib.taxi.run.MultiModeTaxiConfigGroup; import org.matsim.contrib.taxi.run.TaxiConfigGroup; @@ -48,6 +50,8 @@ import org.matsim.core.scenario.ScenarioUtils; import org.matsim.vis.otfvis.OTFVisConfigGroup; +import com.google.inject.Key; + public class RunETaxiScenario { private static final double CHARGING_SPEED_FACTOR = 1.5; // > 1 in this example private static final double MAX_SOC = 0.8; // charge up to 80% SOC @@ -91,11 +95,14 @@ protected void configureQSim() { controler.addOverridingModule(new AbstractModule() { @Override public void install() { - bind(ChargingLogic.Factory.class).toProvider(new ChargingWithQueueingAndAssignmentLogic.FactoryProvider( - charger -> new ChargeUpToMaxSocStrategy(charger, MAX_SOC))); + bind(ChargingLogic.Factory.class).to(ChargingWithQueueingAndAssignmentLogic.Factory.class); //TODO switch to VariableSpeedCharging for Nissan bind(ChargingPower.Factory.class).toInstance(ev -> new FixedSpeedCharging(ev, CHARGING_SPEED_FACTOR)); bind(TemperatureService.class).toInstance(linkId -> TEMPERATURE); + + for (TaxiConfigGroup taxiCfg : multiModeTaxiConfig.getModalElements()) { + bind(Key.get(ChargingStrategy.Factory.class, DvrpModes.mode(taxiCfg.getMode()))).toInstance(new ChargeUpToMaxSocStrategy.Factory(MAX_SOC)); + } } }); diff --git a/contribs/vsp/pom.xml b/contribs/vsp/pom.xml index 8f4e01bec37..29cbf1de5d6 100644 --- a/contribs/vsp/pom.xml +++ b/contribs/vsp/pom.xml @@ -22,59 +22,59 @@ org.matsim.contrib multimodal - 2025.0-SNAPSHOT + ${project.parent.version} compile org.matsim.contrib taxi - 2025.0-SNAPSHOT + ${project.parent.version} compile org.matsim.contrib dvrp - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib parking - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib freight - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib accessibility - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib emissions - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib minibus - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib common - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib analysis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib informed-mode-choice - 2025.0-SNAPSHOT + ${project.parent.version} @@ -97,17 +97,17 @@ org.matsim.contrib otfvis - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib noise - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib signals - 2025.0-SNAPSHOT + ${project.parent.version} org.openstreetmap.osmosis @@ -145,7 +145,7 @@ org.matsim.contrib cadyts-integration - 2025.0-SNAPSHOT + ${project.parent.version} org.apache.poi @@ -174,12 +174,12 @@ org.matsim matsim-examples - 2025.0-SNAPSHOT + ${project.parent.version} org.matsim.contrib drt - 2025.0-SNAPSHOT + ${project.parent.version} org.openjfx diff --git a/contribs/vsp/src/main/java/playground/vsp/ev/UrbanVehicleChargingHandler.java b/contribs/vsp/src/main/java/playground/vsp/ev/UrbanVehicleChargingHandler.java index 592722998fe..8e40eb18120 100644 --- a/contribs/vsp/src/main/java/playground/vsp/ev/UrbanVehicleChargingHandler.java +++ b/contribs/vsp/src/main/java/playground/vsp/ev/UrbanVehicleChargingHandler.java @@ -61,13 +61,16 @@ class UrbanVehicleChargingHandler private final ElectricFleet electricFleet; private final ImmutableListMultimap, Charger> chargersAtLinks; + private final ChargingStrategy.Factory chargingStrategyFactory; + private Map, Map, Tuple, Id>>> chargingProcedures = new HashMap<>(); @Inject - UrbanVehicleChargingHandler(ChargingInfrastructure chargingInfrastructure, ElectricFleet electricFleet) { + UrbanVehicleChargingHandler(ChargingInfrastructure chargingInfrastructure, ElectricFleet electricFleet, ChargingStrategy.Factory chargingStrategyFactory) { this.chargingInfrastructure = chargingInfrastructure; this.electricFleet = electricFleet; this.chargersAtLinks = ChargingInfrastructureUtils.getChargersAtLinks(chargingInfrastructure ); + this.chargingStrategyFactory = chargingStrategyFactory; } /** @@ -89,7 +92,8 @@ public void handleEvent(ActivityStartEvent event) { .findAny() .get(); - charger.getLogic().addVehicle(ev, event.getTime()); + ChargingStrategy strategy = chargingStrategyFactory.createStrategy(charger.getSpecification(), ev); + charger.getLogic().addVehicle(ev, strategy, event.getTime()); Map, Tuple, Id>> proceduresOnLink = this.chargingProcedures.get(event.getLinkId()); if(proceduresOnLink != null && proceduresOnLink.containsKey(event.getPersonId())){ throw new RuntimeException("person " + event.getPersonId() + " tries to charge 2 vehicles at the same time on link " + event.getLinkId() + diff --git a/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java b/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java index dbdb804cb9b..3f1ed342aa5 100644 --- a/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java +++ b/contribs/vsp/src/test/java/playground/vsp/cadyts/marginals/ModalDistanceAndCountsCadytsIT.java @@ -1,5 +1,4 @@ package playground.vsp.cadyts.marginals; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -63,13 +62,14 @@ private static DistanceDistribution createDistanceDistribution() { return result; } - private Config createConfig() { + private Config createConfig(String outputSuffix) { Config config = ConfigUtils.createConfig(); String[] modes = new String[]{TransportMode.car, TransportMode.bike}; config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable); - config.controller().setOutputDirectory(this.utils.getOutputDirectory()); + String outputDirectory = this.utils.getOutputDirectory(); + config.controller().setOutputDirectory(outputDirectory.substring(0,outputDirectory.length()-1)+outputSuffix); config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); config.controller().setLastIteration(40); @@ -244,7 +244,7 @@ private static Plan createPlan(String mode, String endLink, Network network, Pop @MethodSource("arguments") void test(double countsWeight, double modalDistanceWeight) { - Config config = createConfig(); + Config config = createConfig(countsWeight+"_"+modalDistanceWeight); CadytsConfigGroup cadytsConfigGroup = new CadytsConfigGroup(); cadytsConfigGroup.setWriteAnalysisFile(true); config.addModule(cadytsConfigGroup); diff --git a/examples/scenarios/logistics-2regions/2regions-network.xml b/examples/scenarios/logistics-2regions/2regions-network.xml new file mode 100644 index 00000000000..5e45ad6bca0 --- /dev/null +++ b/examples/scenarios/logistics-2regions/2regions-network.xml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java index d6c059897d8..521c237d412 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java @@ -38,15 +38,7 @@ import org.matsim.pt.transitSchedule.api.TransitStopFacility; import org.matsim.vehicles.Vehicle; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; +import java.util.*; /** * The actual RAPTOR implementation, based on Delling et al, Round-Based Public Transit Routing. @@ -118,7 +110,8 @@ public RaptorRoute calcLeastCostRoute(double depTime, Facility fromFacility, Fac reset(); CachingTransferProvider transferProvider = this.data.new CachingTransferProvider(); - Map destinationStops = new HashMap<>(); + // Using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map destinationStops = new LinkedHashMap<>(); // go through all egressStops; check if already in destinationStops; if so, check if current cost is smaller; if so, then replace. This can // presumably happen when the same stop can be reached at lower cost by a different egress mode. (*) @@ -141,7 +134,8 @@ public RaptorRoute calcLeastCostRoute(double depTime, Facility fromFacility, Fac } // same as (*) for access stops: - Map initialStops = new HashMap<>(); + // Also, using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map initialStops = new LinkedHashMap<>(); for (InitialStop accessStop : accessStops) { InitialStop alternative = initialStops.get(accessStop.stop); if (alternative == null || accessStop.accessCost < alternative.accessCost) { @@ -833,7 +827,7 @@ private void handleTransfers(boolean strict, RaptorParameters raptorParams, Cach final int firstTransferIndex; final int lastTransferIndex; final RTransfer[] transfers; - + if (!useAdaptiveTransferCalculation) { // efficient lookup from the precomputed transfer candidates transfers = this.data.transfers; diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java index a02b58c7b35..e4d4f28a1c5 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorData.java @@ -20,17 +20,7 @@ package ch.sbb.matsim.routing.pt.raptor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -148,7 +138,8 @@ public static SwissRailRaptorData create(TransitSchedule schedule, @Nullable Veh // enumerate TransitStopFacilities along their usage in transit routes to (hopefully) achieve a better memory locality // well, I'm not even sure how often we'll need the transit stop facilities, likely we'll use RouteStops more often Map stopFacilityIndices = new HashMap<>((int) (schedule.getFacilities().size() * 1.5)); - Map routeStopsPerStopFacility = new HashMap<>(); + // Using a LinkedHashMap instead of a regular HashMap here is necessary to have a deterministic behaviour + Map routeStopsPerStopFacility = new LinkedHashMap<>(); boolean useModeMapping = staticConfig.isUseModeMappingForPassengers(); for (TransitLine line : schedule.getTransitLines().values()) { diff --git a/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinks.java b/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinks.java index d0532315137..02ea9efcf79 100644 --- a/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinks.java +++ b/matsim/src/main/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinks.java @@ -20,7 +20,6 @@ package org.matsim.pt.utils; -import com.google.common.annotations.Beta; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; @@ -40,11 +39,8 @@ * is assigned to a loop link, located in a node with the same coordinates as the stop. * The stop facility ID is used for node and link IDs. * - * @author mrieser, davibicudo - * - * @implNote THis functionality might be merged with {@link CreatePseudoNetwork}. + * @author mrieser, davibicudo, rakow */ -@Beta public class CreatePseudoNetworkWithLoopLinks { private final TransitSchedule schedule; @@ -82,23 +78,29 @@ public void createNetwork() { List> toBeRemoved = new LinkedList<>(); for (TransitLine tLine : this.schedule.getTransitLines().values()) { for (TransitRoute tRoute : tLine.getRoutes().values()) { - ArrayList> routeLinks = new ArrayList<>(); + + if (tRoute.getStops().size() < 2) { + System.err.println("Line " + tLine.getId() + " route " + tRoute.getId() + " has less than two stops. Removing this route from schedule."); + toBeRemoved.add(new Tuple<>(tLine, tRoute)); + continue; + } + + List> routeLinks = new ArrayList<>(); TransitRouteStop prevStop = null; + for (TransitRouteStop stop : tRoute.getStops()) { if (prevStop != null) { Link link = getNetworkLink(prevStop, stop); routeLinks.add(link.getId()); } + + // Add the loop links of all stops to the route + routeLinks.add(getLoopLink(stop.getStopFacility()).getId()); prevStop = stop; } - if (!routeLinks.isEmpty()) { - NetworkRoute route = RouteUtils.createNetworkRoute(routeLinks); - tRoute.setRoute(route); - } else { - System.err.println("Line " + tLine.getId() + " route " + tRoute.getId() + " has less than two stops. Removing this route from schedule."); - toBeRemoved.add(new Tuple<>(tLine, tRoute)); - } + NetworkRoute route = RouteUtils.createNetworkRoute(routeLinks); + tRoute.setRoute(route); } } @@ -114,6 +116,14 @@ private void createStopNodesAndLoopLinks() { this.nodes.put(stop, node); Link loopLink = this.network.getFactory().createLink(Id.createLinkId (this.prefix + stop.getId()), node, node); + // Loop links needs to have a length so that the travel time is not zero + loopLink.setLength(1); + loopLink.setFreespeed(linkFreeSpeed); + loopLink.setCapacity(linkCapacity); + // Ensure enough vehicles can be placed on the loop link + loopLink.setNumberOfLanes(linkCapacity); + loopLink.setAllowedModes(transitModes); + stop.setLinkId(loopLink.getId()); this.network.addLink(loopLink); Tuple connection = new Tuple<>(node, node); @@ -121,6 +131,15 @@ private void createStopNodesAndLoopLinks() { } } + /** + * Get the loop link for a stop facility. + */ + private Link getLoopLink(final TransitStopFacility stop) { + Node node = this.nodes.get(stop); + Tuple connection = new Tuple<>(node, node); + return this.links.get(connection); + } + private Link getNetworkLink(final TransitRouteStop fromStop, final TransitRouteStop toStop) { TransitStopFacility fromFacility = fromStop.getStopFacility(); TransitStopFacility toFacility = toStop.getStopFacility(); @@ -137,13 +156,15 @@ private Link createAndAddLink(Tuple connection) { Node fromNode = connection.getFirst(); Node toNode = connection.getSecond(); Link link; - link = this.network.getFactory().createLink(Id.createLinkId(this.prefix + fromNode.getId() + "-" + toNode.getId()), fromNode, - toNode); - link.setLength(CoordUtils.calcEuclideanDistance(fromNode.getCoord(), toNode.getCoord())); + link = this.network.getFactory().createLink(Id.createLinkId(fromNode.getId() + "-" + toNode.getId()), + fromNode, toNode); + double dist = CoordUtils.calcEuclideanDistance(fromNode.getCoord(), toNode.getCoord()); + link.setLength(dist); link.setFreespeed(linkFreeSpeed); link.setCapacity(linkCapacity); link.setNumberOfLanes(1); + this.network.addLink(link); link.setAllowedModes(this.transitModes); this.links.put(connection, link); diff --git a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java index 7c263b086e3..d149ad07eb2 100644 --- a/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java +++ b/matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java @@ -299,16 +299,24 @@ public static void setAccessTime(VehicleType vehicleType, double accessTime) { vehicleType.getAttributes().putAttribute(ACCESSTIME, accessTime); } + /** + * @deprecated use getFuelConsumptionPerMeter instead + */ + @Deprecated public static Double getFuelConsumption(VehicleType vehicleType) { - return getFuelConsumption(vehicleType.getEngineInformation()); + return getFuelConsumptionLitersPerMeter(vehicleType.getEngineInformation()); } + /** + * @deprecated use setFuelConsumptionPerMeter instead + */ + @Deprecated public static void setFuelConsumption(VehicleType vehicleType, double literPerMeter) { - setFuelConsumption(vehicleType.getEngineInformation(), literPerMeter); + setFuelConsumptionLitersPerMeter(vehicleType.getEngineInformation(), literPerMeter); } //******** EngineInformation attributes ************ - + //TODO create enum for fuel type public static String getHbefaTechnology( EngineInformation ei ){ return (String) ei.getAttributes().getAttribute( HBEFA_TECHNOLOGY ) ; } @@ -345,6 +353,14 @@ public static void setEnergyConsumptionKWhPerMeter(EngineInformation engineInfor engineInformation.getAttributes().putAttribute(ENERGYCONSUMPTION, energyConsumptionKWhPerMeter); } + public static Double getFuelConsumptionLitersPerMeter(EngineInformation engineInformation) { + return (Double) engineInformation.getAttributes().getAttribute(FUELCONSUMPTION); + } + + public static void setFuelConsumptionLitersPerMeter(EngineInformation engineInformation, double fuelConsumptionLitersPerMeter) { + engineInformation.getAttributes().putAttribute(FUELCONSUMPTION, fuelConsumptionLitersPerMeter); + } + public static Double getEnergyCapacity(EngineInformation engineInformation) { return (Double) engineInformation.getAttributes().getAttribute(ENERGYCAPACITY); } @@ -377,21 +393,33 @@ public static Vehicle createVehicle( Id id , VehicleType type ){ return new VehicleImpl( id , type ); } + /** + * @deprecated use getHbefaTechnology instead + */ @Deprecated static EngineInformation.FuelType getFuelType(EngineInformation engineInformation ){ return (EngineInformation.FuelType) engineInformation.getAttributes().getAttribute( FUEL_TYPE ); } + /** + * @deprecated use setHbefaTechnology instead + */ @Deprecated static void setFuelType(EngineInformation engineInformation, EngineInformation.FuelType fuelType ){ engineInformation.getAttributes().putAttribute( FUEL_TYPE, fuelType); } + /** + * @Deprecated use getFuelConsumptionPerMeter instead + */ @Deprecated static Double getFuelConsumption(EngineInformation engineInformation ){ return (Double) engineInformation.getAttributes().getAttribute( FUELCONSUMPTION ); } + /** + * @Deprecated use setFuelConsumptionPerMeter instead + */ @Deprecated static void setFuelConsumption(EngineInformation engineInformation, double fuelConsumption ){ engineInformation.getAttributes().putAttribute( FUELCONSUMPTION, fuelConsumption); diff --git a/matsim/src/main/resources/dtd/lspsDefinitions_v1.xsd b/matsim/src/main/resources/dtd/lspsDefinitions_v1.xsd index 32a03b4d072..ff3cb9be076 100644 --- a/matsim/src/main/resources/dtd/lspsDefinitions_v1.xsd +++ b/matsim/src/main/resources/dtd/lspsDefinitions_v1.xsd @@ -1,11 +1,11 @@ + targetNamespace="http://www.matsim.org/files/dtd" + xmlns="http://www.matsim.org/files/dtd" + elementFormDefault="qualified" + xml:lang="en"> - + @@ -24,6 +24,7 @@ + diff --git a/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java b/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java new file mode 100644 index 00000000000..99689ade903 --- /dev/null +++ b/matsim/src/test/java/ch/sbb/matsim/RaptorDeterminismTest.java @@ -0,0 +1,207 @@ +package ch.sbb.matsim; + +import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptorData; +import ch.sbb.matsim.routing.pt.raptor.RaptorStopFinder; +import ch.sbb.matsim.routing.pt.raptor.RaptorParametersForPerson; +import ch.sbb.matsim.routing.pt.raptor.SwissRailRaptor; +import ch.sbb.matsim.routing.pt.raptor.RaptorParameters; +import ch.sbb.matsim.routing.pt.raptor.InitialStop; +import com.google.inject.Injector; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.*; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.events.EventsManagerModule; +import org.matsim.core.router.TripRouter; +import org.matsim.core.router.TripRouterModule; +import org.matsim.core.router.TripStructureUtils; +import org.matsim.core.router.costcalculators.TravelDisutilityModule; +import org.matsim.core.scenario.ScenarioByInstanceModule; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.trafficmonitoring.TravelTimeCalculatorModule; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.timing.TimeInterpretationModule; +import org.matsim.examples.ExamplesUtils; +import org.matsim.facilities.ActivityFacilities; +import org.matsim.facilities.FacilitiesUtils; +import org.matsim.facilities.Facility; +import org.matsim.pt.routes.DefaultTransitPassengerRoute; +import org.matsim.pt.transitSchedule.api.TransitStopFacility; + + +import java.net.URL; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +public class RaptorDeterminismTest { + + public static boolean comparePlan(List left, List right) { + if(left.size() != right.size()) { + return false; + } + for(int i=0; i[] transitStopFacilitiesByScenario = new List[scenarioSamples]; + List[] personLists = new List[scenarioSamples]; + TripRouter[] tripRouters = new TripRouter[scenarioSamples]; + + logger.info(String.format("Loading scenario %d times", scenarioSamples)); + for(int scenarioIndex=0; scenarioIndex(scenario.getTransitSchedule().getFacilities().values()); + swissRailRaptorData[scenarioIndex] = swissRailRaptors[scenarioIndex].getUnderlyingData(); + personLists[scenarioIndex] = scenario.getPopulation().getPersons().values().stream().toList(); + + tripRouters[scenarioIndex] = injector.getInstance(TripRouter.class); + } + + logger.info(String.format("Comparing stop facilities order %d", scenarioSamples)); + + for(int scenarioIndex=1; scenarioIndex referenceElements = tripRouters[0].calcRoute("pt", fromFacility, toFacility, referenceTrip.getOriginActivity().getEndTime().seconds(), referencePerson, referenceTrip.getTripAttributes()); + + for(int scenarioIndex=1; scenarioIndex referenceInitialStops = raptorStopFinders[0].findStops(fromFacility, toFacility, referencePerson, referenceTrip.getOriginActivity().getEndTime().seconds(), referenceTrip.getTripAttributes(), referenceRaptorParameters, swissRailRaptorData[0], direction); + List sortedReferenceInitialStops = new ArrayList<>(referenceInitialStops); + sortedReferenceInitialStops.sort(Comparator.comparing(InitialStop::toString)); + + List comparedInitialStops = raptorStopFinders[scenarioIndex].findStops(otherFromFacility, otherToFacility, referencePerson, referenceTrip.getOriginActivity().getEndTime().seconds(), referenceTrip.getTripAttributes(), otherRaptorParameters, swissRailRaptorData[scenarioIndex], direction); + + assert referenceInitialStops.size() == comparedInitialStops.size(); + + List sortedComparedInitialStops = new ArrayList<>(comparedInitialStops); + sortedComparedInitialStops.sort(Comparator.comparing(InitialStop::toString)); + for(int j=0; j comparedElements = tripRouters[scenarioIndex].calcRoute("pt", otherFromFacility, otherToFacility, referenceTrip.getOriginActivity().getEndTime().seconds(), otherPerson, referenceTrip.getTripAttributes()); + assert comparePlan(referenceElements, comparedElements); + } + } + } + } + +} diff --git a/matsim/src/test/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinksTest.java b/matsim/src/test/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinksTest.java new file mode 100644 index 00000000000..431c0c87bcd --- /dev/null +++ b/matsim/src/test/java/org/matsim/pt/utils/CreatePseudoNetworkWithLoopLinksTest.java @@ -0,0 +1,28 @@ +package org.matsim.pt.utils; + +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Scenario; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.scenario.ScenarioUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +class CreatePseudoNetworkWithLoopLinksTest { + + @Test + void createValidSchedule() { + + Scenario scenario = ScenarioUtils.loadScenario(ConfigUtils.loadConfig("test/scenarios/pt-tutorial/0.config.xml")); + + CreatePseudoNetworkWithLoopLinks creator = new CreatePseudoNetworkWithLoopLinks(scenario.getTransitSchedule(), scenario.getNetwork(), "pt_"); + creator.createNetwork(); + + + TransitScheduleValidator.ValidationResult result = TransitScheduleValidator.validateAll(scenario.getTransitSchedule(), scenario.getNetwork()); + + assertThat(result.getWarnings()).isEmpty(); + assertThat(result.getErrors()).isEmpty(); + assertThat(result.isValid()).isTrue(); + + } +} diff --git a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java index 287858329cb..4432063a364 100644 --- a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java +++ b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java @@ -31,8 +31,8 @@ import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.utils.io.IOUtils; import org.matsim.core.utils.misc.CRCChecksum; -import org.matsim.utils.eventsfilecomparison.EventsFileComparator; import org.matsim.utils.eventsfilecomparison.ComparisonResult; +import org.matsim.utils.eventsfilecomparison.EventsFileComparator; import java.io.BufferedReader; import java.io.File; @@ -41,6 +41,9 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Objects; /** @@ -51,6 +54,11 @@ public final class MatsimTestUtils implements BeforeEachCallback, AfterEachCallback { private static final Logger log = LogManager.getLogger(MatsimTestUtils.class); + //used for copying files from output to input. Don't delete even if they are unused in production + public static final String FILE_NAME_PLANS = "output_plans.xml.gz"; + public static final String FILE_NAME_NETWORK = "output_network.xml.gz"; + public static final String FILE_NAME_EVENTS = "output_events.xml.gz"; + public enum TestMethodType { Normal, Parameterized } @@ -60,12 +68,16 @@ public enum TestMethodType { */ public static final double EPSILON = 1e-10; - /** The default output directory, where files of this test should be written to. - * Includes the trailing '/' to denote a directory. */ + /** + * The default output directory, where files of this test should be written to. + * Includes the trailing '/' to denote a directory. + */ private String outputDirectory = null; - /** The default input directory, where files of this test should be read from. - * Includes the trailing '/' to denote a directory. */ + /** + * The default input directory, where files of this test should be read from. + * Includes the trailing '/' to denote a directory. + */ private String inputDirectory = null; /** @@ -144,7 +156,7 @@ public URL packageInputResourcePath() { private URL getResourceNotNull(String pathString) { URL resource = this.testClass.getResource(pathString); if (resource == null) { - throw new UncheckedIOException(new IOException("Not found: "+pathString)); + throw new UncheckedIOException(new IOException("Not found: " + pathString)); } return resource; } @@ -171,7 +183,8 @@ public Config createConfig(URL context) { /** * Loads a configuration from file (or the default config if configfile is null) - * and sets the output directory to {classPath}/{methodName}/. For parameterized tests, the output directory is {classPath}/{methodName}/{parameters}/. + * and sets the output directory to {classPath}/{methodName}/. For parameterized tests, the output directory is {classPath}/{methodName}/{ + * parameters}/. * * @param configfile The path/filename of a configuration file, or null to load the default configuration. * @return The loaded configuration. @@ -181,7 +194,7 @@ public Config loadConfig(final String configfile, TestMethodType testMethodType, if (configfile != null) { config = ConfigUtils.loadConfig(configfile, customGroups); } else { - config = ConfigUtils.createConfig( customGroups ); + config = ConfigUtils.createConfig(customGroups); } return setOutputDirectory(config, testMethodType); } @@ -195,7 +208,7 @@ public Config loadConfig(final URL configfile, TestMethodType testMethodType, fi if (configfile != null) { config = ConfigUtils.loadConfig(configfile, customGroups); } else { - config = ConfigUtils.createConfig( customGroups ); + config = ConfigUtils.createConfig(customGroups); } return setOutputDirectory(config, testMethodType); } @@ -226,7 +239,7 @@ public String getParameterizedTestInputString() { } public Config createConfig(final ConfigGroup... customGroups) { - Config config = ConfigUtils.createConfig( customGroups ); + Config config = ConfigUtils.createConfig(customGroups); this.outputDirectory = getOutputDirectory(); config.controller().setOutputDirectory(this.outputDirectory); return config; @@ -254,7 +267,7 @@ public String getOutputDirectory() { public String getOutputDirectory(String subDir) { if (this.outputDirectory == null) { - this.outputDirectory = "test/output/" + this.testClass.getCanonicalName().replace('.', '/') + "/" + getMethodName()+ "/" + subDir; + this.outputDirectory = "test/output/" + this.testClass.getCanonicalName().replace('.', '/') + "/" + getMethodName() + "/" + subDir; } createOutputDirectory(); return this.outputDirectory; @@ -271,18 +284,20 @@ public String getInputDirectory() { } return this.inputDirectory; } + /** - * Returns the path to the input directory one level above the default input directory for this test including a trailing slash as directory delimiter. + * Returns the path to the input directory one level above the default input directory for this test including a trailing slash as directory + * delimiter. * * @return path to the input directory for this test */ public String getClassInputDirectory() { if (this.classInputDirectory == null) { - LogManager.getLogger(this.getClass()).info( "user.dir = " + System.getProperty("user.dir") ) ; + LogManager.getLogger(this.getClass()).info("user.dir = " + System.getProperty("user.dir")); this.classInputDirectory = "test/input/" + - this.testClass.getCanonicalName().replace('.', '/') + "/"; + this.testClass.getCanonicalName().replace('.', '/') + "/"; // this.classInputDirectory = System.getProperty("user.dir") + "/test/input/" + // this.testClass.getCanonicalName().replace('.', '/') + "/"; // (this used to be relative, i.e. ... = "test/input/" + ... . Started failing when @@ -292,8 +307,10 @@ public String getClassInputDirectory() { } return this.classInputDirectory; } + /** - * Returns the path to the input directory two levels above the default input directory for this test including a trailing slash as directory delimiter. + * Returns the path to the input directory two levels above the default input directory for this test including a trailing slash as directory + * delimiter. * * @return path to the input directory for this test */ @@ -321,7 +338,7 @@ public String getMethodName() { * This should be used for "fixtures" only that provide a scenario common to several * test cases. */ - public void initWithoutJUnitForFixture(Class fixture, Method method){ + public void initWithoutJUnitForFixture(Class fixture, Method method) { this.testClass = fixture; this.testMethodName = method.getName(); } @@ -333,27 +350,62 @@ public static void assertEqualFilesLineByLine(String inputFilename, String outpu String lineInput; String lineOutput; - while( ((lineInput = readerV1Input.readLine()) != null) && ((lineOutput = readerV1Output.readLine()) != null) ){ - if ( !Objects.equals( lineInput.trim(), lineOutput.trim() ) ){ - log.info( "Reading line... " ); - log.info( lineInput ); - log.info( lineOutput ); - log.info( "" ); + while (((lineInput = readerV1Input.readLine()) != null) && ((lineOutput = readerV1Output.readLine()) != null)) { + if (!Objects.equals(lineInput.trim(), lineOutput.trim())) { + log.info("Reading line... "); + log.info(lineInput); + log.info(lineOutput); + log.info(""); } - Assertions.assertEquals(lineInput.trim(), lineOutput.trim(), "Lines have different content: " ); + Assertions.assertEquals(lineInput.trim(), lineOutput.trim(), "Lines have different content: "); } } catch (IOException e) { throw new UncheckedIOException(e); } } - public static void assertEqualEventsFiles( String filename1, String filename2 ) { - Assertions.assertEquals(ComparisonResult.FILES_ARE_EQUAL ,EventsFileComparator.compare(filename1, filename2) ); + public static void assertEqualEventsFiles(String filename1, String filename2) { + Assertions.assertEquals(ComparisonResult.FILES_ARE_EQUAL, EventsFileComparator.compare(filename1, filename2)); + } + + public static void assertEqualFilesBasedOnCRC(String filename1, String filename2) { + long checksum1 = CRCChecksum.getCRCFromFile(filename1); + long checksum2 = CRCChecksum.getCRCFromFile(filename2); + Assertions.assertEquals(checksum1, checksum2, "different file checksums"); + } + + /** + * Creates the input directory for this test. + */ + public void createInputDirectory() { + try { + Files.createDirectories(Path.of(getInputDirectory())); + } catch (IOException e) { + e.printStackTrace(); + Assertions.fail(); + } + } + + /** + * Copies a file from the output directory to the input directory. This is normally only needed during development, if one would not do it + * manually. + */ + public void copyFileFromOutputToInput(String fileName) { + createInputDirectory(); + copyFileFromOutputToInput(fileName, fileName); } - public static void assertEqualFilesBasedOnCRC( String filename1, String filename2 ) { - long checksum1 = CRCChecksum.getCRCFromFile(filename1) ; - long checksum2 = CRCChecksum.getCRCFromFile(filename2) ; - Assertions.assertEquals( checksum1, checksum2, "different file checksums" ); - } + /** + * Copies a file from the output directory to the input directory. This is normally only needed during development, if one would not do it + * manually. + */ + public void copyFileFromOutputToInput(String outputFile, String inputFile) { + createInputDirectory(); + try { + Files.copy(Path.of(getOutputDirectory() + outputFile), Path.of(getInputDirectory() + inputFile), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + Assertions.fail(); + } + } }