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 d6d182c9a7c..9b594c05f6b 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 @@ -195,97 +195,29 @@ public static void runJsprit(Scenario scenario) throws ExecutionException, Inter carrierActivityCounterMap.put(carrier.getId(), carrierActivityCounterMap.getOrDefault(carrier.getId(), 0) + 2*carrier.getShipments().size()); } - HashMap, Integer> sortedMap = carrierActivityCounterMap.entrySet().stream() - .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new)); - AtomicInteger startedVRPCounter = new AtomicInteger(0); - AtomicInteger solvedVRPCounter = new AtomicInteger(0); - - ArrayList> tempList = new ArrayList<>(sortedMap.keySet()); - int nThreads = Runtime.getRuntime().availableProcessors(); - ExecutorService executorService = Executors.newFixedThreadPool(nThreads); + int nThreads = Runtime.getRuntime().availableProcessors(); log.info("Starting VRP solving for {} carriers in parallel with {} threads.", carriers.getCarriers().size(), nThreads); - List>> splitList = splitListAlternating(nThreads, tempList); - log.info("Distribution of carriers on threads: {}", splitList.stream().map(List::size).toList()); - List> futureList = new ArrayList<>(); - for (List> subList : splitList) { - futureList.add(executorService.submit(() -> subList.forEach(carrierId -> { - Carrier carrier = carriers.getCarriers().get(carrierId); - - double start = System.currentTimeMillis(); - if (!carrier.getServices().isEmpty()) - log.info("Start tour planning for {} which has {} services", carrier.getId(), carrier.getServices().size()); - else if (!carrier.getShipments().isEmpty()) - log.info("Start tour planning for {} which has {} shipments", carrier.getId(), carrier.getShipments().size()); - - startedVRPCounter.incrementAndGet(); - log.info("started VRP solving for carrier number {} out of {} carriers. Current thread id: {}", startedVRPCounter.get(), carriers.getCarriers() - .size(), Thread.currentThread() - .getId()); - - VehicleRoutingProblem problem = MatsimJspritFactory.createRoutingProblemBuilder(carrier, scenario.getNetwork()) - .setRoutingCost(netBasedCosts).build(); - VehicleRoutingAlgorithm algorithm = MatsimJspritFactory.loadOrCreateVehicleRoutingAlgorithm(scenario, freightCarriersConfigGroup, netBasedCosts, problem); - - algorithm.getAlgorithmListeners().addListener(new StopWatch(), VehicleRoutingAlgorithmListeners.Priority.HIGH); - int jspritIterations = getJspritIterations(carrier); - try { - if (jspritIterations > 0) { - algorithm.setMaxIterations(jspritIterations); - } else { - throw new InvalidAttributeValueException( - "Carrier has invalid number of jsprit iterations. They must be positive! Carrier id: " - + carrier.getId().toString()); - } - } catch (Exception e) { - throw new RuntimeException(e); - // e.printStackTrace(); - } - - VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); - - log.info("tour planning for carrier {} took {} seconds.", carrier.getId(), (System.currentTimeMillis() - start) / 1000); + ThreadPoolExecutor executor = new JspritTreadPoolExecutor(new PriorityBlockingQueue<>(), nThreads); - CarrierPlan newPlan = MatsimJspritFactory.createPlan(carrier, solution); - // yy In principle, the carrier should know the vehicle types that it can deploy. + List> futures = new ArrayList<>(); + List, Integer>> sorted = carrierActivityCounterMap.entrySet().stream() + .sorted(Map.Entry.comparingByValue((o1, o2) -> o2 - o1)) + .toList(); - log.info("routing plan for carrier {}", carrier.getId()); - NetworkRouter.routePlan(newPlan, netBasedCosts); - solvedVRPCounter.incrementAndGet(); - double timeForPlanningAndRouting = (System.currentTimeMillis() - start) / 1000; - log.info("routing for carrier {} finished. Tour planning plus routing took {} seconds.", carrier.getId(), - timeForPlanningAndRouting); - log.info("solved {} out of {} carriers.", solvedVRPCounter.get(), carriers.getCarriers().size()); - - carrier.setSelectedPlan(newPlan); - setJspritComputationTime(carrier, timeForPlanningAndRouting); - }))); + for (Map.Entry, Integer> entry : sorted){ + JspritCarrierTask task = new JspritCarrierTask(entry.getValue(), carriers.getCarriers().get(entry.getKey()), scenario, netBasedCosts, startedVRPCounter, carriers.getCarriers().size()); + log.info("Adding task for carrier {} with priority {}", entry.getKey(), entry.getValue()); + futures.add(executor.submit(task)); } - for (Future future : futureList) { + for (Future future : futures) { future.get(); } } - // split tempList in nThreads parts such that it is split to 1,2,...,n,1,2,.. - private static List>> splitListAlternating(int nThreads, ArrayList> tempList) { - List>> splitList = new ArrayList<>(); - for (int i = 0; i < nThreads; i++) { - List> subList = new ArrayList<>(); - for (int j = i; j < tempList.size(); j += nThreads) { - subList.add(tempList.get(j)); - } - splitList.add(subList); - } - - assert splitList.size() == nThreads; - assert splitList.stream().mapToInt(List::size).sum() == tempList.size(); - return splitList; - } - /** * Creates a new {@link Carriers} container only with {@link CarrierShipment}s * for creating a new VRP. As consequence of the transformation of @@ -667,4 +599,100 @@ public static void writeCarriers(Carriers carriers, String filename ) { new CarrierPlanWriter( carriers ).write( filename ); } + static class JspritCarrierTask implements Runnable{ + private final int priority; + private final Carrier carrier; + private final Scenario scenario; + private final NetworkBasedTransportCosts netBasedCosts; + private final AtomicInteger startedVRPCounter; + private final int taskCount; + + public JspritCarrierTask(int priority, Carrier carrier, Scenario scenario, NetworkBasedTransportCosts netBasedCosts, AtomicInteger startedVRPCounter, int taskCount) { + this.priority = priority; + this.carrier = carrier; + this.scenario = scenario; + this.netBasedCosts = netBasedCosts; + this.startedVRPCounter = startedVRPCounter; + this.taskCount = taskCount; + } + + public int getPriority() { + return priority; + } + + @Override + public void run() { + FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule( scenario.getConfig(), FreightCarriersConfigGroup.class ); + + double start = System.currentTimeMillis(); + if (!carrier.getServices().isEmpty()) + log.info("Start tour planning for {} which has {} services", carrier.getId(), carrier.getServices().size()); + else if (!carrier.getShipments().isEmpty()) + log.info("Start tour planning for {} which has {} shipments", carrier.getId(), carrier.getShipments().size()); + + startedVRPCounter.incrementAndGet(); + log.info("started VRP solving for carrier number {} out of {} carriers. Thread id: {}. Priority: {}", startedVRPCounter.get(), taskCount, Thread.currentThread().getId(), this.priority); + + VehicleRoutingProblem problem = MatsimJspritFactory.createRoutingProblemBuilder(carrier, scenario.getNetwork()) + .setRoutingCost(netBasedCosts).build(); + VehicleRoutingAlgorithm algorithm = MatsimJspritFactory.loadOrCreateVehicleRoutingAlgorithm(scenario, freightCarriersConfigGroup, netBasedCosts, problem); + + algorithm.getAlgorithmListeners().addListener(new StopWatch(), VehicleRoutingAlgorithmListeners.Priority.HIGH); + int jspritIterations = getJspritIterations(carrier); + try { + if (jspritIterations > 0) { + algorithm.setMaxIterations(jspritIterations); + } else { + throw new InvalidAttributeValueException( + "Carrier has invalid number of jsprit iterations. They must be positive! Carrier id: " + + carrier.getId().toString()); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + VehicleRoutingProblemSolution solution = Solutions.bestOf(algorithm.searchSolutions()); + + log.info("tour planning for carrier {} took {} seconds.", carrier.getId(), (System.currentTimeMillis() - start) / 1000); + + CarrierPlan newPlan = MatsimJspritFactory.createPlan(carrier, solution); + // yy In principle, the carrier should know the vehicle types that it can deploy. + + log.info("routing plan for carrier {}", carrier.getId()); + NetworkRouter.routePlan(newPlan, netBasedCosts); + double timeForPlanningAndRouting = (System.currentTimeMillis() - start) / 1000; + log.info("routing for carrier {} finished. Tour planning plus routing took {} seconds. Thread id: {}", carrier.getId(), + timeForPlanningAndRouting, Thread.currentThread().getId()); + + carrier.setSelectedPlan(newPlan); + setJspritComputationTime(carrier, timeForPlanningAndRouting); + } + } + + // we need this class because otherwise there is a runtime error in the PriorityBlockingQueue + // https://jvmaware.com/priority-queue-and-threadpool/ + private static class JspritTreadPoolExecutor extends ThreadPoolExecutor{ + public JspritTreadPoolExecutor(BlockingQueue workQueue, int nThreads) { + super(nThreads, nThreads, 0, TimeUnit.SECONDS, workQueue); + } + + @Override + protected RunnableFuture newTaskFor(Runnable runnable, T value) { + return new CustomFutureTask<>(runnable); + } + } + + private static class CustomFutureTask extends FutureTask implements Comparable>{ + private final JspritCarrierTask task; + + public CustomFutureTask(Runnable task) { + super(task, null); + this.task = (JspritCarrierTask) task; + } + + @Override + public int compareTo(CustomFutureTask that) { + return that.task.getPriority() - this.task.getPriority(); + } + } } diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl.java new file mode 100644 index 00000000000..38bcf0744be --- /dev/null +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl.java @@ -0,0 +1,425 @@ +package org.matsim.smallScaleCommercialTrafficGeneration; + +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +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.gbl.MatsimRandom; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.freight.carriers.*; +import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; +import org.matsim.vehicles.VehicleType; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +import static org.matsim.smallScaleCommercialTrafficGeneration.SmallScaleCommercialTrafficUtils.getObjectiveFunction; +import static org.matsim.smallScaleCommercialTrafficGeneration.TrafficVolumeGeneration.makeTrafficVolumeKey; + +public class DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl implements IntegrateExistingTrafficToSmallScaleCommercial { + private static final Logger log = LogManager.getLogger(DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl.class); + + /** + * Reduces the demand for certain zone. + * + * @param trafficVolumePerTypeAndZone_start trafficVolume for start potentials for each zone + * @param trafficVolumePerTypeAndZone_stop trafficVolume for stop potentials for each zone + * @param modeORvehType selected mode or vehicleType + * @param purpose certain purpose + * @param startZone start zone + * @param stopZone end zone + */ + protected static void reduceVolumeForThisExistingJobElement( + Map> trafficVolumePerTypeAndZone_start, + Map> trafficVolumePerTypeAndZone_stop, String modeORvehType, + Integer purpose, String startZone, String stopZone) { + + if (startZone == null && stopZone == null) + throw new IllegalArgumentException(); + + TrafficVolumeGeneration.TrafficVolumeKey trafficVolumeKey_start = makeTrafficVolumeKey(startZone, modeORvehType); + TrafficVolumeGeneration.TrafficVolumeKey trafficVolumeKey_stop = makeTrafficVolumeKey(stopZone, modeORvehType); + Object2DoubleMap startVolume = trafficVolumePerTypeAndZone_start.get(trafficVolumeKey_start); + Object2DoubleMap stopVolume = trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey_stop); + + if (startVolume != null && startVolume.getDouble(purpose) == 0) + reduceVolumeForOtherArea(trafficVolumePerTypeAndZone_start, modeORvehType, purpose, "Start", trafficVolumeKey_start.getZone()); + else if (startVolume != null) + startVolume.mergeDouble(purpose, -1, Double::sum); + if (stopVolume != null && stopVolume.getDouble(purpose) == 0) + reduceVolumeForOtherArea(trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, "Stop", trafficVolumeKey_stop.getZone()); + else if (stopVolume != null) + stopVolume.mergeDouble(purpose, -1, Double::sum); + } + + protected static String findZoneOfLink(Map, Link>> linksPerZone, Id linkId) { + AtomicReference resultingZone = new AtomicReference<>(); + + linksPerZone.forEach( (zone, links) -> { + if (links.containsKey(linkId)) { + resultingZone.set(zone); + } + }); + if (resultingZone.get() == null) { + return null; + } + return resultingZone. get(); + } + + /** + * Finds zone with demand and reduces this demand by 1. + * + * @param trafficVolumePerTypeAndZone traffic volumes + * @param modeORvehType selected mode or vehicleType + * @param purpose selected purpose + * @param volumeType start or stop volume + * @param originalZone zone with volume of 0, although a volume of an existing model exists + */ + private static void reduceVolumeForOtherArea( + Map> trafficVolumePerTypeAndZone, String modeORvehType, + Integer purpose, String volumeType, String originalZone) { + ArrayList shuffledKeys = new ArrayList<>( + trafficVolumePerTypeAndZone.keySet()); + Collections.shuffle(shuffledKeys, MatsimRandom.getRandom()); + for (TrafficVolumeGeneration.TrafficVolumeKey trafficVolumeKey : shuffledKeys) { + if (trafficVolumeKey.getModeORvehType().equals(modeORvehType) + && trafficVolumePerTypeAndZone.get(trafficVolumeKey).getDouble(purpose) > 0) { + trafficVolumePerTypeAndZone.get(trafficVolumeKey).mergeDouble(purpose, -1, Double::sum); + log.warn( + "{}-Volume of zone {} (mode '{}', purpose '{}') was reduced because the volume for the zone {}, where an existing model has a demand, has a generated demand of 0.", + volumeType, trafficVolumeKey.getZone(), modeORvehType, purpose, originalZone); + break; + } + } + } + + /** + * Reads existing scenarios and add them to the scenario. If the scenario is + * part of the goodsTraffic or commercialPersonTraffic, the demand of the existing + * scenario reduces the demand of the small scale commercial traffic. The + * dispersedTraffic will be added additionally. + * For this method, the carriers should be located correctly and all needed information is taken from 'existingModels.csv' + * + * @param scenario the scenario + * @param sampleScenario the sample size of the scenario + * @param linksPerZone the links per zone + */ + @Override + public void readExistingCarriersFromFolder(Scenario scenario, double sampleScenario, + Map, Link>> linksPerZone) throws Exception { + Path existingModelsFolder = Path.of(scenario.getConfig().getContext().toURI()).getParent().resolve("existingModels"); + String locationOfExistingModels = existingModelsFolder.resolve("existingModels.csv").toString(); + CSVParser parse = CSVFormat.Builder.create(CSVFormat.DEFAULT).setDelimiter('\t').setHeader() + .setSkipHeaderRecord(true).build().parse(IOUtils.getBufferedReader(locationOfExistingModels)); + for (CSVRecord record : parse) { + String modelName = record.get("model"); + double sampleSizeExistingScenario = Double.parseDouble(record.get("sampleSize")); + String modelTrafficType = record.get("smallScaleCommercialTrafficType"); + final Integer modelPurpose; + if (!Objects.equals(record.get("purpose"), "")) + modelPurpose = Integer.parseInt(record.get("purpose")); + else + modelPurpose = null; + final String vehicleType; + if (!Objects.equals(record.get("vehicleType"), "")) + vehicleType = record.get("vehicleType"); + else + vehicleType = null; + final String modelMode = record.get("networkMode"); + + Path scenarioLocation = existingModelsFolder.resolve(modelName); + if (!Files.exists(scenarioLocation.resolve("output_carriers.xml.gz"))) + throw new Exception("For the existing model " + modelName + + " no carrierFile exists. The carrierFile should have the name 'output_carriers.xml.gz'"); + if (!Files.exists(scenarioLocation.resolve("vehicleTypes.xml.gz"))) + throw new Exception("For the existing model " + modelName + + " no vehicleTypesFile exists. The vehicleTypesFile should have the name 'vehicleTypes.xml.gz'"); + + log.info("Integrating existing scenario: {}", modelName); + + CarrierVehicleTypes readVehicleTypes = new CarrierVehicleTypes(); + CarrierVehicleTypes usedVehicleTypes = new CarrierVehicleTypes(); + new CarrierVehicleTypeReader(readVehicleTypes) + .readFile(scenarioLocation.resolve("vehicleTypes.xml.gz").toString()); + + Carriers carriers = new Carriers(); + new CarrierPlanXmlReader(carriers, readVehicleTypes) + .readFile(scenarioLocation.resolve("output_carriers.xml.gz").toString()); + + if (sampleSizeExistingScenario < sampleScenario) + throw new Exception("The sample size of the existing scenario " + modelName + + "is smaller than the sample size of the scenario. No up scaling for existing scenarios implemented."); + + double sampleFactor = sampleScenario / sampleSizeExistingScenario; + + int numberOfToursExistingScenario = 0; + for (Carrier carrier : carriers.getCarriers().values()) { + if (!carrier.getPlans().isEmpty()) + numberOfToursExistingScenario = numberOfToursExistingScenario + + carrier.getSelectedPlan().getScheduledTours().size(); + } + int sampledNumberOfToursExistingScenario = (int) Math.round(numberOfToursExistingScenario * sampleFactor); + List carrierToRemove = new ArrayList<>(); + int remainedTours = 0; + double roundingError = 0.; + + log.info("The existing scenario {} is a {}% scenario and has {} tours", modelName, (int) (sampleSizeExistingScenario * 100), + numberOfToursExistingScenario); + log.info("The existing scenario {} will be sampled down to the scenario sample size of {}% which results in {} tours.", modelName, + (int) (sampleScenario * 100), sampledNumberOfToursExistingScenario); + + int numberOfAnalyzedTours = 0; + for (Carrier carrier : carriers.getCarriers().values()) { + if (!carrier.getPlans().isEmpty()) { + int numberOfOriginalTours = carrier.getSelectedPlan().getScheduledTours().size(); + numberOfAnalyzedTours += numberOfOriginalTours; + int numberOfRemainingTours = (int) Math.round(numberOfOriginalTours * sampleFactor); + roundingError = roundingError + numberOfRemainingTours - (numberOfOriginalTours * sampleFactor); + int numberOfToursToRemove = numberOfOriginalTours - numberOfRemainingTours; + List toursToRemove = new ArrayList<>(); + + if (roundingError <= -1 && numberOfToursToRemove > 0) { + numberOfToursToRemove = numberOfToursToRemove - 1; + numberOfRemainingTours = numberOfRemainingTours + 1; + roundingError = roundingError + 1; + } + if (roundingError >= 1 && numberOfRemainingTours != numberOfToursToRemove) { + numberOfToursToRemove = numberOfToursToRemove + 1; + numberOfRemainingTours = numberOfRemainingTours - 1; + roundingError = roundingError - 1; + } + remainedTours = remainedTours + numberOfRemainingTours; + if (remainedTours > sampledNumberOfToursExistingScenario) { + remainedTours = remainedTours - 1; + numberOfRemainingTours = numberOfRemainingTours - 1; + numberOfToursToRemove = numberOfToursToRemove + 1; + } + // last carrier with scheduled tours + if (numberOfAnalyzedTours == numberOfToursExistingScenario + && remainedTours != sampledNumberOfToursExistingScenario) { + numberOfRemainingTours = sampledNumberOfToursExistingScenario - remainedTours; + numberOfToursToRemove = numberOfOriginalTours - numberOfRemainingTours; + remainedTours = remainedTours + numberOfRemainingTours; + } + // remove carrier because no tours remaining + if (numberOfOriginalTours == numberOfToursToRemove) { + carrierToRemove.add(carrier); + continue; + } + + while (toursToRemove.size() < numberOfToursToRemove) { + Object[] tours = carrier.getSelectedPlan().getScheduledTours().toArray(); + ScheduledTour tour = (ScheduledTour) tours[MatsimRandom.getRandom().nextInt(tours.length)]; + toursToRemove.add(tour); + carrier.getSelectedPlan().getScheduledTours().remove(tour); + } + + // remove services/shipments from removed tours + if (!carrier.getServices().isEmpty()) { + for (ScheduledTour removedTour : toursToRemove) { + for (Tour.TourElement tourElement : removedTour.getTour().getTourElements()) { + if (tourElement instanceof Tour.ServiceActivity service) { + carrier.getServices().remove(service.getService().getId()); + } + } + } + } else if (!carrier.getShipments().isEmpty()) { + for (ScheduledTour removedTour : toursToRemove) { + for (Tour.TourElement tourElement : removedTour.getTour().getTourElements()) { + if (tourElement instanceof Tour.Pickup pickup) { + carrier.getShipments().remove(pickup.getShipment().getId()); + } + } + } + } + // remove vehicles of removed tours and check if all vehicleTypes are still + // needed + if (carrier.getCarrierCapabilities().getFleetSize().equals(CarrierCapabilities.FleetSize.FINITE)) { + for (ScheduledTour removedTour : toursToRemove) { + carrier.getCarrierCapabilities().getCarrierVehicles() + .remove(removedTour.getVehicle().getId()); + } + } else if (carrier.getCarrierCapabilities().getFleetSize().equals(CarrierCapabilities.FleetSize.INFINITE)) { + carrier.getCarrierCapabilities().getCarrierVehicles().clear(); + for (ScheduledTour tour : carrier.getSelectedPlan().getScheduledTours()) { + carrier.getCarrierCapabilities().getCarrierVehicles().put(tour.getVehicle().getId(), + tour.getVehicle()); + } + } + List vehicleTypesToRemove = new ArrayList<>(); + for (VehicleType existingVehicleType : carrier.getCarrierCapabilities().getVehicleTypes()) { + boolean vehicleTypeNeeded = false; + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + if (vehicle.getType().equals(existingVehicleType)) { + vehicleTypeNeeded = true; + usedVehicleTypes.getVehicleTypes().put(existingVehicleType.getId(), + existingVehicleType); + } + } + if (!vehicleTypeNeeded) + vehicleTypesToRemove.add(existingVehicleType); + } + carrier.getCarrierCapabilities().getVehicleTypes().removeAll(vehicleTypesToRemove); + } + // carriers without solutions + else { + if (!carrier.getServices().isEmpty()) { + int numberOfServicesToRemove = carrier.getServices().size() + - (int) Math.round(carrier.getServices().size() * sampleFactor); + for (int i = 0; i < numberOfServicesToRemove; i++) { + Object[] services = carrier.getServices().keySet().toArray(); + carrier.getServices().remove(services[MatsimRandom.getRandom().nextInt(services.length)]); + } + } + if (!carrier.getShipments().isEmpty()) { + int numberOfShipmentsToRemove = carrier.getShipments().size() + - (int) Math.round(carrier.getShipments().size() * sampleFactor); + for (int i = 0; i < numberOfShipmentsToRemove; i++) { + Object[] shipments = carrier.getShipments().keySet().toArray(); + carrier.getShipments().remove(shipments[MatsimRandom.getRandom().nextInt(shipments.length)]); + } + } + } + } + carrierToRemove.forEach(carrier -> carriers.getCarriers().remove(carrier.getId())); + CarriersUtils.getCarrierVehicleTypes(scenario).getVehicleTypes().putAll(usedVehicleTypes.getVehicleTypes()); + + carriers.getCarriers().values().forEach(carrier -> { + Carrier newCarrier = CarriersUtils + .createCarrier(Id.create(modelName + "_" + carrier.getId().toString(), Carrier.class)); + newCarrier.getAttributes().putAttribute("subpopulation", modelTrafficType); + if (modelPurpose != null) + newCarrier.getAttributes().putAttribute("purpose", modelPurpose); + newCarrier.getAttributes().putAttribute("existingModel", modelName); + newCarrier.getAttributes().putAttribute("networkMode", modelMode); + if (vehicleType != null) + newCarrier.getAttributes().putAttribute("vehicleType", vehicleType); + newCarrier.setCarrierCapabilities(carrier.getCarrierCapabilities()); + + if (!carrier.getServices().isEmpty()) + newCarrier.getServices().putAll(carrier.getServices()); + else if (!carrier.getShipments().isEmpty()) + newCarrier.getShipments().putAll(carrier.getShipments()); + if (carrier.getSelectedPlan() != null) { + newCarrier.setSelectedPlan(carrier.getSelectedPlan()); + + List startAreas = new ArrayList<>(); + for (ScheduledTour tour : newCarrier.getSelectedPlan().getScheduledTours()) { + String tourStartZone = findZoneOfLink(linksPerZone, tour.getTour().getStartLinkId()); + if (!startAreas.contains(tourStartZone)) + startAreas.add(tourStartZone); + } + newCarrier.getAttributes().putAttribute("tourStartArea", + String.join(";", startAreas)); + + CarriersUtils.setJspritIterations(newCarrier, 0); + // recalculate score for selectedPlan + VehicleRoutingProblem vrp = MatsimJspritFactory + .createRoutingProblemBuilder(carrier, scenario.getNetwork()).build(); + VehicleRoutingProblemSolution solution = MatsimJspritFactory + .createSolution(newCarrier.getSelectedPlan(), vrp); + SolutionCostCalculator solutionCostsCalculator = getObjectiveFunction(vrp, Double.MAX_VALUE); + double costs = solutionCostsCalculator.getCosts(solution) * (-1); + carrier.getSelectedPlan().setScore(costs); + } else { + CarriersUtils.setJspritIterations(newCarrier, CarriersUtils.getJspritIterations(carrier)); + newCarrier.getCarrierCapabilities().setFleetSize(carrier.getCarrierCapabilities().getFleetSize()); + } + CarriersUtils.addOrGetCarriers(scenario).getCarriers().put(newCarrier.getId(), newCarrier); + }); + } + } + + @Override + public void reduceDemandBasedOnExistingCarriers(Scenario scenario, Map, Link>> linksPerZone, + String smallScaleCommercialTrafficType, + Map> trafficVolumePerTypeAndZone_start, + Map> trafficVolumePerTypeAndZone_stop) { + for (Carrier carrier : CarriersUtils.addOrGetCarriers(scenario).getCarriers().values()) { + if (!carrier.getAttributes().getAsMap().containsKey("subpopulation") + || !carrier.getAttributes().getAttribute("subpopulation").equals(smallScaleCommercialTrafficType)) + continue; + String modeORvehType; + if (smallScaleCommercialTrafficType.equals("goodsTraffic")) + modeORvehType = (String) carrier.getAttributes().getAttribute("vehicleType"); + else + modeORvehType = "total"; + Integer purpose = (Integer) carrier.getAttributes().getAttribute("purpose"); + if (carrier.getSelectedPlan() != null) { + for (ScheduledTour tour : carrier.getSelectedPlan().getScheduledTours()) { + String startZone = findZoneOfLink(linksPerZone, tour.getTour().getStartLinkId()); + for (Tour.TourElement tourElement : tour.getTour().getTourElements()) { + if (tourElement instanceof Tour.ServiceActivity service) { + String stopZone = findZoneOfLink(linksPerZone, service.getLocation()); + try { + reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, + trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); + } catch (IllegalArgumentException e) { + log.warn( + "For the tour {} of carrier {} a location of the service {} is not part of the zones. That's why the traffic volume was not reduces by this service. startZone = {}, stopZone = {}", + tour.getTour().getId(), carrier.getId().toString(), service.getService().getId(), startZone, stopZone); + } + } + if (tourElement instanceof Tour.Pickup pickup) { + startZone = findZoneOfLink(linksPerZone, pickup.getShipment().getFrom()); + String stopZone = findZoneOfLink(linksPerZone, pickup.getShipment().getTo()); + try { + reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, + trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); + } catch (IllegalArgumentException e) { + log.warn( + "For the tour {} of carrier {} a location of the shipment {} is not part of the zones. That's why the traffic volume was not reduces by this shipment.", + tour.getTour().getId(), carrier.getId().toString(), pickup.getShipment().getId()); + } + } + } + } + } else { + if (!carrier.getServices().isEmpty()) { + List possibleStartAreas = new ArrayList<>(); + for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { + possibleStartAreas + .add(findZoneOfLink(linksPerZone, vehicle.getLinkId())); + } + for (CarrierService service : carrier.getServices().values()) { + String startZone = (String) possibleStartAreas.toArray()[MatsimRandom.getRandom() + .nextInt(possibleStartAreas.size())]; + String stopZone = findZoneOfLink(linksPerZone, service.getLocationLinkId()); + try { + reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, + trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); + } catch (IllegalArgumentException e) { + log.warn( + "For carrier {} a location of the service {} is not part of the zones. That's why the traffic volume was not reduces by this service.", + carrier.getId().toString(), service.getId()); + } + } + } else if (!carrier.getShipments().isEmpty()) { + for (CarrierShipment shipment : carrier.getShipments().values()) { + String startZone = findZoneOfLink(linksPerZone, shipment.getFrom()); + String stopZone = findZoneOfLink(linksPerZone, shipment.getTo()); + try { + reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, + trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); + } catch (IllegalArgumentException e) { + log.warn( + "For carrier {} a location of the shipment {} is not part of the zones. That's why the traffic volume was not reduces by this shipment.", + carrier.getId().toString(), shipment.getId()); + } + } + } + } + } + } + +} 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 e33e6248b16..4077f18d080 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 @@ -102,12 +102,13 @@ public class GenerateSmallScaleCommercialTrafficDemand implements MATSimAppComma // Option 3: Leerkamp (nur in RVR Modell). private static final Logger log = LogManager.getLogger(GenerateSmallScaleCommercialTrafficDemand.class); + private static IntegrateExistingTrafficToSmallScaleCommercial integrateExistingTrafficToSmallScaleCommercial; private enum CreationOption { useExistingCarrierFileWithSolution, createNewCarrierFile, useExistingCarrierFileWithoutSolution } - private enum SmallScaleCommercialTrafficType { + public enum SmallScaleCommercialTrafficType { commercialPersonTraffic, goodsTraffic, completeSmallScaleCommercialTraffic } @@ -167,6 +168,15 @@ private enum SmallScaleCommercialTrafficType { private Index indexZones; + public GenerateSmallScaleCommercialTrafficDemand() { + integrateExistingTrafficToSmallScaleCommercial = new DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl(); + log.info("Using default {} if existing models are integrated!", DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl.class.getSimpleName()); + } + public GenerateSmallScaleCommercialTrafficDemand(IntegrateExistingTrafficToSmallScaleCommercial integrateExistingTrafficToSmallScaleCommercial) { + GenerateSmallScaleCommercialTrafficDemand.integrateExistingTrafficToSmallScaleCommercial = integrateExistingTrafficToSmallScaleCommercial; + log.info("Using {} if existing models are integrated!", integrateExistingTrafficToSmallScaleCommercial.getClass().getSimpleName()); + } + public static void main(String[] args) { System.exit(new CommandLine(new GenerateSmallScaleCommercialTrafficDemand()).execute(args)); } @@ -443,8 +453,8 @@ else if (smallScaleCommercialTrafficType.equals("commercialPersonTraffic")) .createTrafficVolume_stop(resultingDataPerZone, output, sample, modesORvehTypes, smallScaleCommercialTrafficType); if (includeExistingModels) { - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, linksPerZone); - TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, linksPerZone, smallScaleCommercialTrafficType, + integrateExistingTrafficToSmallScaleCommercial.readExistingCarriersFromFolder(scenario, sample, linksPerZone); + integrateExistingTrafficToSmallScaleCommercial.reduceDemandBasedOnExistingCarriers(scenario, linksPerZone, smallScaleCommercialTrafficType, trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop); } final TripDistributionMatrix odMatrix = createTripDistribution(trafficVolumePerTypeAndZone_start, diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/IntegrateExistingTrafficToSmallScaleCommercial.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/IntegrateExistingTrafficToSmallScaleCommercial.java new file mode 100644 index 00000000000..687c68cdcc6 --- /dev/null +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/IntegrateExistingTrafficToSmallScaleCommercial.java @@ -0,0 +1,19 @@ +package org.matsim.smallScaleCommercialTrafficGeneration; + +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; + +import java.util.Map; + +public interface IntegrateExistingTrafficToSmallScaleCommercial { + + void readExistingCarriersFromFolder(Scenario scenario, double sampleScenario, + Map, Link>> linksPerZone) throws Exception; + + void reduceDemandBasedOnExistingCarriers(Scenario scenario, + Map, Link>> linksPerZone, String smallScaleCommercialTrafficType, + Map> trafficVolumePerTypeAndZone_start, + Map> trafficVolumePerTypeAndZone_stop); +} diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java index 5894f36b83b..f180308e69e 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/SmallScaleCommercialTrafficUtils.java @@ -40,18 +40,12 @@ import org.matsim.api.core.v01.population.*; import org.matsim.application.options.ShpOptions; import org.matsim.application.options.ShpOptions.Index; -import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.network.NetworkUtils; import org.matsim.core.population.PopulationUtils; import org.matsim.core.utils.io.IOUtils; -import org.matsim.freight.carriers.*; -import org.matsim.freight.carriers.CarrierCapabilities.FleetSize; -import org.matsim.freight.carriers.Tour.Pickup; -import org.matsim.freight.carriers.Tour.ServiceActivity; -import org.matsim.freight.carriers.Tour.TourElement; -import org.matsim.freight.carriers.jsprit.MatsimJspritFactory; +import org.matsim.freight.carriers.Carrier; +import org.matsim.freight.carriers.CarriersUtils; import org.matsim.vehicles.Vehicle; -import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.Vehicles; @@ -60,7 +54,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicLong; /** @@ -282,238 +278,6 @@ static String getSampleNameOfOutputFolder(double sample) { return sampleName; } - /** - * Reads existing scenarios and add them to the scenario. If the scenario is - * part of the goodsTraffic or commercialPersonTraffic, the demand of the existing - * scenario reduces the demand of the small scale commercial traffic. The - * dispersedTraffic will be added additionally. - */ - static void readExistingModels(Scenario scenario, double sampleScenario, - Map, Link>> linksPerZone) throws Exception { - - Path existingModelsFolder = Path.of(scenario.getConfig().getContext().toURI()).getParent().resolve("existingModels"); - String locationOfExistingModels = existingModelsFolder.resolve("existingModels.csv").toString(); - CSVParser parse = CSVFormat.Builder.create(CSVFormat.DEFAULT).setDelimiter('\t').setHeader() - .setSkipHeaderRecord(true).build().parse(IOUtils.getBufferedReader(locationOfExistingModels)); - for (CSVRecord record : parse) { - String modelName = record.get("model"); - double sampleSizeExistingScenario = Double.parseDouble(record.get("sampleSize")); - String modelTrafficType = record.get("smallScaleCommercialTrafficType"); - final Integer modelPurpose; - if (!Objects.equals(record.get("purpose"), "")) - modelPurpose = Integer.parseInt(record.get("purpose")); - else - modelPurpose = null; - final String vehicleType; - if (!Objects.equals(record.get("vehicleType"), "")) - vehicleType = record.get("vehicleType"); - else - vehicleType = null; - final String modelMode = record.get("networkMode"); - - Path scenarioLocation = existingModelsFolder.resolve(modelName); - if (!Files.exists(scenarioLocation.resolve("output_carriers.xml.gz"))) - throw new Exception("For the existing model " + modelName - + " no carrierFile exists. The carrierFile should have the name 'output_carriers.xml.gz'"); - if (!Files.exists(scenarioLocation.resolve("vehicleTypes.xml.gz"))) - throw new Exception("For the existing model " + modelName - + " no vehicleTypesFile exists. The vehicleTypesFile should have the name 'vehicleTypes.xml.gz'"); - - log.info("Integrating existing scenario: {}", modelName); - - CarrierVehicleTypes readVehicleTypes = new CarrierVehicleTypes(); - CarrierVehicleTypes usedVehicleTypes = new CarrierVehicleTypes(); - new CarrierVehicleTypeReader(readVehicleTypes) - .readFile(scenarioLocation.resolve("vehicleTypes.xml.gz").toString()); - - Carriers carriers = new Carriers(); - new CarrierPlanXmlReader(carriers, readVehicleTypes) - .readFile(scenarioLocation.resolve("output_carriers.xml.gz").toString()); - - if (sampleSizeExistingScenario < sampleScenario) - throw new Exception("The sample size of the existing scenario " + modelName - + "is smaller than the sample size of the scenario. No up scaling for existing scenarios implemented."); - - double sampleFactor = sampleScenario / sampleSizeExistingScenario; - - int numberOfToursExistingScenario = 0; - for (Carrier carrier : carriers.getCarriers().values()) { - if (!carrier.getPlans().isEmpty()) - numberOfToursExistingScenario = numberOfToursExistingScenario - + carrier.getSelectedPlan().getScheduledTours().size(); - } - int sampledNumberOfToursExistingScenario = (int) Math.round(numberOfToursExistingScenario * sampleFactor); - List carrierToRemove = new ArrayList<>(); - int remainedTours = 0; - double roundingError = 0.; - - log.info("The existing scenario {} is a {}% scenario and has {} tours", modelName, (int) (sampleSizeExistingScenario * 100), - numberOfToursExistingScenario); - log.info("The existing scenario {} will be sampled down to the scenario sample size of {}% which results in {} tours.", modelName, - (int) (sampleScenario * 100), sampledNumberOfToursExistingScenario); - - int numberOfAnalyzedTours = 0; - for (Carrier carrier : carriers.getCarriers().values()) { - if (!carrier.getPlans().isEmpty()) { - int numberOfOriginalTours = carrier.getSelectedPlan().getScheduledTours().size(); - numberOfAnalyzedTours += numberOfOriginalTours; - int numberOfRemainingTours = (int) Math.round(numberOfOriginalTours * sampleFactor); - roundingError = roundingError + numberOfRemainingTours - (numberOfOriginalTours * sampleFactor); - int numberOfToursToRemove = numberOfOriginalTours - numberOfRemainingTours; - List toursToRemove = new ArrayList<>(); - - if (roundingError <= -1 && numberOfToursToRemove > 0) { - numberOfToursToRemove = numberOfToursToRemove - 1; - numberOfRemainingTours = numberOfRemainingTours + 1; - roundingError = roundingError + 1; - } - if (roundingError >= 1 && numberOfRemainingTours != numberOfToursToRemove) { - numberOfToursToRemove = numberOfToursToRemove + 1; - numberOfRemainingTours = numberOfRemainingTours - 1; - roundingError = roundingError - 1; - } - remainedTours = remainedTours + numberOfRemainingTours; - if (remainedTours > sampledNumberOfToursExistingScenario) { - remainedTours = remainedTours - 1; - numberOfRemainingTours = numberOfRemainingTours - 1; - numberOfToursToRemove = numberOfToursToRemove + 1; - } - // last carrier with scheduled tours - if (numberOfAnalyzedTours == numberOfToursExistingScenario - && remainedTours != sampledNumberOfToursExistingScenario) { - numberOfRemainingTours = sampledNumberOfToursExistingScenario - remainedTours; - numberOfToursToRemove = numberOfOriginalTours - numberOfRemainingTours; - remainedTours = remainedTours + numberOfRemainingTours; - } - // remove carrier because no tours remaining - if (numberOfOriginalTours == numberOfToursToRemove) { - carrierToRemove.add(carrier); - continue; - } - - while (toursToRemove.size() < numberOfToursToRemove) { - Object[] tours = carrier.getSelectedPlan().getScheduledTours().toArray(); - ScheduledTour tour = (ScheduledTour) tours[MatsimRandom.getRandom().nextInt(tours.length)]; - toursToRemove.add(tour); - carrier.getSelectedPlan().getScheduledTours().remove(tour); - } - - // remove services/shipments from removed tours - if (!carrier.getServices().isEmpty()) { - for (ScheduledTour removedTour : toursToRemove) { - for (TourElement tourElement : removedTour.getTour().getTourElements()) { - if (tourElement instanceof ServiceActivity service) { - carrier.getServices().remove(service.getService().getId()); - } - } - } - } else if (!carrier.getShipments().isEmpty()) { - for (ScheduledTour removedTour : toursToRemove) { - for (TourElement tourElement : removedTour.getTour().getTourElements()) { - if (tourElement instanceof Pickup pickup) { - carrier.getShipments().remove(pickup.getShipment().getId()); - } - } - } - } - // remove vehicles of removed tours and check if all vehicleTypes are still - // needed - if (carrier.getCarrierCapabilities().getFleetSize().equals(FleetSize.FINITE)) { - for (ScheduledTour removedTour : toursToRemove) { - carrier.getCarrierCapabilities().getCarrierVehicles() - .remove(removedTour.getVehicle().getId()); - } - } else if (carrier.getCarrierCapabilities().getFleetSize().equals(FleetSize.INFINITE)) { - carrier.getCarrierCapabilities().getCarrierVehicles().clear(); - for (ScheduledTour tour : carrier.getSelectedPlan().getScheduledTours()) { - carrier.getCarrierCapabilities().getCarrierVehicles().put(tour.getVehicle().getId(), - tour.getVehicle()); - } - } - List vehicleTypesToRemove = new ArrayList<>(); - for (VehicleType existingVehicleType : carrier.getCarrierCapabilities().getVehicleTypes()) { - boolean vehicleTypeNeeded = false; - for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { - if (vehicle.getType().equals(existingVehicleType)) { - vehicleTypeNeeded = true; - usedVehicleTypes.getVehicleTypes().put(existingVehicleType.getId(), - existingVehicleType); - } - } - if (!vehicleTypeNeeded) - vehicleTypesToRemove.add(existingVehicleType); - } - carrier.getCarrierCapabilities().getVehicleTypes().removeAll(vehicleTypesToRemove); - } - // carriers without solutions - else { - if (!carrier.getServices().isEmpty()) { - int numberOfServicesToRemove = carrier.getServices().size() - - (int) Math.round(carrier.getServices().size() * sampleFactor); - for (int i = 0; i < numberOfServicesToRemove; i++) { - Object[] services = carrier.getServices().keySet().toArray(); - carrier.getServices().remove(services[MatsimRandom.getRandom().nextInt(services.length)]); - } - } - if (!carrier.getShipments().isEmpty()) { - int numberOfShipmentsToRemove = carrier.getShipments().size() - - (int) Math.round(carrier.getShipments().size() * sampleFactor); - for (int i = 0; i < numberOfShipmentsToRemove; i++) { - Object[] shipments = carrier.getShipments().keySet().toArray(); - carrier.getShipments().remove(shipments[MatsimRandom.getRandom().nextInt(shipments.length)]); - } - } - } - } - carrierToRemove.forEach(carrier -> carriers.getCarriers().remove(carrier.getId())); - CarriersUtils.getCarrierVehicleTypes(scenario).getVehicleTypes().putAll(usedVehicleTypes.getVehicleTypes()); - - carriers.getCarriers().values().forEach(carrier -> { - Carrier newCarrier = CarriersUtils - .createCarrier(Id.create(modelName + "_" + carrier.getId().toString(), Carrier.class)); - newCarrier.getAttributes().putAttribute("subpopulation", modelTrafficType); - if (modelPurpose != null) - newCarrier.getAttributes().putAttribute("purpose", modelPurpose); - newCarrier.getAttributes().putAttribute("existingModel", modelName); - newCarrier.getAttributes().putAttribute("networkMode", modelMode); - if (vehicleType != null) - newCarrier.getAttributes().putAttribute("vehicleType", vehicleType); - newCarrier.setCarrierCapabilities(carrier.getCarrierCapabilities()); - - if (!carrier.getServices().isEmpty()) - newCarrier.getServices().putAll(carrier.getServices()); - else if (!carrier.getShipments().isEmpty()) - newCarrier.getShipments().putAll(carrier.getShipments()); - if (carrier.getSelectedPlan() != null) { - newCarrier.setSelectedPlan(carrier.getSelectedPlan()); - - List startAreas = new ArrayList<>(); - for (ScheduledTour tour : newCarrier.getSelectedPlan().getScheduledTours()) { - String tourStartZone = findZoneOfLink(tour.getTour().getStartLinkId(), linksPerZone); - if (!startAreas.contains(tourStartZone)) - startAreas.add(tourStartZone); - } - newCarrier.getAttributes().putAttribute("tourStartArea", - String.join(";", startAreas)); - - CarriersUtils.setJspritIterations(newCarrier, 0); - // recalculate score for selectedPlan - VehicleRoutingProblem vrp = MatsimJspritFactory - .createRoutingProblemBuilder(carrier, scenario.getNetwork()).build(); - VehicleRoutingProblemSolution solution = MatsimJspritFactory - .createSolution(newCarrier.getSelectedPlan(), vrp); - SolutionCostCalculator solutionCostsCalculator = getObjectiveFunction(vrp, Double.MAX_VALUE); - double costs = solutionCostsCalculator.getCosts(solution) * (-1); - carrier.getSelectedPlan().setScore(costs); - } else { - CarriersUtils.setJspritIterations(newCarrier, CarriersUtils.getJspritIterations(carrier)); - newCarrier.getCarrierCapabilities().setFleetSize(carrier.getCarrierCapabilities().getFleetSize()); - } - CarriersUtils.addOrGetCarriers(scenario).getCarriers().put(newCarrier.getId(), newCarrier); - }); - } - } - /** * Find the zone where the link is located */ @@ -558,7 +322,7 @@ static Map> readDataDistribution(Path pathToDat /** * Creates a cost calculator. */ - private static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp, final double maxCosts) { + static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp, final double maxCosts) { return new SolutionCostCalculator() { @Override diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java index 9c265cb4eee..a536f751552 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGeneration.java @@ -24,14 +24,6 @@ import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; 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.freight.carriers.*; -import org.matsim.freight.carriers.Tour.Pickup; -import org.matsim.freight.carriers.Tour.ServiceActivity; -import org.matsim.freight.carriers.Tour.TourElement; -import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.utils.io.IOUtils; import java.io.BufferedWriter; @@ -39,7 +31,10 @@ import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author Ricardo Ewert @@ -55,7 +50,7 @@ public class TrafficVolumeGeneration { private static Map> commitmentRatesStart = new HashMap<>(); private static Map> commitmentRatesStop = new HashMap<>(); - static class TrafficVolumeKey { + public static class TrafficVolumeKey { private final String zone; private final String modeORvehType; @@ -263,162 +258,6 @@ static void setInputParameters(String smallScaleCommercialTrafficType) { commitmentRatesStop = setCommitmentRates(smallScaleCommercialTrafficType, "stop"); } - /** - * Reduces the traffic volumes based on the added existing models. - * - * @param scenario scenario - * @param linksPerZone links for each zone - * @param smallScaleCommercialTrafficType used trafficType (commercialPersonTraffic or goodsTraffic) - * @param trafficVolumePerTypeAndZone_start trafficVolume for start potentials for each zone - * @param trafficVolumePerTypeAndZone_stop trafficVolume for stop potentials for each zone - */ - static void reduceDemandBasedOnExistingCarriers(Scenario scenario, - Map, Link>> linksPerZone, String smallScaleCommercialTrafficType, - Map> trafficVolumePerTypeAndZone_start, - Map> trafficVolumePerTypeAndZone_stop) { - - for (Carrier carrier : CarriersUtils.addOrGetCarriers(scenario).getCarriers().values()) { - if (!carrier.getAttributes().getAsMap().containsKey("subpopulation") - || !carrier.getAttributes().getAttribute("subpopulation").equals(smallScaleCommercialTrafficType)) - continue; - String modeORvehType; - if (smallScaleCommercialTrafficType.equals("goodsTraffic")) - modeORvehType = (String) carrier.getAttributes().getAttribute("vehicleType"); - else - modeORvehType = "total"; - Integer purpose = (Integer) carrier.getAttributes().getAttribute("purpose"); - if (carrier.getSelectedPlan() != null) { - for (ScheduledTour tour : carrier.getSelectedPlan().getScheduledTours()) { - String startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(tour.getTour().getStartLinkId(), - linksPerZone); - for (TourElement tourElement : tour.getTour().getTourElements()) { - if (tourElement instanceof ServiceActivity service) { - String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(service.getLocation(), - linksPerZone); - try { - reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, - trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); - } catch (IllegalArgumentException e) { - log.warn( - "For the tour {} of carrier {} a location of the service {} is not part of the zones. That's why the traffic volume was not reduces by this service.", - tour.getTour().getId(), carrier.getId().toString(), service.getService().getId()); - } - } - if (tourElement instanceof Pickup pickup) { - startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(pickup.getShipment().getFrom(), - linksPerZone); - String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(pickup.getShipment().getTo(), - linksPerZone); - try { - reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, - trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); - } catch (IllegalArgumentException e) { - log.warn( - "For the tour {} of carrier {} a location of the shipment {} is not part of the zones. That's why the traffic volume was not reduces by this shipment.", - tour.getTour().getId(), carrier.getId().toString(), pickup.getShipment().getId()); - } - } - } - } - } else { - if (!carrier.getServices().isEmpty()) { - List possibleStartAreas = new ArrayList<>(); - for (CarrierVehicle vehicle : carrier.getCarrierCapabilities().getCarrierVehicles().values()) { - possibleStartAreas - .add(SmallScaleCommercialTrafficUtils.findZoneOfLink(vehicle.getLinkId(), linksPerZone)); - } - for (CarrierService service : carrier.getServices().values()) { - String startZone = (String) possibleStartAreas.toArray()[MatsimRandom.getRandom() - .nextInt(possibleStartAreas.size())]; - String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(service.getLocationLinkId(), - linksPerZone); - try { - reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, - trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); - } catch (IllegalArgumentException e) { - log.warn( - "For carrier {} a location of the service {} is not part of the zones. That's why the traffic volume was not reduces by this service.", - carrier.getId().toString(), service.getId()); - } - } - } else if (!carrier.getShipments().isEmpty()) { - for (CarrierShipment shipment : carrier.getShipments().values()) { - String startZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(shipment.getFrom(), - linksPerZone); - String stopZone = SmallScaleCommercialTrafficUtils.findZoneOfLink(shipment.getTo(), - linksPerZone); - try { - reduceVolumeForThisExistingJobElement(trafficVolumePerTypeAndZone_start, - trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, startZone, stopZone); - } catch (IllegalArgumentException e) { - log.warn( - "For carrier {} a location of the shipment {} is not part of the zones. That's why the traffic volume was not reduces by this shipment.", - carrier.getId().toString(), shipment.getId()); - } - } - } - } - } - } - - /** - * Reduces the demand for certain zone. - * - * @param trafficVolumePerTypeAndZone_start trafficVolume for start potentials for each zone - * @param trafficVolumePerTypeAndZone_stop trafficVolume for stop potentials for each zone - * @param modeORvehType selected mode or vehicleType - * @param purpose certain purpose - * @param startZone start zone - * @param stopZone end zone - */ - private static void reduceVolumeForThisExistingJobElement( - Map> trafficVolumePerTypeAndZone_start, - Map> trafficVolumePerTypeAndZone_stop, String modeORvehType, - Integer purpose, String startZone, String stopZone) { - - if (startZone != null && stopZone != null) { - TrafficVolumeKey trafficVolumeKey_start = makeTrafficVolumeKey(startZone, modeORvehType); - TrafficVolumeKey trafficVolumeKey_stop = makeTrafficVolumeKey(stopZone, modeORvehType); - if (trafficVolumePerTypeAndZone_start.get(trafficVolumeKey_start).getDouble(purpose) == 0) - reduceVolumeForOtherArea(trafficVolumePerTypeAndZone_start, modeORvehType, purpose, "Start", trafficVolumeKey_start.getZone()); - else - trafficVolumePerTypeAndZone_start.get(trafficVolumeKey_start).mergeDouble(purpose, -1, Double::sum); - if (trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey_stop).getDouble(purpose) == 0) - reduceVolumeForOtherArea(trafficVolumePerTypeAndZone_stop, modeORvehType, purpose, "Stop", trafficVolumeKey_stop.getZone()); - else - trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey_stop).mergeDouble(purpose, -1, Double::sum); - } else { - throw new IllegalArgumentException(); - } - } - - /** - * Find zone with demand and reduces the demand by 1. - * - * @param trafficVolumePerTypeAndZone traffic volumes - * @param modeORvehType selected mode or vehicleType - * @param purpose selected purpose - * @param volumeType start or stop volume - * @param originalZone zone with volume of 0, although volume in existing model - */ - private static void reduceVolumeForOtherArea( - Map> trafficVolumePerTypeAndZone, String modeORvehType, - Integer purpose, String volumeType, String originalZone) { - ArrayList shuffledKeys = new ArrayList<>( - trafficVolumePerTypeAndZone.keySet()); - Collections.shuffle(shuffledKeys, MatsimRandom.getRandom()); - for (TrafficVolumeKey trafficVolumeKey : shuffledKeys) { - if (trafficVolumeKey.getModeORvehType().equals(modeORvehType) - && trafficVolumePerTypeAndZone.get(trafficVolumeKey).getDouble(purpose) > 0) { - trafficVolumePerTypeAndZone.get(trafficVolumeKey).mergeDouble(purpose, -1, Double::sum); - log.warn( - "{}-Volume of zone {} (mode '{}', purpose '{}') was reduced because the volume for the zone {} where an existing model has a demand has a generated demand of 0.", - volumeType, trafficVolumeKey.getZone(), modeORvehType, purpose, originalZone); - break; - } - } - } - /** * Sets the generation rates based on the IVV 2005 * diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java index e60dba9c457..1e20839af41 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/RunGenerateSmallScaleCommercialTrafficTest.java @@ -130,8 +130,8 @@ void testMainRunAndResults() { for (File calculatedFile : Objects.requireNonNull( Objects.requireNonNull(new File(utils.getOutputDirectory() + "calculatedData").listFiles()))) { - Map> existingDataDistribution = readCSVInputAndCreateMap(calculatedFile.getAbsolutePath()); - Map> simulatedDataDistribution = readCSVInputAndCreateMap( + Map> simulatedDataDistribution = readCSVInputAndCreateMap(calculatedFile.getAbsolutePath()); + Map> existingDataDistribution = readCSVInputAndCreateMap( utils.getPackageInputDirectory() + "calculatedData/" + calculatedFile.getName()); compareDataDistribution(calculatedFile.getName(), existingDataDistribution, simulatedDataDistribution); } diff --git a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java index d6f82ae1e37..fc0bbe878cf 100644 --- a/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java +++ b/contribs/small-scale-traffic-generation/src/test/java/org/matsim/smallScaleCommercialTrafficGeneration/TrafficVolumeGenerationTest.java @@ -408,7 +408,8 @@ void testAddingExistingScenarios() throws Exception { SmallScaleCommercialTrafficUtils.getIndexZones(shapeFileZonePath, config.global().getCoordinateSystem(), shapeFileZoneNameColumn), facilitiesPerZone, shapeFileZoneNameColumn); - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, linksPerZone); + IntegrateExistingTrafficToSmallScaleCommercial integratedExistingModels = new DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl(); + integratedExistingModels.readExistingCarriersFromFolder(scenario, sample, linksPerZone); Assertions.assertEquals(3, CarriersUtils.getCarriers(scenario).getCarriers().size(), MatsimTestUtils.EPSILON); Assertions.assertEquals(1, CarriersUtils.getCarrierVehicleTypes(scenario).getVehicleTypes().size(), MatsimTestUtils.EPSILON); @@ -476,7 +477,8 @@ void testAddingExistingScenariosWithSample() throws Exception { shapeFileZoneNameColumn), facilitiesPerZone, shapeFileZoneNameColumn); - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, linksPerZone); + IntegrateExistingTrafficToSmallScaleCommercial integratedExistingModels = new DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl(); + integratedExistingModels.readExistingCarriersFromFolder(scenario, sample, linksPerZone); Assertions.assertEquals(2, CarriersUtils.getCarriers(scenario).getCarriers().size(), MatsimTestUtils.EPSILON); Assertions.assertEquals(1, CarriersUtils.getCarrierVehicleTypes(scenario).getVehicleTypes().size(), MatsimTestUtils.EPSILON); @@ -522,9 +524,12 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { String shapeFileZoneNameColumn = "name"; String shapeFileBuildingTypeColumn = "type"; Path pathToInvestigationAreaData = Path.of(utils.getPackageInputDirectory()).resolve("investigationAreaData.csv"); + LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); Map> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection(); + IntegrateExistingTrafficToSmallScaleCommercial integratedExistingModels = new DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl(); + ArrayList modesORvehTypes = new ArrayList<>( Arrays.asList("vehTyp1", "vehTyp2", "vehTyp3", "vehTyp4", "vehTyp5")); Config config = ConfigUtils.createConfig(); @@ -550,9 +555,9 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { Map, Link>> linksPerZone = GenerateSmallScaleCommercialTrafficDemand .filterLinksForZones(scenario, SCTUtils.getZoneIndex(inputDataDirectory), facilitiesPerZone, shapeFileZoneNameColumn); - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, linksPerZone); + integratedExistingModels.readExistingCarriersFromFolder(scenario, sample, linksPerZone); - TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, linksPerZone, usedTrafficType, + integratedExistingModels.reduceDemandBasedOnExistingCarriers(scenario, linksPerZone, usedTrafficType, trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop); // test for "area1" @@ -630,7 +635,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { estimatesStart = new HashMap<>(); estimatesStart.put(1, 2.); estimatesStart.put(2, 7.); - estimatesStart.put(3, 40.); + estimatesStart.put(3, 37.); estimatesStart.put(4, 69.); estimatesStart.put(5, 46.); estimatesStart.put(6, 8.); @@ -652,7 +657,7 @@ void testReducingDemandAfterAddingExistingScenarios_goods() throws Exception { if (modeORvehType.equals("vehTyp3")) { Assertions.assertEquals(1, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(1), MatsimTestUtils.EPSILON); Assertions.assertEquals(1, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(2), MatsimTestUtils.EPSILON); - Assertions.assertEquals(7, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); + Assertions.assertEquals(4, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(3), MatsimTestUtils.EPSILON); Assertions.assertEquals(17, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(11, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); Assertions.assertEquals(5, trafficVolumePerTypeAndZone_start.get(trafficVolumeKey).getDouble(6), MatsimTestUtils.EPSILON); @@ -699,6 +704,9 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th LanduseDataConnectionCreator landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); Map> landuseCategoriesAndDataConnection = landuseDataConnectionCreator.createLanduseDataConnection(); + IntegrateExistingTrafficToSmallScaleCommercial integratedExistingModels = new DefaultIntegrateExistingTrafficToSmallScaleCommercialImpl(); + + Map> resultingDataPerZone = LanduseBuildingAnalysis .createInputDataDistribution(output, landuseCategoriesAndDataConnection, usedLanduseConfiguration, @@ -713,9 +721,9 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Map, Link>> regionLinksMap = GenerateSmallScaleCommercialTrafficDemand .filterLinksForZones(scenario, SCTUtils.getZoneIndex(inputDataDirectory), facilitiesPerZone, shapeFileZoneNameColumn); - SmallScaleCommercialTrafficUtils.readExistingModels(scenario, sample, regionLinksMap); + integratedExistingModels.readExistingCarriersFromFolder(scenario, sample, regionLinksMap); - TrafficVolumeGeneration.reduceDemandBasedOnExistingCarriers(scenario, regionLinksMap, usedTrafficType, + integratedExistingModels.reduceDemandBasedOnExistingCarriers(scenario, regionLinksMap, usedTrafficType, trafficVolumePerTypeAndZone_start, trafficVolumePerTypeAndZone_stop); //because the reduction of the start volume in zone3 (purpose 2) is higher than the value, a start reduction will be distributed over other zones @@ -761,7 +769,7 @@ void testReducingDemandAfterAddingExistingScenarios_commercialPersonTraffic() th Assertions.assertEquals(37, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(4), MatsimTestUtils.EPSILON); Assertions.assertEquals(17, trafficVolumePerTypeAndZone_stop.get(trafficVolumeKey).getDouble(5), MatsimTestUtils.EPSILON); - Assertions.assertEquals(330, sumOfStartOtherAreas, MatsimTestUtils.EPSILON); + Assertions.assertEquals(319, sumOfStartOtherAreas, MatsimTestUtils.EPSILON); } diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv index 04d2d8af059..deab6883654 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose3.csv @@ -1,4 +1,4 @@ O/D area2 area1 area3 -area2 51 24 7 +area2 51 24 8 area1 27 15 4 -area3 8 4 2 +area3 8 4 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv index 3d2f4777106..9fb736fec13 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose4.csv @@ -1,4 +1,4 @@ O/D area2 area1 area3 -area2 16 7 2 -area1 7 3 1 +area2 17 7 2 +area1 6 3 1 area3 2 2 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv index ac996432028..35f48e5ba2d 100644 --- a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv +++ b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/calculatedData/odMatrix_commercialPersonTraffic_total_purpose5.csv @@ -1,4 +1,4 @@ O/D area2 area1 area3 -area2 7 4 1 -area1 3 2 0 +area2 6 3 1 +area1 4 3 0 area3 0 0 1 diff --git a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz index 8d77e5ca6b6..5f61199dc0b 100644 Binary files a/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz and b/contribs/small-scale-traffic-generation/test/input/org/matsim/smallScaleCommercialTrafficGeneration/test.output_events.xml.gz differ diff --git a/pom.xml b/pom.xml index 9672c87de90..f5dc8484acc 100644 --- a/pom.xml +++ b/pom.xml @@ -128,7 +128,7 @@ commons-codec commons-codec - 1.16.1 + 1.17.0 org.apache.commons @@ -200,7 +200,7 @@ com.google.errorprone error_prone_annotations - 2.26.1 + 2.27.0 @@ -436,7 +436,7 @@ org.apache.maven.plugins maven-install-plugin - 3.1.1 + 3.1.2 org.apache.maven.plugins