From bee9a705428fdd66eb4fae50587319744568b438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 6 Dec 2024 21:27:23 +0100 Subject: [PATCH 01/39] feat(ev): add charging priorities and reservations (#3632) --- .../contrib/ev/charging/ChargingModule.java | 11 +- .../contrib/ev/charging/ChargingPriority.java | 29 +++++ ...hargingWithQueueingAndAssignmentLogic.java | 10 +- .../charging/ChargingWithQueueingLogic.java | 44 +++++--- ...ElectricFleetSpecificationDefaultImpl.java | 2 +- ...ectricVehicleSpecificationDefaultImpl.java | 2 +- ...nfrastructureSpecificationDefaultImpl.java | 2 +- .../ChargerReservationManager.java | 106 ++++++++++++++++++ .../reservation/ChargerReservationModule.java | 35 ++++++ .../ReservationBasedChargingPriority.java | 64 +++++++++++ 10 files changed, 281 insertions(+), 24 deletions(-) create mode 100644 contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingPriority.java create mode 100644 contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationManager.java create mode 100644 contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ChargerReservationModule.java create mode 100644 contribs/ev/src/main/java/org/matsim/contrib/ev/reservation/ReservationBasedChargingPriority.java 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 430484e4943..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 @@ -54,15 +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) { - return new ChargingWithQueueingLogic.Factory(eventsManager); + ChargingWithQueueingLogic.Factory provideChargingWithQueueingLogicFactory(EventsManager eventsManager, ChargingPriority.Factory chargingPriorityFactory) { + return new ChargingWithQueueingLogic.Factory(eventsManager, chargingPriorityFactory); } @Provides @Singleton - ChargingWithQueueingAndAssignmentLogic.Factory provideChargingWithQueueingAndAssignmentLogicFactory(EventsManager eventsManager) { - return new ChargingWithQueueingAndAssignmentLogic.Factory(eventsManager); + 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/ChargingWithQueueingAndAssignmentLogic.java b/contribs/ev/src/main/java/org/matsim/contrib/ev/charging/ChargingWithQueueingAndAssignmentLogic.java index a21fde69f40..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 @@ -34,8 +34,8 @@ public class ChargingWithQueueingAndAssignmentLogic extends ChargingWithQueueing implements ChargingWithAssignmentLogic { private final Map, ChargingVehicle> assignedVehicles = new LinkedHashMap<>(); - public ChargingWithQueueingAndAssignmentLogic(ChargerSpecification charger, EventsManager eventsManager) { - super(charger, eventsManager); + public ChargingWithQueueingAndAssignmentLogic(ChargerSpecification charger, EventsManager eventsManager, ChargingPriority priority) { + super(charger, eventsManager, priority); } @Override @@ -68,14 +68,16 @@ public Collection getAssignedVehicles() { static public class Factory implements ChargingLogic.Factory { private final EventsManager eventsManager; + private final ChargingPriority.Factory priorityFactory; - public Factory(EventsManager eventsManager) { + public Factory(EventsManager eventsManager, ChargingPriority.Factory priorityFactory) { this.eventsManager = eventsManager; + this.priorityFactory = priorityFactory; } @Override public ChargingLogic create(ChargerSpecification charger) { - return new ChargingWithQueueingAndAssignmentLogic(charger, eventsManager); + 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 515a586a4c2..15ba10930be 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 @@ -40,15 +40,17 @@ public class ChargingWithQueueingLogic implements ChargingLogic { protected final ChargerSpecification charger; private final EventsManager eventsManager; + private final ChargingPriority priority; 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, EventsManager eventsManager) { + public ChargingWithQueueingLogic(ChargerSpecification charger, EventsManager eventsManager, ChargingPriority priority) { this.charger = Objects.requireNonNull(charger); this.eventsManager = Objects.requireNonNull(eventsManager); + this.priority = priority; } @Override @@ -71,21 +73,22 @@ public void chargeVehicles(double chargePeriod, double 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 cv = arrivingVehiclesIter.next(); - if (pluggedVehicles.size() < charger.getPlugCount()) { - plugVehicle(cv, now); - } else { + if (pluggedVehicles.size() >= charger.getPlugCount() || !plugVehicle(cv, now)) { queueVehicle(cv, now); } - arrivingVehiclesIter.remove(); } + arrivingVehicles.clear(); } @Override @@ -106,8 +109,13 @@ 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 @@ -123,12 +131,20 @@ private void queueVehicle(ChargingVehicle cv, double now) { listeners.get(cv.ev().getId()).notifyVehicleQueued(cv.ev(), now); } - private void plugVehicle(ChargingVehicle cv, double now) { + 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(), 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()); @@ -147,14 +163,16 @@ public Collection getQueuedVehicles() { static public class Factory implements ChargingLogic.Factory { private final EventsManager eventsManager; + private final ChargingPriority.Factory chargingPriorityFactory; - public Factory(EventsManager eventsManager) { + public Factory(EventsManager eventsManager, ChargingPriority.Factory chargingPriorityFactory) { this.eventsManager = eventsManager; + this.chargingPriorityFactory = chargingPriorityFactory; } @Override public ChargingLogic create(ChargerSpecification charger) { - return new ChargingWithQueueingLogic(charger, eventsManager); + return new ChargingWithQueueingLogic(charger, eventsManager, chargingPriorityFactory.create(charger)); } } } 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 From 9c30281362b042413bbc913c6ccae85f548ac323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Sat, 7 Dec 2024 11:00:13 +0100 Subject: [PATCH 02/39] fix(ev): unqueuing a vehicle (#3633) --- .../ev/charging/ChargingWithQueueingLogic.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) 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 15ba10930be..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 @@ -118,10 +118,19 @@ public void removeVehicle(ElectricVehicle ev, double now) { } } } 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())); } } From c6e1bf582e43ecb4df801fcd0cf4d74678f6e41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Sat, 7 Dec 2024 11:22:31 +0100 Subject: [PATCH 03/39] feat/fix(ev): minor changes (#3634) * fix case where vehicle is still queued at end of day * make all profiles optional * fix code error --- .../ev/stats/ChargingProceduresCSVWriter.java | 8 ++- .../contrib/ev/stats/EvStatsModule.java | 60 ++++++++++--------- 2 files changed, 39 insertions(+), 29 deletions(-) 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"); - } - }); + } + }); + } } } From 5f58a97e2538b5c7a184ab07d52d2fcdcd8909d8 Mon Sep 17 00:00:00 2001 From: rakow Date: Sat, 7 Dec 2024 14:35:53 +0100 Subject: [PATCH 04/39] calculate correct speed when using loop links (#3636) --- .../pt/CreateTransitScheduleFromGtfs.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) 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 cef7709361e..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 @@ -33,10 +33,7 @@ import java.io.File; import java.nio.file.Path; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; @@ -206,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()); @@ -477,8 +481,12 @@ private Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network networ // 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 @@ -490,8 +498,23 @@ private Scenario getScenarioWithPseudoPtNetworkAndTransitVehicles(Network networ // 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(); } From 77bf4a43fd11e1f3c0a5636a9dbdea8f5661c8e9 Mon Sep 17 00:00:00 2001 From: Aleksander1234519 <111151521+Aleksander1234519@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:26:40 +0100 Subject: [PATCH 05/39] Fixed ConcurrentModificationException in scenario-cutout util (#3624) * Fixed ConcurrentModificationException when loading populations with unselected plans * Changed to more stable solution (instead of directly manipulating the list-object, we now use the removePlan-method) --------- Co-authored-by: rakow --- .../prepare/scenario/CreateScenarioCutOut.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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); + } + } } From cc4c4e0c8afb86788772a83d2cf9689dff91801c Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Tue, 26 Nov 2024 15:14:43 +0100 Subject: [PATCH 06/39] add parking tests for random and benenson --- .../run/RunParkingSearchScenarioIT.java | 41 +++++++++++++++++- .../output_events.xml.gz | Bin 0 -> 46258 bytes .../output_plans.xml.gz | Bin 0 -> 5914 bytes .../output_events.xml.gz | Bin 0 -> 44970 bytes .../output_plans.xml.gz | Bin 0 -> 5208 bytes 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy/output_plans.xml.gz 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 index e3959961195..e8e0478cc5e 100644 --- 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 @@ -55,6 +55,23 @@ void testRunParkingBenesonStrategy() { 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 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); + } catch (Exception e) { e.printStackTrace(); Assertions.fail("something went wrong"); @@ -77,6 +94,24 @@ void testRunParkingRandomStrategy() { e.printStackTrace(); Assertions.fail("something went wrong"); } + + 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 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); + } @Test @@ -101,7 +136,8 @@ void testRunParkingDistanceMemoryStrategy() { 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"); + Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are " + + "different"); } } @@ -139,7 +175,8 @@ void testRunParkingNearestParkingSpotStrategy() { 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"); + Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are " + + "different"); } } diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..4e4e4efe77ab9e92b508b7946e953996aacf1078 GIT binary patch literal 46258 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
K(1YAh(iemho`3TtfO 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 ~Oq|ITAOh;x(8jdCWHkG_JkN2= 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 U8_uajO{srx^&+_YTiH4P4NMhkZvX%Q literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..e80c449a03b7d66106265b3bd3ca28592c62f2f3 GIT binary patch literal 44970 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

ZlG^odod-ET41Os(*Hq>ma;dVkNl!7 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 Date: Tue, 26 Nov 2024 15:47:13 +0100 Subject: [PATCH 07/39] move parking tests --- .../parkingsearch/sim/SetupParking.java | 31 ++- .../run/RunParkingSearchScenarioIT.java | 194 ------------------ .../parkingsearch/AbstractParkingTest.java | 71 +++++++ .../parkingsearch/BenensonParkingTest.java | 8 + .../DistanceMemoryParkingTest.java | 8 + .../parkingsearch/NearestParkingSpotTest.java | 8 + .../parkingsearch/RandomParkingTest.java | 8 + .../output_events.xml.gz | Bin 46258 -> 0 bytes .../output_plans.xml.gz | Bin 5914 -> 0 bytes .../testParking100/output_events.xml.gz | Bin 0 -> 46401 bytes .../testParking100/output_plans.xml.gz | Bin 0 -> 5882 bytes .../testParking100}/output_events.xml.gz | Bin .../testParking100}/output_plans.xml.gz | Bin .../testParking100}/output_events.xml.gz | Bin .../testParking100}/output_plans.xml.gz | Bin .../testParking100}/output_events.xml.gz | Bin .../testParking100}/output_plans.xml.gz | Bin 17 files changed, 118 insertions(+), 210 deletions(-) delete mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT.java create mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java create mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java create mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java create mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java create mode 100644 contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java delete mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_events.xml.gz delete mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy => parkingsearch/DistanceMemoryParkingTest/testParking100}/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingDistanceMemoryStrategy => parkingsearch/DistanceMemoryParkingTest/testParking100}/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy => parkingsearch/NearestParkingSpotTest/testParking100}/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingNearestParkingSpotStrategy => parkingsearch/NearestParkingSpotTest/testParking100}/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy => parkingsearch/RandomParkingTest/testParking100}/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/{parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingRandomStrategy => parkingsearch/RandomParkingTest/testParking100}/output_plans.xml.gz (100%) 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..41d3e3b477b 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; @@ -38,7 +40,7 @@ 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,27 +55,27 @@ 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(); this.install(new ParkingSearchQSimModule()); addControlerListenerBinding().to(ParkingListener.class); @@ -85,12 +84,12 @@ public void install() { } }); - 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/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 e8e0478cc5e..00000000000 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT.java +++ /dev/null @@ -1,194 +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); - - 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 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); - - } 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"); - } - - 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 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); - - } - - @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/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java new file mode 100644 index 00000000000..6f4d2d25679 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java @@ -0,0 +1,71 @@ +package org.matsim.contrib.parking.parkingsearch; + +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.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 testParking100() { + ParkingSearchConfigGroup parkingSearchConfigGroup = prepare(); + run(parkingSearchConfigGroup); + validate(); + } + + private ParkingSearchConfigGroup prepare() { + ParkingSearchConfigGroup parkingSearchConfigGroup = new ParkingSearchConfigGroup(); + parkingSearchConfigGroup.setParkingSearchStrategy(getParkingSearchStrategy()); + return parkingSearchConfigGroup; + } + + void run(ParkingSearchConfigGroup parkingSearchConfigGroup) { + Config config = ConfigUtils.loadConfig("parkingsearch/config.xml", parkingSearchConfigGroup); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); + + Scenario scenario = ScenarioUtils.loadScenario(config); + + Controller controller = ControllerUtils.createController(scenario); + SetupParking.installParkingModules(controller); + controller.run(); + } + + void validate() { + 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 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); + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java new file mode 100644 index 00000000000..55be4a073a0 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java @@ -0,0 +1,8 @@ +package org.matsim.contrib.parking.parkingsearch; + +public class BenensonParkingTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.Benenson; + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java new file mode 100644 index 00000000000..f22e28ef54f --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java @@ -0,0 +1,8 @@ +package org.matsim.contrib.parking.parkingsearch; + +public class DistanceMemoryParkingTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.DistanceMemory; + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java new file mode 100644 index 00000000000..29fdb41c8f2 --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java @@ -0,0 +1,8 @@ +package org.matsim.contrib.parking.parkingsearch; + +public class NearestParkingSpotTest extends AbstractParkingTest { + @Override + ParkingSearchStrategy getParkingSearchStrategy() { + return ParkingSearchStrategy.NearestParkingSpot; + } +} diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java new file mode 100644 index 00000000000..dc1660a263c --- /dev/null +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java @@ -0,0 +1,8 @@ +package org.matsim.contrib.parking.parkingsearch; + +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/testRunParkingBenesonStrategy/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingchoice/run/RunParkingSearchScenarioIT/testRunParkingBenesonStrategy/output_events.xml.gz deleted file mode 100644 index 4e4e4efe77ab9e92b508b7946e953996aacf1078..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46258 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

K(1YAh(iemho`3TtfO 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 ~Oq|ITAOh;x(8jdCWHkG_JkN2= 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 U8_uajO{srx^&+_YTiH4P4NMhkZvX%Q diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..f4ef65ec98d671d30de43625a2da432adbd976ac GIT binary patch literal 46401 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

FGU?ZPO%S0(7i)M0VdsA3RPRhN2QMTAD3ra8~u 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 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..0f6c10dd24a02e9358a9f9c93d4af19e8baddff0 GIT binary patch literal 5882 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 Date: Tue, 26 Nov 2024 16:25:13 +0100 Subject: [PATCH 08/39] make benenson test deterministic --- .../search/BenensonParkingSearchLogic.java | 137 ++++++++++-------- .../resources/parkingsearch/population1.xml | 21 +++ .../parkingsearch/AbstractParkingTest.java | 21 ++- .../testParking1/output_events.xml.gz | Bin 0 -> 711 bytes .../testParking1/output_plans.xml.gz | Bin 0 -> 612 bytes .../testParking100/output_events.xml.gz | Bin 46401 -> 46408 bytes .../testParking100/output_plans.xml.gz | Bin 5882 -> 5876 bytes .../testParking1/output_events.xml.gz | Bin 0 -> 713 bytes .../testParking1/output_plans.xml.gz | Bin 0 -> 613 bytes .../testParking1/output_events.xml.gz | Bin 0 -> 664 bytes .../testParking1/output_plans.xml.gz | Bin 0 -> 655 bytes .../testParking1/output_events.xml.gz | Bin 0 -> 713 bytes .../testParking1/output_plans.xml.gz | Bin 0 -> 613 bytes 13 files changed, 110 insertions(+), 69 deletions(-) create mode 100644 contribs/parking/src/main/resources/parkingsearch/population1.xml create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_plans.xml.gz 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..ba7d4ff081a 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,13 @@ 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 +127,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()); + 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); + 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 +199,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/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/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java index 6f4d2d25679..ec79b4e33f8 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java @@ -25,24 +25,35 @@ public abstract class AbstractParkingTest { abstract ParkingSearchStrategy getParkingSearchStrategy(); + @Test + void testParking1() { + Config config = getConfig(getParkingConfig()); + config.plans().setInputFile("population1.xml"); + run(config); + validate(); + } + @Test void testParking100() { - ParkingSearchConfigGroup parkingSearchConfigGroup = prepare(); - run(parkingSearchConfigGroup); + Config config = getConfig(getParkingConfig()); + run(config); validate(); } - private ParkingSearchConfigGroup prepare() { + private ParkingSearchConfigGroup getParkingConfig() { ParkingSearchConfigGroup parkingSearchConfigGroup = new ParkingSearchConfigGroup(); parkingSearchConfigGroup.setParkingSearchStrategy(getParkingSearchStrategy()); return parkingSearchConfigGroup; } - void run(ParkingSearchConfigGroup 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); @@ -50,7 +61,7 @@ void run(ParkingSearchConfigGroup parkingSearchConfigGroup) { controller.run(); } - void validate() { + private void validate() { Population expected = PopulationUtils.createPopulation(ConfigUtils.createConfig()); PopulationUtils.readPopulation(expected, utils.getInputDirectory() + "/output_plans.xml.gz"); diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..36d8ae41c21887c8822b0c02c27afb5b988ba1c8 GIT binary patch literal 711 zcmV;&0yzC2iwFP!00000|LvK}ZsIT$hS$@lh_at)?${F0Rd-XV(u`&wC8k)I1Q|E& zy#1KaQETw!IPsEQo6E=V^P6)q%ZK+piw44vwC`4N`Xh-W(lvccyO&k`DmLFy{II@T zl7V#Ms6M#9`*yw_3A!h%I4iRxIRV7qgZ#H{1nJs1I>>iUugDvWc02iQTEvmO`+IzB z+wVynMfVO`OAa*`ubh~GjJ!Pct$gyWW;*~-@OmJO5mjMJkD~4xd4GI#??bFPr$fy` z36v3%TDWjVu&H@OJ3+X-BF%xJA=dbVZ!Q^wDFd^UUn&E#@^=Rggu5ag2k@Rp$m3~e z9RH9lZJ0_P&ez7jov@FGW!5?2B5C+$LmQLQujr15x1R65DCdOLf)3=lKT`3T(DWM8 zPYsN0#P})3&vGKhO+eb{!|-QF&fi*X4`Q3CYq5Kv^s- zLi`b0A=$!BDJpCe;*HQ+lOs2!v~M|YgkA`CQ>xUuN4ybQYYIRjs7mV|@kZ!`#2vG5+0&Nvf zU9-8&E5IOqh`MH=DNr2L6;M+*#T|d}%_U zxNprQYy81CmnIbmgg`UaR3O|HQJ|i@WW;H1-E!UtZA1V=G|sGh z#2=xJ2;h_gXN7J2^+)JWCLk1?PnfZSp8BX7X3khD40^0+%KjI$5T}YbFLOY}n+gnY t)~f02j5%*{PMKCKmWe9{s%OxD^Cv_006V1Qtbc$ literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..cf995fee8419c0f90ebc51bf1ad99d6c48a202ae GIT binary patch literal 612 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

{a6$6i;{^! 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 z zwcNBH!35y{&`vt>R~=xcDPkrf>B zGx=KT{`{hhR}xpdUp;CwTuZ}Ss(>^Ft|Ct`i`Bxtn_`(Ga^8&MI9%H~6sNcYs?yfP zUsWkI7}GydUHsi8ZL(~I5uza#v)`Epon>sH0tmWo(c_dO5kkCgQ&4V1Q#k@ZFE!l3 z&31Wl*Vo}avuQv4PfwoZ2G6lJZF_yg`lX@gsUO9DU>dcM=_{xWM zkxFlJN&X)HPI#8A9G~X<%1=OCB-ITsT?s?IRKzN|ylYep4@w#yrJz5F@lxNMYQ(7x zQ?jse#g81xRE{QpdS<}~9*!$J^67pXY|ZtTRzd-Drq_!kQ{|>X|Ck+U&Ko|z7h0)x zFS-LWhwbr62~0|fx&m#oylj6qC3QjYtS-HP;|7WT zRIj8HM3K~|>7mzs*a&k@^`dyMUh7N!Sk#nWj1$RFqE=OAxJk7C-uSU4beUuW)inB^ z%)m#7Rd^a?Xj3&_WLsF6%8r6%>-zu;zvKgbnAe?Zx*X66@(aHm!5zu^$Twu}5fC{$ z`Js4LOe9;c1iA(RJsGH9h=#Sidl9PQWCu=jy^AfYk&6fqR@1+TQj9 z)d0)GT9^%K+542FZJim=FXBXTBy`T zUQPIJp=JX7qvP^1Kk5nrzLH~;%_F0=Sge~-y6+tFF%eiRbCo6qk{9Nt*xf`c6dL$K zZHHLF{AYw_)sAj@?7a|l`wuU;uQ_c$^pVhoo1#w|JpfATO;pqQlUHg@pC6}=1*YPu z&P>@*<@0RrHelnY8_B6u+gld~6|WDH3ynU}_&u&e)}CcdD^gNF0%sDznp+kTM+Q?@ z`57^jN3vm24F15^$ft}k;6#hQ^2bFG{#9yFjFbVCWq+s3whZ={1xuFE;2Vw8zum{^ z$k=m?uWr=cGiglR&2x!jA3_$|VN`q-j_5jhm@UM}xZ#IA8a4?W_u5w_Vr z9l{=>COR=ScPn$h%;H02E2|hbL3?zU_O_)ld!T0OR|VBgh%n4aCTvjM+7BV&LzAGgfx>3di7$YxyE_W=Rmq&hzu5G5{AzaJ2+^WW%RY3Nx2kWbP8c%# zPhsQv?XSY7)u-T8<%A+mZfDKQ`|k9)7mvpo_z%8kD#N8r1v1oc;MdlA-r&l%3JN5L zS;*Qi5=WMAy(D|WoN_N(ZwaD90j3?h!sD)H4Jw>9JJEOiXn0V1zt{vZ4P{8&;Z=_T_Q%$r@#+ zKf!5L$5D^&^w8d=cHfy}|Hebw3H|LiW*4|!`vn<#Oizy5qEO#_rahnc!9P2JLfchV zwLeW?br3iZ{L>PuZ7s#XaiSJ^R&|0F6pr∓g;N26C~)_Dc2=XFe~`c?7y#n)_hu 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�L7t5VbJ-WQ=GW;#=DSXuE=ldMK;Ugs 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

FGU?ZPO%S0(7i)M0VdsA3RPRhN2QMTAD3ra8~u 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 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz index 0f6c10dd24a02e9358a9f9c93d4af19e8baddff0..29cc4abae96372bcb3b3ce521ab2d383ddb3877e 100644 GIT binary patch literal 5876 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 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..26b51e95fffc38d6b4da72841d024ae355465f4f GIT binary patch literal 613 zcmV-r0-F6FiwFP!00000|J7FCkD5Rbem?(-y?uuTwZa+T(zN$@>7`zp+>_bDid%st z%ZQq$|9c0}J5+jY?zD-<2WDh`ec#MD-t9U~NGWt7RpwLMv?vi-s3MugK3&4haOrK( z^R7RC`Skeoa7S{LFB1;{l5#po zES-~X|E_Upvc8~kIPahE(XG<~smH3Ls=oJFbMOUcI3_*TzLS3ggH1Ztt_uJF73C>D literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..8e1a8f4a86a198774d58d988e9469a555eac9622 GIT binary patch literal 664 zcmV;J0%!dniwFP!00000|E-u!bK4*ghR@BfV03SzPg|O?ol|b@OlI2YosrftV=QS9 zQJQ~Wgfn$W5iGKAi3E>dc47Awn})LIUe2XIjZQV7jecnbda{slA9(H#d z7@?JeIdFIP<@}sTc7kn`7HJ$$0QuIde`zhDZ6eaEInxyNg0uFh<|cVW)Z1Tr*r7W? zM995|)<92%d=W4QA>Q!`M?;bMX6Z?#%XpLsIo*kvZX-$ zPMSM6Chtl|X2Q^p?4~u!)PQzmT7wt2%#k_RE=Pvx3MRtdTl_t{tYViV3rE<6_+3m{ zYLm{pv)99cNRnwr#axvO~Xa%ABMYeWzqAytyPPE9z% y{`r8RtcnGW?55wJriLpWnF+&Q%FK0^Pc-cP#^qLPbAP@&+x-Q=Wl`;G6951}gFHO| literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..c3d3666b97ed333b1dbc6f55c315f5d8a7076498 GIT binary patch literal 655 zcmV;A0&x8wiwFP!00000|J7DoZ`v>velEY_)bHeCLI@~HHEn&^L$zvDllp|b#DGU` za!deC`|mqR2n`UrYGP7{u#|J~xqY9%824@)M^JE?i!||wsTl-#5~QI>79LrvdEX&- ze$T!A^yTBz^W!~aX||4-!rd@^o<7|_09h)PO>}*;*=R9Sxrnt?F7&yGc&>*k)L%ko zg{`57_`RO{;zjGmWlBl$eXV%z_ikDyBrN703DQ(zPfYQze9k4d$fvtp@t8mmu{`(4 z4^}WOV#z|AVra4;{s)Do61l4%vSIF)g{82O+kPLst9+o}uV%>*PQ*uq9x=%AIMsCL z;}v`<0>tYu4I)nw<>aGP~M`P+%AyRP>>&d{?hh?;%1^I$_2xK_rUH(w`is~ilh@mcfMWazXxpd(tr zwU-mVMn2d2#9UySLtHjca|9-JfYLEg%K%LLHrh6+Ts2%(-L%x<{H;2i|4f;@d&>@Z!3c6lU)`T8WK+Ox{z+5N-2iFL!0WNC8fDXZ` pL}R^;wX>_Eg92AC@2Kkf)a(1x{|9%otGEAl{028WIxYPO005oJII#c# literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..2bc7be4d53f676887e1e0bcb89891e3cc46614fc GIT binary patch literal 713 zcmV;)0yh00iwFP!00000|LvJgZ=)~}hR@qyfw=D$3@6%?)h0=xPACCUynFB;!TVSlq3^?|2v6~P0MlL#nDMTGd&`1P|_d7vuPej;_h#` zY(E@v97T@~T8B>!xfE2&{96GV`t)T}1kh5mQlwwt3N6x(ITXA15J^BzE#>m*v zPy$7Sgcin~5o{Y4k)C5Ft_X8rXoxlb;JZu4V2Z#T#7kvBuKeAB1L3X+#{s-&3Hd(# zXPp1wJ!z>*9_MTFZzt@1vB)|TE)s_CcBC~a{fzE0e;e50lX8Y>!^w!Bhcn?H2~Dpd z{m?-1j>~T`ewPy=<>T&xQn)EumRp7RBJ@I507_X}h4>YD-UzLb9Ps8AMQsz}jgYBR2zk$Czi`9ay~>!;SzZHhx_!wf zU7}WnCL>WSYL6`=U7>HvNQ#Cz#r}{AmZVq(W-fVh2kz{z(##c4;$Q`;Od%C-DbQB& z)IFQayaEhz4pH|EGzE%-x&k`XEpf*me0Rwh%qfj%c~u2E$Sq_<=xn0sW5Pl74$?SG}wA9$iYlS=#O{qQ+QP; zwjRqLp%>!rOR74z^;rH0osc|(P-gWOGYos_m7%O9bQ z2w<#Gr^xo!_#?nQmK=IGar*fJMAWKS&|?Li`luRi?6FiBbgXE~{ui_mQ^gvg0#Nam v0t3u?RbYs7$i<#-o%LRYFx*6bkvsn2yGwvyp4N}^?_1mdsJJvq4;uggx7S;5 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..26b51e95fffc38d6b4da72841d024ae355465f4f GIT binary patch literal 613 zcmV-r0-F6FiwFP!00000|J7FCkD5Rbem?(-y?uuTwZa+T(zN$@>7`zp+>_bDid%st z%ZQq$|9c0}J5+jY?zD-<2WDh`ec#MD-t9U~NGWt7RpwLMv?vi-s3MugK3&4haOrK( z^R7RC`Skeoa7S{LFB1;{l5#po zES-~X|E_Upvc8~kIPahE(XG<~smH3Ls=oJFbMOUcI3_*TzLS3ggH1Ztt_uJF73C>D literal 0 HcmV?d00001 From d1919d65d24d6457e2d289899fe9ce669a694da2 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Tue, 26 Nov 2024 17:28:11 +0100 Subject: [PATCH 09/39] make parking tests acutally test parking --- .../manager/FacilityBasedParkingManager.java | 44 ++++++--- .../search/BenensonParkingSearchLogic.java | 5 +- .../DistanceMemoryParkingSearchLogic.java | 85 ++++++++++-------- .../parkingsearch/parkingFacilities.xml | 22 ++--- .../parkingsearch/NearestParkingSpotTest.java | 2 + .../testParking100/output_events.xml.gz | Bin 46408 -> 54637 bytes .../testParking100/output_plans.xml.gz | Bin 5876 -> 6384 bytes .../testParking100/output_events.xml.gz | Bin 44970 -> 54969 bytes .../testParking100/output_plans.xml.gz | Bin 5208 -> 5541 bytes .../testParking100/output_events.xml.gz | Bin 44970 -> 53576 bytes .../testParking100/output_plans.xml.gz | Bin 5208 -> 6009 bytes 11 files changed, 94 insertions(+), 64 deletions(-) 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..b2389a3d927 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 @@ -76,12 +76,12 @@ public FacilityBasedParkingManager(Scenario scenario) { canParkOnlyAtFacilities = psConfigGroup.getCanParkOnlyAtFacilities(); this.network = scenario.getNetwork(); parkingFacilities = scenario.getActivityFacilities() - .getFacilitiesForActivityType(ParkingUtils.ParkingStageInteractionType); + .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; + this.startTime = 9 * 3600; //TODO yyyy? this is a magic variable and should either be deleted or configurable, paul nov '24 for (ActivityFacility fac : this.parkingFacilities.values()) { Id linkId = fac.getLinkId(); @@ -138,17 +138,23 @@ public boolean canParkAtThisFacilityUntilEnd(Id linkId, double stopDuratio double totalNeededParkingDuration = getOffDuration + stopDuration + pickUpDuration; for (Id facility : facilities) { double maxParkingDurationAtFacilityInHours = Double.MAX_VALUE; - if (this.parkingFacilities.get(facility).getAttributes().getAsMap().containsKey("maxParkingDurationInHours")) + 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) + 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 + } + } + } else { return true; + } } } } @@ -172,7 +178,7 @@ private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id Set> parkingFacilitiesAtLink = this.facilitiesPerLink.get(linkId); for (Id fac : parkingFacilitiesAtLink) { double cap = this.parkingFacilities.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) - .getCapacity(); + .getCapacity(); this.reservationsRequests.get(fac).increment(); if (this.occupation.get(fac).doubleValue() < cap) { // LogManager.getLogger(getClass()).info("occ: @@ -191,7 +197,9 @@ private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id 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); + } else { + return this.parkingLocationsOutsideFacilities.getOrDefault(vehicleId, null); + } } @Override @@ -209,7 +217,9 @@ protected boolean parkVehicleAtLink(Id vehicleId, Id linkId, doub if (fac != null) { this.parkingLocations.put(vehicleId, fac); this.numberOfParkedVehicles.get(fac).increment(); - foundParkingByTime.get(getTimeSlotIndex(time) * timeBinSize).increment(); + int timeSlot = getTimeSlotIndex(time) * timeBinSize; + foundParkingByTime.putIfAbsent(timeSlot, new MutableLong(0)); + foundParkingByTime.get(timeSlot).increment(); return true; } else { throw new RuntimeException("no parking reservation found for vehicle " + vehicleId.toString() @@ -228,7 +238,9 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double } else { Id fac = this.parkingLocations.remove(vehicleId); this.occupation.get(fac).decrement(); - unparkByTime.get(getTimeSlotIndex(time) * timeBinSize).increment(); + int timeSlot = getTimeSlotIndex(time) * timeBinSize; + unparkByTime.putIfAbsent(timeSlot, new MutableLong(0)); + unparkByTime.get(timeSlot).increment(); return true; } } @@ -239,14 +251,17 @@ public List produceStatistics() { 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(); + .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( + 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(); + e.getKey()).toString() + ";" + this.numberOfStaysFromGetOffUntilGetIn.get(e.getKey()) + .intValue() + ";" + this.numberOfParkingBeforeGetIn.get(e.getKey()) + .intValue(); stats.add(s); } return stats; @@ -360,8 +375,9 @@ public void checkFreeCapacitiesForWaitingVehicles(QSim qSim, double now) { 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) + if (startWaitingTime > now) { break; + } Id vehcileId = waitingVehicles.get(linkId).remove(startWaitingTime); DynAgent agent = (DynAgent) qSim.getAgents().get(Id.createPersonId(vehcileId.toString())); reserveSpaceIfVehicleCanParkHere(vehcileId, linkId); 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 ba7d4ff081a..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 @@ -118,7 +118,8 @@ public Id getNextLinkRandomInAcceptableDistance(Id currentLinkId, Id } outGoingLinks.remove(nextLink); } - logger.error("vehicle " + vehicleId + " finds no outlink in acceptable distance going out from link " + currentLinkId + ". it just takes a " + + 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(); @@ -140,7 +141,7 @@ public boolean wantToParkHere(double pUnoccupied, Id currentLinkId, Id + * 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; - + private Network network; - private HashSet> knownLinks; - + private HashSet> knownLinks; + /** - * @param network - * + * @param network */ public DistanceMemoryParkingSearchLogic(Network network) { this.network = network; @@ -49,49 +47,62 @@ public Id getNextLink(Id currentLinkId, Id destLinkId, Id nextLink = null; - - if(doLogging) logger.info("number of outlinks of link " + currentLinkId + ": " + outLinks.size()); + + if (doLogging) { + logger.info("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){ + if (doLogging) { + logger.info("currently chosen link: " + nextLink + " distToDest: " + 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){ + if (MatsimRandom.getRandom().nextBoolean()) { + 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(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); - + 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); + } + //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" + + "."); + } + if (doLogging) { + logger.error("vehicle " + vehicleId + " takes link " + nextLink + " as next link"); + } this.knownLinks.add(nextLink); return nextLink; } @@ -105,8 +116,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/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/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java index 29fdb41c8f2..7acb5003a4d 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java @@ -5,4 +5,6 @@ public class NearestParkingSpotTest extends AbstractParkingTest { 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/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz index 3a6ca30255c45626b35320d867cd903528504241..3300cf6fc43975fe21fa82ec7b5a8e546f6a346c 100644 GIT binary patch literal 54637 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

dI%DQ7&+@a<={Mt$tMsJ@z2)+~IRvEWCP?i%u2! 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 literal 46408 zcmagFby$_#7WPfESk$5y-QC^Y-6`ED3IfvIv5;=0Q#u5c?p8V!krtGekp3R_+52qI z_rBNl@)sx<&zf_NXN=#t?=dOkKyZJ3J?wX?f8rQTB5!F4MDFc8Xzi+ki*G*th=R0q zoVRx77`>i|P%gjxuo}ReWtOCwhxc7>;q9^8d`G~ISQ5cEoGhG&d&zsrhwI^Qx98>E zw_hmlZ_9&zADngj-(3hw-tAom-49FN?nyrMyFC2-^l&Db-+hS4tCjb6=Hb3yb z^*7N&e>d>cP5#5qcgfqInh(ccd~&+G0^x3NAMP_O?vIWFAAV^D0gt%f>ApSvcKcg1 z@QNttwm<)VJLAFAB_ytVt{Q_%fle&9{cx7#|j&yx3N7J-);`42xW0%d}O z9zO&n@M$dWcYI42>_uXx~NcGxYm=ub`_*%KJ0mGhJb{jS^v31kQuE<9>e~Z1&BJ;3!}7O# zVdNXipev%{--w5T-6NZlce9j%2~3@`4}0bL4`1>hPB{g~9!_T|gD!tj0vi`}{j2+K z{kz4%a}`-dGzJSa&oZQbnrSBZMB~XK{M265KvT}u{!+PD|0qeMvRD?ZH`r@tKmz8(-$QQNbR@gD<2(~i_6}*yr?kTK1T6N4_ z3>hKe>xECqUfUajDZ`Dc9nTSUIZYvkz*-0*Er+OY;cP;O>3Ly3BN4_qLz@$NW6k*X%t1p9i(d1 z`p2<?o4zL$9Q1FiMCmImBXzUg%RNjq&~RSuX`o%b8+TKIvorH3FOl--R&rGV+0py9 zeb8Voc$Mn%$}T6_FliqqQxGu4j12twbW&bIcs6$xRSWVA>2iF>-OToR0k5Q}n)jrH zF+(fxS!w=?^2GjY!{-~~rYd@dUMgC>80F0+8q7W0zysd_5B&WOE=iO=ywPHUnORsP zcsDR<8()j#t7uV^slgbEmcWAJ7t^CQ`mgUM^?6jx{B2kzK^`5J%08zo=V&@N?9&uE~HLizh;r#E&6?)-cwtsYmuXl7*N0!sKFd%7>peusn$I z<90=KFG!w#STAc`QTG$%fQ%KkJ8kV@kE_$Bx|bi5a6O=;ud}`b_9G%PWSqkS`$Lll zQBPx!-O-b=04~?%lsLwy16(iP6I&xXk_?coK`bZB*czf_Ez!}sPSFS74mg5|Xrc=~ z^QF$8($P$tz7U#$b_yhIft^%*O-iZ{7Pk6Y2IA&$Xgkpp2C`2S%_+2E##F{(MQc+zlQSz zaX2n;?`gFu`6L~lX+B(bYis#@rtCSUi|&3S#eL3*w+CX3ZGPE+CzliD)qq#H@2iP{ z?9)Dv7slipkIo$C)sJ6zJd=#SWmj5SAp(jh$4l;2nT>HJi!K_jR+?xOZRNH{W@2o& zH#%W+aO;G4OFA-ZT)0WKpVYT4O-uJeBIxxmwiV@RNR$U=GcZaDZEut ziqg_dL$hcln#=Q%zs+#KujbaS>{sDJeWz zt1Y|REmy+YOlS*+T(N5vo4+lCxa4W3(#UANBX2;!-_-}rK{VqekWfF1;|QKTa#|Ed zW%r?js2OB8&nuP6Q)7Sv(mun0@I}||GrNdk$#9!b$z0f9lI2W0fFi|7bNA0t4Nr|+ z8;2|05mb|O6pGv7*OR|ZYg}gUBgHmm{7P=276?v=z#C5%axt8 z%omk77R*>1raNhEQbtN6ozSO&C?s@i_xKv02+DEC;<4^i!Q}BWOmdAPx&{YrT@S{o zUaxYngjTsczpUdF-`pz);m~~YrW)gD&Az5!m)WXeh%PEOzgtxcAJOFuw^ozi{oaH_ z^FRX{H0GZZ+E%pYW+QoS4PRo2HvII@C1ZhrCBx62%i?GPPcRtvhh!zh8iK9aXjzK!oHb^zs=nm@BK3G?DZb7UGN&RxA@GtOPl#ry0(qtzdX*5taJT6jN6 zpI`h`#zVPqsXgke1#lSs$(+o)*^SEZCpEyiU4#521)wV+T&IEtX^9E`(DgebYiF(# zWq3b&fz0?)<=wc+)df0`&A>syN3kqFLY#@W!v_VgAylVrc(B~@UDzV;`A5GDT@KUuk%)j)?%(0msvi^Nw^rK7y66Ql4B3EpoeQnfzMVI%Y~jK zoH{;Frzizx4EG+2^Q(VEKcTCbVnu<#so?!n3EzUNEm!)Y?5b00>|rMKd?SlDWIk$i zTeqga=#c+;V`By`Kdw6IxsL244A788PM7Z&->+=df&#q5mjq;&(&b56n|g?Q|Cy?pWjwEq)gV!Vjc0CC@LjRX{)%%BdtZ)y+Ma*#vWwiYENv_7&ZdRs^06V9i*AI|PK^lrP+CWE;C7=o zKpJN+Jcb)#yIHsC8S>%po^Ph1lz8Qq8ca~3io+WexQIdn}XdQRj${aPLFO|L~YrXJGN z>z};@GD%<#gg)~UkfLYuTblaW9v=k1Z*8FC)da$G`_BAGRZ!&OET7+-h1rc5Dj3c% zZLz(EA3PUpP6Joa`B&E0n~S#fGGR<|K=Md__~a<34c5!m&lkrH$2dzje0DK{Tof_w zd6kXP{JU3~SIBfvDh{Zff~|0SX+;NrR!^Mau zM|F(XBW^)VNw>$%@fh91Ql$7;Qa+!)LWMGEmxfg~CYT6HsscC;{)%yn5qLTT}V4 zifB6edi*p8zR(qThs9I5j4O^K-mzzIVmL5?2xe>77z&?2ekMO04vSOBX@uXKp9qrY z^xyifzolQTa<(*5s}0Upw{*G(PjZQ=agk6iDNX;V{;3MCp)(w1)54rZCz~ zTr%uqWY_2LG8Y4IfNgxtPTYMQmSUgSIDLW+-~kG=ly7N8UCAHOiS!c4t5h$*hhl?x zp+ZW8tiFbQDZxsYvsLfPgELXGU+%qNy2r?77M{{Gpc}$YFiedLu^(4#E9@8>H8*Z7 zI!HS<8BE!HHtkQS*Z&`EWHFUqg;7f~MSbm{mV^#LPZ4o5C&^C3EDZu2c;3pOVieY5 zS;0~<^a=&tqftY-cZ8%E9K5cqDZ;H_!dTIxJ7lOx{i{`b8jL4u?(@3ezfN+p;J#Vdos7g9@wZWR3I-|=p^I;(*5QD44qXA+=E3xjY$Kp@ zTcMGGDe9>5m~F^q-g!0l3nK}a7W1#;(8Wdcl;&=z$yg-*=Gs${`4)?y=f+E*sqs-R zPRBAS;dYYcT3R{X8YUAWPvU|P4qfhs&A~y_gQ?~6AVY18s3c%Nfe(dylGM;_g{K^r zpJqmOHi3{+l~%i09Z}_SntVPOv#v!(QnAM0s;{JkxKiF=bTfnyd5?2AYfz2+(AFfl z^y_m%s;f#1BX%9BT(6WH0&AhE3N1*8+hS`O=~t(YXqd{u;RJ(YH0GMk+e9(%hhF7b zufwz6n>NShmlBEQ%uwdNh=kjY*p68J7z$Em;)>aW9cKh&2G!Am&!WuB>Id2*o0AN| zw!}?nS|+W2O=wgTFIMiQrxyhLM%c&e!=`_05*zX@sv6y(%?;-hH@X-^c}dD0~8 zc(H@h-+lmKq$`3%^U)8fe>5-gw|GCYQ-W4KFp=n@1a%RU?Iz}=g!k7c=KyR_aY__I z!68YV8F@wt9ojt&R*>s~d=P^~cJ|iM`6ymotgbHkLGehnnzoJ^1eCZs zsXke__#bn_*;uG*uJ9k}{x|(7i5;pr!=)wl=Pm_X3Z#F~cUuo$!ox|dPdRddxdl^v zB;BU!Ju7(!iFlrN8X3#DD9CqSrxXXQehxUbf%>T!u%*1P@>vr%*iuqhn47*nmCBYc zln;gR`nn_uQdn%;o6UzC14KYfpg>pAn%&j!SgUErCPk{w>{pe$e;j{|#2i24boX9% zC?nl9Xb8#+ABVh}iH1=uSr_VbVkKS|$~82Ap84GlkJEY&p&y#X>exxXJP@}d2e)&} zBXALltI`9}K}51q>ySG2w8!Jju747ue3OkT^nF)jK??ck84Irt!iobQnm|;48+~5@ zN{Xes5dYZslJ0t0UkWZar*JNhHbf&inCutcoL#sUh)wwjT6Nn%s=``ZL-ek!W~f_O z6*-3wD! z9Yy*X!;>v7i(l6SPA5tE8QF#n;EdmzBHHlI&GbH60t)ceP4tXqNa-8pFa^lARYJ8U z2^t|H{pmtUk`mBgqlY%05R}(p`1=n6G1|+YXg>Kt@6Q+&0|7CL`qcx|$Irb3l`d}b zHIw}B_aMWur+mVd`aGyPTq+U{@-C!`Pw1G0cV)q4E`k3eHQ^S?0Az|KaN zL)8Dn@1;Z_STPBKTt&hDN3QybXRc-TaLUl3#AR%NHNQGK25>{;>8&F-xsOW(!^U=Tq&o*O_nK>% zC`YNm|BmE?67%!$pV3dlGRNT=>v6&5d_}?JrOh~r<;~I~*MnoAjI!oO5=@>^U=d-k zZcvx&A6t+Ekimu~@r*^F_0Kk@r1?(AYhah;Y?lZ>ldUx3=}}3u;Jc$Jo2%(;5B#KU zjQG9sK^$2nCu-Pq_Vp|5O@~3h2`-JN&s2=JNY+PmJZm_ody?Ml`!2Zo3%eU!>)%FC z6NDHY>RamIz{QO#da=o~w1Gfz#lT4xzm0{+ zs)16`GkK}0F!ucBXy(E$MYW*nNOx;@uiqEM{qwT%z91mH8u?aTM2Sz>l)&kbjy6`> zXw0ClPS#i7rO3Q2loA-#-Xlh1Pt5ifvVJ%Lg>&fY7Ld0%Pln$=nT20w`ElfT}Zj^3PBvWo8HR zZfWNpN#p)18&oZQ7CZK5zHFAy6w=5Ym6e@S_zeuwW8iH4%4bL02q{Qyhz+XuINVoP#{uEC_+|qNC8ErU;{>^zHi5X}Qo^g1(Y~Y*sXpI^##lRKqM`Nt{}% zjY*u`c>`QSISh0zQI}1Uy$Av_c;!lHZ0`qPk101PZP<_PGVmDT zx;KS)^$`veuHM<&4`6G2IKh2G%*{dayaTDk5M7G(Pa(w-{naGe^Y4(Y5^ott^ik{c zOP#6o37Aw8y^WKOSDlg>{crt~tzARCO@uiAEf<4nY!#NQA#dzVE8k6VE?81&LFOvi z5xnINCoMmm0EZ zjjJbsB<`IHn`H<2y2SHAljDRYUV8-Q3}JhO-umxnVXw#JrD`FxPTU!7lP0sYxN z1nAGmf&MH)3@DgN>D=}Rc9~6r_6U9Z3iG7$7VWKiXnngUbSx7emvw)8)1Wb6Zg@f{ zFgRFZ^p2@CGQSf5FR37Zv?_%+k*6AE)2|`YWz1jkg5lIQlh1H|3=U@%b7gzOZIX-d z!L5pVpfSv6VmeN&EsQB4FG8)>fQ&f7Uh1Bjff;_!9_gJiy;06vu);66O!lhzxm zZ{IQ_5x)8eV3wYsgVi)m(5b&0RBl&zyKyV(KEyTy8m{VOm61FKI=KphKx@id1%Vi( z>gSA)Rk^VcrjXdQ?kz{TfH#AaN^IQk`&gCOkR}*<@H^P@;dlYD=`BWyVG{>I=W$ZL zVUl43%d}1LTliO#l}}eZ)O+#Xl7NOX6A@WySHsCLiVgWKG1uzfl0b$s`4E2nbe>Ui zrvde!mg*p6Pr_UmITZ)0-@^MA#tAyfh3?54Tr~cOM0~0)J(v;)&K~`j_Jly@-LU6g z1zRLs;rk@L&=iHlQS&Bc+LIdA@IpL-9v=5xlImqBa{VaTUqwf!gfFxQwG5?7!imn6 zaK+E0Mw#|6^#S;;-{5a@)&Jp(69#~Rcm5Rc_0VmPrCXosst zWXOxgH9D0gj_-M5Jzkb@31WkfznUjGdI^Ur;`_yN(q17qFtN`;0V7U-~@n2%B_%-hsN2%ng`6|tl_aQ+V;dEM~n@FeyiVHB#OSe?bh zRe(F~Z1gu&Ux0XlW=hEuF)}fk8tTx8KJ|;eeSFd16jZE9BJJDdlcGR{@utG{?y35_ zeb@0JCONs@=dK8>+IA|m(E)|R%V)~8(hgGkFPa$Q2vX2oNF7IPnoY&%`8R} z&L%iyfO zS1s+@($pk1*`>r}r(*O9(OM+xjwp2TF(Pn@`t^4Op4%Yg`tOhSpQC6eBC1$2JB~Wa z6%z23wM%@VZi8w$E!Qk#J%-^{_l2!x54J`&gLOF~;*fkXH;$4oea@3Vvh2bzS<%K) z-bd?bmZ~0GABdhGBld?%aaSHd2g3ry&mpy7)2D*NYEn>Kt2CK~V5Qc@Dl1hfwUmT5 zH-S0LVb~=dBjs3j_wV%+1b6N$$1BifhN18>YY)CNmE?J*ED#L8-yNanopb~m=Aw0$UYrdosXaQNH`5@5fNG&r zsbDH{)<)cqQo)hHUf5S98}3L7?TN5mkNE?9bPERf2>ySVUk|z+w}*KD$bfVNLr+~w z`n=w8QnHscB(gaOz^jx`E+auA2X9J|ekg7DCvM|NOC}3-KjIM%P;b@r{>7uz5?g0J zY4$!%1>6F@aI$QyMu@1`GF9A=I1`sRPF4U;;VceHcY5CcUnWa`n;vJ+KF`pO!i8Fw zsj5AfWH7M_2!u&yVOpCb_D}hi`9rOm5Dn_3$s86HdAI8EU7 zWy9+DH7nCk%8zRCkE>2KqZ}=WoNqNiC7y+l>d$qR6Lxb^}ZvE1QI!k zWz>6ZgR9Aa2rT9%)0;-caunN+55XnomC@rGa_U(f`zZcigS|kCG$wFzD9j#O{eZ9{ z4Nf#?|55d4XMIA)G)%sX0eeJSV=**9=45nvnsEC@a1}9S8|fu$?Fohnt#I^{w9mM2 zKtP1OgcFO7^Dgor<)yadSbMCb)yTTBT6HDo2z`#$mbE44I`ttQdi_)}z7=)CY2d#( zD)#4(a$a4;EuC^wUg^D|@V>F*vW#(%*q)vj6@?d@8LlaQte zxfKwmLX=8%TQUFR9a10xMq1d54=ASvv!u2mqt-YE^nKXT9>O0;T95|#4CAU+W$rwt z)JETD^ZXJC^zNX1GBIx=(RaS2uW>>1Ikv@+M-PzEwB>&pYhnIvdnlb+O{_`V70l-J zhFQUg#h6049ge9ozbXN3Y?B`|ariQESV^7^Ai>x|6uMbrd{xSUz3qc;iWhX)c})XZ zs>jp=2ERldtJ}z$V+KbUZJpB#s6=jnO0*XK`Z9UgubNs7iGBr0n}4Z9)^AvIh}T_i zJAY3^0}bdS{v`)-{F!i>iGhSm|3ua{X#{QlZZ(B<^JiA8qi*Qf`IlK%jId^8rm{-DEE+B55_DhFT9mT=Nv|H z-K>dQ?4#JMFWXdpJQ;J%^?fk|NArUAJeqnS1vKRS3`39E+M_#`r)rNV6YN+ z0!XY1-`vsNDx<08ZXrYO-w|h^N2y$8TFnj9ffDp-$c)EoBkM;q!~3#Nem&!FbW828 zT|njnRDta~1-Su8qZ=TKIR^_@3pT*_k+F?%*s&|(nug8Adc!%SA~wqJFrgxs5q&4R z-PTr?(-#xQn@33emr!*YZ?>i<>ZuHUh9MZ}p@seAJq-5A+ZgeEPDNCzv)^U;vsLqa^t`cLK13p5 zyU&1V# ztC5n;nGu-&%u|(IK%OG#+9Pp2Y!Y5aPL`+nqLVDhXd|n|FlIDH`}rM!!nVePDNS~N zps(bGA zKuy_Likk$~l&s`f#&VTx`nUh8)I-E6Fzi*4EgJ9~SNWbr2u8rp#wcus&LaatG zF;TpL9pX$?*2ACZ&s~jb*S{>6Q&wEwLl+}q;72>%T@`Td$lV`oE8Op^)zCw>fM}I_ zaf3m&zIHvYgnXn561AfxTgK+Rpa))M>?1lY51u5W!A}f${MTSh!ff7WV;=x>8802M zXY!D6J2Q(tAs9L2^&#pLLeWo>L*OxsEboOw2sZO)K&JS5x$*!beEkwn>L|$ZHzU|q zrQ2%t1EibOD}%}phA0tKPGEdUK2QuaGyM$@mOAL~HnNX1BTTkgeXF$Muv~2u z-aaifSe-CpC5$zY9T1|eisZXu44?j`xeIH$640)o#>mmA4|z9B_n@YL>umX*j~f{{ zw3X~>P|-8Cn$x-02j&K!rHq|kmU%vs12n`ZAyvz^!F(14{9_wRF}hf$xD)YP5GN5GaT$cU&{@v@}(u{XezIcM03qw4-|`l$e4K`1cotQM~!=@gsFYp z?i_{ZA`Mu^zR=xd@*B_l6}COMBnil6tHPx?0}w4a0iTUQLNQ54b(fC=agP{ZlJ-PE z!Kz8NH9kQb3e2o{AkMH3_WcjWk41jiky{2b@<)eX4CYdeuvdOI1HYp|KU+Cln;$qDu;s zP-UA{pwF`vvsrzWVqzx{skV)jcF$h07WV1SUe**Z1`$W0;K&zJuObYCrvzq(> zrrc_PV?FG3KEo7P8c;he*k9*2>Q~cHLt`7%B#x&V>$jK9SBD@#@l}nR(EhR`bR4i( z?>hHLgN`NsE;#?I{LubWaCDEu#Xx;R3B_2D>i9!M483DZb)P(nwUO(W{6=4{(yGQH zS0H;PE_CwcJ#!(Li^_bcfHP45~0@Hd98Ukyxv zty_+K_zGAXvoV?-(MSk3a8=p}2e1rKNE@vW! zObbC(+ed+RgxuA$=2IOS8$4##*K7;CN3(SKl>mOJCCzWG)JIYTMEmT?nm+*fU(ueg z+*~DY#4U2Dpm~Xm1kvgYy_GAms~Wu(I^@)C(H6vS59NG+$8kRSdnBcbQqamGRZZ;u zwH2Ozb3fDH3r`PE+w!+1wQoTofimKAk;#tho(^*n>WUJh1ooMMDM`n->EFB@Bah8ld z!ZNo(J$iI`scc6MtoHf#P3Xs{*fAqD`h@4ngkJd`EE?`$>aiW!mn34-xQ$noqDy5O zjrq2_!&nBDct17K*dpkG)a2dgpY(lW|FXkVQD#H~!&|K}f2&yv6om_Z~K1L@Ecn|ya|0&q=Ii)v$&!>XH3?uRFcLw;#Pv^xQG*3gkFXir2wE$`V&-n z$j%5~%$8FKyqPQvc}_|6X*ihjk`lO|K$FGx?e>_ESuXv>Dj7~}YZJV=Ds-1mYnw(*=K6sx7VDjo4Hl`^x!B1|ks4hIF2 zV>m+r+L{J9u-egm1f`#u$MM42;>O*_mVv1wZ$# z&pc(7vm^M-h~??k%++?m(j3iZGeq(B)O-~tjv-5todynsZ^+QTzHUE8wSUsv$ClPt z8Ovy>!5?O3_0Kqx%uw0gJh*H$RZ?%BKB}yV`d!=$LjlspmwtdlB1dQ;x7*X(TUScd z%m1e8zw|Db#<^4tRWfV^F zGonp9UXYER$8`(8HHd&5sh?rs@Y!*+k33`Fd1Fd+=CC1JNJNihIZg?q(etg*(VIJs ztJQAZkD3_OT-CcJ<;X9JMiOP(a&#Qciv*Wmevj;fHD}|}GrIatJQvanF2_rlnPSDO ze!;R3J)@Xqxn$66hhX_Jb)v&09N4=clzq@wEb&p zxGUXUWp1wf-x}ZF$64(}KeOLwVq*lEs5H#iK6_;{?-1R$%EYQ(4Vu2A`^8Z(by1Kh zYkSZ;GytQ>q(isS6Q@vn$#heW;CnDjqmypR6d?YXUeib~&jE zTBf1MYs#xE^-<2P-yF6XTjFgzO}_Z+p0dPfDHJXn3H)dKt8uYNuEGNR6aGoHbt69& z3GpnjxSUx(({OS*=u{Z+{PE^o04H_ebT4iJkS96B(B1^J`00D$`CtC5kQc zIFf;t5@eP*Vg?jxH+NmhLDI`n0avli6BL<-iZJvRvK!@zxkU%L6bi9Qt(J>mfCg+|I99Xu6TT?N0L4d^iPa_{ zJ*yVYi-sB^&pASM{-h=pLuOr_f6}vD{hiUzP%Z^>B;ru#H!8H3U^QP=&td)hhB*a` z@?TiLCUf|EXD`k2Q<`%|W5!m>hEX3Csg4ARM^9nWWaai%6c- zq`=2{?d@lVU({Ii2@i0(1(7wGuBD*g(e^^>m@!1muFxv$KhyRF*egVlJDspTRg~9< z1&GvJem|J)<+?UEG0Gjg*c+(AgDTYB6zVoz&wpkNG`|F%HxnXvH1!Odlm@?g#qM2=X-uPhL8V11dswvV4$ zLIS?kQBmSU0XA$Uou%Eq<)vsKPIRAVjh=Ol@RtT_)bOT;EYz#ygQ#+%r9yP8xNV^Z{$bm^*%LC8UYwg=c%R3GFd0dSJ2T zHdl$L+m3dCC2-N^$3IWu2+x0Ot`_$jcLlb;@q!k$-A6FBA!po`%6LD?a}uDQCiE6Q zpIo!)GL`iwgDI@vihNk=M-=bv3GNE$NIfo;sheI}=2 zL@L_tL_5>=suG0PK1+u?-CIQ=i|%{7Vv@sSxfM?f+H~%bF5@O;n!;Zp$UGzIiTM&~ zBOfc z7NOt-wZ2T-SBQxSxQ^VXDp~R}g??ss>4pz0#^BnSso6sZR|OR`$tS;XaTJ%eRWEr- zq_sETBlmj^SlLFwV{1bTyAkYhkvm}#h!TqOjO?O!)vy=Z#4QBz<8VW2s&428GpK

{a6$6i;{^! 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 z zwcNBH!35y{&`vt>R~=xcDPkrf>B zGx=KT{`{hhR}xpdUp;CwTuZ}Ss(>^Ft|Ct`i`Bxtn_`(Ga^8&MI9%H~6sNcYs?yfP zUsWkI7}GydUHsi8ZL(~I5uza#v)`Epon>sH0tmWo(c_dO5kkCgQ&4V1Q#k@ZFE!l3 z&31Wl*Vo}avuQv4PfwoZ2G6lJZF_yg`lX@gsUO9DU>dcM=_{xWM zkxFlJN&X)HPI#8A9G~X<%1=OCB-ITsT?s?IRKzN|ylYep4@w#yrJz5F@lxNMYQ(7x zQ?jse#g81xRE{QpdS<}~9*!$J^67pXY|ZtTRzd-Drq_!kQ{|>X|Ck+U&Ko|z7h0)x zFS-LWhwbr62~0|fx&m#oylj6qC3QjYtS-HP;|7WT zRIj8HM3K~|>7mzs*a&k@^`dyMUh7N!Sk#nWj1$RFqE=OAxJk7C-uSU4beUuW)inB^ z%)m#7Rd^a?Xj3&_WLsF6%8r6%>-zu;zvKgbnAe?Zx*X66@(aHm!5zu^$Twu}5fC{$ z`Js4LOe9;c1iA(RJsGH9h=#Sidl9PQWCu=jy^AfYk&6fqR@1+TQj9 z)d0)GT9^%K+542FZJim=FXBXTBy`T zUQPIJp=JX7qvP^1Kk5nrzLH~;%_F0=Sge~-y6+tFF%eiRbCo6qk{9Nt*xf`c6dL$K zZHHLF{AYw_)sAj@?7a|l`wuU;uQ_c$^pVhoo1#w|JpfATO;pqQlUHg@pC6}=1*YPu z&P>@*<@0RrHelnY8_B6u+gld~6|WDH3ynU}_&u&e)}CcdD^gNF0%sDznp+kTM+Q?@ z`57^jN3vm24F15^$ft}k;6#hQ^2bFG{#9yFjFbVCWq+s3whZ={1xuFE;2Vw8zum{^ z$k=m?uWr=cGiglR&2x!jA3_$|VN`q-j_5jhm@UM}xZ#IA8a4?W_u5w_Vr z9l{=>COR=ScPn$h%;H02E2|hbL3?zU_O_)ld!T0OR|VBgh%n4aCTvjM+7BV&LzAGgfx>3di7$YxyE_W=Rmq&hzu5G5{AzaJ2+^WW%RY3Nx2kWbP8c%# zPhsQv?XSY7)u-T8<%A+mZfDKQ`|k9)7mvpo_z%8kD#N8r1v1oc;MdlA-r&l%3JN5L zS;*Qi5=WMAy(D|WoN_N(ZwaD90j3?h!sD)H4Jw>9JJEOiXn0V1zt{vZ4P{8&;Z=_T_Q%$r@#+ zKf!5L$5D^&^w8d=cHfy}|Hebw3H|LiW*4|!`vn<#Oizy5qEO#_rahnc!9P2JLfchV zwLeW?br3iZ{L>PuZ7s#XaiSJ^R&|0F6pr∓g;N26C~)_Dc2=XFe~`c?7y#n)_hu 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�L7t5VbJ-WQ=GW;#=DSXuE=ldMK;Ugs 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 literal 44970 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

ZlG^odod-ET41Os(*Hq>ma;dVkNl!7 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 Hq6Pl|O|pk? literal 5208 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 z zdpJF#zC=XWJp1!Ee6t3xiT2n2W=z`pkg}3o};e(7n#F9Rq4YElYQ2}%`haMSD9t{hW zK*_BwE8#xQMqMYbe!tl{l>z!d%!fE66+)(ZlUwK}g}47XIou>aS_*woO)icQZXGH z_X|19+0Qq0(q5(%I_Vz0KoDmNF+}ICKeUzQZ$E?=(6#CVC3p+TLhGR2q}kt4-I`tI z)`%CF7M5Vq|C-!rMA~mUgx)WKL;+f0{QGBX@llMR$E@C-m9y?*0qLHE^LtwhEosUA zqRd4}R5C%J(D2q&G$ap>B_U6pZ)m=0VR0Dyee1kYy1b;;gf7lCiKN!ttkn@Gk?o#z z=?Yn3^sR`2T#lmS;e7U=<>*@F`D-J7#gB$aY;-n{aFCyoohtl1{uh^5~X zFFX^MKaXXY;iZ2uJQNd>_n~9#qGtn{H4F0;JWJIK;)`F3|+qzUycximy_(JPW ze76RBP3l-y{;t56qKxrUBVC_4s)dl~>YvX`>`Gl=1pT7Cc3)%}O<36%H)pO&WtE1C zPPRPErxmh%b%O!X9l9_?9zFajk8!}1PL$^ewjs^ z4QKF5G7G`PGoe^9z<|&Tf3=qSPc(AV*)Aj$C}IzU0EgdjqB0fzJIuo92BEV|4=1u% z=gAF}w$X}XB&kS9+!*El6kWw-Jp8mQ@UFt=y+GzD61y;|`q3C(&_X4#q@5=h*#R*6 z`TsC_^k+tIh>1E?WIpIwD3*m#@ZJOo)eAqdL@`qUEtuJ!7Ng4rV4lb(mq(wP}(H)}oOibksDy(U-_3BcKaRm(Di*pplR z3w&$$w)Pk1LVh0xFU*lSVV>d5RJBk5&EM|ATgJ>fRRRgsgJ^52+Kx zF)@n>`+n%udta#|Ij1`d93W?S+r=8%X27Bo0x{!1Pw`?07X9h4G|Dw^RjWcJH!TV5 z7qJMW-d&QbnwR{870B;LYI0BltBdES;Qg6`8NfVr?-lVt-2e{p(9!E=OS$B`ig?<- zQAB6hooZAzGcd=K_gL7pP4>qhT%5s<$|QCNC< zr+}y6d&EI7p5h~H7vzlOg!F7vkSQ|rT!hyJ_@tc)l@`A3pzd52#B2wS0XJ4F*l~_e zzrBIb)dcGB(48ue$t^(=kS@$z(h3JKf%ClNmKL)FX!aiOVeVmd~WV7V>#^j~DUr7rJY$EOh7vM~jnUYL`j z{s2&ci`5H17B}GrFi43wZomge4mOb4UNiC3?TiExtgn@^jmzj#B^x1LVr9O&Q_%ZN zWbqpHdC=2j=-B@u$8$qv!2)Qxlr>)Rr0?vlF@1vt$-Z5$EivU-^s;8+hJ}~sPJ6S;%wFueNLn*T%yg4Ey^}j z<_|3)7Fgvo9TFoY{|B}{0kDM};5JyepC1^7!O&rqtRVBpovL+mp4}Q@3k|;|0CxuH z|Nj&xaYcYT&u~D-e6e2U$8LGdyz=T^q;D?i(EcTK7k-w0)Yi~|hc{C{{qgWUxB&5a z@0n}$!9I=`;;hO8*U2?WM(VvNzY7M{EMb`SSIW)3x<&srt85!AzWb$l zYRI!!15^cWAJSM2Ya5TV6n3_jsRN=ETgcg3x~>O@p%;%YKZxOrm#je*ZQty`7cdD za}2JsOe+m4m^s%{NE0z~PpK{hW`ia$yQWtSq-PqODETm5gR(aCotBp`}oG zYrvq_1wdGZ5t}uT+5c0W>HyVDjI19MLJG`lEof2O9grDwzJ#95aiY0;*0rWuF=jD} zx-Uf(jd;?cagGWFd}ady+8Tk_08!=%K;dX$Vta`TPtg1a*!V|-O@6O_C9e8dy`F*f zHU{*;-Q#r!3o7@7_5U$cmIF|wulr^kQe|lbg0Zb8O%4aVCJ_1^{#ZDwzVMxu9&=V< zruI+xrtKyg_~gvv<{sqCz^1>Ao2nBtB7aI;M~XuODVILsr!T9|r>3v1E8j*dA zIV`@Zw7`-TF_e>i5lQDqW&*2fuh@?O$ci}Og>qyBP!0ka!;g1XEgmQHTbA84u4WY< zS`oM=wSU)F^pDk_ce37v79Ac>VQxdS-KB+{ zwgdO#IU*)h$pva|Uz=0E$l6`OH+_V4u5iw%o%^e4tnwCU8h;HpKyAfOJj%?}1H3#b zN^O4pPV=#( z-55*jjvhdXWGFC(6DD$0Ore{o306Y=nbAZTmiZh7`(h0&OL+R(2kT9Y0QHG10NM}n z3I8cp7GQxW@Bl~Va0jRq4NYal8Cbk)j6pEt_r)quODd0Y6?^^7?}?$xPe+B3B}x8Y z9gV5R`(>^aja)0AG9{`*Y}sVI9YW6nF0?sw+EdzAC4HKrP`*|44?+&oLhb|1RZ-_@ zysBY)^pYK(-Y}qM?j@`PX#UO&un*HH)BNRf({G&FdYL59QCQlBurC3>f5994&7e4q z(gj&pIT5<Ql_31!GgqJt2D>pICU)F-1A;5>+Y zKa$2vLGGk$pm5Y$S9xy59E`8-3K#C z{MNk|$D}}OFRH`@WVm|?K!!ufp5Q=jr_iCVgVL?b@sUHAv$fndhU=IWi>~A^ ztcedshs#E%kl=^Ivex$sV(zlRDRt)o1G1u@Z|Bz{SZG7SDEQ3?xhVMO1^V&0@lnQ7 z&bjWd*l<@XceL%t1=9mp=3(u}`O<$&0*u|5mw*DqQ0Xzrj@xBjl7bF2+`UOimv>4- z`jn@Qc(e(=Xbx)2%>tw>75zYuUdsA!QWm%ZkTPI5btJ&o?-uB~0|XLUr%4rxXC=5M zKPY8^$%rO8hY6%3#%CEUFg++%bwveJG?@@^8^P;Wv zQM?-@^OmAuQp!)#lwxV$m(!AFXfhC^jMD@9xq`6G z-MyEmdlBZz885(5unQf>QS)Nuo2NJ%mXFYaT%igmkQvJdN8Lk)4BV$gB?RwBt4bA` zB#COgNk`Mg`4)*(F22>8UaedBe0HR6Jz%>+J4QP{e6KsUI9qy(FF)c^K~|iwoZ^$8 zijpb^(3z@!*-w^U{Sw?K^)*h^(S&uT9}|Fa6|`V>RyW_n(+q3+;!JFLUl`@NXDzDJ zl|v$tr6b>c#+0=S=%{|CpO54M8WBlqV_~@6^+{~4D{|i;xAhWh593Ek(f>s>6*K_R zzLG^Q2cRkML+246A`=mg%`2Zk5q4U>b_FOH5j5txB{C%`(ARuAADrUv+&M2k>-H{y zl?kMX!s;!FV)dERUk&5n(Vu3gmlf^87AiK#!xfk0`#Sfbh>D6s?bnW|0uB%UKgC_f z$#C!)+-td!w6h+7Ao9UWrJJd`!E{j;A1@o#p~!o?creoO-7I-Tel+CkWiomFZt5Rt z9<#}Pw41>IORbmekY|&dH7k&GYI_dWF`$h6Y`ELo{dI? zoeC&EIx%uUKjQPldi27nPeeax%DEdypsl{}rkPlz0l%0P0lF0$X2x*yjLQ$zlp|M7 zsvIVJ(UkJft(e!yg3daQ4&hZdb>{KQ(U?=&cd)G%iNqrC@T|_Y>Kp=FG zfu{mSoIf&M!FXkA^dN$J?S_tpbdM^sm?^R24~3UtA4z?S|3dJPg+7v&FkFt_jm{}w3h_yX~9+T`^qcl$uT z#=m>~=~~xJ?M1;Fl;i@^_wq8=WtY(}5`0d}ZY(z=AMS^JispN|6{uY@6#&`$_tJd9 znqhw!lu`FT@XF#NxeT6OnU!0vw50$`Y@?HTtPT)}Kt%b`&8jlp2?Gr=*cMnGHVqMS zDf-LVaE=UO*J*zmLIQY&gu@GL@doN}6j#xqh9#0(>b4y}{_IR1a1j?XBmgEaHwl65 zGJ_lYEwA3NC?Wvs+B%}#@CJ}Uo4dZ!C&-^)@^dnLngP;sAkKjvE%-zAUs{PR;`j{T z5mYCn+CJ20j!%mlHE(;1MrHo_$sv{|k7@%o^cxLqey@q~Xym2&z$gs46+VfolwG8G zrWf3AFzGcBsEIEtm$BB)tu0SL`Zub==1p{RlH>H4kd+zhk1-&#_W5S}oKFK!WDG$t zdn4E>0AcLMyhzFH#|)lOh1+2yipwiyyyJlLT)n1-B!EYm*ns~c;({1R04lS|JRI46b>{nkVy_m z>YJd#m(R;FtH9yFyOK+SgTo2g;jPm8F+=GF`W(fg$CWd}2w%Kg0LGYLmB%;32n|#7 z%b7WGayY(b)GXBJa+YV*T6hMGnX#K*RRm2H!!GuM*I(W$Cp> z0zLP-%K1#k)XY7@>OYrE{@dXD|1@m>ZSeI)=ys?drTHq69Y-4wLX*Wh9~Sz81DRD` zftinibpy3NTXbAzoUuIT%@Q3nrL#OBfYl;K+{p=dRjj^j9|hZD=c-)GHPDu0Jr_|p z3GQ9;07vZgV=gX=2r$f$)T6!<_X@5WifO^|D*L>08KF-Gk+A>4xE>a~wu4FbWU+@S z454Tie*7^(v0(HreI02YD1U$Ga_LqFhs9uEsY01Ye0jgIu0nkgF$VMH&$pge^8NXac#Ylus zLJajFbEITg@fX9B$DXYGR}O4W0P4D!h+%%9$QMdpF!{ zQtLgTJ$d`ozk>@Mv$09S1`sbec zW6Mt_ldn=g{$Kv+7z3s6klqCFlnH(j>bhbNVB`S-`SV=zkus$kkPiKTba=~fcadQo z=O-hk3s9$sDQJ#@;CYBJOvFnXt!tVL4PJ7MIlRT*se_M)XADGosv?PzU`i|4`4m9eBdKAWG4N90|^eZL!i-nzIy zTj$a|x}N7@jsJ}hU)1^i3MFuzgNj#mEI8-xTP7Y24bn~M26lvJ4^tBY?AIm4$OR?! zUG{_B{+S%tpNVAwObFjYH4#+n&^t3mzcnADPJB+>Md4MrS@=9z!_=`8?KmjDw4rHsLe4&STv#%)mUr{ZBb1!bf^30V!89eC7DYosa8}2217k4TV2l(98 zjo(n(DhG~{zMzg~{TU-vWC>o^x5Djn>KY?$Gc!H~-5;gtYB2pbT{`Sr%7d#RFKxJg zSXEsAh-Ux4?G_nLdDZr1-MGDi28nxhG#{#FK>4n#4;l4jlarxW}t zoAe=lu}kxuNWhK1fzjz*uq#;WXR&|0T~QeYZG$SDacCd;x{F>|D_CXDqqi?}i7 z@L+jOosu1NmGkEpCqX?z>d9&5(wFI!X8XC>Trw4_XZ@zHTSXuNrecX9#TVfQgasOj zy6G|%Uniu3FV>O2Wkww7k-D=FHCXKex@b={>CK(j7g8( ze<_$GlHRJ3^l_@+rxR$}4pSYMAzob#FSN}B1C9x(~<{wtP7`Z-p+5Wyok)s_egXPXmG_PQ4p`11{2G9_L@k3pF2(_eP)usQH^MS!_SP?a;9{okN3 z+}>Z&t-R1VH(>5sdT_o+?z9=ZFE{AHe&9%wR3e`MDK9~t7iL2U1$gdTACUked!kHg zajD1^fFgYghfV@a2lO28J2X+D3wHhZ{U!7Zmo`ra!dGe%3ex<_mxB-3SF@b79uM-! zPwPJfwBsvu52t{;h<>Y5k|3#6=%Ldl{6Qm=`x}+|)=^HyWk~oEf%9U6@^t9h4~*dt zDZ$U+(G7q{ob}(}F|88PslRl{Gt`qqjroy_E%;!xP5SvlpmX8qT6aMI`pJvL$Zi`V z=}vZvRC(%AWt~UlIP7h3FX^aq-QMN54kiSB*}_XlRQe}?ffy*qYXV5E&JR*-_%rl0EjB)vcX%1+$x z)`uEx6lij0YktR%ns$}=FS$!Ct2~i2{>I9j$=fJ$wleVg01qV-{NYG$&mHA_e z8TL)7A#-ErL0{rmQxy9~CzqMra@!Gz;N&&<`|DL?VFxpZzoF5py5;V@wG5}m(SRBj zBj~mShEv1esLr6hB1gW9!>9}jko^uy6@kPn+6xx($Kqwf$hOZNYNvRYEo#MJR0O#V zN`U67{&iAN)HiF7))(F%QG1Wjnyr4)SVXoiT~y75pl8x>!b>>FeZog8|dn$8T4w&$>)syi?7)>E$d*_ksdN6Z7sf&TZipIE<* z5kLIU4c58Y$&79742qin{74DeLfWZpJ%bBmCT@fogKK zOw23nrQ$H}h^8!#ri1S!S05LDJ$#)0?dpkA=n%0qfLiKXr*wLh$gxT$iv%#DAH@T$xXI(1=cenW@;8OF0>k&d!+*qFmsWWiUUIPaW#1AnZwr?KfpTkko z`dnrf_viLU>8FHOHr^BNh4RZyF4lI|S3jXYRA~WsTW@AQtV|3|+jLN!qIk+ZiA0GK zANN1sT(tS9v^-AXp2!(UhR3K4S>kTAL6Ul32Zcb3u>j}dj1+C0edD?8*_e7}AChj> zWP_r4Fcz%7j#+J#6oZgw`9<`Ltp%CLgn^SL(9{^?43y`wvTpX7d{km~KUJu^PweJJw`k>f+-j@_OJr`3$ zyz%O_k6yuPb-9PjjlG6H9QgBl&Ae9Eera#qN;0apL#NP^pD;h5u%o-RP}~6*np(<~ zll_P%-V6yr;_2D!Zo_Yx9#fC@{JcVtxg#e$_Xx?!XRNT$8jY#U^jlk0(n2_~(kW3Ee= zT|2V?;ZOH;rQ)LVlg@PE30-Uu5raRjMd;(}en>eUCEM!-4HU4`$Hm;+$cj_rU{eg` zqXgs<)I#U&6&Qt~bwS`^HZ@vCPaqQ8`Y%E=e8g!K5N(C97|alD;WjRG5#FyGUFilh zAsmK{q8A;X5x>00QOxF_sMKtiX#Q14DUW~nm6T}NJ7`K9G+TZ8B6JBDAnKW7hG~K_ zGmcos<(Z=z@6s-1==c-$ce?RMpS^`Wa+Y|TfvC5?`ib#x)RSlYiF(sO*#A$|k7oi= zUrQZG#-@n!9vAA(C%AEUOK8*u>X> zr*xq>AI*%Tme6tL=5vwMP48bbwrS35^!kU7lCqO$--@(U!-yEC&_&C23lBg2Z!8sr z^oy-mJTh+{2d|Us@a+Wj$2yH5CWMf1bn>Fsy&6gKUrMc4Uq5KR`8edv_jA=kKE3Ki zXxFm@Ec2;`Id_vdGpl4-kDU%lQ|q=jLHFCBK)sM-3Z<#?hGlTYad`1ee%kt)2C2q^ ze3j2}@>k-Hmi+Vb0b3wPbKEP-7VxGoMCDFoEtwA{@rrjWUL23x^#|yr3m1sAA1W7v zg9H2N`E;O4hjFu!=S^O!?Y+zD`L=jhqV`n?tB1B739`5bg*G?~M6N5=lNQOJ+xb)9 zbF1$DFLH4Y9q3Q3j&S@i1Z~Gs-mi?Pnx4XpFDZz@c@x@4E$jf>u+~#{%UPvHiIHyh zID$5<-C=S#t9bYcmhfY{_aOE6&65>}-$5OvSD$ARhJD6h@(5Os?yq&STs#dFGoCU( z{aX6M;+K1CaYY-#B$0#!o-LU#BJ3PSxr&o_3ij2ca1de+gsd5S4mi-4}J5i;0@a zzneA`3|WV@T>n_j45N-jLTB&Nz2Q_uxPxP=&o^JzSu;itUZNTZT{Gh7p1p=AkiKr{ z_8F+3ys~@ns5c?-AeP{GSq|Jj4;Hj2c9c}52$uA5E~3>4HC(m2b=l$if2g|3u&TDM z3rKf!q$DIH58d4@(#@e8q(f4=lx`#i>COX4Hwe<*(%l%}Mz7z!?=KcUj~v)*?zzSs zbIh@}#8{N*LaSFB!XfAq;Z?MnufM^AD1_(DUc=eh&&^As@<5m(CSC}*{Bhe zAZIde+NbbUvIGh@gUpu_;Mtr1dZYA%Xy5~*HeqmYT)X&9h%wT)g=@l!BV+x=n=wk~ zbpMwX%p0E;gQ`iCm?q<@NCNgvK8(_bEV9T_?xXDF=78Xz%DatfrUFl409(YQp-U2+ zA|{+`v$JiG0Yv3pa4~W11#!T9W~gOA$^1yDC30woyO#UUiw5xuHE&*ZL zH%*y@XCyTedOMxQojI%5+F)df?pL2Gh=K0LJUOnSbCksq^e4XGnqQmQRZ86IC!JPq zveuuR=*@i%m%kgG-|jNB8F0Tb1;g7y1mKKgGKx9ac@_25ahVFZ;k551X`(L)T3F%q zcv0Lr-y6RsfGp}H!87t8*a+C#qwRcf)ZIvPJuYUZu6p=( z&a63`SKL2f9lm~L%|7(AoBu`_ejHyA%wVPS`m!A|7r(*~_6us8-==YY>YIw^}WAZReM?z#inlQJEXz86ga*> zc$ltVhyoYn-hU%RJzlxtL;V@0zw#<<_UpqrjOb&TxH@>Pm5{L zXIqZmQLIwm;j-)kBSwXWlh^X$0n>pT0;TvL=|t7XOLUsdS_R6DKYKM=mK)DVy=B`K ze7|&J!3cskbu|`S>OXcf?gU4R$8E&HsJ^qogf*u;flCiB3D6d>hsg+4$ym11dJFA2 zt}pEbBVL6-gQqKKue+7b;P=rmqTJMZ54A9SCZ%&l)f-^Rj1{EQV<(b6t#12)`x%*i zVRX~|&dg@#{-g@ITKF#wYrD*dhjRWg-5speUw;wUHW&bD6Y(A ze5K@PH-KrMhV=G6$Zs*fonk~fG>-ub6L$uQdU zA_3T4u%ACVJ5?G*QPqsDt!>B}FlKbh7mCQSPO-irTQ)!j zj7k1J_>AAv7?kx^g7J+mDXDn#T&5My0;6Q#3wxC!)Z;V6rWS!@MDtVkfqWn4SK#Q* zMap*$^|BEd1^{o__ymk}REIsQyLJ>?)+R2A4@V&UIoXw;j9T`7UCecW`Bm)uU$7Us zK!P@SSMxhT%XzidJ6y?}Y`&#FXkGWH;`dyQId0R77yAr-ew_E;labhw=e|}zskv+M zinHAI+*HEdYFH2iCA(ZCcSM4?wxDlK!BQ0sV-HF0)({##hpAz?rZONr-EDp#M#&Ym zV&ARdoz&WGr)E|?dnc46*?ySA{&UUX#|-3fDHV0Dv@kW)VP2;a~0I1j00`% z%Bqd;@ci?SmxlYc`IDy%hC_C{t?dJ1p=I@AuNzUjcBjbFPkZx@DI&#|Ve<}7y_t+b zJ7dqK=|$DG`lUY&dMGo89g2SlSQr}V?^+GG-jz+6%TbYIWk1rI{7WEr_3cUrfrh&e zq=O)?@g#R$(^SnkkrRXni0X!V_~QHimPCLLirewiHDen;e`u#{LD{Lex7I<+=cI52jH=8mZ#FOXsrQy3^6a$@+r}ro z&&8-YHQBRcPr7$CU?ow>H8o)JKpL<;DBiwO;E}?N-daxm_>e5=*Adc`&{kyQf{TV! zWJJzM&&6;`70obflauiROw-{Ga!YZtF=nJ0xj_j%AHj`@<0U^qZ}w~tkn?2oC&(W< zj|xBhD<+Cmw~jzTUKujvGKhe`kG0eoK{YyvfU3N$T@iVQ^PZiu;`Z{M9Rg}m!>_p= zVWI1d+Q62oL<%S;q&WA65zqC&t+TpU)YBN1xAP}%D|xBz;oVjOjy6n(ffxh~DBxlD z(klfNAG@YokW~*QZ=e*Sa563UeDkbm)lBED4Hdvqa@n}iR7jQXe3uX61Dd>d~4W^M4u|Klu6 z9A2bYCZcGs@e|KgulPEcbY0}+gliaYZVxrb&E$+H+|3-v=pWEbJ9LqE00^iKgErQ# z*P;5ZG0m-zyc=}LXDq2wYl#^=G4JyEW#&B1RH}s-{#zj#_>fsBQn$V*PviS;*s7Vy ziZP>vHYmS2>nXS8iEk#Jbmy=ksteKD@nyjSAw$>l{9y8pE*+6WJaWEP_~o<@^0QY> zEhH}y&Ff0VdGN=}3^Wo=I>G#Bk=&COIF$hXXo#by7FjD=P{D6a`hdJkLnj>+Y34f^Qc~9Q}E2C z8Ft}D{0Qb-2Jot6X5v=zud+QOfMP5kXPm`8iBa-1&FBfO&O*ora^ZAo=ZVgApA4lHEU z#@MgF7kk{G8KUq#Ss*y5!MZOam@)6C()8%SBVBEKmsDA1zO;>G4>i{Zz%d@0v7s*h zl1URlJ(B!GyqmFANy7{S zIn=Oda&?1tz>7W0vapteeW^!dZC=3Y9(v)(3ZA_%DLr z0>K*f3URtPt5z|Y{xZ&x;XNx(`uwBkEyZ5u_H=YO(j9S_^J0}J&qLXEtt3~{W9V?A zzk1^0Bw1|AA?JUc2qzd}p^{Q~^>WgZ@04G~X!njE@h3f9ha~>z<73u0f!O;>BHdDWagY@z2r%`3{ zZ%T)t^yTnh)VQiOG&|4;{|;6JEGJ@r2?HWY>|UIWqvF8KUKQ()dJ5SGAm z&UG)#YXu98-5L(9HiVtoCA{8nMtIv98w z(g;WWrK-RJ931Xe`x+d?r!y_S#XMeSgOgy5yh-oG4B-jgSN!lPy9RFd)prL}56i3M zmN=6WPiKUR!d~eZ+Okt&8(PTI;R#S5y*?%R^r0^*Bwlx5Vxxvt7lTdjWs>KOjjT_1 znE`u^;jo++W?Mk>M@bY|BVe&LvQqYak8b?w7^Al-J(=;l!tc~dl7<+ALRg5j%gn1s4 zE>IHFdj&Rvns9V_j!qFuf)8epk5DO)G1E{H~EjMkYMi}Ph|u4>zT`rAR< zIUbqdVbr&|IT_@Te@YZa9ku1d@s-8zYLn=5~aFWBFVsuEgK0S9$7;=B_|8{#~w zV!Hm@A~Ts2wHh#Lwti*r$w#M~tp(pU9_GvkM=ulJr!j*QZNY=Kim{OBJP^eZUF|d8 zAf1>zknZRI&>Q**q%@rWGr+4hop~h5gpmZvK86FGF!In;V|u6xDha&wMoyxKe+cZBYP9z}~ne6rTJ7F+(-lgUiEQHQg)DG4)&0KV3#eX>*78^ruy zqHL)2Pn2wH{2L|ol>o<^q(vF6YA6NS*aKGR+ktfpU(!ywL#D`ra>q#}kLi4Nuz{iY zDtSk>7bo%zZ8>Y<)bR=xm!ZL^2oWi2dqSUwuJ^BkRi_x*lb%f+2HawYniK9VrgiR%Ehga82tv4zHKZufFSe=5eQ4U>%sAYC^&_G(Pr7QQ ze+7Zz5E<}ucu|b-dB`1+O9Yzn#MnC*7Ahd@y-F6QdWwdjch-7Wx5~oVq|!F5!Nkg0 z2bKBotdB9~o6;|V`Z>Onea4tQ)yEVgVzQw{f1zCJi;&HGq8_T(S}an;zjW3DI5-7s zPbhy7q|`(<#Yclt;<3aX4fz%V?h}KPUFG{K#e#{8@KF=HgSe|It=(*4RJxyLrS193 zO7dMSnIkK@M8&eFLkW-Wt&Gt(WKkBFzPOx$ewmA*O6I2~fTjLVRcdC4M;oFY3hO?lRp@ndA?48z zu@B1hx(H3g>tr|tAEc4yx@d|_;iGvlskNG|u1XS}^NIs}&!7v!f_F=B69(~hR`pXt zU*=0y@T65sgUfz;K_}&90aVCH`59UVQ`Gw(zF&93<~Oo0v_kl|){+bZ5|pUAXgzqx64wz5ST&5uA%rd0jImInkEzU9nNbq8>ne>&3jJE^GIVStypT{k0(^zZct~PC@ zQZnz}-5-!Tll!q{Jk1-ytc%{0%!a{_=fmw{H96oLuqWWQhmhS8AFS(GYIl_RN@km< zfd|vn@lD4M@5)J!;~0r$5|^{q7fZg5J(Vx7`^0Xfd+@a48M_o3m%k~7wH2>PfOPYx zZf~hSsS*Zr1W(u|R>{Z7x%R^VBadA2lH1Sbdwav2f3ba5ADiBsh$kc~J9QI0Ot{Jk zsf7E2uCe>%17x7SyTS3FqFoHzSM~W!dJU0i$P@x_JVIWUab@XHvhq_Qo6;}jDUi%h zf7_@5#wnEV5Hin~w}aG#w^KGe)S4b%bTk!xA5^(3+)gZ-#g`JNZT+Y{M-UF2+$|5K;eFa7Bi z>9U-1{}6B`J*P;qm~zfty|!sawlJw*N;WYNEsJx?DG0}c%2jNKlAF^brUAd&Z#Ak4 zt>JK%o@`W8Dv!^P?4}ZCs^L-91zULaMx;{YxMxR|LZs0}^}G(uyGj?2M}%s~QI5Rildnm%L@h7SYx)TPUF z!dCALi;+d7&Kxd%@N~CpQN8kA@kl;VA^lw=no?|PAtSAfoTvcjISp0~kM86DXy6eg zi#Wu%w-L)fCp?%IkFHgNwwz3bnorfjND+WbFc}+W0h1ma6sJZ7S{lP9V`Nk8%~Kaa z6VlEyL^jOu)&NTEP3+J#8?Ax%sl0WOp^fn8JTh>CSWDf>=%fTYHWT?L4HI3u! z9acbf(iSkK{qdug&b6SU8yI6uZ3l||cRjG*SW@uC+arR=u6teVXp0l^r?Ak3*mpsm*?Am$QLP;e-i=?0+0~m;ey#XF>vy0ECnHo ztpur;CgV2?XFpaTMfoW-p^3H$u*ZJYbbcYuw=NO6;YIwI5(>DzVXZ|p5yqIW)@(|R zNui%Z_L)2pFzY{abto@IH!MQ%n|__m7_j?*Vl<2LzU)1pg5~7~uILWwg@2T^29KbK3 z@%YM|ywKuFB9sNx3Li;2#KYZ{4VR+?MW++emL+hVvxYic54n9pTc z`5zHv4+AKt>L}0+D1h;*S`tSoWn>6?nsC(sY<_kIDe8#Xz-1slk8uIQ2{ozJi|m)D zq1_uHMak03uouVS`h9j;P1O6w6bieZnlW${WI6`_*p9NCmR;_rCTo??PglEX)R8X6g@EY-Y)(~rd_ z5fO`=wVT5kG8%Ka@H3Zi{;KUA`tfDtVh61JI#i(CEEfj>i+w>@3HrySesJ+d8MU++ zEJbS4nIZFtpJ*A5Va|6^?w$Q9tIrRs`8PitK?s!-^u1BMXFQXmzRm^}rgAOyP&6Yg zd8qZ$4@PNu_kO5gFW!IyXPFYKNUqNzZ2p-0i*vsNi(-Pj(K;`i5Mc5PFcnn&xM0x4 z1K@=lRVmYpx<33=;`R1A(iM`V&$Vs=)GNzBeS(t|4n3s-c#uW#|DaTDPmi*?Ca(Pm zWd;jkSSe?TV7Ikl#1;$(cuzavif|P>68YWdA^xDPcAl`>=7|6jld6Ps0`EqIYBwZt z04MM~GEN%9lAMclJ{dR6T%AglINsob;gA5RG-T`2Fe`CUAkp&Aj@S3iwV^ZHc0I;mbXV^1i;ur;RPvAHBVQ=J8Ig*5!OGW6E354gJLx7V z>gKac73PV;94CQ7t59K7C?zjl=R#MU`2CLFk0+${L;AaWa*95g7k6+f%W%>-X!p#O z;Rq1)*K&y;4YHe_180SGxYJk*E`9`4aI>xfVs_BR6oMrGCpX9SUu zFWGJg*%qM1x6^ETB}RbfgwkS+W}{4(QY8kG7ED|1*HV%LDX4$|8Eo4?T~BNj&>?Qn z{=1*F5)FgJk#HvL##0J$#OURb^1a~!s$}w~en9;n2?ysrTvr$+f!YPqP!%?a=D@<$i3}^h32k*?RJAg5^%<<0=(DnR5`kA!#bP}`g06rOZ zP@2vQ#nK7@DG{SW<}i+v`B#&d*ARPUYw!qxJNZQC!lMF9)m6z1c+k ztoj*Xg6Flp$_xE~Rw5%(iQw(w^49r+?XT6RArcvChI*e}uerG}^NaanX_KAvx9h)| zs;D-UE|C@G1hL7h=2T&WgJ0nX=N8h( zY!5#}JH(AvjTC2E-AT%$7zw#?(Tm$As7^kAD~~-t-l{6&Cydo%^kvt@t5sJ9(+9=? z9mVO!S?4?Idg8n_S@WZtNZL)&`FK|AuT{>IZ|dJGL{56OT*rL^>Bb%)>e?@jUCnZ{ zkxkXLzeGPX1ehfd0imRm1>8u;NeEbO-qAL~4^#KHwiQPP>a$*1YEgWL+hHH-xJAE2Fm< zNTQoCiND5YxHpO$`GS4aI_E)LFQxvrJ>b9%U+{}i)T+|@u@9SH2)0w!8%AkCwl#jY zBjW+dtYmj^aBd@hZ-GE-A?U=w1e8A+8Gk%nS|<+Dv?fS6W-P5kI%S z@YKB$%$-CHtrtNi^P3kI{ygmf1S~di9Rcif5^9F8qBr<3UWNbYi-xJoDzS+y{#2iu zy1ykx{54(lHa98Xu^Gm`AHk^sMTaB!s;A(;Bn2?)@$`|2e)G$2>#x>jw73o^KQ(l5 zMtX)an6F9$v>6?P7)XRqX`7*U{I5A8#b}G5PamCA#}Zz=aBRSS^P0_Zd$e5mjA5k> z+RSB-C0(;($=6%_@mU-H3bt zr$yDGb~*WE=n{`0ei5J%3K1&MUJ_@nfZ;Tl>sr}*JSxoofAjhFhDlSp7suR82G8B#!Ko0-A%7oL0`Xy|jAn=-NbA9+irAr`sVhE{j>*{Ok zn%uP5v)_UYa2*`}Q*wnrS=GrMe3x}y(6SZg0mzL*GVG#rpus2?TB7o)MwJzZ;_6%v z8#E238qPnqe)s*@r8`oAzMpUO&+J4pl2-{?$z-hnE#ZDRbft?v3*3d!4cvv$lK)8~ z{Eq^Pq37S`ts!Nf-(m^2X{vl1e*1)%g5J}c8!BB((S|LKV zO?e{TEJLP`y9$RUAr87f%kyQMrP^=esy?rR1`GOMvTS1@bXS$)Db=4*H}k_X+;q=VBDA8mHTDwPl2!g4m2fv?Quf$b`-E!C zhLdi?td$2#%OQgsWvH$Z$s%A;JULR|Gqljj4M4A72SYZ-J@dAue2s6w! z|I%WweX*K^OJOU+qtXH>z8bW8rY;Dm%d>hdp8>^!z}s#U$CM1zm%l3IMLu z5IvkVgssrLu6kB*2FtC1510_NAkn@xg!S4xzhZa@856wj9X3HC9Q>mpD;#b<4y;%~ zf(M?scj~WH_Ob8f}jQdH7l! z)D0vfEdW`o$;m(2(~0(tu&e4TNm-=m#Kx#*N5F`~-AX$_)gL|>5RH(_12$h%&pMw1 zh~}OeK(OxuECo2M&%64?LGF8sn|m*xH`ZM?O$^fX{ulw^oachEy4RefxQuxk)BFy}O_pxUdd&u<(;i0j6b7a+~ z^RcQ$xY2KP{I5(=v*FqAX84Q6Cyrk`B>E|_oUNtj$?xqe?XV#9%}mo5aMD7&yab?o zkks?U+J1T|S|F3SwHJN|*qmvvm(TkkpJ}zeb#LVl*twKk&}q-t-Xt!^@4vz8Z=Klx z?vbtHJEY?f%PtZN;8$ZZTD{0NpiK5bR4kVa(up?G@49hVOnf~fPXUyJa%7`SODBOKxdx5M^%g| zwVTLA&hcnCN3JbAED!LoWTeiqE<rwC2#rD zEsFP|aq>}FtY9g0qm}+Y*o5y7HYv&c7n`VV2m39SI#Z?2@=#fSJT++8@hfi{Z*7ka zvP4z;{RgUr8&PI9;T4jg3Qp+KY0B8YNJQw-^~4W@%m6kt>}=>MOYY6k(=LE%7DWWAKxv@L*V6wIVllZs zp~C=9BPFB2`kIShc|{Rz*etcRo>Xrb36#BQI(Hp~v`?{Zd!Er};<{vI72&OZc)!BB zbm`TgL`D-rCyy5{aVe!rf^-w&W!C~I-{%ATh+J-}V8U0{SOVk( z{a2~F8;v1`YN=iKj7VKwl`kYkIYChxKO7~n6CFlAC&6X0<K^MXAtY!b0U>vIWeN0@CTNbsH`=cgz@lAE7yPafcm1>>`_rpR}fG#3%dwZnLO zyevA(;V#)%he;>*r-su9-Xcr6f4pj>#^SS*5PsxatJnno+>-<76TnIoIWmw}!XIJl z>bq!k9(uCx8Log8GeTbLb88`yF^k)K;Ta2+$R3QiRpqE2AOkVsdW1~=53k0c z@uvsp#_(?suJ{|ERh+&6F6**+DplEfWAn7LN(Reb>SC+Pvs-CYpPhktuIE6>vG2?m~cgfH3VrlLjR##P*r<%@*BI;(& zwJem8#8hvP=P7lGLIRtibT3wxtCq8S{{a`!oUf%M=dhK0Ij2Bo;Vp=6(J+Q1jUJd5 z0uH6vz3@8vF{v~jNFdYcsDu$<(+MjrEQNa->r5EAhE_I z$FQ|fjCh#j?V8@jxnXl<|BSdp`HXr^rphPXJd$HhrER0T!!sg_+a;3Y$M4Qq;zsmi zbK_(n9dBjCZ@_5edkoLPN-K@yOm6fSi~p*nHb{RT5V^d8|F4#My8*oM`Mi{hA)P_9 zejk9_NXmx+RZaf(m-^M(M^%kqB{M*OZ%h(Bf2>B-SH&UBRMK3i??!Ng)@NOle5i5q ziJ$f50!F36WgPlA5;<4|sS9qy^BpX>VkabD?cp@nmOU(FwCYLRw|annc2o7=EG)SY z)wxAwVRM$M4`0jgDD&C2r}l!&gcLzU5}usBYndnD4yG=kwbH+vae7azFuKt8H4b%= z9$WO;XSmVZ9ib{fOmh+CIjJbxP{oRzf3qL-T*vzd+Z&wVc??|QII~t6aS2e1Jy$$a z=_ye)Rxstw!D8x)q&)t_#Magv*_a>NX)gKPHv^BfTB7~;z_2s#L%FcrT&pwlS2z`Y zIR;CHzM14qYbbmA#`Ie~du??_#i(hlqS*tMH|etn1en9cFLFk`Jh=diKkPgDI(||r z5yUv4FTa%!$%@8utrV7NB1YL=8B<1_>!~z1g=eC;)+til3R@11WxwuKIBY8{Ao}Nw zm;9;9^H6#b;zcSIL)KtKh|l3~8U|F9gP0zI(^ee+l>=|R`!kDh_ixq~+X7xOoIC7L z{dW8OVimtT!n0kwmU!+A3||kb-5&gjUt zN+FCU7k!N*eoo-&@r?vlO0Ofj3vCF>QhA#9d8+Aq16PjSPZNQkQMGpp<7{r#UBf_~ zF7p=x%38QS#X@^Y?B|7r1{`Nk#7W&g-Wg&Oz*u-Ey)17Yqfn{+XL!~(JGOsQ&x>M_ zXdUU;;qp#b?f|U1w!CZwKee=bX?%jLD=!FJZBdhh+1tKIKO?mL^w>P7f>SU$XmT*+ zm0u*D|L_6%m0Zx2Vsosy?v0hMocD-KKXIZx zZ+A58X3I~;JzoEFF8`#`KI#LF#z5~LyCIlN$ATkp#Mc@ zj9sog&jrKBh6+?#&*`h<-kP#8FzyNvRn`Dr{IkRq?x>)vmV4SxkQ6z- z0JCx&9by?!i)@K?o3xFw3N&ZOBYsQC`gH-@;8eK>f|ZD-j?iE^hffKC(%FkV)5Ajf zq{b62?CZ7&{ub=VQ~U?x#UTM0 zZ{V%*Ziot-jsoi&Bo=cI_3JzlOh10Hz};{6f2U z%NxSYWe=M#kMJW|t1t-c{r0IWwmnKdZlOP0G;s46{KO6cEcS?SoJ4Mfs=rhj8EU{y z|HC=K`)8?iK3( z4$PMHZ4-Viz8GjwpXHi-v`q|wnNL6t+1L2XCajxd=I6jwSOF%_Vsrp0jV@Vdxe?S$ z8DgxQ?;4Q0`IV7O6tszgXJTC&tXhb)Z6e=sq*G}_b_8zh3o|C?wWf4iZD z946dBuelb{KWY9PcKn9*#{1a`aE8<2#s10#COudsn~S_+*8H$@FcuX`|c1BHMMT$bkU;J6<6t;|%w zxHNYVLDbL*)d-z7*6-}z=}E?;o}BU;HQc)M#p6-S!XrrcW23`2^%7TZsPT#PbZxJI3aX;{lks<`Kpys!`(=n^oF_=gFlkYhC7rEeKy2`g$mIv$vGwXJon1&T2!ifh5lZSWwK{nPWoY8N?)tc9Fd+ z@tVrZQK3FrIr%uV7y`+zKupN<|BVTVaJ2G7xMOCU@&tC@9)8RiOsyJcFeEEa&+3lv z03X8!$&AtNIksJ1)e{r@=m1MgQ%>2}uEORXqLE6d5cF51Qcf18_Q(=)uVX-i#I{5p zzQE90WWMpFO&M9#7?9v28M{lWahS2LEf>n~>X%ywWKJDM5pujlYx)*8-zPNO{PkSO zjn%&S>Q=dSdsZwb1= zub>fEBmBp34up<~ZJQ3My!dw7WFC*&#t%QpP+qL`aFZtDuO8r4Zp4Ld%v>8skNmox72&MRg3cB>0sBTKYThuhrLpy~HRZPY6|JfVF=oRj z&bs^duaBe?#~{x*v%%u6)_Cnv*{v2)z!M%|sC1!u@*hU3+NGENN!OE3#wT#8+mJ+9 zu@D+#WOGsEZe_jlt{O8B=O`I$K=w>NX_XcbM_|()2t5QUjO>p#-Rul56w??WadXTr z&^Gw}K8xnN2kk1AvtVZsF`=y_bitlHrQiX$=>4{i#u~rv-oYa`Chu_*xi4Lx+3P-g z=Jn+jj$dPh48X|=6bBqynobD-*b?wBeQFBwK2XUcNI6V4d`pZ0h(uvoc5fiMH%eqIr@7Zw-1wuoCrBhh|1qQ@bfIh zbASsF66vsinKtOjfR*35^uVPGjZsGX8KInW>AZ7^iz$(t>g2InU1eKlmAJYaY&|CT ze(V05l8RWlB?$V!6pW^j&9f1~-J({ar9gcXoe+5pT=`o*0&za7V>jBMSq851;99Tp z%;;*C!r}>7@t7qJEhdFUn*9(NV1fFkijEVY6$w84gE3LH-Vhd{2@au`v7A=h0PcC} zJivZVw=Tq7B^QV|1{O0}Ov-y*83{1eB{_e?W>oi3>FED>bry%joFqn_PrZF#V3$XpomF>~81@6RDuN^Y_aBfF z#enBA0n`BBif)0)lG{HbmRitgw@CcuxW*mnmS&G-@oQy!47QTfI| zQYUrU19oJHc$~ZXjqRi-p=zAx&sn7TF(oE#(XuS_fYP^?Ixt(7^9QXh2+&eAr#&6Q z$BQ4vYLZIOSNxfJi(4+;;*IZFwaN|0b%8sr%Md2!ZLZ5gz;%}8J*QI2-~TZCY56uyM%m{&)eF8BG$Odh2q!%> zA_K?Ki>IuOobbMlc_LDLI~ZG*td`<_zIg50Khp;VU^pmCylg)FS- z{p@O6NOus&?HK+}c)!9)4a(^B9kuuN)^{qr$N~0ks0<`!{ug2A7qoDy`9uRzecD33 zyB3aaY?nK&XwK?rViLd*TRRWJx6C$imSxk)OdKt?Oob;PxKG#xdh&8EDtu2Rg0E3z3hVRtp?J7*yEAEf+}F z_e%Lh86RG!O~AAq(0J3c!PHKWhqy-_GutX!dEl(pkjD!nw4Ra2`%09(G!e?$%$Vty zA+J*pMZLUW?h$f6aaMugPYE&0_hGLc@A-X?ToRIM@@aT>#(7gW@j$Jc-fn&)6WL&m z9eS1g1vf2V!q9oy%C?74(|lN$8txbgIK;S2kg?vgHtJG85=p`j3c%uHhe>+v#7ubQ zkwZOU;PwuMy}x;%d44&L9&aYIZ47ca?e#Ju8**cs3_2C42xYC5RC}=L=18*{W$pZr zzJl%Q+ij^Yxd#I88CbRHK%7Zs`+D++p#2`0aw0KmL3rw4T zs=m?m`)$6~eq+>QC`K!iiolwvscC6J&sn}Rf1RP}h)~nDRNJAQQJic^E z06uXfGAj;eO|Ox=PcY~cr;;PS4B!wq zaSMZS){b8T)*I_@^!EyD;Zy{lX-U^a?0rj*HwlB282)B*pBC8|4nF*1N6GQTpvThq|QfX7Fhu?~i}JpZzF*AU=c~i^U%B!%jzC?l}!h-V*&h#vI7@g*BUWA`eeLeZrDQ zYS8PjR-SPz-6U{{nr_8jWA354w74Y^(Dq!(@kY!5pNc>M{bhH+daLa2esu{QMKGqG- z&koe}+F6qqRQnC8_Z--#jhvrflio|NFXc`hj+}2irzaU@>NkRr%EwqH1CS|Enc-@4 zIVn?qzewOEMJRqp%H&QU?|GJ}!?VhVizL~ex2BZfXi34Y(*~Dh5C0PG*JrMQpalxX z<@gJAgX&2G36<&3Oda{z(7^d6Y$U#(H05fVhpoX?HiEV%*Gr3PtFRw*qV0Sv`IYGG z8!jAfcajIPq4UZ}oHwH}3LFg!Se6^nCoIlC#d9~J$-vEJJXC_WLhMH$wbGHS%Z%6w z_$V7BHBsRs1K9*049A91h4ESWze+@8Wnzam7?%_ebkm8@U-U`Pm9_)NT@+alXKVPjCBWluNKSKQfUxXKn&@=@XIV`+dEcxvZtB!S{Xj!Zz zIxISdo-d269FZ>@jSS)uOti03_bBvByqUO1ML`SCpEF1Lm5fnXFJG&1y&mk?S2zfPN3-UgUyA&f*O04 zT1zM5Z6*f`f6*aLQG~nlogMcU0n&BUTTX+TXWg0VLYsWU@oa*-ii%W`A*(7Zk#1my z1{umg;z*)X{mPKak(YaQS+gBK@B90`EBt?KADlEvluw>wWtY05kfc`2Q=c@;Q-9Gb zoQPVk`Lw)7;Cp&L~voVN= zN8+vDrcDaUn*NCYRMqNRei;}|01MyeRQm3LvFABw#)?XKcEtRPU)0e-bWg}$w@1y? zxOa%Rz9C{YKl0qENJ+bCT$%hD^V6U6WHbWq7V6Pq;=Lk}%?CIDHfGf4HIw8NRMtP# z(Vfeh9(3t_%Er+31wL~4-9I0B%2;Nr@I38{N7Ht^BC^EQvEKcZ8r2Q6FZkqwhar$H zR;_`_0>219nZYpz%%k^q03I~;aLuSdqw;gI6? z!DOy|lV;#aclaGn=oK}6p%=@NydQcVxx425Elq%f?UMjFD`$z`gUQ zeY!dA$(NeI`Mh-drSi&qbaU@h+*|l_n$x}7leJvu&x17BNF-}63TtL*AHRttM86iE z>i*I;5#=EA^t@S;X(P z*JdTS{W8N)&{fbyphYLL0)KvmiVLaBaf7~^ZKj6YB$}S9yKh(PiRi2hLv=p~8pKNK z!ydK;!~II{xM%l}#^pMM20v`=((FFItWRb5iYBmIe#(i$QR?dLiQx#$$Y@X9yICJa zL#Qtr!cnZ%8@onqfnOP^=+2G|?*G@+SB6EwbNOy{a(jeVAbeD9O zG)jjsbPV0y-O}P6K6&rGe|#Q?KQrg-v-etSuYHb)0BFxB+F}AlTJdHuvD2K{GsDKi zr16yEuM1w-14|jqb_z6bRljyxCQGlg8k(G{t+RP=Zy{7V<2NBkm z=&^XmdL{EGvpl3eT0PFLoU3H-t@rv0866p)p;y``A>*xsjhZl{Vx%DklyB(QL`Ly4 zL;{BJWIc?5d4{y_bHrTZuQ`-x&*dr%*CdE*Xap^Asbge~xSxutV-h7v`Omnik6+W* zNwRgeV7d0Lh1tBJ(jdO(gL9W@=t1++Tn;KCZYgb>`ojyd7D>iNFNjO1sOs^ZklV@f z<_5?=_CiZ*E3Ijsc_>J=*}jwPFaG7+z^krz6Uz>jj-4gZbUZwe0vAAkiiOjSyD$HU};h2(gc zO?X_8`SsxJ`eks^uT06h#Rv0>_;RGCJqsMakd3(S201L3N@3<7%T^WG*s-j=XzCfn zpe{A+9q`1mthxp@>`86>!IeBkj(YNBZ>t=?ot96qW0Xc`=#jG|-erCoB-+!qN31_{ zd309u58zyVWpr{DSZ{FM_wgVY)sbbeARlvvta@_?x3tCFv(n6hA4- zRl=qNQV-kLFAG?X>5*!@=Fcjf^RS`$mgVz3-FRooJ0AqIbbwTXTtB>r2EUqrm<-c7 zRS@2n9Xn=_6xm-3WTjQH^j@z?6IqF$ZLpC@I+Yu?eZ#W*5v3jP<6vQW3r_02)`-+e9TO)R8e7Qo2$8sZ4I5q5QwLQ>H3J-%Cy-r)MkH4@ zAK20&NSDrbT+TOT4R@Q{q7mZiTWbr$4!@K@Rtm=X?Zd6PdI5a$eLmgzg@6)TZ(eS$ z^IDeMW^{}J=UX5qtWT0m3rMC3?wCInC>4lfX6^0`>}vn!j+!v_-2<)M<(t5?Z> zqEn|kosUaQ!pja!lNt#%kfjrzIhjFnzLRI#Hzs2iz2Ta)@iPUzR}v@Xk_eB=Sg@_y z!Y1Z3rt|a3ddjUQ9ljz-FYDxJOI;+tssH%f#-Yyc^W)=Auj%4?;mWjNu60mkO1LM+ za1nLwz6~WBz9y&W7p8I?KkROEDa~<lCL< zzb80)!Du=VjJ7e-`(SU%+@?dwOnI%Ua0s6msfHdQwMEFTu+EfYuh-Ny1;JFmXw#&> zB&QxHGWZQ@w4qJOGsB0*tA(cBAK&CR6t{Td2J6m8YtiwbNR^A8yv2$X^DV$X4G_a% zUEhw@f}92wIs`(h@A%0ZN}`T=-Fo)#dH9@82@$7569xjg=;OJMdBwH?3fy7GT?;yC zH!K)Z{d&$QnXPHi=9cOvF(N0I4l#6q@|jVT?`sCeuGtwJ+m2y<9Cdb^VeZT|rAgu0 zuXtK4WtN>~BRae9xZFCZq_dlS&I>z}WA!yAJFliFLmS;|yxUbmM~ZrpzimRTM!1f$T)Yz~MI?O701b-d*R1$gmLCFs5c%-{FY3`zDHZEJyhf#uIgS-!a4 z=V5c%gt_Dj_NsDFW^!V>kwn4I#1UW4%RU|Dz_TBV$-2n={Z0Z&8UiR1e_6`$TcGJ6 zQ!Ud6^-13-B7^qvTQ1%GIRE(LWN_erFjJBt-Uhc`SQcA2(ajH0%2X5qX$%KP`DC$W zza=nKU8F>IK75hgKoJ(p`Sj`jX-j(T&yO;j1Lx(Z zOacpKb8zSIBeqpOt>U>{pP(`}Ln6ydWog7$!ykA73Kt9OrphhHjg@t>J`y>E?zMtr zx_1G$ZC#OF+sc!*TZWK;DrlW;eoeWpS`Q8bN@<1U7`=_C36``%kdzZ?MXzLjKR(|A4!SEHieEMbt(>YbCHcMN!hh{mFvbmiGrg#=_cgLNg>ny?pDPv+oL`ER|DB z>6h^^X-02+P)sE5nr;jsl;E$_bAb|F$4BPVi#t+UNrv~F^b;58?!PNK0(?Gkayhy{ zrGBgnksyUvAr&Aj1=!}z{6VqoDXtSH0~<#BqEOKN(VDp~*N?`qNFuOKj8*Lxb*Got z^L5LGmO~t|YoyhBB2VZ2!#Wzoli3{qS3fPnJxb}mCaKpr2i_A?IZ)bhrrf=J`?NvtUc~dn8EPE<$2RYJ<&Oe;@9L(nUAMx_L2~Wm z@L7D>faxoRyR$PXI`q^Pp9Yc$c&g9k9o&b3A7|7m&(92(6rY$c$QW>9&h>}sNU7+lBWfMa%xb^_z9*w4 z@Ql_8%R;`P8XnuqglOX(=uRFJF90FbloEKcgqn-Q!*N{~lJ++K8p_!8e}6ZxnpSq0 zA2S-Te@^~Jqy6Io@Ppf9-fmOjgoQMEDP><4=-SCT7mHNYM)fEqPkur+{j@wC3KnjImtI%pk8?ED-4B%7|_ z-5*{Gxmdfo6yFSZXv9R03R1m>3zRW~@ocqtXg=iq?i@fFY8b6eT_{$FE;sVf54G*} zU>PtEjRNBJ{A=lXbNF1Xp69@E=^lPX;Jdec;Y7=fvr)Lqj6>CjX>IE5SSX)N{efZfIH0jBj*pOM{B;G~g!=_iw9_w;JC%)I~$n zq;Oy>_k~hH{zNIwY$1Eh&gf1^<{8`V>B1%Q_}X9f-+<1$>4rl-ATL)vBbz<(APIBo zGouG`2;m+)^?y_<5_ioTS-_6QmqOG*$(bfnjYDi~gW6_uMjGuRz;&2Zi4HlqJE_a zIAMR&;nH;s!=O2`MlehN6?Er-3~N($-kbGV}1E)s6d{js+Me5OEeIzAX!kHqjt4O3kQ;Eij)jl zAsI}M9H|6^=WAMbwK$hui=H(um#DVJDa49RJ?aiJ=_`mLY%;RJ$g7bO`oMS?Tr;V7 zLwRiaCpxOW;K^QT!23y&=XCR^Ip2DYa02jvvmrNY_SQ3#M?ucdv>r1}uVhj)%1NU` zyBQ%v=Ww(;Q0cD%}4KFmpn)s5e0 zrp%k_whceW6m}6pvHd8~{Ny)2eV9>;l2OBvr{?TX1mRNGL9UBMG!~Zr*J~tiWIsmV^~fbZti;G)Ws1cG_Q9C3e@GN zOq4U>hM1jR3g-v`3hUX2**GtUw@S7+9O;R!nV}U)(zrWa{ER`ePf{<;OPl>D<*7y{ z{mF+n>}!4G!j=lV>@D)S?^NUhhLvwzW6oqqdazLZq)#I$_09Vtmx~&l1GNU&)n*r_ z?gl9zwjrek10Ocf9sVgtVy-crXPT4|M#vd!YAS5n)(%5Y+z|zlAS^tm!NQ7@C5)s| z-SK6laFW_n0!50#Bh;-NMv*=rhDBk<4}vO3*raRjukTI=XwcuIQYnEEDk&@m8{nm0 ziJPDqhL z$TdS4|G=9--Rq7&5&x5kA}AWhq-9Kq0(e0+u`8&S7-dh{{iTRjlvdM{;o6=^^>hhb zR%eS&^2ET4L@q{hYbU40Ao;h+OlJC}uBZv-oGh!Hm# zHQ_hi(#lc9vdd9Ai3FyunF5G!j?+h?X3s^Yr-JE3S<*uyU6HPMlS71VKs`eIRLx;- zSX(7rCI-zVYQ#h|aAAN+e`tl4hsD*qF}g6z2ca9A+%r+dV!^-vk-)C-^3#k3=%SW2 z+iI*H7zS=jCt#O#?dc$l3^VeRhwCF6*51!)u&M)Hz%E=dqL;_~ACxVBk^P>Y7)wv= zYwJMb>!A|ljT3^t^CK<5hkNq@&}JnW!dIWxv>pXvN~sB%x_H>`@gse1gsHj4j1c)k z{RxKRD(qHtd@~#vIL5^$Cm1-S9*s%xiLEVn2yNknP`)!YiuHB9gO$4V^&l07nw$y2 zJN8nu9N~M#;%}WwsAx2->n77Z+zliZc`nUHz>5`fBA8WX<0q#oM9f8*tk_6LFcdK7?-z)pRH6<|QJJf$$pB1B;im>B-qP9iM**ad4 zB7#>b6p-)p_j;iBx?xjwQ-<`X_idwqfNvJcbvfk)Zsf@~0xZ!hFOGBxi@%hN47gYfWuGgHzDax+K& zwjPRy~dhavtM79YtxsnzpgAvpC#*H6RU4v`E1vc>aF=J92 zIF~zMrHx4oCBG^MWb`AmDPt5qcFsSP^z>8U#~Cl*hGT7tV$_fOTa4^NF7jF3E8Vn4 zx@~Jy@6Nb(Z#IX0KAHZ$!D!kuBJ~TYB{aTHmhR`CYb;g!A;GkuB~T2YqMtgrAgAbm zv{7k>xcMm@1S{Z{r;uCf`!7a)a$B9cd2p;}xGxia9KWvfP<*$3q8}ctT4q+1KhLu#o z=I6w4es3DQ9?)=9-#e!q>CITnOddXmqAMS;yUIAqAGH_EZPr~$cS~5B@0zMy?qO^q zX%>K9f4?T*XKdOO&*#TL>~Y%0V0S-0k(|H~1>U6tBPER2EQY)Fd;|ZHC-oSh@mgjUJzpC-vWuI_>idJ7~Mq6s#KZ}f|BX=ido%?kU97?U0UjtXDZDz ztB&P;0KJvoCJxTMm5>I2GA&1B%8_~Z5bi#&-|M`}q zs1o+P^Jn{C}z+=~$*7e3)#+Bs)AVRFH& z>}-7T{D@o3)6PkMp|Ar{Uu6J^fL}gEW^bdB`6tDeT`bO`JJb%`cX4t9)pi}*EV-V& z=Jn~o4i;3Q?{q8Np9A=vEX3ULaO(}@o_c@(`EuJEZTRV8ve=UMNQP;85G&GKGM?!*_q%T^e2(FTArni=j9vahLayr zJ?$_M-|tRzIjQIi2Gid9WIB-LFk0~WNtvkG=WffEsR#(`4O@@y|E(Ht1Fkh1AWga@ zAGjuutAH*0E5VjZd!mTu9hQfi$CSXAifXPf*X=G25xU?F*62!b?O;k@Mo1oAm900= z$GNhymf4hdu^G(bcGh!c7dYFHtukPMY*ok-|X_#YQ?{N+`L#>TD8xCG^+a~0t@X(+Y9aIP0q*5GMOW%kT)ss zqWZ~YsUopfqD}Llr#Q3SQ)P#-aEEE)XM^cSir!N75mvy&d^IN$K?K#X=uwG9NG-w- zqgnnWtn}jc0ce)YBFBlLRWk{ofYWJ`6bRG3eh>AmBEwf9lBD>L#Y;0;{U`qGylaZ| z#bchPPTFst?|jHre&AGel6AWng*DhpgkEcW{EDpXw_|dyv{=TCXcV^u`F; zLsiW?s#IFhS6#lXW1Inu{7arbfQ}{3vB2^`lD$viXhq;BAEqmmXqu&pY z1+#s*ML$^W(Twz#inaJE0-xWcqvWMR)_&~C?wM6dx`RZE*OT?Er%$OcLT@5w|H({s z)(c-)U2j%M03=S0Ka$@#1o*eu1Qi*oTV-ayb;zPP2o=+lov2gg(gQ}&mD3Gfhgg)B z?}*hvgGstCbfRcP1Kn9XxSE@ut!ItTIVCEcGXZ_i2jhR7#2lQ&fJPJ5>iz z7I}u%!fu~c4a-}|pv~-BxMCIHaC4;q1MgO8VuA4ZPes}23i+0U4LmJ8n3Fn?j?8g5 zE9yzH6`5B6)y#aMx$bs!M|&@+7Ii$d>knyO^F{pZL4S3wS^2GH(ixH4Y4GQetnA}om-phCu`#!Q5BvwOf_{8{ zAWzr&__8Vglj8Siuy3f(&Idx;k(?vWi!?iu6A?HLG@Q1vt&4^tM0CI3zva?|XMBwp zZ@~A>$A_zf1=To4$ki`n>;(At+NQ7t`1g=@kCeCxLA$0=?LVct?s>ql#aY)6n3tWq zH_zxgBD{a9|3SB?bMO^MpDv@)I5rdEPqH83GEWdC34QRS#A%XB#}?LH*0C3whv*k-10F_M(#zMAUf2Am zadDoL58kcEAW##j#6@b45H&gjVC>wY7M%eB&k5N7|1u_E52&s=49sER9l{@ej z3i^PXFTc`2k|=m`hGtqRz0F5D$xa&5nr1tTsM33?w}J3K6%537;C`+h0CYHiu0@){DWkyyG$b~PgSqR!3&Whl zgsAa;(Rm}_sVV3aXpn;q(hw@?ZhCJ8mj3gBTVcNRW?5fginZ{B5K#l`eNvZ=hSw>? zLSQOPE}oXWubrAe9Wby&^eyJRm@VpNNN_`2#_OhL1(ZA?veABRlRLzxSbXUHO7O5d ztqSBR0U#7Knox*PfrAt*6~OsMA(bDZMAgC|g~NR02V8iNbe{vb0qsA_0QK{J*dMtt z9Ys>ia@;b6Jl!6tViI}L_$R48UO4^6mVIN+68=%%U`{6{zolwnZr7xAb@ZM*kywT) zK10rhSFT7lDb|*+N*2;93eZQem=MDImxIee=)#xK;AM2-ZjN{P-*Q;4fpL7Xd<6Qj z`wy8-s3-Zv@AB3aOC;S2^;14#>gg$bGb2@m<4XQ-Av{ z=^`eEJ|`UF8A>AKnhFt0K6XbvZGsmPN`!+r>}oJ>YA8{5Oc;YmjlCWUQpQCpB1qrGJw!pR$vhqfclA z(x=Q8J%`0u0AKD%&Gt)V@eX4mp=A|^5WT_l@Vd?0%sXX*1<|TGTA?mEmGKAXh0NJ{ z13xkxeVCbL^>U&p=MZ7fazF3BgZu^zMF>CyX#B(SWXSIXUA)Ptb5Agsfu{G>5w}jj z&o0{^HzWtDWI9CvlI#s7=H(Nukc70{%w9fG5EXK;Oy2P3k9yayse&UyMC`hnUKEUn zwuApUdYs>(z28mpCP^NF#vtN^W?%Y^;iCC-X(t$KSGjOwoXK-<(gD)XO$;8(Nf3yh zd&Zh_&*`qu-^a_9VjuC5BlVEt_8BOMB&hy4&DEeu^JWffJ7a09D0 zqGP8406z)kZx4$hs{bv)ZOIT7AfJhWJ?zOD^)N;9CK5J=NvJj`S3;&xDO}q2$Ir*c*~=rv@8DKjA0i%fW}X zWrSD0rv*1IeHZ3v+htaROJ^rPZPpfUFTorye#e_#wWZz zR5|=OPNVQhv2B21bEFv1^p^{ho|<$mWpR&kgE1ZnFUbe|uf-8&FC88>J5}jg%U+6Y z$iMufm0yQ~4qk9$J|n?54sASC&SxRY{kh@%`BZ1X*Hxw6Qat)qiCrX6o%!2wzWm}Z zC96Q!4pb1wTCYp*qFY`3sCIlnm5yTB0OiOJ;FqeQtw5-vNhYIp91jg4Ix^%N8y#z5 zSpxk2SE{fmm)$cK5JmZF{uTDT%QHuWuhs&innH-?1 z%sH95ZLUM2@L>=`MWQ)Eo3HTwPSn0uc2xwQKJCo?2$jSX_UVLt@IOE~7N$B7=zhDu zQYz%vo`rUmxX>g-5pa4bw;U~wyL;M4*;kz-9bmr+@3BU3TaFcGhw z%pxsIq*rY#sHwgA^C^PQKEcv}NvKEdp2)>wNbP#G=MG-~e56ecUZ03&^Kb}I1VyKy z=W6bAG2mGYtqw-e!-v=?bX8wNOg@l9*Wb&_uhRlY$_n~_$Z8?fYnUWth*t^2F%Ay8 ze!ueaRpcPN4TKJ428OE)aaf4ZQ4sZI(RcHtz%fZTzo!)!V~J_6vS1MJzDLbwMaWbN zd;vU}1rVLi*uxj+D(Fsm@{pa~zCk&6&P$uod7?=z0tVXU z+KdZXZJEYVK@+#g-Kuv!2$X+C=2R-aBPjdkyzCI<9#3}9wLf>337iJSdE5jb^Jy_L zD>sH2F-m&J0MyMKeR&5LDy;7BzGbWtelR`!V`NdDB+xJ#0!cG1Z<@6)^DB~akff@X z>^t^b4u-#igId(t=eBkr9t&%PU{e&5TiM!p!s=xStpXZBXLh^~r%&%6-s69u590@F zcd_WHO268Lni{0Z$Ff@+q|18jRu!V)n?~m;E_-zX(Zx?r zvT#0zL;6($esbZp4H9im&YT3}I#WB?7lqT8a==C`?hv@>AC z8ShEifg1;l&u8gHO5NI0c@)ZSh8qK+zje}v0F1YwJNW2v!*|@;JT1$6TC61m_B!c= zeO3^|p5qe%hfLuj0CUVf+eXC=u2Z_sr?}S>99pO1Y)GK;?tIreH>|a0Ee&W1*D}9_#8u-*)(9#Tc`~H&%TJ~We{apfeOhde4 z1B#Uf6C>|WKA7|3?EvbDd6aKzPD5*(yj9yT1{x>~i;2bOe;&PZPzcre+&3lY{`UlC zIGZw*o>uaXG{L$!gUaiN@Sz*U;%LM08iDP_plC5Ul-s7=NRp6`@WQz^OpXPRLC73I zt#4R-5uaU(y_QRxCQ2|ev||_8G4f?CJJ0MjmiJ#U<2DTBj+mUJ{AKzf~NQ-XL`&qB83UdqydP2 zY=IKYbvtUmvByudL81yyv@2U3OkdNye-=A_O@owXVMLBdqa?LgiWi8nU0k~C&?rEK zrfyW$>?GjFa&_`IW(VqGo?)C7GLYP=Z-Xz_DxulZ_}%8 z)4m_ef}+hpaxNpqJoS^tuD2N!6Vnj9If0iZZCUaC1#iZbr3q@#6-P;xuN~pb$WW>X zc#E7h^@D||mD{(8y^P~IR|CN;G8UqnZ6Rv{TmAj2av?%s>%&?6*(UvnBfQVctX^hC z4{yJ@zb*RA!%0u2@%E;N=A&@Z)URWfzs5)z)bTd~KmG(xqc3BhQ~lw--MHg(kXdBf zlv|@=hdOmAJW=gSxLzE-7E+%xn&?Rp-daS(0APQhp|}`;pN8Py90`gGx#S!Pw9%n& zC7DA*uBMnETDXw$)f7BD38HdDr%uA?1AhQ^oSe&zY|&hTa)fK=y<;vI-O(X8NcVbq z`(K)6rjfhdbG=H(%n%w9k^L3RRe;90DK`hL5?9p|UkvN}>(*GQ^Ayk1)~);$&n%7q z{b)V@CeOg%K7yKF>r<7BNRpEsV#ja)qZ#`l{O>h>IKfgdD__kz*TGV-DNjMK?EHes z*<(@cb2tf;z>AWH6B#g0NJX3waNsy3hxLdb^g{F3HS%SmcUpmwd=w<=nFJ+MnyFfw zVI8d7o9lw!OXPhPk|>L){+c>|Q5t1`CAxS zSL*K?#~S|!3Pah1XaO@g?@+?;MuzXPmQg-W&V}B%OcY<4sOtHJhG}D3OgygtPd74W zrr*{IKZ1?tE#VAVrdB0g9gkeqG{C~JkJ>=@%o6@=5`}rT@{1#+Tuq||DTEnMsHd>k z44|=+gNb)`0ow~ql#hH#JPLX&8l?yKVA>ww3O0SgWYF?Nl7fmi6TqX-7VFKdw0)59 z?M*@~90sZ+nJc)xJ*kKMDhtUOGHJd2Zn>EQ!HmoL3UGW+^@r=0^TFC#l9GN?$Bmuc zwgcF3uPI=ZVSEQE94SrEzJ!0)?K_I>AgJ)^r_Q;?llj1j&0Al+@=*eEE$T^`R-a+% zMW}i%>!h3hdAsWxly^xnR!v?NaaGp$`%XoZZxbcGednzRSSdPR@Ul?x5U{~N(N~k2 zHA@E{1Z*voh|NPPN{~&_k?Su=khKdr=(sGdm^CFQa+KsPreWvzl>GXlw`Vxin18AyAI*McMqK{m*mw)c43dpeV(t%Jf48 zZsPiDx`3I=&s*^2!#5LfSA*0wqu|%f1eoS1G`h_mK#fkFJn!4Lq;dCgi#$arWL zIrYoi;@}f(5#;I6uRphRz+an))XMz`%FF65T~}lJpGyO_7GK{?bnV zN{(pMC%t1Ng36!B@w-Q{_NSjH>B$4!ds(ZTY0qAVG2*;dvBFz1(2(g5HHrAlB-?Ny z_%54jDfFE^RwarcmC92Nl$I8b{TkwG#ix=;I#a zU6q*&cXZQURUN%sGSKUk`HQLc0v8PVdhluj3^`U$&ILb%iwRLRD#XW_+fo?KmwzL-# zfRrt2jn5vmcowl%8ubcSpfIrsl{hnS%a1(L0 zO)};b%$Fv$rn2imi{+mb7rr3fK2wD9PD^UM=7c~Ese$|pS=NWVM zJt7owC5Z>*5Ow(jhG6T4{2|2+-iyopR?Z-z6jCPXPK6K@(Ei>0rDkdOc92sAYmo&0 zivuM)P%V$yCF39}eCELbzuebR>_>-G`f-k*`wUkqHBj7LeOqxJo8IJXu-R!-bGU8a z+Av*WuN|Q`^Fximb13Z>n|CEhcWNAxZWY38yl0Y|~I1j))qOn*h+_mA^vTCtHtw$R~7e4YyEQfR{$+~D2j>CMu2V7-+hJKIXh(!hQl>A(M zEp~bJL2V_4V;CS>YN>7Y(`F=W(-^5>q)Yw)Qz;-;4>d>usRl4efmLb(9#4Hj=7o#> zbepuT^3uc**a`z;0WOOt(sU+l-WjjXd7UG1LfVh<C&4*B>|s+!dIDr2#EWnUK=P1O6}@|vu{d1_k46l_J` zjg+5LFnh0iWt&gb@F6127i<{Oq{I9#t}58GK{i}$P4?yzbBQ@1bnVdH@X$q{ISYx zZnr%JnJwr`fy@?MdW_YXqur`v)}MAvAt6L&gz4ycXpUXGBDNb-|#P4vuY>N>XULpj4LKB-bq*)9eu zI>UBDV$O+-;)(MwUaKvshG}%(E(Yyyz!YXdXT%wY2fUsu9^hlIxD>Q)cy-Wc{&$wT zTrLf8oWv(@w%Lm(Q!a|dE~A#oNwp+e5#W*JPu@TfGK>DNZH69)Q|Mi9x=l1JC4^8; zJm8=(S+pUqWRk!S)U4+zRfd*#_fx9l06e>=5_ds8Yb(zV9jMcL$OxCK2OFZ~3{lnk z2yymP87&cn@I0#&rNm=aD_5m(@_~LK!&^*THoguettHC#Z;)%i3UeC)zrq#SpCLn$liM=xi`2&K7io4P?1wkdPh{~e1@$w=&w*Wq-10kG9Wup>{I6>J25Ls4$PG(x&0#GAQo~@Z z$e&W8hd-8(D?`(UQ+-2ZPm&XSd((nj5Czu~4k5KDlJRef_TZTlA)w&+n}=YTycHUh3RQ8Mib_}#KXAr_V4}Ba=CQLUVi8hcL*4MPGs;ZyIrxkiK2l ziEN!awVB557hG<4b!%-BIeR0+rX(#wDHcvyc?6OoS1n|94|zwz$S|5v7O3{>?3!O| zE7eGJ!!lIRW19VCf~E*gZ|zLbIxMuo3RSpmxV7Gdl!Br;-0(5M50eTZMMFi&kgRjw z(Z%Aq=KFF)-IS8Cv0)B20Zi0zoGg0fO+Bet*b>S@BEh!Uc{lf=#Q}Ug+A>n5F9Qnq z?E+H7b<8hQ0jYvAY}( zKMPxW!cRw?Jlj!1@+JN>??Xn}lCWhxQ5YWJ4N9tc&|u5dgF`2Nb)}6sU&Ojm`tXP} z!YMyCHx-EBIuruZ?hT#<@0~9OxKq1!=DtXZ{#KazqMtTVX;x&mzj+%`J6Gq-2=wYj zQfkq=M!EX}xv%}dx{r)r#+yPcC!b!m-y{(=C(IR}hTW*i=q0r)TEG%QdYx3K;oU;( zv2|U=$0EuVrmUhUy^G|0mB4;<-mW>QZIDEiSULe^WNm_GN!KwWK~x;Cak*@t7azQd z>i%u*r;HkEBBs_&)`Z+4gtV(;OusJ*%!ai0`ow!}P3Nuk98>Kl1flM)-6PvPG!wt# z!G$hUXDn0OYtsFISaz!=09BtUCox1$E59t9XDG-OsJ7$Bd}cR$KwQl%622j)@zy+A{v*Nlao%l#nJ$^ zH{)Z@W#IK4_rpewQSDU{U3tD)ZLh{)QF!d&aI4>86 zc-J&c1^A=R&CXGWgV29{EKXr&iG`?R&1Wk3DcajyB)+o-3gY(9((?&LbH@V4*om73o;KWnQDi`@%n(fL6-E0+}ECQ$Qk1s zc7t1C3eBd~tZXD_3m&V*JK;<%TZnNCBZ)?u!l6(-xlA0_u~1brzqHWs7?-u#JoSzz zU`=k;rx@uC8R{Ul6;OV8C-Rl~W(j8?W79u81GOwg)){x%w?dCio6g8nY{t_T|+R7bECR_bL{q97}2{7M!8* z`9*S)_(Xy3Ncvsu9B7De?!7Z=@S!iIzHwhOz*HKc^a7^GOZb8Lvm=VKhAhNt7c) z5j&`k?`bF5K3UXy)0QjV)`H22`-)nF;oD9ReNY8#Z`{ur^-k73~?Yl+gOAF%!vOpT}eCl`&n=v=K-IDgM>RgrIVzSqC2nXLq=V#fS(Ld}i*@>)t z6St(~tSt*oVe-Pl;!Cbo3;f+I=@2%ZVVJ=FKt=CJADCsM%Kp$gD4j-EtJSqfPSmFt zkOuN%I`=@3S+O(_@md)AxzhhRq#0V_jT?La@WTjAEYImP;=Zj6s*k{#&sF3xVx0}f z?o|kwapD7`MeGN)cgMwV2quoHVVs*YveB7YAvWvH{8u!YiLZx~Rlbpzbfgi@xjFg$ zJd;_%I{n8NC|_IN37WfKp`SRN%~i?&D|q)>R=wc|(a#Vs6Omz@3*Og z;>i{Mo+}w&?uv*{V=Rpw8Cwd){5D8^@fnpREdRFqhWOXnzBW6u@n}UDn>^r@_V~`E zym>zdq}l-mhckbZBbM!q)-lkOZV4L9{P+T~eeC$q=_y_e3sg4{!-7%5Hkn>IZP^tr z6+O0Dfuu|_t@IzpU|r*@@UX5@2J%^LiH4i3&)(T0>HyxTKnkp}4PpnWpQFN*)G?($ z=`etAC$xyAMZQ#3a)G{YYW4_tXhB9%c!CWv-(3QM4piF*3u5q=DM~XA5L%CJ39tT_ zzPS6>bjvEJq_pXCfLsPP=p^uIKUzk2_7|k@Z13e3bMe(un-{-?4Xe!ki_5!<(-u*3 zASEG-K}t*o6SZ=S$;(-C%bg&|dWkkk!V%C2Vqb-4@c2C}QsVw8vPy-(i=V?;ujL&Pn9S2We*Wcs;)KOq@WC>WX(*>=ng=itBy>{IlUw?y5D)KMzDC(-i6 zK?>M2mmxSCnYylLIYgIJz=J4Rpy6ykrFsa6BoHh9YGl2(p6~hnb_~L zMiVL6`Kp%!=e#T@n@B{G_kIp9DR1emcD7UrukY`cYFjkZI~z_& z)JGh{k)HuJv}(u8Dkk7noRaHE;=U2sH8yPB63biYFCj`}X07UyZmXB;9JI{%6tY*h?&L^t5~` zE63hSB!#?~l)rml<|5r{9L&Ll9)fy|oVc^?h$k%UklkT#AW8L%LPl;QAxU*PQlEQ) z`}^!N&QRQ|1N+>yc}k{zRiv>(rhNr~5q$4m zTkUFB1BMT+b*4dMC9AZ7Yh@;bZ^bu431DozCb2oFpNWJRWEI^GT{l6vwpjLxXD7fS zah#OGv8LwfWbReNACx1O&&ED&R%L!%QL%(3F@%q1%vYqqHqZGdGmLo3dfyTStFI{# z4J+^ByI(2V`_xNGBHxWf%Yg<{4X8w68e3rK*Q*>0-9rM&0}CV*WoC|(Kbh*tO4YM1 z0=mI)TM#$|I zlcTc++n&xYyg%!GGR-IbgwM&jcSJ)~9sW)%E{Ql6M$CJgU^^B9`5jlBi=J*mqXpld zrJgkkS(isXojHKa&+^B1>$hc4AZI7RII% zZ)~vK!3ow-|CyjgI_=)kjp+HzSYRe15b|KL$9 zu1SpZ|2)-MWla xq)U0G&E9>L?f&l3q({y*hJ||Z_57`(UU&X&^z;Aw==Vg?jW_+lkr)-~{{VqXFO>iQ literal 44970 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

ZlG^odod-ET41Os(*Hq>ma;dVkNl!7 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 literal 5208 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 Date: Wed, 27 Nov 2024 14:42:03 +0100 Subject: [PATCH 10/39] adapt parking tests and refactor FacilityBasedParkingManager --- .../manager/FacilityBasedParkingManager.java | 196 +++++++++--------- .../manager/ZoneParkingManager.java | 17 +- .../DistanceMemoryParkingSearchLogic.java | 36 ++-- .../search/NearestParkingSpotSearchLogic.java | 78 ++++--- .../resources/parkingsearch/population10.xml | 141 +++++++++++++ .../parkingsearch/AbstractParkingTest.java | 33 ++- .../testParking1/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/output_events.xml.gz | Bin 0 -> 5173 bytes .../testParking10/output_plans.xml.gz | Bin 0 -> 1214 bytes .../testParking100/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking1/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/output_events.xml.gz | Bin 0 -> 5068 bytes .../testParking10/output_plans.xml.gz | Bin 0 -> 1114 bytes .../testParking100/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking1/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/output_events.xml.gz | Bin 0 -> 3851 bytes .../testParking10/output_plans.xml.gz | Bin 0 -> 1064 bytes .../testParking100/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking1/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ .../testParking10/output_events.xml.gz | Bin 0 -> 5054 bytes .../testParking10/output_plans.xml.gz | Bin 0 -> 1170 bytes .../testParking100/0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 62 ++++++ 38 files changed, 1141 insertions(+), 164 deletions(-) create mode 100644 contribs/parking/src/main/resources/parkingsearch/population10.xml create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv 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 b2389a3d927..95857028a07 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,10 +22,10 @@ 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; @@ -42,64 +42,56 @@ * @author jbischoff, schlenther, Ricardo Ewert */ public class FacilityBasedParkingManager implements ParkingSearchManager { + private static final Logger logger = LogManager.getLogger(FacilityBasedParkingManager.class); 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<>(); + protected Map, ParkingFacilityInfo> infoByFacilityId = new HashMap<>(); + + protected Map, TreeMap>> waitingVehiclesByLinkId = new HashMap<>(); protected TreeMap rejectedReservationsByTime = new TreeMap<>(); protected TreeMap foundParkingByTime = new TreeMap<>(); protected TreeMap unparkByTime = new TreeMap<>(); - protected Map, ActivityFacility> parkingFacilities; + protected Map, ActivityFacility> parkingFacilitiesById; 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 Map, Set>> parkingFacilitiesByLink = new HashMap<>(); 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; + protected static class ParkingFacilityInfo { + protected long occupation = 0; + protected long reservationRequests = 0; + protected long rejectedParkingRequests = 0; + protected long parkedVehiclesCount = 0; + protected long waitingActivitiesCount = 0; + protected long staysFromGetOffUntilGetIn = 0; + protected long parkingBeforeGetInCount = 0; + } + @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()); + psConfigGroup = (ParkingSearchConfigGroup) scenario.getConfig().getModules().get(ParkingSearchConfigGroup.GROUP_NAME); + parkingFacilitiesById = scenario.getActivityFacilities().getFacilitiesForActivityType(ParkingUtils.ParkingStageInteractionType); + + logger.info(parkingFacilitiesById.toString()); + this.timeBinSize = 15 * 60; this.maxTime = 24 * 3600 - 1; this.maxSlotIndex = (this.maxTime / this.timeBinSize) + 1; this.startTime = 9 * 3600; //TODO yyyy? this is a magic variable and should either be deleted or configurable, paul nov '24 - 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)); + for (ActivityFacility fac : this.parkingFacilitiesById.values()) { + initParkingFacility(fac); } + initReporting(); + } + + private void initReporting() { int slotIndex = getTimeSlotIndex(startTime); while (slotIndex <= maxSlotIndex) { rejectedReservationsByTime.put(slotIndex * timeBinSize, new MutableLong(0)); @@ -109,17 +101,22 @@ public FacilityBasedParkingManager(Scenario scenario) { } } - @Override - public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId) { - boolean canPark = false; - - 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 = new HashSet<>(); + if (this.parkingFacilitiesByLink.containsKey(linkId)) { + parkingOnLink = this.parkingFacilitiesByLink.get(linkId); } + parkingOnLink.add(fac.getId()); + this.parkingFacilitiesByLink.put(linkId, parkingOnLink); + this.waitingVehiclesByLinkId.computeIfAbsent(linkId, (k) -> new TreeMap<>()); + + this.infoByFacilityId.put(fac.getId(), new ParkingFacilityInfo()); + } - return canPark; + @Override + public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id linkId) { + return linkIdHasAvailableParkingForVehicle(linkId, vehicleId); } /** @@ -133,17 +130,17 @@ public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id * @return */ public boolean canParkAtThisFacilityUntilEnd(Id linkId, double stopDuration, double getOffDuration, double pickUpDuration, double now) { - Set> facilities = this.facilitiesPerLink.get(linkId); + Set> facilities = this.parkingFacilitiesByLink.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( + if (this.parkingFacilitiesById.get(facility).getAttributes().getAsMap().containsKey("maxParkingDurationInHours")) { + maxParkingDurationAtFacilityInHours = 3600 * (double) this.parkingFacilitiesById.get(facility).getAttributes().getAsMap().get( "maxParkingDurationInHours"); } if (maxParkingDurationAtFacilityInHours > totalNeededParkingDuration) { - ActivityOption parkingOptions = this.parkingFacilities.get(facility).getActivityOptions().get("parking"); + ActivityOption parkingOptions = this.parkingFacilitiesById.get(facility).getActivityOptions().get("parking"); if (!parkingOptions.getOpeningTimes().isEmpty()) { if ((parkingOptions.getOpeningTimes().first().getStartTime() == 0 && parkingOptions.getOpeningTimes().first() .getEndTime() == 24 * 3600)) { @@ -163,7 +160,7 @@ public boolean canParkAtThisFacilityUntilEnd(Id linkId, double stopDuratio private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id vid) { // LogManager.getLogger(getClass()).info("link "+linkId+" vehicle "+vid); - if (!this.facilitiesPerLink.containsKey(linkId) && !canParkOnlyAtFacilities) { + if (!this.parkingFacilitiesByLink.containsKey(linkId) && !psConfigGroup.getCanParkOnlyAtFacilities()) { // 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 @@ -172,23 +169,23 @@ private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id // space, we will say yes "+linkId); return true; - } else if (!this.facilitiesPerLink.containsKey(linkId)) { + } else if (!this.parkingFacilitiesByLink.containsKey(linkId)) { return false; } - 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) { + double cap = this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) + .getCapacity(); + this.infoByFacilityId.get(fac).reservationRequests++; + if (this.infoByFacilityId.get(fac).occupation < cap) { // LogManager.getLogger(getClass()).info("occ: // "+this.occupation.get(fac).toString()+" cap: "+cap); - this.occupation.get(fac).increment(); + this.infoByFacilityId.get(fac).occupation++; this.parkingReservation.put(vid, fac); return true; } - this.rejectedParkingRequest.get(fac).increment(); + this.infoByFacilityId.get(fac).rejectedParkingRequests++; } return false; } @@ -196,7 +193,7 @@ private boolean linkIdHasAvailableParkingForVehicle(Id linkId, Id @Override public Id getVehicleParkingLocation(Id vehicleId) { if (this.parkingLocations.containsKey(vehicleId)) { - return this.parkingFacilities.get(this.parkingLocations.get(vehicleId)).getLinkId(); + return this.parkingFacilitiesById.get(this.parkingLocations.get(vehicleId)).getLinkId(); } else { return this.parkingLocationsOutsideFacilities.getOrDefault(vehicleId, null); } @@ -208,7 +205,7 @@ public boolean parkVehicleHere(Id vehicleId, Id linkId, double ti } 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); return true; @@ -216,7 +213,7 @@ protected boolean parkVehicleAtLink(Id vehicleId, Id linkId, doub Id fac = this.parkingReservation.remove(vehicleId); if (fac != null) { this.parkingLocations.put(vehicleId, fac); - this.numberOfParkedVehicles.get(fac).increment(); + this.infoByFacilityId.get(fac).parkedVehiclesCount++; int timeSlot = getTimeSlotIndex(time) * timeBinSize; foundParkingByTime.putIfAbsent(timeSlot, new MutableLong(0)); foundParkingByTime.get(timeSlot).increment(); @@ -237,7 +234,7 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double // we assume the person parks somewhere else } else { Id fac = this.parkingLocations.remove(vehicleId); - this.occupation.get(fac).decrement(); + this.infoByFacilityId.get(fac).occupation--; int timeSlot = getTimeSlotIndex(time) * timeBinSize; unparkByTime.putIfAbsent(timeSlot, new MutableLong(0)); unparkByTime.get(timeSlot).increment(); @@ -248,20 +245,19 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double @Override public 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; @@ -281,10 +277,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; @@ -292,20 +288,20 @@ 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) { @@ -349,36 +345,32 @@ public double getUnParkStageActivityDuration() { @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()); + 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; } } 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(); + for (Id linkId : waitingVehiclesByLinkId.keySet()) { + if (!waitingVehiclesByLinkId.get(linkId).isEmpty()) { + for (Id fac : this.parkingFacilitiesByLink.get(linkId)) { + int cap = (int) this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) + .getCapacity(); + while (this.infoByFacilityId.get(fac).occupation < cap && !waitingVehiclesByLinkId.get(linkId).isEmpty()) { + double startWaitingTime = waitingVehiclesByLinkId.get(linkId).firstKey(); if (startWaitingTime > now) { break; } - Id vehcileId = waitingVehicles.get(linkId).remove(startWaitingTime); + Id vehcileId = waitingVehiclesByLinkId.get(linkId).remove(startWaitingTime); DynAgent agent = (DynAgent) qSim.getAgents().get(Id.createPersonId(vehcileId.toString())); reserveSpaceIfVehicleCanParkHere(vehcileId, linkId); agent.endActivityAndComputeNextState(now); @@ -394,10 +386,10 @@ public void setQSim(QSim qSim) { } public void registerStayFromGetOffUntilGetIn(Id vehcileId) { - this.numberOfStaysFromGetOffUntilGetIn.get(parkingLocations.get(vehcileId)).increment(); + this.infoByFacilityId.get(parkingLocations.get(vehcileId)).staysFromGetOffUntilGetIn++; } public void registerParkingBeforeGetIn(Id vehcileId) { - this.numberOfParkingBeforeGetIn.get(parkingLocations.get(vehcileId)).increment(); + this.infoByFacilityId.get(parkingLocations.get(vehcileId)).parkingBeforeGetInCount++; } } 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..29f9228e7e2 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 @@ -52,6 +52,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) { @@ -88,12 +89,12 @@ private void calculateTotalZoneParkCapacity(String zoneName) { 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)) { + if (linksOfZone.get(zone).contains(linkId) && this.parkingFacilitiesByLink.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( + String t = "Occupied: " + this.infoByFacilityId.get(this.parkingLocations.get(vehicleId)).occupation; + String u = "Capacity: " + this.parkingFacilitiesById.get(this.parkingLocations.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( @@ -105,8 +106,9 @@ public boolean parkVehicleHere(Id vehicleId, Id linkId, double ti } } return true; - } else + } else { return false; + } } @Override @@ -116,9 +118,9 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double // we assume the person parks somewhere else } else { Id fac = this.parkingLocations.remove(vehicleId); - this.occupation.get(fac).decrement(); + this.infoByFacilityId.get(fac).occupation--; - Id parkingLink = this.parkingFacilities.get(fac).getLinkId(); + Id parkingLink = this.parkingFacilitiesById.get(fac).getLinkId(); for (String zone : this.linksOfZone.keySet()) { if (linksOfZone.get(zone).contains(parkingLink)) { double newOcc = this.occupationOfZone.get(zone) - 1; @@ -135,8 +137,9 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double public double getOccupancyRatioOfZone(String zone) { - if (!(this.linksOfZone.keySet().contains(zone))) + if (!(this.linksOfZone.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)); } 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 08228b6e376..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 @@ -28,7 +28,9 @@ 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; @@ -48,9 +50,7 @@ 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(); @@ -61,31 +61,22 @@ public Id getNextLink(Id currentLinkId, Id destLinkId, Id getNextLink(Id currentLinkId, Id destLinkId, Id(); 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java index ec79b4e33f8..704b054163b 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java @@ -33,6 +33,14 @@ void testParking1() { validate(); } + @Test + void testParking10() { + Config config = getConfig(getParkingConfig()); + config.plans().setInputFile("population10.xml"); + run(config); + validate(); + } + @Test void testParking100() { Config config = getConfig(getParkingConfig()); @@ -62,6 +70,26 @@ private void run(Config config) { } 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"); @@ -73,10 +101,5 @@ private void validate() { double scoreCurrent = actual.getPersons().get(personId).getSelectedPlan().getScore(); Assertions.assertEquals(scoreReference, scoreCurrent, MatsimTestUtils.EPSILON, "Scores of person=" + personId + " are different"); } - - 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); } } diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..7bd305e83eb --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..fd76d129a1b29f57a1e79cc630c53ff3e30c0db7 GIT binary patch literal 5173 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 SYoXVxUFNTh9{t|V>+8Aqq{A|V~cF^ zjq>}OWw-mCDHUFQVetWlb`L|_uAcihThRCyIi6yNk@Y z!e8YbI9&dC^~2lob$@?ep5FhyIdyBy*<#l9e0lrs)KvXf<7zN+F)l2d*<^&RpI zy=t&L=H&e+bJrwxeM-Bnv6G|uq)q;;z#s1W&MmHtJGV$$BI?|skN#X{p%-}`uXk@w zo}Y7YWr9*Zdvn5-li>yuZ?11@DRQdqda2>^@bl9*;pO}GY~7=;7O;N(>P9ZP?#e&0 zUkdAQoIgIj?>~=vrEJ_`%YRk-j)-Tsyj2ZR%1{gCeXgXmNK#pI*%YBB0lsFpb5C77 zXS^>fe{fhteN}{bmh_6ZLT-1%xh2^?FRE!+&2sr}sL|fgqj{e+cDr%xJN&@F$d1o8 z=iF1Bh>+llhidcfTMmZkoo8ER6)#`DX!+dV7t@zs7FoY8j7#btS2JdPUF7w= zw8?gN^U39==TkIaCoz2utX!KHuk$Y@*!*uo)B%GXeu?sTLLVpYvHud>xj^HV(P5qD zMIoE+ycVc%B_5bpWh31%koVwdr@{n{K@a$AC0#YgRkvFx5xThU?tJ|sB*gbKviKoY@T?bUmYO9j2C+(d+<4W1VC9ev&)Yj|_XFL``;!huZ)#ON8`N$+!>V@6l5L##CW&uQ`97`Wz@#fps+rl|%cgvo z68J#H-KQkcGwaufCF_<}>Fch1+q8X2sdv&7-J6FdrL8oeCbD(E&#{z>kLpbBrR zgp)wcm#0nhQ9kJDCE>&q=wto!_3SHGCapxa`UZy8-*h`CZePMYEk#V{WK^`!yj3Qu zN`joqiza_pow-tVCbH(v?J3;evzGFe8E|NFfT6wdU@U?@dYW5G+#2P?qv1)G;KkicN#Y)Wu1_nDUN0FzHD2B}Q*9?r9=#?@tr) z2spKA%CZ@yp9(z_vpgS0t@?gx(k;CT?_1kbUSSEZNmbte>~$@B{QoaMf8Y47l2ud& G0|NkwN>=y) literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..ee6192c5425 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..716c4f390f1 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..2ee1656326c --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..a216a012aefd9351c851e8542aa5bdff86927553 GIT binary patch literal 5068 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 X9`~!$wzJ)fFyg82b;b%HVxs>6fg-hW literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..a8ff7a8b2bd83e1b5bfacab0a2b5aac85ed1a302 GIT binary patch literal 1114 zcmb2|=3oGW|8MV}&!6of!v3N7bGXm*ygKP)6W?ZSeY-Jh>&mcKnn{U|E+lM7$T`01 z*Z%j$ebGYa%TAj}8ozM0lz7xQ^ZN|_`O(Yr-%Yo?`C-+$Q%P>Irx&(}d(KQdn&fu< zQQDCgvwt4_^7S@t&U-Cla~6K??ta<7x!_Bd6n9|i|23@ZpNp@LYG2YZy~b_wrZowE z8z0nvl#V+n^7HCCu^La$NykfV7so&H&3Rh5al^WVjExIE+q1}Yt(kZ0{(83Sd9nxB zCMd0US2n7iCT}EVnjPtAxzH}sYB68!o;hiy%TM3_a9gLbsy3cC9|{zJL@a{3=nN zmdX`>=h#nKRn7RhJR+fcEa#QT`I#;D&r)9*7rKtM+Di_FBaE{(y<>dW#AylQuD{ zT@7lNoMGjBWXTrJj+4d-lN8l>52P$$oa`uXAh}|nE%W81+6gnJlrb8vl%2e;8H*Kj z6o5LOL@=uzziaTaeVR0@Bgc#qr*_MK#SukovQBQyTxsXw4RqqPEBT({x;GC_%367t z$7il$RM0J!ElcXWckxACV(@O0(vkdjVA8@>s?L{#Y9~ws+Nito{v^4mP0gxMCvE{c zG2^6h#3fg6sf3dr&8my#B8-Bzrldrz;=eTMlHLNy~{Q%iF#$g9Gu=UZHgJA zZY7&{RfZ?C&PkJqNna04^0_+c%$5-OC91$s_I|ZJrD58e1Xw8R0z*0K6VJ3S7bmer t6fHV9X|f!U$~xJJudk9+AnHNj>}+R000b_9eV%( literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..804d206d189 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..12979cdbad0 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..cadcc82dcbcf533496b788917f498156b8a5de9a GIT binary patch literal 3851 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 U;O9T$=lx}oy&?Ry(wBh&08$nflmGw# literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..7e2bf32fac8 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/parkingsearch/RandomParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/RandomParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStats.csv new file mode 100644 index 00000000000..f3c91e1630b --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..aee46863f7a --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/RandomParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..fa9a7b934f20bc1be65fd406a6471a0cdcbf89ce GIT binary patch literal 5054 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 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..4c36398342cc20135aeacde77f4da881bb4fb19b GIT binary patch literal 1170 zcmb2|=3oGW|8MWc=HE6GVSDiUS@?!M+f`mQFJZcUbi>z85gSFAt3)%*9b&T! z#NmIx``+v*Ovya)& zJF8#Kte-Bv=;QLDSM}0GyBEp5Irw<>>WAC+Zupuu!!z=Ez3$SCW8wLHW`Q%$9_8>~ zwW`fBHRzAxI~U$y5%bw@U6yW>m9l3E{+qPcX#I&(Gs~HsPfN=ES4s?icJ{*mDie!u z2gT-aseLLla9BL~&w_&qyQi^E5q>q<-`(QC`RSWu?|%Fg_Q-C&!`^-C*tB-&Kl_(| z@A%uq|9AG6{xP4IV!E%b_|NB>PW@{fx4BoaWT}PnKJQ}IPii^VQ!KVjCCSjOSL28a z*NhL#Y(M4o3C~<#w9~O@b3@|yt1$^7Po6TzsHx=XPky=f%%^Th%dhDQEy+e zJ+eb`R(Np5V=HYrgIQfiFFHh~ul{@PLFV(aFM)4GuC89aw56}Up}6LGQA5&Rjmw1# z6a1?UK5lt7Q^R$x{{lOs)lc7cAC=EpwXA=cB~LTA=(mHprgFb-JKIm?=vt&>d`9T$ zQjyZ#`?cnW{wZu>54<49llwsR{@yw1{o606)>b_GpXpqE^N)x4i&7Vzmrf$fU%iws zQA~Mw-aM&VDdUKvywhE~6?yG`q+VF~A|7x(@C8jbb7wz<@#N+Wt+FXD66>J{$XONh^p)_-BsJ} zeJ+0>z28i&lhJ3A_W_lQwN*m5llD%Z5mI(A@sf?&%)=?{KChPY0S*7v;h8EdqjtW* z^OZp+qnb1G3?6;P$qV0IHr}Fpt-8}QRa{2xZ1N;)pRxl>;$9VS2QTlR5n^^Q@e|LC z6u!w~2}VW@CtnB|NWQeQRYtZVxcwyGj4R%F*iUh`dO@+mzFAF1OioHAcK6Ym{lK7-&1V_d4#S3%OQhA5 zUtKie6>>}3ap~}k`7Dz=_0)usZS2JG6wuu)ApMi14ye5CJK1vFrpxn`(lOyGE}x)S zpCDw-&e)uL1ms*J<{2q-4QH~LbOoIg_H%Oc|8!F2@==w|NTFj?G~-Q!=iVz1#g_TW z8?MZ0I{ZY^K+?)5s=+glVe%ehwZ{evOcru>X9~=J((Jh|+cPhE)%Q!2fd2NLwLRsH z&dr09s#YG>^_goI6?Bs&{iJb(QPH$52PUm#^j1=DPrRg=?Cp5F50g8iTCcK?}9%eG4- IW-u@S07Qi{$N&HU literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStats.csv new file mode 100644 index 00000000000..ddfea464dac --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..89a94f7925f --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 From 0a7575c4973580f778b71b7bcf94ff1ccb963985 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Wed, 27 Nov 2024 14:42:28 +0100 Subject: [PATCH 11/39] add helpful development methods to MatsimTestUtils --- .../org/matsim/testcases/MatsimTestUtils.java | 94 +++++++++++++------ 1 file changed, 64 insertions(+), 30 deletions(-) diff --git a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java index 287858329cb..6052c3606ff 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,8 @@ 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.util.Objects; /** @@ -60,12 +62,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 +150,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 +177,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 +188,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 +202,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 +233,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 +261,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 +278,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 +301,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 +332,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 +344,50 @@ 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" ); - } + 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() throws IOException { + Files.createDirectories(Path.of(getInputDirectory())); + } + + /** + * 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) throws IOException { + copyFileFromOutputToInput(fileName, fileName); + } + + /** + * 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) throws IOException { + Files.copy(Path.of(getOutputDirectory() + outputFile), Path.of(getInputDirectory() + inputFile)); + } } From 58ba8fbaca97e6e66af6af03fa48f5ba524ce0a8 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Wed, 27 Nov 2024 15:59:45 +0100 Subject: [PATCH 12/39] refactored FacilityBasedParkingManager for readability --- .../NearestParkingSpotAgentLogic.java | 90 +++--- .../manager/FacilityBasedParkingManager.java | 266 ++++++++++-------- .../manager/ZoneParkingManager.java | 64 +++-- 3 files changed, 241 insertions(+), 179 deletions(-) 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/manager/FacilityBasedParkingManager.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java index 95857028a07..f6221048c9c 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 @@ -29,10 +29,12 @@ 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.gbl.Gbl; 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.*; @@ -44,20 +46,23 @@ public class FacilityBasedParkingManager implements ParkingSearchManager { private static final Logger logger = LogManager.getLogger(FacilityBasedParkingManager.class); - protected Map, Integer> capacity = new HashMap<>(); protected Map, ParkingFacilityInfo> infoByFacilityId = new HashMap<>(); protected Map, TreeMap>> waitingVehiclesByLinkId = new HashMap<>(); - protected TreeMap rejectedReservationsByTime = new TreeMap<>(); - protected TreeMap foundParkingByTime = new TreeMap<>(); - protected TreeMap unparkByTime = new TreeMap<>(); protected Map, ActivityFacility> parkingFacilitiesById; - protected Map, Id> parkingLocations = new HashMap<>(); - protected Map, Id> parkingReservation = new HashMap<>(); - protected Map, Id> parkingLocationsOutsideFacilities = new HashMap<>(); + 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; + + //The following maps are used for reporting + protected TreeMap rejectedReservationsByTime = new TreeMap<>(); + protected TreeMap foundParkingByTime = new TreeMap<>(); + protected TreeMap unparkByTime = new TreeMap<>(); private final int maxSlotIndex; private final int maxTime; private final int timeBinSize; @@ -65,12 +70,28 @@ public class FacilityBasedParkingManager implements ParkingSearchManager { 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; + } } @Inject @@ -111,7 +132,8 @@ private void initParkingFacility(ActivityFacility fac) { this.parkingFacilitiesByLink.put(linkId, parkingOnLink); this.waitingVehiclesByLinkId.computeIfAbsent(linkId, (k) -> new TreeMap<>()); - this.infoByFacilityId.put(fac.getId(), new ParkingFacilityInfo()); + ActivityOption activityOption = fac.getActivityOptions().get(ParkingUtils.ParkingStageInteractionType); + this.infoByFacilityId.put(fac.getId(), new ParkingFacilityInfo(activityOption)); } @Override @@ -121,84 +143,78 @@ public boolean reserveSpaceIfVehicleCanParkHere(Id vehicleId, Id /** * 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) { + public boolean canParkAtThisFacilityUntilEnd(Id linkId, double now, double getOffDuration, double stopDuration, double pickUpDuration) { Set> facilities = this.parkingFacilitiesByLink.get(linkId); - if (facilities != null) { - double totalNeededParkingDuration = getOffDuration + stopDuration + pickUpDuration; - for (Id facility : facilities) { - double maxParkingDurationAtFacilityInHours = Double.MAX_VALUE; - if (this.parkingFacilitiesById.get(facility).getAttributes().getAsMap().containsKey("maxParkingDurationInHours")) { - maxParkingDurationAtFacilityInHours = 3600 * (double) this.parkingFacilitiesById.get(facility).getAttributes().getAsMap().get( - "maxParkingDurationInHours"); - } - if (maxParkingDurationAtFacilityInHours > totalNeededParkingDuration) { - ActivityOption parkingOptions = this.parkingFacilitiesById.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; - } + 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.parkingFacilitiesByLink.containsKey(linkId) && !psConfigGroup.getCanParkOnlyAtFacilities()) { - // 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.parkingFacilitiesByLink.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.parkingFacilitiesByLink.get(linkId); for (Id fac : parkingFacilitiesAtLink) { - double cap = this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) - .getCapacity(); - this.infoByFacilityId.get(fac).reservationRequests++; - if (this.infoByFacilityId.get(fac).occupation < cap) { - // LogManager.getLogger(getClass()).info("occ: - // "+this.occupation.get(fac).toString()+" cap: "+cap); - this.infoByFacilityId.get(fac).occupation++; - this.parkingReservation.put(vid, fac); - + if (this.infoByFacilityId.get(fac).park()) { + this.parkingReservationByVehicleId.put(vid, fac); return true; } - this.infoByFacilityId.get(fac).rejectedParkingRequests++; } return false; } @Override public Id getVehicleParkingLocation(Id vehicleId) { - if (this.parkingLocations.containsKey(vehicleId)) { - return this.parkingFacilitiesById.get(this.parkingLocations.get(vehicleId)).getLinkId(); + if (this.parkingFacilityLocationByVehicleId.containsKey(vehicleId)) { + //parked at facility + return this.parkingFacilitiesById.get(this.parkingFacilityLocationByVehicleId.get(vehicleId)).getLinkId(); } else { - return this.parkingLocationsOutsideFacilities.getOrDefault(vehicleId, null); + //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); @@ -207,39 +223,43 @@ public boolean parkVehicleHere(Id vehicleId, Id linkId, double ti protected boolean parkVehicleAtLink(Id vehicleId, Id linkId, double time) { 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.infoByFacilityId.get(fac).parkedVehiclesCount++; - int timeSlot = getTimeSlotIndex(time) * timeBinSize; - foundParkingByTime.putIfAbsent(timeSlot, new MutableLong(0)); - foundParkingByTime.get(timeSlot).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.infoByFacilityId.get(fac).occupation--; - int timeSlot = getTimeSlotIndex(time) * timeBinSize; - unparkByTime.putIfAbsent(timeSlot, new MutableLong(0)); - unparkByTime.get(timeSlot).increment(); - return true; + //unpark at facility + Id fac = this.parkingFacilityLocationByVehicleId.remove(vehicleId); + reportUnParking(time, fac); } + return true; } @Override @@ -334,18 +354,9 @@ 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) { - infoByFacilityId.replaceAll((k, v) -> new ParkingFacilityInfo()); + infoByFacilityId.replaceAll((k, v) -> new ParkingFacilityInfo(v.activityOption)); waitingVehiclesByLinkId.clear(); } @@ -359,23 +370,38 @@ public void addVehicleForWaitingForParking(Id linkId, Id vehicleI } + //@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 : waitingVehiclesByLinkId.keySet()) { - if (!waitingVehiclesByLinkId.get(linkId).isEmpty()) { - for (Id fac : this.parkingFacilitiesByLink.get(linkId)) { - int cap = (int) this.parkingFacilitiesById.get(fac).getActivityOptions().get(ParkingUtils.ParkingStageInteractionType) - .getCapacity(); - while (this.infoByFacilityId.get(fac).occupation < cap && !waitingVehiclesByLinkId.get(linkId).isEmpty()) { - double startWaitingTime = waitingVehiclesByLinkId.get(linkId).firstKey(); - if (startWaitingTime > now) { - break; - } - Id vehcileId = waitingVehiclesByLinkId.get(linkId).remove(startWaitingTime); - DynAgent agent = (DynAgent) qSim.getAgents().get(Id.createPersonId(vehcileId.toString())); - reserveSpaceIfVehicleCanParkHere(vehcileId, linkId); - agent.endActivityAndComputeNextState(now); - qsim.rescheduleActivityEnd(agent); + 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); } } } @@ -386,10 +412,24 @@ public void setQSim(QSim qSim) { } public void registerStayFromGetOffUntilGetIn(Id vehcileId) { - this.infoByFacilityId.get(parkingLocations.get(vehcileId)).staysFromGetOffUntilGetIn++; + this.infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).staysFromGetOffUntilGetIn++; } public void registerParkingBeforeGetIn(Id vehcileId) { - this.infoByFacilityId.get(parkingLocations.get(vehcileId)).parkingBeforeGetInCount++; + this.infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).parkingBeforeGetInCount++; + } + + private void reportParking(double time, Id fac) { + this.infoByFacilityId.get(fac).parkedVehiclesCount++; + int timeSlot = getTimeSlotIndex(time) * timeBinSize; + 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) * timeBinSize; + unparkByTime.putIfAbsent(timeSlot, new MutableLong(0)); + unparkByTime.get(timeSlot).increment(); } } 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 29f9228e7e2..21d0ebdf06e 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 @@ -23,9 +23,9 @@ */ 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 +34,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); } } @@ -73,35 +73,37 @@ 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.parkingFacilitiesByLink.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.infoByFacilityId.get(this.parkingLocations.get(vehicleId)).occupation; - String u = "Capacity: " + this.parkingFacilitiesById.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 } } @@ -113,22 +115,22 @@ public boolean parkVehicleHere(Id vehicleId, Id linkId, double ti @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); + Id fac = this.parkingFacilityLocationByVehicleId.remove(vehicleId); this.infoByFacilityId.get(fac).occupation--; Id parkingLink = this.parkingFacilitiesById.get(fac).getLinkId(); - for (String zone : this.linksOfZone.keySet()) { - if (linksOfZone.get(zone).contains(parkingLink)) { - double newOcc = this.occupationOfZone.get(zone) - 1; + 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; @@ -137,19 +139,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); } } From 1acda048dce140937f196b72d9d78c3de7c98d66 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Thu, 28 Nov 2024 12:10:24 +0100 Subject: [PATCH 13/39] add test cases with parking only at facilities --- .../evaluation/ParkingListener.java | 117 --------------- .../manager/FacilityBasedParkingManager.java | 142 +++++++++--------- ...ngManagerWithRandomInitialUtilisation.java | 65 +++++--- .../manager/ParkingSearchManager.java | 20 +-- .../manager/ParkingStatsWriter.java | 74 +++++++++ .../parkingsearch/sim/SetupParking.java | 5 +- .../parkingsearch/AbstractParkingTest.java | 32 ++++ .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 12124 bytes .../output_plans.xml.gz | Bin 0 -> 1221 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 12124 bytes .../output_plans.xml.gz | Bin 0 -> 1221 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 711 bytes .../output_plans.xml.gz | Bin 0 -> 612 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 711 bytes .../output_plans.xml.gz | Bin 0 -> 612 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 5068 bytes .../output_plans.xml.gz | Bin 0 -> 1114 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 713 bytes .../output_plans.xml.gz | Bin 0 -> 613 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 3851 bytes .../output_plans.xml.gz | Bin 0 -> 1064 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 664 bytes .../output_plans.xml.gz | Bin 0 -> 655 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 9465 bytes .../output_plans.xml.gz | Bin 0 -> 1188 bytes .../0.parkingStats.csv | 5 + .../0.parkingStatsPerTimeSteps.csv | 1 + .../output_events.xml.gz | Bin 0 -> 713 bytes .../output_plans.xml.gz | Bin 0 -> 613 bytes .../org/matsim/testcases/MatsimTestUtils.java | 28 +++- 48 files changed, 313 insertions(+), 230 deletions(-) delete mode 100644 contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/evaluation/ParkingListener.java create mode 100644 contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/ParkingStatsWriter.java create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz create mode 100644 contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz 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 f6221048c9c..40d4934e838 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 @@ -29,7 +29,10 @@ 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; @@ -45,6 +48,7 @@ */ 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<>(); @@ -60,39 +64,13 @@ public class FacilityBasedParkingManager implements ParkingSearchManager { private QSim qsim; //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<>(); - private final int maxSlotIndex; - private final int maxTime; - private final int timeBinSize; - private final int startTime; - - 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; - } - } + private int reportingMaxSlotIndex; + private int reportingMaxTime; @Inject public FacilityBasedParkingManager(Scenario scenario) { @@ -101,36 +79,24 @@ public FacilityBasedParkingManager(Scenario scenario) { logger.info(parkingFacilitiesById.toString()); - this.timeBinSize = 15 * 60; - this.maxTime = 24 * 3600 - 1; - this.maxSlotIndex = (this.maxTime / this.timeBinSize) + 1; - this.startTime = 9 * 3600; //TODO yyyy? this is a magic variable and should either be deleted or configurable, paul nov '24 - for (ActivityFacility fac : this.parkingFacilitiesById.values()) { initParkingFacility(fac); } - initReporting(); + + initReporting(scenario); } - private void initReporting() { - 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++; - } + private void initReporting(Scenario scenario) { + this.reportingMaxTime = (int) scenario.getConfig().qsim().getEndTime().seconds(); + this.reportingMaxSlotIndex = (this.reportingMaxTime / REPORTING_TIME_BIN_SIZE) + 1; } private void initParkingFacility(ActivityFacility fac) { Id linkId = fac.getLinkId(); - Set> parkingOnLink = new HashSet<>(); - if (this.parkingFacilitiesByLink.containsKey(linkId)) { - parkingOnLink = this.parkingFacilitiesByLink.get(linkId); - } + Set> parkingOnLink = parkingFacilitiesByLink.getOrDefault(linkId, new HashSet<>()); parkingOnLink.add(fac.getId()); this.parkingFacilitiesByLink.put(linkId, parkingOnLink); - this.waitingVehiclesByLinkId.computeIfAbsent(linkId, (k) -> new TreeMap<>()); + this.waitingVehiclesByLinkId.put(linkId, new TreeMap<>()); ActivityOption activityOption = fac.getActivityOptions().get(ParkingUtils.ParkingStageInteractionType); this.infoByFacilityId.put(fac.getId(), new ParkingFacilityInfo(activityOption)); @@ -243,7 +209,6 @@ private boolean parkVehicleInReservedFacility(Id vehicleId, Id li this.parkingFacilityLocationByVehicleId.put(vehicleId, fac); reportParking(time, fac); return true; - } /** @@ -262,8 +227,7 @@ public boolean unParkVehicleHere(Id vehicleId, Id linkId, double return true; } - @Override - public List produceStatistics() { + private List produceStatistics() { List stats = new ArrayList<>(); for (Entry, ParkingFacilityInfo> e : this.infoByFacilityId.entrySet()) { Id linkId = this.parkingFacilitiesById.get(e.getKey()).getLinkId(); @@ -325,30 +289,19 @@ public Map, ActivityFacility> getParkingFacilitiesById() { } 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(); @@ -412,7 +365,7 @@ public void setQSim(QSim qSim) { } public void registerStayFromGetOffUntilGetIn(Id vehcileId) { - this.infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).staysFromGetOffUntilGetIn++; + infoByFacilityId.get(parkingFacilityLocationByVehicleId.get(vehcileId)).staysFromGetOffUntilGetIn++; } public void registerParkingBeforeGetIn(Id vehcileId) { @@ -421,15 +374,60 @@ public void registerParkingBeforeGetIn(Id vehcileId) { private void reportParking(double time, Id fac) { this.infoByFacilityId.get(fac).parkedVehiclesCount++; - int timeSlot = getTimeSlotIndex(time) * timeBinSize; + 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) * timeBinSize; + 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/sim/SetupParking.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/SetupParking.java index 41d3e3b477b..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 @@ -32,9 +32,9 @@ 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; @@ -77,8 +77,9 @@ public void install() { .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); } diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java index 704b054163b..f5ac6146d0a 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java @@ -48,6 +48,38 @@ void testParking100() { validate(); } + @Test + void testParking1_onlyFacilityParking() { + ParkingSearchConfigGroup parkingConfig = getParkingConfig(); + parkingConfig.setCanParkOnlyAtFacilities(true); + Config config = getConfig(parkingConfig); + config.plans().setInputFile("population1.xml"); + run(config); + utils.copyFileFromOutputToInput("output_plans.xml.gz"); + utils.copyFileFromOutputToInput("output_events.xml.gz"); + utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStats.csv", "0.parkingStats.csv"); + utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStatsPerTimeSteps.csv", "0.parkingStatsPerTimeSteps.csv"); + 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); + utils.copyFileFromOutputToInput("output_plans.xml.gz"); + utils.copyFileFromOutputToInput("output_events.xml.gz"); + utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStats.csv", "0.parkingStats.csv"); + utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStatsPerTimeSteps.csv", "0.parkingStatsPerTimeSteps.csv"); + validate(); + } + private ParkingSearchConfigGroup getParkingConfig() { ParkingSearchConfigGroup parkingSearchConfigGroup = new ParkingSearchConfigGroup(); parkingSearchConfigGroup.setParkingSearchStrategy(getParkingSearchStrategy()); diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..dcdd85c0325 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..983cb03d56a7e0f25694cd3c956d77a10225ca03 GIT binary patch literal 12124 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 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..983cb03d56a7e0f25694cd3c956d77a10225ca03 GIT binary patch literal 12124 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 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv new file mode 100644 index 00000000000..11b81e47e1d --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv new file mode 100644 index 00000000000..fc35dee9a03 --- /dev/null +++ b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv @@ -0,0 +1 @@ +time;rejectedParkingRequest;foundParking;unpark diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..36d8ae41c21887c8822b0c02c27afb5b988ba1c8 GIT binary patch literal 711 zcmV;&0yzC2iwFP!00000|LvK}ZsIT$hS$@lh_at)?${F0Rd-XV(u`&wC8k)I1Q|E& zy#1KaQETw!IPsEQo6E=V^P6)q%ZK+piw44vwC`4N`Xh-W(lvccyO&k`DmLFy{II@T zl7V#Ms6M#9`*yw_3A!h%I4iRxIRV7qgZ#H{1nJs1I>>iUugDvWc02iQTEvmO`+IzB z+wVynMfVO`OAa*`ubh~GjJ!Pct$gyWW;*~-@OmJO5mjMJkD~4xd4GI#??bFPr$fy` z36v3%TDWjVu&H@OJ3+X-BF%xJA=dbVZ!Q^wDFd^UUn&E#@^=Rggu5ag2k@Rp$m3~e z9RH9lZJ0_P&ez7jov@FGW!5?2B5C+$LmQLQujr15x1R65DCdOLf)3=lKT`3T(DWM8 zPYsN0#P})3&vGKhO+eb{!|-QF&fi*X4`Q3CYq5Kv^s- zLi`b0A=$!BDJpCe;*HQ+lOs2!v~M|YgkA`CQ>xUuN4ybQYYIRjs7mV|@kZ!`#2vG5+0&Nvf zU9-8&E5IOqh`MH=DNr2L6;M+*#T|d}%_U zxNprQYy81CmnIbmgg`UaR3O|HQJ|i@WW;H1-E!UtZA1V=G|sGh z#2=xJ2;h_gXN7J2^+)JWCLk1?PnfZSp8BX7X3khD40^0+%KjI$5T}YbFLOY}n+gnY t)~f02j5%*{PMKCKmWe9{s%OxD^Cv_006V1Qtbc$ literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..cf995fee8419c0f90ebc51bf1ad99d6c48a202ae GIT binary patch literal 612 zcmV-q0-OCGiwFP!00000|J7FCZ=ygDey)GTcHdz^Xtf4tE_Z!wt~r|~eKLEn;-0{g zWkk*8{`VU|TU4%hY4s9~56sB?`o5WQyxUcpkW%PEs?4XhX;C7wP(?C}eY$|DF{HOa z&%6Bc_4DKN!yU<0zDPLW+hqJae!ROUbOw-*7+WrvX3C+Esi}0#rZN!)iy&gJCX@2o zL=6pkJ?~YE(uKzXwEVsRQ3Sn(%L9%>jUUIz|(30NccU*c%vH-t38wsaY9YyOl)e7 zMJBWi5g*_hCVR!V#IE#7B+(4}6m>XNfyZjs8;B5;PM9%EA~O)W(yMF-@s&>vycxh2@8&U)17{ch5n%baU$wKNJNW={(E`o8iyw7 zGa82)khh8Wz&I?Gp6@{4+B(Dc!aO{~t#ewK|3kCyFP%S;aD_8)CM0yN{yP2k(y@=Q ybdI|HyT+l(`i#cmw12_}w@wG79;>iUugDvWc02iQTEvmO`+IzB z+wVynMfVO`OAa*`ubh~GjJ!Pct$gyWW;*~-@OmJO5mjMJkD~4xd4GI#??bFPr$fy` z36v3%TDWjVu&H@OJ3+X-BF%xJA=dbVZ!Q^wDFd^UUn&E#@^=Rggu5ag2k@Rp$m3~e z9RH9lZJ0_P&ez7jov@FGW!5?2B5C+$LmQLQujr15x1R65DCdOLf)3=lKT`3T(DWM8 zPYsN0#P})3&vGKhO+eb{!|-QF&fi*X4`Q3CYq5Kv^s- zLi`b0A=$!BDJpCe;*HQ+lOs2!v~M|YgkA`CQ>xUuN4ybQYYIRjs7mV|@kZ!`#2vG5+0&Nvf zU9-8&E5IOqh`MH=DNr2L6;M+*#T|d}%_U zxNprQYy81CmnIbmgg`UaR3O|HQJ|i@WW;H1-E!UtZA1V=G|sGh z#2=xJ2;h_gXN7J2^+)JWCLk1?PnfZSp8BX7X3khD40^0+%KjI$5T}YbFLOY}n+gnY t)~f02j5%*{PMKCKmWe9{s%OxD^Cv_006V1Qtbc$ literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..cf995fee8419c0f90ebc51bf1ad99d6c48a202ae GIT binary patch literal 612 zcmV-q0-OCGiwFP!00000|J7FCZ=ygDey)GTcHdz^Xtf4tE_Z!wt~r|~eKLEn;-0{g zWkk*8{`VU|TU4%hY4s9~56sB?`o5WQyxUcpkW%PEs?4XhX;C7wP(?C}eY$|DF{HOa z&%6Bc_4DKN!yU<0zDPLW+hqJae!ROUbOw-*7+WrvX3C+Esi}0#rZN!)iy&gJCX@2o zL=6pkJ?~YE(uKzXwEVsRQ3Sn(%L9%>jUUIz|(30NccU*c%vH-t38wsaY9YyOl)e7 zMJBWi5g*_hCVR!V#IE#7B+(4}6m>XNfyZjs8;B5;PM9%EA~O)W(yMF-@s&>vycxh2@8&U)17{ch5n%baU$wKNJNW={(E`o8iyw7 zGa82)khh8Wz&I?Gp6@{4+B(Dc!aO{~t#ewK|3kCyFP%S;aD_8)CM0yN{yP2k(y@=Q ybdI|HyT+l(`i#cmw12_}w@wG79;fP~akFgzX-_w!jKeGV(-^Gvw`nk>$Wn z=2i=bm05|1*aWnhLv&n3vyBJXVnk@jJ$aB)OcZl?b~!xel#tR{zxaGuK3!@H@LRamyP2tmL8C`afeRJ)%GN}q2CCQkOuDC{RqSZq@LNil>caU2+C zw)~4u2Z53R(%#P9=o#>v_KOK3W5l=dDFBdjtv*fxQkm2&j#MN)x`?k|xM@>1db&O_ zKs!CKm2y4T9ILb)kihZcWM7?koHTCROmA`_oxVptc zDj8Lcnh_e}Lze#tWQ5@EB%9GgHUb%+J*8MNQArF1Er@}sv< zc{9R`-3bOS&ld`>V6zGhr|l9-xl!VP+D2c+i}!+{voxhBN~Sf+Q`We!dkwhtHLV+5 zQXabU^VYP}!kBCGxMI ztgM!;{GRWxNBxsn{weOi-T7}~0M;Fns(x1aSu*~hg_jZ+bOP3Nj*|du|IQ?f@``hW z!Kg3NMGn&z_B;`rC)?8OA^O)aMFfwy5#keUkeRp97+y635@4iv9M#n@w(8BfPj5tm zU`tSL?~_xDwiVzCvn0v4bMNVF|DDeTjApa4`kIgPHho5oVCA(n`r^q$Dod|P{F`cR zv4@_RCk7n=?;!qi!(r$t3Hb>lXF{w zA|>B_n2gC>hyW4tNLPx~(NM9FTZBPUUK5w|npqV;elDegPun_v;QTBpB>@SpP#a5| z@fzQPf-CAsj4JFuQe+(B4j^Oc5!TJRdtchv|M_}Pm-A2s%J#@8VEAr!86Cufh+QFB zsO;Ja3J7~a3mgQ>zo6wml?3a+)#sUA#HyDT&k;gAAbH(PT)#QS`^6*)Bdz^n3g~H8 z1U9X$TiZ=&-11DIxd9<0xB<2?y8+W2eW0*D#JxGfn?PpssKSz5(Bl=Xw(g;ITq^6> zNOl>aX|f2o1Lj1xhf~e%iSyR`&7s2vIS3)R1!@VzxK8PRbC*i>r{@HqWSzNa&LF2s zxa%(YX$<7hcuF{GnEpGWIP$a0!=hGRb)S>O&3kI0rQa7rkjiZ>y%&pKmGG=Gl3w%m z9G=mbNGQ@t=+F@8(xH~D^5;rrPC{CP*=2@YI!HwE;CLM7AiL~^q2Oi_|HlZ^f^2eQ z7qL^k7t@$u)uaAVEv7dqKA6&Pl`dE_auIH00WKYaVVvPoY({?n@IF0h@tsk@aOgG9 zSBY|8i6)j=?kwHJnhDUHC19%?=eksMH6Gg{XS`q}8bXZTWHf%G~4#NpN0c)-C3|X2c6j)v;?JF4xv5tYLYSWZ{ZF zcKr^3^6Btbzj5ZHxh#a#ro*1(p&JX6Z{MP_lQDGxDL&8fV0YP7O;!n~r6?^UXNLn0 zN3fr6ZWLLZ=h1H#sj891IdQYK$2sjhSXD2Wx(p?$yfJsosZnzgGGZR#enx0lCzSLZ zuO5%1dwq++N$P5`jh8VBEwv^GF|Ll-{;p8vlE{QW&ml>#yWC5Q%coD2Nc+e+M>+|w zZ#eniq0Qwt=DO)2yMfFlko`c}-(MKd8mOQ%Ew^aXs`4}9h=(k!EPEZ0S-<+lyvzcd z5|BYnVeb{DycB%24=$~d9;^3NBEz?RI2>3ac6?A03`;_m6FspEu1ey4vX9z#d^Q*s7wAJw$XvMv!!6>!yYP%_a&wOHv;*A~si3}N)?D?-6u|UM z4b!qBs;;|xw5lKy+~SRXEaKYj9nei_vu|y$Oex;u^vIO#?^Bh8Q{!RIS}VG!7aR;@!+kP zva)8dy=ytySX`OxRFmJ=SJB1{*TY8c5Asy_I{tEk%ex4dsJcrq;e#4K4`R*qQh)sx z9*;i@Nt$xUoZ-I<^=xKTCb|vY!5UTgw;} zJC!Lb-DsBcSww}Xp0o6gwQbX&jz3#ihP$bX*rLe-faIMzmba;AFWYn}4_^K{h}o@_ zs9f*w@iCvu4s-%;eRjtDS4qrMvk8G3=p7v{pqAronW4#^hR}*EjRDJ5L$E4H+EihZ z*zpN5~1Enx0l8r(=e{uCo=Jk9Vz`2MHKYlhgo335CSt8{1pGjJA zgRm&Ts>#ph*3&sG&*!-ODzudAlYL<88?MTiRuS2Kbopb$6PNET|Co_+KL?~oSSG{| zlT;q(I^^ovrH*2I<1l9P?@A+D_|;Q24+@oux?39>P8Aq330&P`A#f!vokig4c=*3u zDdN?xQ?8i6(+?Y>frFrLMJS2QKY~b>AX*~z7Y2a|GLZ3}>v#xRa$Lwn%2OW?7gTe z&FB61a5Ka||DaEuL}vZOmPIDA;e3M1uT8XYoI6B84_Atl*{E7wFc)(Ln+4(xB5v+B znY_taZK~zsH{5LA+x$RtI_%g`rfCFM%;c6=_5l9;&1cU zRFX&S3x8_QId^TTirVi##@lSd6P_;4OIyC}!_fW`*{`^1Y8LG3cw()`IH%$E_+0wkAk$Mf9i z;^B+#s(!MlR(&~mhMrJ~YJD78wewgv*m|neyE<&^ZQ-9juNfSQfC!_z z$h-7MqknZ;VBZ+a-<&Q?EKET1np{PgSFh}%^3#k7%Y`A8uv|QeW-YujwYwrC)*pF> z{qs8ju;tG+MhOpk<(a+cda=j0q{W zK$(h(6%Gn{a?rC3LY-m@z~i_*DJzd>OB)lHRW7t5_w`t(@9Og8gI3m33V?=cC}0r8 zl-6Fy23=JMNev5@nDPpsvlK2fecN?v$yn_??U`zg0D4*Q%b8FAD??f#qbf~k?Yb$B zhHp+Df*CDM!AA7avw_eQl5qdEoEbKF!gh)oWwdJJJzG5!_07MQE6B!Zs9=N{V9)ly z+yDVs$V3;Bg2@V z#v*M@WLKfa$bxy2s-v$GYO9;OXgRIxtu}-i-DmToug5P(OwA3$=cqgA&$3e@SMI4# zQF;j(HgQ}J%33h$KM>U~7wbRBTH}QZs%Lc1rGwk${f(_Ly8ilFGY8mxwX7&8L;Wkg zgY@otncnGf6tuGLz7=N5dP4B*?WC=`1M>6^97f7>hxBCZfkhea=fJI;QE?d*3}f-)7oHus4!MUxMs{qeNkOqPdIsnmZU+zoq>ma8P!uGtQVflPOd(_|m=ZhO)kD^zDKd z_AC+X1$2%BOCS%|@ZBX)-nu6R?0C`EZI05UP0e7yWzyGRfRd>?8yfUZZ8B5MlfvjE zbLaktgY97U9!(dm!AA1*3E=)Mxc28U4oO{3JQ6hH@;be4Y&2tq=-W2~guvvT8#}MN z-uyaQf8F(?abQa-$A^!!!;bC?0~bZpHQT+Vk@{=1g@F46uc^x)@3%a8&hknAK+F+hpPi+s8kA4GjjS+I5gGXk@g< zN_RhhGWkSpV~{+soi17$B|)%Ag~E65#6o|5Fi4=5*9?Am76*9zozwS zSLUYCI4rhy!$C!^LT~?)YCZ6Zq@<|zOp^J-uX=a>ec{driJ%>2GY-~7kRc~qcFshN zyrVU4H;^eY#DI9mAnq3eHg}d_Slsei%U<99j+nrrPXh9qpz+hp;qGhKr)9i;r!Lho zsCN z83T`M7bpjT(mfxSDC5|#defFq@U;#Y?#{5K+$)DhI^huU X9`~!$wzJ)fFyg82b;b%HVxs>6fg-hW literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..a8ff7a8b2bd83e1b5bfacab0a2b5aac85ed1a302 GIT binary patch literal 1114 zcmb2|=3oGW|8MV}&!6of!v3N7bGXm*ygKP)6W?ZSeY-Jh>&mcKnn{U|E+lM7$T`01 z*Z%j$ebGYa%TAj}8ozM0lz7xQ^ZN|_`O(Yr-%Yo?`C-+$Q%P>Irx&(}d(KQdn&fu< zQQDCgvwt4_^7S@t&U-Cla~6K??ta<7x!_Bd6n9|i|23@ZpNp@LYG2YZy~b_wrZowE z8z0nvl#V+n^7HCCu^La$NykfV7so&H&3Rh5al^WVjExIE+q1}Yt(kZ0{(83Sd9nxB zCMd0US2n7iCT}EVnjPtAxzH}sYB68!o;hiy%TM3_a9gLbsy3cC9|{zJL@a{3=nN zmdX`>=h#nKRn7RhJR+fcEa#QT`I#;D&r)9*7rKtM+Di_FBaE{(y<>dW#AylQuD{ zT@7lNoMGjBWXTrJj+4d-lN8l>52P$$oa`uXAh}|nE%W81+6gnJlrb8vl%2e;8H*Kj z6o5LOL@=uzziaTaeVR0@Bgc#qr*_MK#SukovQBQyTxsXw4RqqPEBT({x;GC_%367t z$7il$RM0J!ElcXWckxACV(@O0(vkdjVA8@>s?L{#Y9~ws+Nito{v^4mP0gxMCvE{c zG2^6h#3fg6sf3dr&8my#B8-Bzrldrz;=eTMlHLNy~{Q%iF#$g9Gu=UZHgJA zZY7&{RfZ?C&PkJqNna04^0_+c%$5-OC91$s_I|ZJrD58e1Xw8R0z*0K6VJ3S7bmer t6fHV9X|f!U$~xJJudk9+AnHNj>}+R000b_9eV%( literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..2bc7be4d53f676887e1e0bcb89891e3cc46614fc GIT binary patch literal 713 zcmV;)0yh00iwFP!00000|LvJgZ=)~}hR@qyfw=D$3@6%?)h0=xPACCUynFB;!TVSlq3^?|2v6~P0MlL#nDMTGd&`1P|_d7vuPej;_h#` zY(E@v97T@~T8B>!xfE2&{96GV`t)T}1kh5mQlwwt3N6x(ITXA15J^BzE#>m*v zPy$7Sgcin~5o{Y4k)C5Ft_X8rXoxlb;JZu4V2Z#T#7kvBuKeAB1L3X+#{s-&3Hd(# zXPp1wJ!z>*9_MTFZzt@1vB)|TE)s_CcBC~a{fzE0e;e50lX8Y>!^w!Bhcn?H2~Dpd z{m?-1j>~T`ewPy=<>T&xQn)EumRp7RBJ@I507_X}h4>YD-UzLb9Ps8AMQsz}jgYBR2zk$Czi`9ay~>!;SzZHhx_!wf zU7}WnCL>WSYL6`=U7>HvNQ#Cz#r}{AmZVq(W-fVh2kz{z(##c4;$Q`;Od%C-DbQB& z)IFQayaEhz4pH|EGzE%-x&k`XEpf*me0Rwh%qfj%c~u2E$Sq_<=xn0sW5Pl74$?SG}wA9$iYlS=#O{qQ+QP; zwjRqLp%>!rOR74z^;rH0osc|(P-gWOGYos_m7%O9bQ z2w<#Gr^xo!_#?nQmK=IGar*fJMAWKS&|?Li`luRi?6FiBbgXE~{ui_mQ^gvg0#Nam v0t3u?RbYs7$i<#-o%LRYFx*6bkvsn2yGwvyp4N}^?_1mdsJJvq4;uggx7S;5 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..26b51e95fffc38d6b4da72841d024ae355465f4f GIT binary patch literal 613 zcmV-r0-F6FiwFP!00000|J7FCkD5Rbem?(-y?uuTwZa+T(zN$@>7`zp+>_bDid%st z%ZQq$|9c0}J5+jY?zD-<2WDh`ec#MD-t9U~NGWt7RpwLMv?vi-s3MugK3&4haOrK( z^R7RC`Skeoa7S{LFB1;{l5#po zES-~X|E_Upvc8~kIPahE(XG<~smH3Ls=oJFbMOUcI3_*TzLS3ggH1Ztt_uJF73C>D literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..cadcc82dcbcf533496b788917f498156b8a5de9a GIT binary patch literal 3851 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 U;O9T$=lx}oy&?Ry(wBh&08$nflmGw# literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..8e1a8f4a86a198774d58d988e9469a555eac9622 GIT binary patch literal 664 zcmV;J0%!dniwFP!00000|E-u!bK4*ghR@BfV03SzPg|O?ol|b@OlI2YosrftV=QS9 zQJQ~Wgfn$W5iGKAi3E>dc47Awn})LIUe2XIjZQV7jecnbda{slA9(H#d z7@?JeIdFIP<@}sTc7kn`7HJ$$0QuIde`zhDZ6eaEInxyNg0uFh<|cVW)Z1Tr*r7W? zM995|)<92%d=W4QA>Q!`M?;bMX6Z?#%XpLsIo*kvZX-$ zPMSM6Chtl|X2Q^p?4~u!)PQzmT7wt2%#k_RE=Pvx3MRtdTl_t{tYViV3rE<6_+3m{ zYLm{pv)99cNRnwr#axvO~Xa%ABMYeWzqAytyPPE9z% y{`r8RtcnGW?55wJriLpWnF+&Q%FK0^Pc-cP#^qLPbAP@&+x-Q=Wl`;G6951}gFHO| literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..c3d3666b97ed333b1dbc6f55c315f5d8a7076498 GIT binary patch literal 655 zcmV;A0&x8wiwFP!00000|J7DoZ`v>velEY_)bHeCLI@~HHEn&^L$zvDllp|b#DGU` za!deC`|mqR2n`UrYGP7{u#|J~xqY9%824@)M^JE?i!||wsTl-#5~QI>79LrvdEX&- ze$T!A^yTBz^W!~aX||4-!rd@^o<7|_09h)PO>}*;*=R9Sxrnt?F7&yGc&>*k)L%ko zg{`57_`RO{;zjGmWlBl$eXV%z_ikDyBrN703DQ(zPfYQze9k4d$fvtp@t8mmu{`(4 z4^}WOV#z|AVra4;{s)Do61l4%vSIF)g{82O+kPLst9+o}uV%>*PQ*uq9x=%AIMsCL z;}v`<0>tYu4I)nw<>aGP~M`P+%AyRP>>&d{?hh?;%1^I$_2xK_rUH(w`is~ilh@mcfMWazXxpd(tr zwU-mVMn2d2#9UySLtHjca|9-JfYLEg%K%LLHrh6+Ts2%(-L%x<{H;2i|4f;@d&>@Z!3c6lU)`T8WK+Ox{z+5N-2iFL!0WNC8fDXZ` pL}R^;wX>_Eg92AC@2Kkf)a(1x{|9%otGEAl{028WIxYPO005oJII#c# literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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/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/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..998560e44105171cea2baafcc0f6d29da3e2e95c GIT binary patch literal 9465 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 K$X{9~Ci*|dT{rmv literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..c9e8cf0c73608877e4621672b6f916c1e141fa12 GIT binary patch literal 1188 zcmV;V1Y7$biwFP!00000|Lxt;Z`wE<2k__hukid%Vkb^)SHN_-?Qz<4ole?Ql?yJ- z3JFRK6ixfz&p_GI;@d4AHFe~w4)8~)xz@l0#XPH#*23Mc2KD~Pn;H{L4%P?H8*TFoKO)(Fu zdK%soGtq<-ISGFZxn8A#+5^WI7sDTW)z+(FCS_gxvy`G4U%YB-a0o zvl?Eib9{Te#3yT1+Y40*(BxIE&P7lVQ=AgY7>ziNDS@C7Gm%T7CcN1mc|XTo7OO&T zfZQz9u-j@bAea^9ow`gg*r>KB6j$nY?9zc~|AFs~-+jq7Z72f;)v zjt0s)TOD?yhn>68N43*budbF-b^N_L$4@Q?RjemvIxdvjvptx2So2hrqAqe(ADPwi z`pM#3o4VB2^S^nbj;oQA$y7_gCekirJh{@pEGmTfiiK37EvDPfzSxtoIU=+AerZ z+Q%gInCyT_v(#Y@rcNI*scnMCP#K=>!10~H;hdG!!eWawe37(Q?pd|N{bbykH1xhB}D9HngNJ`QqA!&+P zatcZ&rj$%v3-w-7QriVjN&A$jJ+j0Skf$Yn1iX) zM@wp(;4OIuOGe(34p@>|uq5mFxnvSxL=odWjwnyl$E1Bs z5|7Cam^4cr=3wgd5tG^`cubxFld;F71DNC%Fv&Z9FiC@mCxphBlQd3FV@YmmN$y&z z_tKKuE_h4Yw`Afi*};-#slyyhojzJp+XQdPGgy*%OTJ7?4#W0;_4yY?{>@6%?)h0=xPACCUynFB;!TVSlq3^?|2v6~P0MlL#nDMTGd&`1P|_d7vuPej;_h#` zY(E@v97T@~T8B>!xfE2&{96GV`t)T}1kh5mQlwwt3N6x(ITXA15J^BzE#>m*v zPy$7Sgcin~5o{Y4k)C5Ft_X8rXoxlb;JZu4V2Z#T#7kvBuKeAB1L3X+#{s-&3Hd(# zXPp1wJ!z>*9_MTFZzt@1vB)|TE)s_CcBC~a{fzE0e;e50lX8Y>!^w!Bhcn?H2~Dpd z{m?-1j>~T`ewPy=<>T&xQn)EumRp7RBJ@I507_X}h4>YD-UzLb9Ps8AMQsz}jgYBR2zk$Czi`9ay~>!;SzZHhx_!wf zU7}WnCL>WSYL6`=U7>HvNQ#Cz#r}{AmZVq(W-fVh2kz{z(##c4;$Q`;Od%C-DbQB& z)IFQayaEhz4pH|EGzE%-x&k`XEpf*me0Rwh%qfj%c~u2E$Sq_<=xn0sW5Pl74$?SG}wA9$iYlS=#O{qQ+QP; zwjRqLp%>!rOR74z^;rH0osc|(P-gWOGYos_m7%O9bQ z2w<#Gr^xo!_#?nQmK=IGar*fJMAWKS&|?Li`luRi?6FiBbgXE~{ui_mQ^gvg0#Nam v0t3u?RbYs7$i<#-o%LRYFx*6bkvsn2yGwvyp4N}^?_1mdsJJvq4;uggx7S;5 literal 0 HcmV?d00001 diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..26b51e95fffc38d6b4da72841d024ae355465f4f GIT binary patch literal 613 zcmV-r0-F6FiwFP!00000|J7FCkD5Rbem?(-y?uuTwZa+T(zN$@>7`zp+>_bDid%st z%ZQq$|9c0}J5+jY?zD-<2WDh`ec#MD-t9U~NGWt7RpwLMv?vi-s3MugK3&4haOrK( z^R7RC`Skeoa7S{LFB1;{l5#po zES-~X|E_Upvc8~kIPahE(XG<~smH3Ls=oJFbMOUcI3_*TzLS3ggH1Ztt_uJF73C>D literal 0 HcmV?d00001 diff --git a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java index 6052c3606ff..4432063a364 100644 --- a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java +++ b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java @@ -43,6 +43,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Objects; /** @@ -53,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 } @@ -371,15 +377,21 @@ public static void assertEqualFilesBasedOnCRC(String filename1, String filename2 /** * Creates the input directory for this test. */ - public void createInputDirectory() throws IOException { - Files.createDirectories(Path.of(getInputDirectory())); + 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) throws IOException { + public void copyFileFromOutputToInput(String fileName) { + createInputDirectory(); copyFileFromOutputToInput(fileName, fileName); } @@ -387,7 +399,13 @@ public void copyFileFromOutputToInput(String fileName) throws IOException { * 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) throws IOException { - Files.copy(Path.of(getOutputDirectory() + outputFile), Path.of(getInputDirectory() + inputFile)); + 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(); + } } } From ebd7b5da6435c0c57df734aae9a3fb7dfd0d5843 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Thu, 28 Nov 2024 12:47:19 +0100 Subject: [PATCH 14/39] moved parking tests --- .../sim/ParkingSearchConfigGroup.java | 29 ++++++++++++------ .../AbstractParkingTest.java | 3 +- .../BenensonParkingTest.java | 4 ++- .../DistanceMemoryParkingTest.java | 4 ++- .../NearestParkingSpotTest.java | 4 ++- .../RandomParkingTest.java | 4 ++- .../testParking1/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking1/output_events.xml.gz | Bin .../testParking1/output_plans.xml.gz | Bin .../testParking10/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking10/output_events.xml.gz | Bin .../testParking10/output_plans.xml.gz | Bin .../testParking100/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking100/output_events.xml.gz | Bin .../testParking100/output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../testParking1/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking1/output_events.xml.gz | Bin .../testParking1/output_plans.xml.gz | Bin .../testParking10/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking10/output_events.xml.gz | Bin .../testParking10/output_plans.xml.gz | Bin .../testParking100/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking100/output_events.xml.gz | Bin .../testParking100/output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../testParking1/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking1/output_events.xml.gz | Bin .../testParking1/output_plans.xml.gz | Bin .../testParking10/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking10/output_events.xml.gz | Bin .../testParking10/output_plans.xml.gz | Bin .../testParking100/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking100/output_events.xml.gz | Bin .../testParking100/output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../testParking1/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking1/output_events.xml.gz | Bin .../testParking1/output_plans.xml.gz | Bin .../testParking10/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking10/output_events.xml.gz | Bin .../testParking10/output_plans.xml.gz | Bin .../testParking100/0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../testParking100/output_events.xml.gz | Bin .../testParking100/output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin .../0.parkingStats.csv | 0 .../0.parkingStatsPerTimeSteps.csv | 0 .../output_events.xml.gz | Bin .../output_plans.xml.gz | Bin 94 files changed, 34 insertions(+), 14 deletions(-) rename contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/AbstractParkingTest.java (97%) rename contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest.java (54%) rename contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest.java (56%) rename contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest.java (68%) rename contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest.java (54%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking100/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking100/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking100/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking100/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking100/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking100/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking100/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking100/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking100/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking100/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz (100%) rename contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/{ => facilityBasedParking}/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz (100%) diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java index f48abf3b80a..d86ebccb779 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java @@ -50,9 +50,11 @@ public enum ParkingSearchManagerType {FacilityBasedParkingManager, LinkLengthBas private static final String PARKINGSEARCH_MANAGER = "parkingSearchManager"; private ParkingSearchManagerType parkingSearchManagerType = ParkingSearchManagerType.FacilityBasedParkingManager; + //yyyy this parameter is only read by the NearestParkingSpotSearchLogic. Should this really be a global parameter? paul, nov'24 private static final String FRACTION_CAN_CHECK_FREE_CAPACITIES_IN_ADVANCED = "fractionCanCheckFreeCapacitiesInAdvanced"; private double fractionCanCheckFreeCapacitiesInAdvanced = 0.; + //yyyy this parameter is only read by the NearestParkingSpotSearchLogic. Should this really be a global parameter? paul, nov'24 private static final String FRACTION_CAN_RESERVE_PARKING_IN_ADVANCED = "fractionCanReserveParkingInAdvanced"; private double fractionCanReserveParkingInAdvanced = 0.; @@ -145,14 +147,19 @@ public void setCanParkOnlyAtFacilities(boolean canParkOnlyAtFacilities) { @Override public final Map 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 +169,15 @@ 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/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java similarity index 97% rename from contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java rename to contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java index f5ac6146d0a..245043b1b3f 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/AbstractParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/AbstractParkingTest.java @@ -1,4 +1,4 @@ -package org.matsim.contrib.parking.parkingsearch; +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -7,6 +7,7 @@ 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; diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java similarity index 54% rename from contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java rename to contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java index 55be4a073a0..fe21aa68bbe 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest.java @@ -1,4 +1,6 @@ -package org.matsim.contrib.parking.parkingsearch; +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; public class BenensonParkingTest extends AbstractParkingTest { @Override diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java similarity index 56% rename from contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java rename to contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java index f22e28ef54f..9822c5a68d5 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest.java @@ -1,4 +1,6 @@ -package org.matsim.contrib.parking.parkingsearch; +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; public class DistanceMemoryParkingTest extends AbstractParkingTest { @Override diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java similarity index 68% rename from contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java rename to contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java index 7acb5003a4d..0403332ec60 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest.java @@ -1,4 +1,6 @@ -package org.matsim.contrib.parking.parkingsearch; +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; public class NearestParkingSpotTest extends AbstractParkingTest { @Override diff --git a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java similarity index 54% rename from contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java rename to contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java index dc1660a263c..c473a821ea7 100644 --- a/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/RandomParkingTest.java +++ b/contribs/parking/src/test/java/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest.java @@ -1,4 +1,6 @@ -package org.matsim.contrib.parking.parkingsearch; +package org.matsim.contrib.parking.parkingsearch.facilityBasedParking; + +import org.matsim.contrib.parking.parkingsearch.ParkingSearchStrategy; public class RandomParkingTest extends AbstractParkingTest { @Override diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking100/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking100/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10OnlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1OnlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/BenensonParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking100/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/DistanceMemoryParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking100/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking100/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/parkingsearch/NearestParkingSpotTest/testParking100/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/parkingsearch/NearestParkingSpotTest/testParking100/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/parkingsearch/NearestParkingSpotTest/testParking100/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/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking10_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/NearestParkingSpotTest/testParking1_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/output_events.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_events.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/output_plans.xml.gz b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_plans.xml.gz similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking100/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking100/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking10_onlyFacilityParking/output_plans.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStats.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv b/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/0.parkingStatsPerTimeSteps.csv diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_events.xml.gz diff --git a/contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/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 similarity index 100% rename from contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz rename to contribs/parking/test/input/org/matsim/contrib/parking/parkingsearch/facilityBasedParking/RandomParkingTest/testParking1_onlyFacilityParking/output_plans.xml.gz From b4989470df7e22c661065d8b76cddd6c471d3cb3 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Thu, 28 Nov 2024 14:43:45 +0100 Subject: [PATCH 15/39] left some comments --- .../org/matsim/contrib/dynagent/DynAgent.java | 26 ++-- .../DynAgent/BenensonDynLeg.java | 119 ++++++++++-------- .../DynAgent/NearestParkingDynLeg.java | 34 +++-- .../agentLogic/ParkingAgentLogic.java | 77 +++++++----- .../manager/FacilityBasedParkingManager.java | 6 + .../manager/ZoneParkingManager.java | 3 + .../sim/ParkingSearchConfigGroup.java | 4 +- .../AbstractParkingTest.java | 8 -- 8 files changed, 158 insertions(+), 119 deletions(-) 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/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/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/manager/FacilityBasedParkingManager.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/manager/FacilityBasedParkingManager.java index 40d4934e838..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 @@ -44,6 +44,12 @@ 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 { 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 21d0ebdf06e..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,6 +19,9 @@ 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 { diff --git a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java index d86ebccb779..176f26f3cda 100644 --- a/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java +++ b/contribs/parking/src/main/java/org/matsim/contrib/parking/parkingsearch/sim/ParkingSearchConfigGroup.java @@ -75,6 +75,7 @@ public double getParkduration() { return parkDuration; } + //yyyy shouldn't this parameter be facility specific? paul, nov'24 @StringGetter(AVGPARKINGSLOTLENGTH) public double getAvgparkingslotlength() { return avgParkingSlotLength; @@ -170,7 +171,8 @@ 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" + + 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."); } 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 index 245043b1b3f..fee02ad587f 100644 --- 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 @@ -56,10 +56,6 @@ void testParking1_onlyFacilityParking() { Config config = getConfig(parkingConfig); config.plans().setInputFile("population1.xml"); run(config); - utils.copyFileFromOutputToInput("output_plans.xml.gz"); - utils.copyFileFromOutputToInput("output_events.xml.gz"); - utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStats.csv", "0.parkingStats.csv"); - utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStatsPerTimeSteps.csv", "0.parkingStatsPerTimeSteps.csv"); validate(); } @@ -74,10 +70,6 @@ void testParking10_onlyFacilityParking() { Config config = getConfig(parkingConfig); config.plans().setInputFile("population10.xml"); run(config); - utils.copyFileFromOutputToInput("output_plans.xml.gz"); - utils.copyFileFromOutputToInput("output_events.xml.gz"); - utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStats.csv", "0.parkingStats.csv"); - utils.copyFileFromOutputToInput("ITERS/it.0/0.parkingStatsPerTimeSteps.csv", "0.parkingStatsPerTimeSteps.csv"); validate(); } From d67ce8a631e8c7e56665cf8cf7afe059af302e4e Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Wed, 11 Dec 2024 19:12:16 +0100 Subject: [PATCH 16/39] adapt readme --- contribs/parking/README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) 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 From 27867b978862fd87d05b6ae3f12f07a31eaca2c6 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 16 Dec 2024 13:27:49 +0100 Subject: [PATCH 17/39] update distanceConstraint --- .../carriers/jsprit/DistanceConstraint.java | 281 +++++------------- 1 file changed, 67 insertions(+), 214 deletions(-) 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 8615e0b3d75..8265dca2666 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 @@ -23,10 +23,7 @@ import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; -import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; -import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment; -import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupShipment; -import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; +import com.graphhopper.jsprit.core.problem.solution.route.activity.*; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -64,124 +61,81 @@ public DistanceConstraint(CarrierVehicleTypes vehicleTypes, } /** - * When adding a TourActivity to the tour and the new vehicle has an - * energyCapacity (fuel or electricity etc.) the algorithm always checks the - * fulfilled method if all conditions (constraints) are fulfilled or not. - * Because every activity is added separately and the pickup before the delivery - * of a shipment, it will investigate which additional distance is necessary for - * the pickup and which minimal additional distance of the associated Delivery - * is needed. This is also important for the fulfilled decision of this - * function. At the end the conditions checks if the consumption of the tour - * including the additional shipment is possible with the possible - * energyCapacity. + * When adding a TourActivity to the tour and the new vehicle has an energyCapacity (fuel or electricity etc.) the algorithm always checks the fulfilled method if all conditions (constraints) are fulfilled or not. + * If a delivery is added, it also accounts for the necessary consumption if the pickup is added at the given position of the tour. This is also important for the fulfilled decision of this + * function. In the end, the conditions check if the consumption of the tour including the additional shipment is possible with the possible energyCapacity. */ //TODO add the time dependencies of the distance calculation because the route choice can be different for different times @Override public ConstraintsStatus fulfilled(JobInsertionContext context, TourActivity prevAct, TourActivity newAct, - TourActivity nextAct, double departureTime) { - double additionalDistance; + TourActivity nextAct, double prevActDepTime) { +// double additionalDistance; + Vehicle newVehicle = context.getNewVehicle(); VehicleType vehicleTypeOfNewVehicle = vehicleTypes.getVehicleTypes() - .get(Id.create(context.getNewVehicle().getType().getTypeId(), VehicleType.class)); - if (VehicleUtils.getEnergyCapacity(vehicleTypeOfNewVehicle.getEngineInformation()) != null) { - - Vehicle newVehicle = context.getNewVehicle(); - - Double energyCapacityInKWhOrLiters = VehicleUtils - .getEnergyCapacity(vehicleTypeOfNewVehicle.getEngineInformation()); - Double consumptionPerMeter; - if (VehicleUtils.getHbefaTechnology(vehicleTypeOfNewVehicle.getEngineInformation()).equals("electricity")) - consumptionPerMeter = VehicleUtils - .getEnergyConsumptionKWhPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); + .get(Id.create(newVehicle.getType().getTypeId(), VehicleType.class)); + if (VehicleUtils.getEnergyCapacity(vehicleTypeOfNewVehicle.getEngineInformation()) == null) return ConstraintsStatus.FULFILLED; + + Double energyCapacityInKWhOrLiters = VehicleUtils + .getEnergyCapacity(vehicleTypeOfNewVehicle.getEngineInformation()); + Double consumptionPerMeter; + if (VehicleUtils.getHbefaTechnology(vehicleTypeOfNewVehicle.getEngineInformation()).equals("electricity")) + consumptionPerMeter = VehicleUtils + .getEnergyConsumptionKWhPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); + else + consumptionPerMeter = VehicleUtils.getFuelConsumptionLitersPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); + + double currentDistance = calculateRouteDistance(context, newVehicle); + double currentRouteConsumption = currentDistance * (consumptionPerMeter); + if (currentRouteConsumption > energyCapacityInKWhOrLiters) return ConstraintsStatus.NOT_FULFILLED_BREAK; + + double distancePrevAct2NewAct = getDistance(prevAct, newAct, newVehicle, prevActDepTime); + double distanceNewAct2nextAct = getDistance(newAct, nextAct, newVehicle, prevActDepTime); + double distancePrevAct2NextAct = getDistance(prevAct, nextAct, newVehicle, prevActDepTime); + if (prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0; + if (nextAct instanceof End && !context.getNewVehicle().isReturnToDepot()) { + distanceNewAct2nextAct = 0; + distancePrevAct2NextAct = 0; + } + double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; + double additionalConsumption = additionalDistance * (consumptionPerMeter); + if (currentRouteConsumption + additionalConsumption > energyCapacityInKWhOrLiters) return ConstraintsStatus.NOT_FULFILLED; + + + double additionalDistanceOfPickup; + double additionalConsumptionOfPickup = 0; + if (newAct instanceof DeliverShipment) { + int iIndexOfPickup = context.getRelatedActivityContext().getInsertionIndex(); + TourActivity pickup = context.getAssociatedActivities().getFirst(); + TourActivity actBeforePickup; + if (iIndexOfPickup > 0) actBeforePickup = context.getRoute().getActivities().get(iIndexOfPickup - 1); + else actBeforePickup = new Start(context.getNewVehicle().getStartLocation(), 0, Double.MAX_VALUE); + TourActivity actAfterPickup; + if (iIndexOfPickup < context.getRoute().getActivities().size()) + actAfterPickup = context.getRoute().getActivities().get(iIndexOfPickup); else - consumptionPerMeter = VehicleUtils.getFuelConsumptionLitersPerMeter(vehicleTypeOfNewVehicle.getEngineInformation()); - - double routeDistance = calculateRouteDistance(context, newVehicle); - double routeConsumption = routeDistance * (consumptionPerMeter); - - if (newAct instanceof PickupShipment) { - // calculates the additional distance for adding a pickup and checks the shortest possibility for adding the associated delivery - additionalDistance = getDistance(prevAct, newAct, newVehicle) + getDistance(newAct, nextAct, newVehicle) - - getDistance(prevAct, nextAct, newVehicle)+ findMinimalAdditionalDistance(context, newAct, newAct); - - } else if (newAct instanceof DeliverShipment) { - // calculates the distance new for integrating the associated pickup - routeDistance = calculateRouteDistanceWithAssociatedPickup(context); - routeConsumption = routeDistance * (consumptionPerMeter); - - additionalDistance = getDistance(prevAct, newAct, newVehicle) + getDistance(newAct, nextAct, newVehicle) - - getDistance(prevAct, nextAct, newVehicle); - - } else { - additionalDistance = getDistance(prevAct, newAct, newVehicle) + getDistance(newAct, nextAct, newVehicle) - - getDistance(prevAct, nextAct, newVehicle); + actAfterPickup = nextAct; + double distanceActBeforePickup2Pickup = getDistance(actBeforePickup, pickup, newVehicle, actBeforePickup.getEndTime()); + double distancePickup2ActAfterPickup = getDistance(pickup, actAfterPickup, newVehicle, context.getRelatedActivityContext().getEndTime()); + double distanceBeforePickup2AfterPickup = getDistance(actBeforePickup, actAfterPickup,newVehicle, actBeforePickup.getEndTime()); + if (context.getRoute().isEmpty()) distanceBeforePickup2AfterPickup = 0; + if (actAfterPickup instanceof End && !context.getNewVehicle().isReturnToDepot()) { + distancePickup2ActAfterPickup = 0; + distanceBeforePickup2AfterPickup = 0; } - double additionalConsumption = additionalDistance * (consumptionPerMeter); - double newRouteConsumption = routeConsumption + additionalConsumption; - - if (newRouteConsumption > energyCapacityInKWhOrLiters) { - return ConstraintsStatus.NOT_FULFILLED_BREAK; - } else { - return ConstraintsStatus.FULFILLED; - } - } else { - return ConstraintsStatus.FULFILLED; + additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup; + additionalConsumptionOfPickup = additionalDistanceOfPickup * (consumptionPerMeter); } - } - /** - * Calculates the distance based on the route-based distances between every tour - * activities. The method also integrates the associated pickup in the tour. - */ - private double calculateRouteDistanceWithAssociatedPickup(JobInsertionContext context) { - double routeDistance; - int positionOfRelatedPickup = context.getRelatedActivityContext().getInsertionIndex(); - int nextRouteActivity = 0; + if (currentRouteConsumption + additionalConsumption + additionalConsumptionOfPickup > energyCapacityInKWhOrLiters) + return ConstraintsStatus.NOT_FULFILLED; - // checks if the associated pickup is on first position - if (positionOfRelatedPickup == 0 && context.getRoute().getActivities().isEmpty()) { - context.getRoute().getStart().setLocation(context.getNewVehicle().getStartLocation()); - context.getRoute().getEnd().setLocation(context.getNewVehicle().getEndLocation()); - routeDistance = getDistance(context.getAssociatedActivities().getFirst(), context.getRoute().getEnd(), - context.getNewVehicle(), context.getNewDepTime()); - return routeDistance; - } else if (positionOfRelatedPickup == 0 && !context.getRoute().getActivities().isEmpty()) { - routeDistance = getDistance(context.getAssociatedActivities().getFirst(), - context.getRoute().getActivities().getFirst(), context.getNewVehicle(), context.getNewDepTime()); - } else { - routeDistance = getDistance(context.getRoute().getStart(), context.getRoute().getActivities().getFirst(), - context.getNewVehicle(), context.getNewDepTime()); - } - // adds distances between every tour activity and adds the associated pickup on - // the correct position of the tour - while (context.getRoute().getTourActivities().getActivities().size() > (nextRouteActivity + 1)) { - if (positionOfRelatedPickup == (nextRouteActivity + 1) && positionOfRelatedPickup != 0) { - routeDistance = routeDistance + getDistance(context.getRoute().getActivities().get(nextRouteActivity), - context.getAssociatedActivities().getFirst(), context.getNewVehicle()); - routeDistance = routeDistance + getDistance(context.getAssociatedActivities().getFirst(), - context.getRoute().getActivities().get(nextRouteActivity), context.getNewVehicle()); - } else { - routeDistance = routeDistance + getDistance(context.getRoute().getActivities().get(nextRouteActivity), - context.getRoute().getActivities().get(nextRouteActivity + 1), context.getNewVehicle()); - } - nextRouteActivity++; - } - if (positionOfRelatedPickup == context.getRoute().getActivities().size()) { - routeDistance = routeDistance + getDistance(context.getRoute().getActivities().get(nextRouteActivity), - context.getAssociatedActivities().getFirst(), context.getNewVehicle()); - routeDistance = routeDistance + getDistance(context.getAssociatedActivities().getFirst(), - context.getRoute().getEnd(), context.getNewVehicle()); - } else - routeDistance = routeDistance + getDistance(context.getRoute().getActivities().get(nextRouteActivity), - context.getRoute().getEnd(), context.getNewVehicle()); + return ConstraintsStatus.FULFILLED; - return routeDistance; } /** - * Calculates the distance based on the route-based distances between every tour - * activities. - * + * Calculates the distance based on the route-based distances between every tour activity. */ private double calculateRouteDistance(JobInsertionContext context, Vehicle newVehicle) { double realRouteDistance = 0; @@ -189,121 +143,20 @@ private double calculateRouteDistance(JobInsertionContext context, Vehicle newVe return realRouteDistance; int n = 0; realRouteDistance = getDistance(context.getRoute().getStart(), - context.getRoute().getTourActivities().getActivities().getFirst(), newVehicle); + context.getRoute().getTourActivities().getActivities().getFirst(), newVehicle, context.getRoute().getStart().getEndTime()); while (context.getRoute().getTourActivities().getActivities().size() > (n + 1)) { + + TourActivity from = context.getRoute().getTourActivities().getActivities().get(n); realRouteDistance = realRouteDistance - + getDistance(context.getRoute().getTourActivities().getActivities().get(n), - context.getRoute().getTourActivities().getActivities().get(n + 1), newVehicle); + + getDistance(from, context.getRoute().getTourActivities().getActivities().get(n + 1), newVehicle, from.getEndTime()); n++; } + TourActivity from = context.getRoute().getTourActivities().getActivities().get(n); realRouteDistance = realRouteDistance + getDistance( - context.getRoute().getTourActivities().getActivities().get(n), context.getRoute().getEnd(), newVehicle); + context.getRoute().getTourActivities().getActivities().get(n), context.getRoute().getEnd(), newVehicle, from.getEndTime()); return realRouteDistance; } - /** - * Finds a minimal additional distance for the tour, when a pickup is added to - * the plan. The AssociatedActivities contains both activities of a job which - * should be added to the existing tour. The TourActivities which are already in - * the tour are found in context.getRoute().getTourActivities. In this method - * the position of the new pickup is fixed and three options of the location of - * the delivery activity will be checked: delivery between every other activity - * after the pickup, delivery as the last activity before the end and delivery - * directly behind the new pickup. This method gives back the minimal distance - * of this three options. - * - * @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, - TourActivity nextAct) { - double minimalAdditionalDistance = 0; - - if (context.getAssociatedActivities().get(1) instanceof DeliverShipment) { - TourActivity assignedDelivery = context.getAssociatedActivities().get(1); - minimalAdditionalDistance = 0; - int indexNextActivity = nextAct.getIndex(); - int tourPositionOfActivityBehindNewPickup = 0; - int countIndex = 0; - Vehicle newVehicle = context.getNewVehicle(); - VehicleRoute route = context.getRoute(); - - // search the index of the activity behind the pickup activity which should be - // added to the tour - a: for (TourActivity tourActivity : route.getTourActivities().getActivities()) { - if (tourActivity.getIndex() == indexNextActivity) { - while (countIndex < route.getTourActivities().getActivities().size()) { - if (route.getTourActivities().getActivities().get(countIndex).getIndex() == indexNextActivity) { - tourPositionOfActivityBehindNewPickup = countIndex; - break a; - } - countIndex++; - } - } - } - - // search the minimal distance between every exiting TourActivity - while ((tourPositionOfActivityBehindNewPickup + 1) < route.getTourActivities().getActivities().size()) { - TourActivity activityBefore = route.getTourActivities().getActivities() - .get(tourPositionOfActivityBehindNewPickup); - TourActivity activityAfter = route.getTourActivities().getActivities() - .get(tourPositionOfActivityBehindNewPickup + 1); - double possibleAdditionalDistance = getDistance(activityBefore, assignedDelivery, newVehicle) - + getDistance(assignedDelivery, activityAfter, newVehicle) - - getDistance(activityBefore, activityAfter, newVehicle); - minimalAdditionalDistance = findMinimalDistance(minimalAdditionalDistance, possibleAdditionalDistance); - tourPositionOfActivityBehindNewPickup++; - } - // checks the distance if the delivery is the last activity before the end of - // the tour - if (!route.getTourActivities().getActivities().isEmpty()) { - TourActivity activityLastDelivery = route.getTourActivities().getActivities() - .getLast(); - TourActivity activityEnd = route.getEnd(); - double possibleAdditionalDistance = getDistance(activityLastDelivery, assignedDelivery, newVehicle) - + getDistance(assignedDelivery, activityEnd, newVehicle) - - getDistance(activityLastDelivery, activityEnd, newVehicle); - minimalAdditionalDistance = findMinimalDistance(minimalAdditionalDistance, possibleAdditionalDistance); - - // Checks the distance if the delivery will be added directly behind the pickup - TourActivity activityAfter = route.getTourActivities().getActivities() - .get(tourPositionOfActivityBehindNewPickup); - possibleAdditionalDistance = getDistance(newInvestigatedPickup, assignedDelivery, newVehicle) - + getDistance(assignedDelivery, activityAfter, newVehicle) - - getDistance(newInvestigatedPickup, activityAfter, newVehicle); - minimalAdditionalDistance = findMinimalDistance(minimalAdditionalDistance, possibleAdditionalDistance); - } - - } - return minimalAdditionalDistance; - } - - /** - * Checks if the find possible distance is the minimal one. - * - * @param minimalAdditionalDistance the minimal additional distance - * @param possibleAdditionalDistance the possible additional distance - * @return the minimal transport distance - */ - private double findMinimalDistance(double minimalAdditionalDistance, double possibleAdditionalDistance) { - if (minimalAdditionalDistance == 0) - minimalAdditionalDistance = possibleAdditionalDistance; - else if (possibleAdditionalDistance < minimalAdditionalDistance) - minimalAdditionalDistance = possibleAdditionalDistance; - return minimalAdditionalDistance; - } - - private double getDistance(TourActivity from, TourActivity to, Vehicle vehicle) { - double distance = netBasedCosts.getDistance(from.getLocation(), to.getLocation(), from.getEndTime(), - vehicle); - if (!(distance >= 0.)) - throw new AssertionError("Distance must not be negative! From, to" + from + ", " + to - + " distance " + distance); - return distance; - } - private double getDistance(TourActivity from, TourActivity to, Vehicle vehicle, double departureTime) { double distance = netBasedCosts.getDistance(from.getLocation(), to.getLocation(), departureTime, vehicle); From 9d7491b338ee625969f606418f46d2466049f1a7 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 16 Dec 2024 13:32:24 +0100 Subject: [PATCH 18/39] add columns for load analysis --- .../carriers/analysis/CarrierLoadAnalysis.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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 760ce513035..652d0740975 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 @@ -27,10 +27,8 @@ 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 java.util.*; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; @@ -54,6 +52,7 @@ public class CarrierLoadAnalysis implements CarrierShipmentPickupStartEventHandl final Carriers carriers; private final Map, LinkedList> vehicle2Load = new LinkedHashMap<>(); + private final Map, Integer> vehicle2DemandPerTour = new HashMap<>(); public CarrierLoadAnalysis(String delimiter, Carriers carriers) { this.delimiter = delimiter; @@ -69,9 +68,11 @@ public void handleEvent(CarrierShipmentPickupStartEvent event) { if (! vehicle2Load.containsKey(vehicleId)){ list = new LinkedList<>(); list.add(demand); + vehicle2DemandPerTour.put(vehicleId, demand); } else { list = vehicle2Load.get(vehicleId); list.add(list.getLast() + demand); + vehicle2DemandPerTour.put(vehicleId, vehicle2DemandPerTour.get(vehicleId) + demand); } vehicle2Load.put(vehicleId, list); } @@ -98,6 +99,8 @@ void writeLoadPerVehicle(String analysisOutputDirectory, Scenario scenario) thro "vehicleTypeId", "capacity", "maxLoad", + "maxLoadPercentage", + "handledDemand", "load state during tour")); bw1.newLine(); @@ -109,10 +112,15 @@ void writeLoadPerVehicle(String analysisOutputDirectory, Scenario scenario) thro final VehicleType vehicleType = VehicleUtils.findVehicle(vehicleId, scenario).getType(); final Double capacity = vehicleType.getCapacity().getOther(); + final Integer demand = vehicle2DemandPerTour.get(vehicleId); + final double maxLoadPercentage = Math.round(maxLoad / capacity * 10000)/100.0;; + bw1.write(vehicleId.toString()); bw1.write(delimiter + vehicleType.getId().toString()); bw1.write(delimiter + capacity); bw1.write(delimiter + maxLoad); + bw1.write(delimiter + maxLoadPercentage); + bw1.write(delimiter + demand); bw1.write(delimiter + load); bw1.newLine(); } From 9e014f2c40c338418294bf8647dfacc0c2a33022 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 16 Dec 2024 13:33:50 +0100 Subject: [PATCH 19/39] add logging --- .../freight/carriers/analysis/RunFreightAnalysisEventBased.java | 2 ++ 1 file changed, 2 insertions(+) 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 0502ae2e1c4..00c1f1dea61 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 @@ -124,6 +124,8 @@ public RunFreightAnalysisEventBased(Carriers carriers, String analysisOutputPath private void createScenarioForFreightAnalysis(String vehiclesPath, String networkPath, String carriersPath, String carriersVehicleTypesPath, String globalCrs) { + log.info("########## Starting Freight Analysis ##########"); + Config config = ConfigUtils.createConfig(); config.vehicles().setVehiclesFile(vehiclesPath); config.network().setInputFile(networkPath); From d66b1c5e96a0c1e774eb8b5a449c8defc7a13dbe Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Mon, 16 Dec 2024 13:52:08 +0100 Subject: [PATCH 20/39] adjust resulting test --- .../runServiceEventTest/Load_perVehicle.tsv | 2 +- .../runShipmentEventTest/Load_perVehicle.tsv | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 a1e0058ce5b..3d861e42d95 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 vehicleTypeId capacity maxLoad load state during tour +vehicleId vehicleTypeId capacity maxLoad maxLoadPercentage handledDemand 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 d61ddd36308..4216eeed0f3 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 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] +vehicleId vehicleTypeId capacity maxLoad maxLoadPercentage handledDemand load state during tour +freight_carrier1_veh_freight_carrier1_veh_heavyVehicle_1_1 heavy 50.0 26 52.0 26 [3, 8, 18, 25, 26, 23, 13, 12, 7, 0] From 426d78c7644c6610dfcd7b2ced981851f2e7576f Mon Sep 17 00:00:00 2001 From: rakow Date: Mon, 16 Dec 2024 14:37:21 +0100 Subject: [PATCH 21/39] IMC Trip Score Estimator (#3642) * add interface for trip score estimates * fix injection * fix test * make strategy names final --- .../InformedModeChoiceConfigGroup.java | 2 +- .../modechoice/InformedModeChoiceModule.java | 79 +++++++++++++------ .../matsim/modechoice/PlanModelService.java | 12 ++- .../modechoice/commands/StrategyOptions.java | 3 +- .../estimators/TripScoreEstimator.java | 18 +++++ .../pruning/PlanScoreThresholdPruner.java | 23 ++++++ .../modechoice/search/TopKMinMaxTest.java | 3 + 7 files changed, 109 insertions(+), 31 deletions(-) create mode 100644 contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/estimators/TripScoreEstimator.java create mode 100644 contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/pruning/PlanScoreThresholdPruner.java diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceConfigGroup.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceConfigGroup.java index 709de1e45ba..76c9e429e0a 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceConfigGroup.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceConfigGroup.java @@ -43,7 +43,7 @@ public class InformedModeChoiceConfigGroup extends ReflectiveConfigGroup { @Parameter @Comment("Require that new plan modes are always different from the current one.") - private boolean requireDifferentModes = true; + private boolean requireDifferentModes = false; @Parameter @Comment("Defines how constraint violations are handled.") diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceModule.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceModule.java index e681025ef92..6c422644a14 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceModule.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/InformedModeChoiceModule.java @@ -6,6 +6,8 @@ import com.google.inject.TypeLiteral; import com.google.inject.multibindings.MapBinder; import com.google.inject.multibindings.Multibinder; +import org.matsim.core.config.Config; +import org.matsim.core.config.groups.ReplanningConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.listener.ControlerListener; import org.matsim.core.router.PlanRouter; @@ -13,20 +15,14 @@ import org.matsim.core.utils.timing.TimeInterpretation; import org.matsim.facilities.ActivityFacilities; import org.matsim.modechoice.constraints.TripConstraint; -import org.matsim.modechoice.estimators.ActivityEstimator; -import org.matsim.modechoice.estimators.FixedCostsEstimator; -import org.matsim.modechoice.estimators.LegEstimator; -import org.matsim.modechoice.estimators.TripEstimator; +import org.matsim.modechoice.estimators.*; import org.matsim.modechoice.pruning.CandidatePruner; import org.matsim.modechoice.replanning.*; import org.matsim.modechoice.search.BestChoiceGenerator; import org.matsim.modechoice.search.SingleTripChoicesGenerator; import org.matsim.modechoice.search.TopKChoicesGenerator; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * The main and only module needed to install to use informed mode choice functionality. @@ -35,12 +31,12 @@ */ public final class InformedModeChoiceModule extends AbstractModule { - public static String SELECT_BEST_K_PLAN_MODES_STRATEGY = "SelectBestKPlanModes"; + public final static String SELECT_BEST_K_PLAN_MODES_STRATEGY = "SelectBestKPlanModes"; - public static String SELECT_SINGLE_TRIP_MODE_STRATEGY = "SelectSingleTripMode"; + public final static String SELECT_SINGLE_TRIP_MODE_STRATEGY = "SelectSingleTripMode"; - public static String SELECT_SUBTOUR_MODE_STRATEGY = "SelectSubtourMode"; - public static String RANDOM_SUBTOUR_MODE_STRATEGY = "RandomSubtourMode"; + public final static String SELECT_SUBTOUR_MODE_STRATEGY = "SelectSubtourMode"; + public final static String RANDOM_SUBTOUR_MODE_STRATEGY = "RandomSubtourMode"; private final Builder builder; @@ -49,6 +45,33 @@ private InformedModeChoiceModule(Builder builder) { this.builder = builder; } + /** + * Replaces a strategy in the config. Can be used to enable one of the strategies in this module programmatically. + */ + public static void replaceReplanningStrategy(Config config, String subpopulation, + String existing, String replacement) { + + // Copy list because it is unmodifiable + List strategies = new ArrayList<>(config.replanning().getStrategySettings()); + List found = strategies.stream() + .filter(s -> s.getSubpopulation().equals(subpopulation)) + .filter(s -> s.getStrategyName().equals(existing)) + .toList(); + + if (found.isEmpty()) + throw new IllegalArgumentException("No strategy %s found for subpopulation %s".formatted(existing, subpopulation)); + + if (found.size() > 1) + throw new IllegalArgumentException("Multiple strategies %s found for subpopulation %s".formatted(existing, subpopulation)); + + ReplanningConfigGroup.StrategySettings old = found.getFirst(); + old.setStrategyName(replacement); + + // reset und set new strategies + config.replanning().clearStrategySettings(); + strategies.forEach(s -> config.replanning().addStrategySettings(s)); + } + public static Builder newBuilder() { return new Builder(); } @@ -56,14 +79,10 @@ public static Builder newBuilder() { @Override public void install() { - bindAllModes(builder.fixedCosts, new TypeLiteral<>() { - }); - bindAllModes(builder.legEstimators, new TypeLiteral<>() { - }); - bindAllModes(builder.tripEstimators, new TypeLiteral<>() { - }); - bindAllModes(builder.options, new TypeLiteral<>() { - }); + bindAllModes(builder.fixedCosts, new TypeLiteral<>() {}); + bindAllModes(builder.legEstimators, new TypeLiteral<>() {}); + bindAllModes(builder.tripEstimators, new TypeLiteral<>() {}); + bindAllModes(builder.options, new TypeLiteral<>() {}); bind(ActivityEstimator.class).to(builder.activityEstimator).in(Singleton.class); @@ -77,12 +96,16 @@ public void install() { bind(PlanModelService.class).asEagerSingleton(); addControlerListenerBinding().to(PlanModelService.class).asEagerSingleton(); - Multibinder> tcBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() { - }); + Multibinder> tcBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}); for (Class> c : builder.constraints) { tcBinder.addBinding().to(c).in(Singleton.class); } + Multibinder tripScores = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}); + for (Class c : builder.tripScoreEstimators) { + tripScores.addBinding().to(c).in(Singleton.class); + } + MapBinder pBinder = MapBinder.newMapBinder(binder(), String.class, CandidatePruner.class); for (Map.Entry e : builder.pruner.entrySet()) { CandidatePruner instance = e.getValue(); @@ -133,8 +156,7 @@ public PlanRouter planRouter(Provider tripRouter, ActivityFacilities private void bindAllModes(Map> map, TypeLiteral value) { // Ensure to bind to internal strings - MapBinder mapBinder = MapBinder.newMapBinder(binder(), new TypeLiteral<>() { - }, value); + MapBinder mapBinder = MapBinder.newMapBinder(binder(), new TypeLiteral<>() {}, value); for (Map.Entry> e : map.entrySet()) { Class clazz = e.getValue(); mapBinder.addBinding(e.getKey().intern()).to(clazz).in(Singleton.class); @@ -153,6 +175,7 @@ public static final class Builder { private final Map> options = new HashMap<>(); private final Set>> constraints = new LinkedHashSet<>(); + private final Set> tripScoreEstimators = new LinkedHashSet<>(); private final Map pruner = new HashMap<>(); @@ -230,6 +253,14 @@ public Builder withActivityEstimator(Class activity return this; } + /** + * Add general score estimator that is applied to all trips. + */ + public Builder withTripScoreEstimator(Class tripScoreEstimator) { + tripScoreEstimators.add(tripScoreEstimator); + return this; + } + /** * Builds the module, which can then be used with {@link #install()} */ diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/PlanModelService.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/PlanModelService.java index 85f80664279..93e0fb86c67 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/PlanModelService.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/PlanModelService.java @@ -12,10 +12,7 @@ import org.matsim.core.router.TripStructureUtils; import org.matsim.core.utils.timing.TimeInterpretation; import org.matsim.modechoice.constraints.TripConstraint; -import org.matsim.modechoice.estimators.ActivityEstimator; -import org.matsim.modechoice.estimators.LegEstimator; -import org.matsim.modechoice.estimators.MinMaxEstimate; -import org.matsim.modechoice.estimators.TripEstimator; +import org.matsim.modechoice.estimators.*; import java.util.*; import java.util.function.Predicate; @@ -33,6 +30,9 @@ public final class PlanModelService implements StartupListener { @Inject private Map tripEstimator; + @Inject + private Set tripScores; + @Inject private Set> constraints; @@ -223,6 +223,10 @@ public void calculateEstimates(EstimatorContext context, PlanModel planModel) { // early or late arrival can also have an effect on the activity scores which is potentially considered here estimate += actEstimator.estimate(context, planModel.getStartTimes()[i] + tt, trip.getDestinationActivity()); + for (TripScoreEstimator tripScore : tripScores) { + estimate += tripScore.estimate(context, c.getMode(), trip); + } + values[i] = estimate; } } diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/commands/StrategyOptions.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/commands/StrategyOptions.java index 532c0995236..0b10695df86 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/commands/StrategyOptions.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/commands/StrategyOptions.java @@ -154,8 +154,7 @@ public Module applyModule(Binder binder, Config config, Consumer config.replanning().addStrategySettings(s)); if (group.forceInnovation > 0) - binder.bind(new TypeLiteral>() { - }).toInstance(new ForceInnovationStrategyChooser<>(group.forceInnovation, ForceInnovationStrategyChooser.Permute.yes)); + binder.bind(new TypeLiteral>() {}).toInstance(new ForceInnovationStrategyChooser<>(group.forceInnovation, ForceInnovationStrategyChooser.Permute.yes)); InformedModeChoiceModule.Builder builder = InformedModeChoiceModule.newBuilder(); diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/estimators/TripScoreEstimator.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/estimators/TripScoreEstimator.java new file mode 100644 index 00000000000..d3105ce4514 --- /dev/null +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/estimators/TripScoreEstimator.java @@ -0,0 +1,18 @@ +package org.matsim.modechoice.estimators; + +import org.matsim.core.router.TripStructureUtils; +import org.matsim.modechoice.EstimatorContext; + +/** + * This class can be used to estimate additional scores for a trip. + * These score are added to the existing estimates and might be independent of the mode. + */ +public interface TripScoreEstimator { + + /** + * Compute a score estimate for a trip. + */ + double estimate(EstimatorContext context, String mainMode, TripStructureUtils.Trip trip); + + +} diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/pruning/PlanScoreThresholdPruner.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/pruning/PlanScoreThresholdPruner.java new file mode 100644 index 00000000000..e3446686715 --- /dev/null +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/pruning/PlanScoreThresholdPruner.java @@ -0,0 +1,23 @@ +package org.matsim.modechoice.pruning; + +import org.matsim.modechoice.PlanModel; + +/** + * Removes plans by a fixed utility threshold. + */ +public class PlanScoreThresholdPruner implements CandidatePruner { + + private final double threshold; + + /** + * Threshold to be applied on the best known plan estimate. Candidates with a larger difference to the best, than this threshold are discarded. + */ + public PlanScoreThresholdPruner(double threshold) { + this.threshold = threshold; + } + + @Override + public double planThreshold(PlanModel planModel) { + return threshold; + } +} diff --git a/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/search/TopKMinMaxTest.java b/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/search/TopKMinMaxTest.java index 04cfe9860e2..5490b076de8 100644 --- a/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/search/TopKMinMaxTest.java +++ b/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/search/TopKMinMaxTest.java @@ -217,6 +217,9 @@ else if (invocationOnMock.getArgument(0).equals(TransportMode.walk)) { Multibinder> tcBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() { }); + Multibinder tEstBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() { + }); + MapBinder fcBinder = MapBinder.newMapBinder(binder(), new TypeLiteral<>() { }, new TypeLiteral<>() { }); From 1c940ae9382385b67e23f2f146d31dd3041fe05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedrich=20V=C3=B6lkers?= Date: Wed, 18 Dec 2024 11:05:07 +0100 Subject: [PATCH 22/39] added activity dashboard and activity analysis (#3544) * added activity dashboard and activity analysis * first version of the activity analysis and the dashboard * add csv example for berlin * remove unused files * remove unused files * remove unused files * remove unused files * remove unused files * remove unused files * remove unused files * remove unused files * remove unused files * Improve wording on the activity dashboards * add some documentation * fix: activity dashboard bug * catch non existing network nodes * update activity dashboard * fix relative legend * fix scale in test data * fix number of breakpoints --------- Co-authored-by: rakow --- .../activity/ActivityCountAnalysis.java | 220 ++++++++++++++++++ .../traveltime/TravelTimeComparison.java | 23 ++ .../application/options/ShpOptions.java | 1 + .../main/java/org/matsim/simwrapper/Data.java | 33 ++- .../simwrapper/SimWrapperConfigGroup.java | 14 ++ .../matsim/simwrapper/SimWrapperListener.java | 7 +- .../matsim/simwrapper/SimWrapperRunner.java | 5 + .../dashboard/ActivityDashboard.java | 185 +++++++++++++++ .../org/matsim/simwrapper/viz/MapPlot.java | 6 +- .../simwrapper/dashboard/DashboardTests.java | 19 +- .../src/test/resources/kehlheim_ref.csv | 12 + .../src/test/resources/kehlheim_shape.cpg | 1 + .../src/test/resources/kehlheim_shape.dbf | Bin 0 -> 187 bytes .../src/test/resources/kehlheim_shape.prj | 1 + .../src/test/resources/kehlheim_shape.qmd | 44 ++++ .../src/test/resources/kehlheim_shape.shp | Bin 0 -> 4476 bytes .../src/test/resources/kehlheim_shape.shx | Bin 0 -> 188 bytes 17 files changed, 564 insertions(+), 7 deletions(-) create mode 100644 contribs/application/src/main/java/org/matsim/application/analysis/activity/ActivityCountAnalysis.java create mode 100644 contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/ActivityDashboard.java create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_ref.csv create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.cpg create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.dbf create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.prj create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.qmd create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.shp create mode 100644 contribs/simwrapper/src/test/resources/kehlheim_shape.shx diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/activity/ActivityCountAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/activity/ActivityCountAnalysis.java new file mode 100644 index 00000000000..b944ee044fb --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/application/analysis/activity/ActivityCountAnalysis.java @@ -0,0 +1,220 @@ +package org.matsim.application.analysis.activity; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.geotools.api.feature.Property; +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.application.CommandSpec; +import org.matsim.application.MATSimAppCommand; +import org.matsim.application.options.*; +import org.matsim.core.utils.io.IOUtils; +import picocli.CommandLine; +import tech.tablesaw.api.*; +import tech.tablesaw.io.csv.CsvReadOptions; +import tech.tablesaw.selection.Selection; + +import java.util.*; +import java.util.regex.Pattern; + +@CommandSpec( + requires = {"activities.csv"}, + produces = {"activities_%s_per_region.csv"} +) +public class ActivityCountAnalysis implements MATSimAppCommand { + + private static final Logger log = LogManager.getLogger(ActivityCountAnalysis.class); + + @CommandLine.Mixin + private final InputOptions input = InputOptions.ofCommand(ActivityCountAnalysis.class); + @CommandLine.Mixin + private final OutputOptions output = OutputOptions.ofCommand(ActivityCountAnalysis.class); + @CommandLine.Mixin + private ShpOptions shp; + @CommandLine.Mixin + private SampleOptions sample; + @CommandLine.Mixin + private CrsOptions crs; + + /** + * Specifies the column in the shapefile used as the region ID. + */ + @CommandLine.Option(names = "--id-column", description = "Column to use as ID for the shapefile", required = true) + private String idColumn; + + /** + * Maps patterns to merge activity types into a single category. + * Example: `home;work` can merge activities "home1" and "work1" into categories "home" and "work". + */ + @CommandLine.Option(names = "--activity-mapping", description = "Map of patterns to merge activity types", split = ";") + private Map activityMapping; + + /** + * Specifies activity types that should be counted only once per agent per region. + */ + @CommandLine.Option(names = "--single-occurrence", description = "Activity types that are only counted once per agent") + private Set singleOccurrence; + + public static void main(String[] args) { + new ActivityCountAnalysis().execute(args); + } + + /** + * Executes the activity count analysis. + * + * @return Exit code (0 for success). + * @throws Exception if errors occur during execution. + */ + @Override + public Integer call() throws Exception { + + // Prepares the activity mappings and reads input data + HashMap> formattedActivityMapping = new HashMap<>(); + Map regionAreaMap = new HashMap<>(); + + if (this.activityMapping == null) this.activityMapping = new HashMap<>(); + + for (Map.Entry entry : this.activityMapping.entrySet()) { + String pattern = entry.getKey(); + String activity = entry.getValue(); + Set activities = new HashSet<>(Arrays.asList(activity.split(","))); + formattedActivityMapping.put(pattern, activities); + } + + // Reading the input csv + Table activities = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(input.getPath("activities.csv"))) + .columnTypesPartial(Map.of("person", ColumnType.TEXT, "activity_type", ColumnType.TEXT)) + .sample(false) + .separator(CsvOptions.detectDelimiter(input.getPath("activities.csv"))).build()); + + // remove the underscore and the number from the activity_type column + TextColumn activityType = activities.textColumn("activity_type"); + activityType.set(Selection.withRange(0, activityType.size()), activityType.replaceAll("_[0-9]{2,}$", "")); + + ShpOptions.Index index = crs.getInputCRS() == null ? shp.createIndex(idColumn) : shp.createIndex(crs.getInputCRS(), idColumn); + + // stores the counts of activities per region + Object2ObjectOpenHashMap> regionActivityCounts = new Object2ObjectOpenHashMap<>(); + // stores the activities that have been counted for each person in each region + Object2ObjectOpenHashMap> personActivityTracker = new Object2ObjectOpenHashMap<>(); + + // iterate over the csv rows + for (Row row : activities) { + String person = row.getString("person"); + String activity = row.getText("activity_type"); + + for (Map.Entry> entry : formattedActivityMapping.entrySet()) { + String pattern = entry.getKey(); + Set activities2 = entry.getValue(); + for (String act : activities2) { + if (Pattern.matches(act, activity)) { + activity = pattern; + break; + } + } + } + + Coord coord = new Coord(row.getDouble("coord_x"), row.getDouble("coord_y")); + + // get the region for the current coordinate + SimpleFeature feature = index.queryFeature(coord); + + if (feature == null) { + continue; + } + + Geometry geometry = (Geometry) feature.getDefaultGeometry(); + + Property prop = feature.getProperty(idColumn); + if (prop == null) + throw new IllegalArgumentException("No property found for column %s".formatted(idColumn)); + + Object region = prop.getValue(); + if (region != null && region.toString().length() > 0) { + + double area = geometry.getArea(); + regionAreaMap.put(region.toString(), area); + + // Add region to the activity counts and person activity tracker if not already present + regionActivityCounts.computeIfAbsent(region, k -> new Object2IntOpenHashMap<>()); + personActivityTracker.computeIfAbsent(region, k -> new HashSet<>()); + + Set trackedActivities = personActivityTracker.get(region); + String personActivityKey = person + "_" + activity; + + // adding activity only if it has not been counted for the person in the region + if (singleOccurrence == null || !singleOccurrence.contains(activity) || !trackedActivities.contains(personActivityKey)) { + Object2IntMap activityCounts = regionActivityCounts.get(region); + activityCounts.mergeInt(activity, 1, Integer::sum); + + // mark the activity as counted for the person in the region + trackedActivities.add(personActivityKey); + } + } + } + + Set uniqueActivities = new HashSet<>(); + + for (Object2IntMap map : regionActivityCounts.values()) { + uniqueActivities.addAll(map.keySet()); + } + + for (String activity : uniqueActivities) { + Table resultTable = Table.create(); + TextColumn regionColumn = TextColumn.create("id"); + DoubleColumn activityColumn = DoubleColumn.create("count"); + DoubleColumn distributionColumn = DoubleColumn.create("relative_density"); + DoubleColumn countRatioColumn = DoubleColumn.create("density"); + DoubleColumn areaColumn = DoubleColumn.create("area"); + + resultTable.addColumns(regionColumn, activityColumn, distributionColumn, countRatioColumn, areaColumn); + for (Map.Entry> entry : regionActivityCounts.entrySet()) { + Object region = entry.getKey(); + double value = 0; + for (Map.Entry entry2 : entry.getValue().object2IntEntrySet()) { + String ect = entry2.getKey(); + if (Pattern.matches(ect, activity)) { + value = entry2.getValue() * sample.getUpscaleFactor(); + break; + } + } + + + Row row = resultTable.appendRow(); + row.setString("id", region.toString()); + row.setDouble("count", value); + } + + for (Row row : resultTable) { + Double area = regionAreaMap.get(row.getString("id")); + if (area != null) { + row.setDouble("area", area); + row.setDouble("density", row.getDouble("count") / area); + } else { + log.warn("Area for region {} is not found", row.getString("id")); + } + } + + Double averageDensity = countRatioColumn.mean(); + + for (Row row : resultTable) { + Double value = row.getDouble("density"); + if (averageDensity != 0) { + row.setDouble("relative_density", value / averageDensity); + } else { + row.setDouble("relative_density", 0.0); + } + } + + + resultTable.write().csv(output.getPath("activities_%s_per_region.csv", activity).toFile()); + log.info("Wrote activity counts for {} to {}", activity, output.getPath("activities_%s_per_region.csv", activity)); + } + + return 0; + } +} diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/TravelTimeComparison.java b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/TravelTimeComparison.java index 3c22fc678a3..41abdbcff54 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/TravelTimeComparison.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/TravelTimeComparison.java @@ -1,5 +1,7 @@ package org.matsim.application.analysis.traffic.traveltime; +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; @@ -47,6 +49,8 @@ ) public class TravelTimeComparison implements MATSimAppCommand { + private static final Logger log = LogManager.getLogger(TravelTimeComparison.class); + @CommandLine.Mixin private InputOptions input = InputOptions.ofCommand(TravelTimeComparison.class); @@ -90,6 +94,13 @@ public Integer call() throws Exception { for (Row row : data) { LeastCostPathCalculator.Path congested = computePath(network, congestedRouter, row); + + // Skip if path is not found + if (congested == null) { + row.setDouble("simulated", Double.NaN); + continue; + } + double dist = congested.links.stream().mapToDouble(Link::getLength).sum(); double speed = 3.6 * dist / congested.travelTime; @@ -102,6 +113,8 @@ public Integer call() throws Exception { row.setDouble("free_flow", speed); } + data = data.dropWhere(data.doubleColumn("simulated").isMissing()); + data.addColumns( data.doubleColumn("simulated").subtract(data.doubleColumn("mean")).setName("bias") ); @@ -129,6 +142,16 @@ private LeastCostPathCalculator.Path computePath(Network network, LeastCostPathC Node fromNode = network.getNodes().get(Id.createNodeId(row.getString("from_node"))); Node toNode = network.getNodes().get(Id.createNodeId(row.getString("to_node"))); + if (fromNode == null) { + log.error("Node {} not found in network", row.getString("from_node")); + return null; + } + + if (toNode == null) { + log.error("Node {} not found in network", row.getString("to_node")); + return null; + } + return router.calcLeastCostPath(fromNode, toNode, row.getInt("hour") * 3600, null, null); } diff --git a/contribs/application/src/main/java/org/matsim/application/options/ShpOptions.java b/contribs/application/src/main/java/org/matsim/application/options/ShpOptions.java index 5d9f8ccec99..55b7e01846e 100644 --- a/contribs/application/src/main/java/org/matsim/application/options/ShpOptions.java +++ b/contribs/application/src/main/java/org/matsim/application/options/ShpOptions.java @@ -230,6 +230,7 @@ public Geometry getGeometry() { /** * Return the union of all geometries in the shape file and project it to the target crs. + * * @param toCRS target coordinate system */ public Geometry getGeometry(String toCRS) { diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/Data.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/Data.java index d13bbc48ae4..16029040d47 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/Data.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/Data.java @@ -3,8 +3,10 @@ import org.apache.commons.io.FilenameUtils; import org.matsim.application.CommandRunner; import org.matsim.application.MATSimAppCommand; +import org.matsim.core.utils.io.IOUtils; import javax.annotation.Nullable; +import java.io.UncheckedIOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Path; @@ -154,13 +156,40 @@ public String subcommand(String command, String file) { */ public String resource(String name) { - URL resource = this.getClass().getResource(name); + String path = resolveResource(name, true); + + // Handle shape files separately, copy additional files that are known to belong to shp files + if (name.endsWith(".shp")) { + resolveResource(name.replace(".shp", ".cpg"), false); + resolveResource(name.replace(".shp", ".dbf"), false); + resolveResource(name.replace(".shp", ".qix"), false); + resolveResource(name.replace(".shp", ".qmd"), false); + resolveResource(name.replace(".shp", ".prj"), false); + resolveResource(name.replace(".shp", ".shx"), false); + } + + return path; + } + + private String resolveResource(String name, boolean required) { + URL resource = null; + + try { + resource = IOUtils.resolveFileOrResource(name); + } catch (UncheckedIOException e) { + // Nothing to do + } if (resource == null) { // Try to prefix / automatically resource = this.getClass().getResource("/" + name); - if (resource == null) + } + + if (resource == null) { + if (required) throw new IllegalArgumentException("Resource '" + name + "' not found!"); + else + return null; } String baseName = FilenameUtils.getName(resource.getPath()); diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperConfigGroup.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperConfigGroup.java index 6bb420d1292..0914fda1eb7 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperConfigGroup.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperConfigGroup.java @@ -1,5 +1,6 @@ package org.matsim.simwrapper; +import org.matsim.core.config.Config; import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.ReflectiveConfigGroup; @@ -28,6 +29,10 @@ public class SimWrapperConfigGroup extends ReflectiveConfigGroup { @Comment("Set of simple class names or fully qualified class names of dashboards to exclude") public Set exclude = new HashSet<>(); + @Parameter + @Comment("Set of simple class names or fully qualified class names of dashboards to include. Any none included dashboard will be excluded.") + public Set include = new HashSet<>(); + @Parameter @Comment("Sample size of the run, which may be required by certain analysis functions.") public Double sampleSize = 1.0d; @@ -83,6 +88,15 @@ public void addParameterSet(ConfigGroup set) { } } + @Override + protected void checkConsistency(Config config) { + super.checkConsistency(config); + + if (!include.isEmpty() && !exclude.isEmpty()) { + throw new IllegalStateException("Include and exclude option can't be set both."); + } + } + /** * Mode how default dashboards are loaded. */ diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperListener.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperListener.java index 1270c938ee4..b9bd8c261a3 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperListener.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/SimWrapperListener.java @@ -34,8 +34,8 @@ public class SimWrapperListener implements StartupListener, ShutdownListener { @Inject public SimWrapperListener(SimWrapper simWrapper, Set bindings, Config config) { this.simWrapper = simWrapper; - this.bindings = bindings; - this.config = config; + this.bindings = bindings; + this.config = config; } /** @@ -105,6 +105,9 @@ private void addFromProvider(SimWrapperConfigGroup config, Iterable exclude; + @CommandLine.Option(names = "--include", split = ",", description = "Use only the dashboards which classnames match.") + private Set include; + public static void main(String[] args) { new SimWrapperRunner().execute(args); } @@ -58,6 +61,8 @@ public Integer call() throws Exception { if (exclude != null) simWrapperConfigGroup.exclude.addAll(exclude); + if (include != null) + simWrapperConfigGroup.include.addAll(include); SimWrapperListener listener = new SimWrapperListener(SimWrapper.create(config), config); try { diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/ActivityDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/ActivityDashboard.java new file mode 100644 index 00000000000..5561ea641e8 --- /dev/null +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/ActivityDashboard.java @@ -0,0 +1,185 @@ +package org.matsim.simwrapper.dashboard; + +import org.apache.commons.lang3.StringUtils; +import org.matsim.application.analysis.activity.ActivityCountAnalysis; +import org.matsim.simwrapper.Dashboard; +import org.matsim.simwrapper.Header; +import org.matsim.simwrapper.Layout; +import org.matsim.simwrapper.viz.ColorScheme; +import org.matsim.simwrapper.viz.MapPlot; +import org.matsim.simwrapper.viz.TextBlock; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Dashboard to show activity related statistics aggregated by type and location. + *

+ * Note that {@link #addActivityType(String, List, List, boolean, String)} needs to be called for each activity type. + * There is no default configuration. + */ +public class ActivityDashboard implements Dashboard { + + private static final String ID_COLUMN = "id"; + private static final String REF_JOIN = "id"; + + private final String shpFile; + private final Map activityMapping = new LinkedHashMap<>(); + private final Map refCsvs = new LinkedHashMap<>(); + private final Set countMultipleOccurrencesSet = new HashSet<>(); + private List indicators = new ArrayList<>(); + + public ActivityDashboard(String shpFile) { + this.shpFile = Objects.requireNonNull(shpFile, "Shapefile can not be null!"); + } + + /** + * Convenience method to add an activity type with default configuration. + */ + public ActivityDashboard addActivityType(String name, List activities, List indicators) { + return addActivityType(name, activities, indicators, true, null); + } + + /** + * Add an activity type to the dashboard. + * + * @param name name to show in the dashboard + * @param activities List of activity names to include in this type + * @param indicators List of indicators to show + * @param countMultipleOccurrences Whether multiple occurrences of the same activity for one person should be counted. + * Can be used to count home or workplaces only once. + * @param refCsv Reference CSV file to compare the activities to. Can be null. + */ + public ActivityDashboard addActivityType(String name, List activities, List indicators, + boolean countMultipleOccurrences, @Nullable String refCsv) { + activityMapping.put(name, String.join(",", activities)); + refCsvs.put(name, refCsv); + + if (countMultipleOccurrences) { + countMultipleOccurrencesSet.add(name); + } + + this.indicators = indicators; + return this; + } + + @Override + public void configure(Header header, Layout layout) { + + header.title = "Activities"; + header.description = "Displays the activities by type and location."; + + List args = new ArrayList<>(List.of("--id-column", ID_COLUMN, "--shp", shpFile)); + args.add("--activity-mapping"); + args.add(activityMapping.entrySet().stream() + .map(e -> "%s=%s".formatted(e.getKey(), e.getValue())) + .collect(Collectors.joining(";"))); + + args.add("--single-occurrence"); + if (!countMultipleOccurrencesSet.isEmpty()) { + args.add(String.join(";", countMultipleOccurrencesSet)); + } + + + for (Map.Entry activity : activityMapping.entrySet()) { + + String activityName = StringUtils.capitalize(activity.getKey()); + + layout.row("category_header_" + activity.getKey()) + .el(TextBlock.class, (viz, data) -> { + viz.content = "## **" + activityName + "**"; + viz.backgroundColor = "transparent"; + }); + + for (Indicator ind : Indicator.values()) { + + if (indicators.contains(ind)) { + + Layout.Row row = layout.row(activity.getKey() + "_" + ind.name) + .el(MapPlot.class, (viz, data) -> { + viz.title = "Simulated %s Activities (%s)".formatted(activityName, ind.displayName); + viz.height = 8.; + String shp = data.resource(shpFile); + viz.setShape(shp, ID_COLUMN); + viz.addDataset("transit-trips", data.computeWithPlaceholder(ActivityCountAnalysis.class, "activities_%s_per_region.csv", activity.getKey(), args.toArray(new String[0]))); + viz.display.fill.columnName = ind.name; + viz.display.fill.dataset = "transit-trips"; + viz.display.fill.join = REF_JOIN; + if (ind == Indicator.RELATIVE_DENSITY) { + viz.display.fill.setColorRamp(ColorScheme.RdBu, 11, false, "0.2, 0.25, 0.33, 0.5, 0.67, 1.5, 2.0, 3.0, 4.0, 5.0"); + } + }); + + if (refCsvs.get(activity.getKey()) != null) { + row.el(MapPlot.class, (viz, data) -> { + + viz.title = "Reference %s Activities (%s)".formatted(activityName, ind.displayName); + viz.height = 8.; + + String shp = data.resource(shpFile); + viz.setShape(shp, ID_COLUMN); + + viz.addDataset("transit-trips", data.resource(refCsvs.get(activity.getKey()))); + + viz.display.fill.dataset = "transit-trips"; + viz.display.fill.join = REF_JOIN; + + if (ind == Indicator.RELATIVE_DENSITY) { + viz.display.fill.columnName = "relative_density"; + viz.display.fill.setColorRamp(ColorScheme.RdBu, 11, false, "0.2, 0.25, 0.33, 0.5, 0.67, 1.5, 2.0, 3.0, 4.0, 5.0"); + } else if (ind == Indicator.DENSITY) { + viz.display.fill.columnName = "density"; + } else { + viz.display.fill.columnName = "count"; + } + }); + } + } + } + } + } + + /** + * Metric to show in the dashboard. + */ + public enum Indicator { + COUNTS("count", "Counts"), + DENSITY("density", "Density"), + RELATIVE_DENSITY("relative_density", "Relative Density"); + + private final String name; + private final String displayName; + + Indicator(String name, String displayName) { + this.name = name; + this.displayName = displayName; + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/MapPlot.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/MapPlot.java index ac675cc6381..96ea10d5d94 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/MapPlot.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/MapPlot.java @@ -10,15 +10,14 @@ */ public final class MapPlot extends Viz { + private final Map datasets = new HashMap<>(); public double[] center; public Double zoom; - public Display display = new Display(); public Double minValue; public Double maxValue; @JsonProperty(required = true) private Object shapes; - private Map datasets = new HashMap<>(); public MapPlot() { super("map"); @@ -77,6 +76,9 @@ public static final class DisplaySettings { @JsonProperty(required = true) public String columnName; + @JsonProperty(required = true) + public String normalize; + @JsonProperty(required = true) public String join; diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java index e3e92fa87a7..a741dfeba78 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java @@ -20,11 +20,12 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.List; import java.util.Set; public class DashboardTests { @RegisterExtension - private MatsimTestUtils utils = new MatsimTestUtils(); + private final MatsimTestUtils utils = new MatsimTestUtils(); private void run(Dashboard... dashboards) { @@ -153,4 +154,20 @@ void ptCustom() { Assertions.assertThat(out) .isDirectoryContaining("glob:**pt_pax_volumes.csv.gz"); } + + @Test + void activity() { + ActivityDashboard ad = new ActivityDashboard("kehlheim_shape.shp"); + + ad.addActivityType( + "work", + List.of("work"), + List.of(ActivityDashboard.Indicator.COUNTS, ActivityDashboard.Indicator.RELATIVE_DENSITY, ActivityDashboard.Indicator.DENSITY), true, + "kehlheim_ref.csv" + ); + + run(ad); + } + + } diff --git a/contribs/simwrapper/src/test/resources/kehlheim_ref.csv b/contribs/simwrapper/src/test/resources/kehlheim_ref.csv new file mode 100644 index 00000000000..1b3ba9c3824 --- /dev/null +++ b/contribs/simwrapper/src/test/resources/kehlheim_ref.csv @@ -0,0 +1,12 @@ +id;count;area;density;relative_density +2;12000.0;1743518.43;0.006882634;1.07723188785 +6;11000.0;350075.92;0.031421756;3.91795945 +4;2000.0;545791.40;0.003664404;0.5735321986 +8;13000.0;2121061.25;0.006129007;0.9592783427 +9;15000.0;3785838.06;0.003962135;0.6201314016 +10;7000.0;5744728.89;0.001218508;0.19071418629999998 +1;2000.0;1981892.09;0.001009137;0.19071418629999998 +3;12000.0;1955593.52;0.006136245;0.9604110622400001 +7;7000.0;942460.23;0.007427369;1.1624907459 +5;1000.0;876651.07;0.001140705;0.1785367932 +0;8000.0;6205676.03;0.001289142;0.2017694383 \ No newline at end of file diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.cpg b/contribs/simwrapper/src/test/resources/kehlheim_shape.cpg new file mode 100644 index 00000000000..3ad133c048f --- /dev/null +++ b/contribs/simwrapper/src/test/resources/kehlheim_shape.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.dbf b/contribs/simwrapper/src/test/resources/kehlheim_shape.dbf new file mode 100644 index 0000000000000000000000000000000000000000..d3b37577b5dff9efce8a897c02f1f0018b8ded66 GIT binary patch literal 187 zcmZRs;TGX$U|?`$0Fjs=GX*Z@2V!x-xex}g0vs5@SqjDorU`;+ieQ={nC1wk1%hb_ OXBry7nF>fuLn#13UJ_6M literal 0 HcmV?d00001 diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.prj b/contribs/simwrapper/src/test/resources/kehlheim_shape.prj new file mode 100644 index 00000000000..bd846aeb220 --- /dev/null +++ b/contribs/simwrapper/src/test/resources/kehlheim_shape.prj @@ -0,0 +1 @@ +PROJCS["ETRS_1989_UTM_Zone_32N",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.qmd b/contribs/simwrapper/src/test/resources/kehlheim_shape.qmd new file mode 100644 index 00000000000..53f5af5ac96 --- /dev/null +++ b/contribs/simwrapper/src/test/resources/kehlheim_shape.qmd @@ -0,0 +1,44 @@ + + + + + + dataset + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.shp b/contribs/simwrapper/src/test/resources/kehlheim_shape.shp new file mode 100644 index 0000000000000000000000000000000000000000..ff0f9b67afd83cba76787f3f2db8f4f606c8669a GIT binary patch literal 4476 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 literal 0 HcmV?d00001 diff --git a/contribs/simwrapper/src/test/resources/kehlheim_shape.shx b/contribs/simwrapper/src/test/resources/kehlheim_shape.shx new file mode 100644 index 0000000000000000000000000000000000000000..1be796e8141d61ef66765e3577cb6dce8dc65f5b GIT binary patch literal 188 zcmZQzQ0HR64&q)gGcd3M<#wH7^?5W;)p66Gw5i@}LL3T*1J=Xa%HCFfcH&0qFoB9R;LsFfcHi0p&Ot7+9Pj@~nJ7z5oLQn-YX( Khstw+ Date: Thu, 19 Dec 2024 13:35:57 +0100 Subject: [PATCH 23/39] Noise maintenance: Add an option to independently enable or disable reflection calculation, regardless of noise shielding. --- .../contrib/noise/NoiseConfigGroup.java | 23 +- .../contrib/noise/RLS19NoiseImmission.java | 34 +-- .../contrib/noise/ReflectionContext.java | 35 +-- .../contrib/noise/ShieldingContext.java | 249 ++++++++---------- 4 files changed, 159 insertions(+), 182 deletions(-) diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java index c2c9bc8d039..0833d66f019 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java @@ -43,7 +43,7 @@ * Provides the parameters required to build a simple grid with some basic spatial functionality. * Provides the parameters required to compute noise emissions, immissions and damages. * - * @author ikaddoura + * @author ikaddoura, nkuehnel */ public final class NoiseConfigGroup extends ReflectiveConfigGroup { @@ -81,6 +81,7 @@ public final class NoiseConfigGroup extends ReflectiveConfigGroup { private static final String RECEIVER_POINT_GAP_CMT = "horizontal and vertical distance between receiver points in x-/y-coordinate units"; private static final String WRITE_OUTPUT_ITERATION_CMT = "Specifies how often the noise-specific output is written out."; private static final String CONSIDER_NOISE_BARRIERS = "considerNoiseBarriers"; + private static final String CONSIDER_NOISE_REFLECTION = "considerNoiseReflection"; private static final String NOISE_BARRIERS_GEOJSON_FILE = "noiseBarriersGeojsonPath"; private static final String NOISE_BARRIERS_SOURCE_CRS = "source coordinate reference system of noise barriers geojson file"; private static final String NETWORK_MODES_TO_IGNORE = "networkModesToIgnore"; @@ -142,6 +143,7 @@ public enum NoiseAllocationApproach { private double noiseTollFactor = 1.0; private boolean considerNoiseBarriers = false; + private boolean considerNoiseReflection = false; private String noiseBarriersFilePath = null; private String noiseBarriersSourceCrs = null; @@ -204,6 +206,7 @@ public Map getComments() { comments.put(NOISE_TOLL_FACTOR, "To be used for sensitivity analysis. Default: 1.0 (= the parameter has no effect)"); comments.put(CONSIDER_NOISE_BARRIERS, "Set to 'true' if noise barriers / building shielding should be considered. Otherwise set to 'false'."); + comments.put(CONSIDER_NOISE_REFLECTION, "Set to 'true' if reflections should be considered. Otherwise set to 'false'. Has a considerable performance impact."); comments.put(NOISE_BARRIERS_GEOJSON_FILE, "Path to the geojson file for noise barriers."); comments.put(NOISE_BARRIERS_SOURCE_CRS, "Source coordinate reference system of noise barriers geojson file."); @@ -308,6 +311,14 @@ private void checkNoiseParametersForConsistency(Config config) { + " It is therefore recommended not to use speeds outside of the range of valid parameters!"); } + if(considerNoiseReflection) { + if (!this.considerNoiseBarriers) { + if (this.noiseBarriersFilePath == null || "".equals(this.noiseBarriersFilePath)) { + log.warn("Cannot consider noise reflection without a specified file path to the geojson file of barriers / buildings."); + this.considerNoiseBarriers = false; + } + } + } if (this.considerNoiseBarriers) { if (this.noiseBarriersFilePath == null || "".equals(this.noiseBarriersFilePath)) { log.warn("Cannot consider noise barriers without a specified file path to the geojson file of barriers / buildings."); @@ -782,6 +793,16 @@ public void setConsiderNoiseBarriers(boolean considerNoiseBarriers) { this.considerNoiseBarriers = considerNoiseBarriers; } + @StringGetter(CONSIDER_NOISE_REFLECTION) + public boolean isConsiderNoiseReflection() { + return this.considerNoiseReflection; + } + + @StringSetter(CONSIDER_NOISE_REFLECTION) + public void setConsiderNoiseReflection(boolean considerNoiseReflection) { + this.considerNoiseReflection = considerNoiseReflection; + } + @StringGetter(NOISE_BARRIERS_GEOJSON_FILE) public String getNoiseBarriersFilePath() { return this.noiseBarriersFilePath; diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/RLS19NoiseImmission.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/RLS19NoiseImmission.java index 1e8f1cd2563..e0bb566141c 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/RLS19NoiseImmission.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/RLS19NoiseImmission.java @@ -101,7 +101,9 @@ public double calculateCorrection(double projectedDistance, NoiseReceiverPoint n @Override public void setCurrentRp(NoiseReceiverPoint nrp) { - reflection.setCurrentReceiver(nrp); + if(noiseParams.isConsiderNoiseReflection()) { + reflection.setCurrentReceiver(nrp); + } } private double getSectionsCorrection(NoiseReceiverPoint nrp, Link link) { @@ -127,10 +129,12 @@ private double getSubSectionsCorrection(Coordinate nrpCoordinate, LineSegment se final double sectionCorrection = 10 * Math.log10(length) - calculateCorrection(nrpCoordinate, segment, null); correctionTemp += Math.pow(10, 0.1*sectionCorrection); - final Set reflectionLinks = reflection.getReflections(segment); - for(ReflectionContext.ReflectionTuple reflection: reflectionLinks) { - double sectionCorrectionReflection = 10 * Math.log10(reflection.reflectionLink.getLength()) - calculateCorrection(nrpCoordinate, reflection.reflectionLink, reflection.facade); - correctionTemp += Math.pow(10, 0.1 * sectionCorrectionReflection); + if(noiseParams.isConsiderNoiseReflection()) { + final Set reflectionLinks = reflection.getReflections(segment); + for (ReflectionContext.ReflectionTuple reflection : reflectionLinks) { + double sectionCorrectionReflection = 10 * Math.log10(reflection.reflectionLink().getLength()) - calculateCorrection(nrpCoordinate, reflection.reflectionLink(), reflection.facade()); + correctionTemp += Math.pow(10, 0.1 * sectionCorrectionReflection); + } } } else { double lMid = length / 2; @@ -149,10 +153,12 @@ private double getSubSectionsCorrection(Coordinate nrpCoordinate, LineSegment se final double sectionCorrection = 10 * Math.log10(central.getLength()) - calculateCorrection(nrpCoordinate, central, null); correctionTemp += Math.pow(10, 0.1 * sectionCorrection); - final Set reflectionLinks = reflection.getReflections(central); - for(ReflectionContext.ReflectionTuple reflection: reflectionLinks) { - double sectionCorrectionReflection = 10 * Math.log10(reflection.reflectionLink.getLength()) - calculateCorrection(nrpCoordinate, reflection.reflectionLink, reflection.facade); - correctionTemp += Math.pow(10, 0.1 * sectionCorrectionReflection); + if(noiseParams.isConsiderNoiseReflection()) { + final Set reflectionLinks = reflection.getReflections(central); + for (ReflectionContext.ReflectionTuple reflection : reflectionLinks) { + double sectionCorrectionReflection = 10 * Math.log10(reflection.reflectionLink().getLength()) - calculateCorrection(nrpCoordinate, reflection.reflectionLink(), reflection.facade()); + correctionTemp += Math.pow(10, 0.1 * sectionCorrectionReflection); + } } correctionTemp += getSubSectionsCorrection(nrpCoordinate, leftRemaining); @@ -174,7 +180,10 @@ private double calculateCorrection(Coordinate nrp, LineSegment segment, LineSegm //to maintain the correct signs. nk, Sep'20 double intersectionCorrection = intersection.calculateIntersectionCorrection(coordinate); - double multipleReflectionCorrection = reflection.getMultipleReflectionCorrection(segment); + double multipleReflectionCorrection = 0; + if(noiseParams.isConsiderNoiseReflection()) { + multipleReflectionCorrection = reflection.getMultipleReflectionCorrection(segment); + } double geometricDivergence = 20 * Math.log10(distance) + 10 * Math.log10(2 * Math.PI); double airDampeningFactor = distance / 200.; @@ -191,11 +200,6 @@ private double calculateCorrection(Coordinate nrp, LineSegment segment, LineSegm } else { return geometricDivergence + airDampeningFactor - intersectionCorrection + groundDampening ; } - - //TODO: implement reflection - if someone is looking for a (bachelor) thesis... -// double firstReflectionCorrection = 0; -// double secondReflectionCorrection = 0; -// return dampeningCorrection + firstReflectionCorrection + secondReflectionCorrection; } diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/ReflectionContext.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/ReflectionContext.java index 02639ac3d3b..145367afee6 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/ReflectionContext.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/ReflectionContext.java @@ -1,5 +1,6 @@ package org.matsim.contrib.noise; +import jakarta.inject.Inject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.algorithm.Angle; @@ -7,7 +8,6 @@ import org.locationtech.jts.geom.util.AffineTransformation; import org.matsim.core.config.Config; -import jakarta.inject.Inject; import java.util.*; /** @@ -15,18 +15,19 @@ * * @author nkuehnel */ -public class ReflectionContext { +public final class ReflectionContext { static final double SCAN_LINE_LENGTH = 1; - private final static Logger logger = LogManager.getLogger(org.matsim.contrib.noise.ShieldingContext.class); + private final static Logger logger = LogManager.getLogger(ReflectionContext.class); private Set visibleEdges; private Coordinate receiver; - private BarrierContext barrierContext; - private GeometryFactory geomFactory = new GeometryFactory(); + private final BarrierContext barrierContext; + private final GeometryFactory geomFactory = new GeometryFactory(); + record ReflectionTuple(LineSegment facade, LineSegment reflectionLink) { } @Inject ReflectionContext(BarrierContext barrierContext) { @@ -38,6 +39,7 @@ public class ReflectionContext { } void setCurrentReceiver(NoiseReceiverPoint nrp) { + receiver = new Coordinate(nrp.getCoord().getX(), nrp.getCoord().getY()); final Collection candidates = @@ -60,7 +62,7 @@ void setCurrentReceiver(NoiseReceiverPoint nrp) { } - Set findVisibleEdgesOfPolygon(List polygonEdges, Coordinate coordinate) { + private Set findVisibleEdgesOfPolygon(List polygonEdges, Coordinate coordinate) { Coordinate coordXinc = new Coordinate(coordinate.x + 1, coordinate.y); @@ -155,13 +157,9 @@ Set getReflections(LineSegment originalLink) { } } return reflections; -// return Collections.EMPTY_SET; } double getMultipleReflectionCorrection(LineSegment segment) { - if(this.receiver.x == 1420 && this.receiver.y == 20) { - System.out.println("jo"); - } final Coordinate coordinate = segment.midPoint(); Coordinate candidateRight = getReflectionSegment(coordinate, segment, 400); @@ -174,7 +172,7 @@ Set getReflections(LineSegment originalLink) { } else { return 0; } - if (candidateLeft != null && candidateRight != null){ + if (candidateLeft != null){ double w = candidateLeft.distance(candidateRight); return Math.min(2 * Math.min(candidateLeft.z, candidateRight.z) / w, 1.6); } @@ -265,7 +263,7 @@ private boolean hit(LineSegment facade, LineSegment originalLink) { return true; } - static boolean intersects(LineSegment segment1, LineSegment segment2) { + private static boolean intersects(LineSegment segment1, LineSegment segment2) { double dx0 = segment1.p1.x - segment1.p0.x; double dx1 = segment2.p1.x - segment2.p0.x; @@ -277,17 +275,6 @@ static boolean intersects(LineSegment segment1, LineSegment segment2) { double p1 = dy1 * (segment2.p1.x - segment1.p1.x) - dx1 * (segment2.p1.y - segment1.p1.y); double p2 = dy0 * (segment1.p1.x - segment2.p0.x) - dx0 * (segment1.p1.y - segment2.p0.y); double p3 = dy0 * (segment1.p1.x - segment2.p1.x) - dx0 * (segment1.p1.y - segment2.p1.y); - return (p0 * p1 <= 0) & (p2 * p3 <= 0); - } - - - static class ReflectionTuple { - final LineSegment facade; - final LineSegment reflectionLink; - - public ReflectionTuple(LineSegment facade, LineSegment reflectionLink) { - this.facade = facade; - this.reflectionLink = reflectionLink; - } + return (p0 * p1 <= 0) && (p2 * p3 <= 0); } } diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/ShieldingContext.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/ShieldingContext.java index 97af40ce515..ea4e97ca7e6 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/ShieldingContext.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/ShieldingContext.java @@ -24,8 +24,6 @@ final class ShieldingContext { private final static Logger logger = LogManager.getLogger(ShieldingContext.class); - //STRtree increases performance by ~40% by reducing the amount of potential - //obstruction candidates. nkuehnel, mar '20 private final static double GROUND_HEIGHT = 0.5; private final ShieldingCorrection shieldingCorrection; @@ -35,7 +33,6 @@ final class ShieldingContext { ShieldingContext(Config config, ShieldingCorrection shieldingCorrection, BarrierContext barrierContext) { this.shieldingCorrection = shieldingCorrection; this.barrierContext = barrierContext; - NoiseConfigGroup noiseParams = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class); } ShieldingContext(ShieldingCorrection shieldingCorrection, BarrierContext barrierContext) { @@ -51,83 +48,73 @@ final class ShieldingContext { final Coordinate midPoint = segment.midPoint(); midPoint.z = GROUND_HEIGHT; -// final Point fromPoint = GeometryUtils.createGeotoolsPoint(link.getFromNode().getCoord()); -// final Point toPoint = GeometryUtils.createGeotoolsPoint(link.getToNode().getCoord()); - - Coordinate from = segment.p0; - Coordinate to = segment.p1; - LineString projectedLineOfSight = constructLineOfSight(rpPoint, midPoint); -// LineString fromLineOfSight = constructLineOfSight(rpPoint, from); -// LineString toLineOfSight = constructLineOfSight(rpPoint, to); NavigableMap edgeCandidates = getObstructionEdges(rpPoint, midPoint, projectedLineOfSight); edgeCandidates.put(projectedLineOfSight.getLength(), midPoint); - if (!edgeCandidates.isEmpty()) { - Coordinate lastFixedEdge = rpPoint; - Coordinate tmpEdge = rpPoint; - double currentHeight = GROUND_HEIGHT; + Coordinate lastFixedEdge = rpPoint; + Coordinate tmpEdge = rpPoint; + double currentHeight = GROUND_HEIGHT; - List consideredEdges = new ArrayList<>(); + List consideredEdges = new ArrayList<>(); - double distToCurrentEdge = 0; - while (lastFixedEdge != midPoint) { - if (edgeCandidates.isEmpty()) { - logger.warn("Skipping obstacle as distance appears to be 0."); - return correctionTermShielding; - } - Iterator edgesIterator = edgeCandidates.values().iterator(); - double maxSlope = Double.NEGATIVE_INFINITY; - double tmpDistance = 0; - while (edgesIterator.hasNext()) { - Coordinate edge = edgesIterator.next(); - double distance = lastFixedEdge.distance(edge); - double slope = (edge.z - currentHeight) / distance; - if (slope >= maxSlope) { - maxSlope = slope; - tmpEdge = edge; - tmpDistance = distance; - } + double distToCurrentEdge = 0; + while (lastFixedEdge != midPoint) { + if (edgeCandidates.isEmpty()) { + logger.warn("Skipping obstacle as distance appears to be 0."); + return correctionTermShielding; + } + Iterator edgesIterator = edgeCandidates.values().iterator(); + double maxSlope = Double.NEGATIVE_INFINITY; + double tmpDistance = 0; + while (edgesIterator.hasNext()) { + Coordinate edge = edgesIterator.next(); + double distance = lastFixedEdge.distance(edge); + double slope = (edge.z - currentHeight) / distance; + if (slope >= maxSlope) { + maxSlope = slope; + tmpEdge = edge; + tmpDistance = distance; } - lastFixedEdge = tmpEdge; - distToCurrentEdge += tmpDistance; - currentHeight = tmpEdge.z; - consideredEdges.add(lastFixedEdge); - edgeCandidates = edgeCandidates.tailMap(distToCurrentEdge, false); } + lastFixedEdge = tmpEdge; + distToCurrentEdge += tmpDistance; + currentHeight = tmpEdge.z; + consideredEdges.add(lastFixedEdge); + edgeCandidates = edgeCandidates.tailMap(distToCurrentEdge, false); + } - consideredEdges.remove(midPoint); + consideredEdges.remove(midPoint); - if (consideredEdges.isEmpty()) { - return correctionTermShielding; - } + if (consideredEdges.isEmpty()) { + return correctionTermShielding; + } - final double firstEdgeYDiff = GROUND_HEIGHT - consideredEdges.get(0).z; - double firstEdgeDistance = rpPoint.distance(consideredEdges.get(0)); - double receiverToFirstEdgeDistance - = Math.sqrt(firstEdgeYDiff * firstEdgeYDiff + firstEdgeDistance * firstEdgeDistance); - - double shieldingDepth = 0; - - Iterator it = consideredEdges.iterator(); - Coordinate edgeTemp = it.next(); - while (it.hasNext()) { - Coordinate edge = it.next(); - double xyDiff = edgeTemp.distance(edge); - double zDiff = edgeTemp.z - edge.z; - shieldingDepth += Math.sqrt(xyDiff * xyDiff + zDiff * zDiff); - edgeTemp = edge; - } + final double firstEdgeYDiff = GROUND_HEIGHT - consideredEdges.get(0).z; + double firstEdgeDistance = rpPoint.distance(consideredEdges.get(0)); + double receiverToFirstEdgeDistance + = Math.sqrt(firstEdgeYDiff * firstEdgeYDiff + firstEdgeDistance * firstEdgeDistance); + + double shieldingDepth = 0; + + Iterator it = consideredEdges.iterator(); + Coordinate edgeTemp = it.next(); + while (it.hasNext()) { + Coordinate edge = it.next(); + double xyDiff = edgeTemp.distance(edge); + double zDiff = edgeTemp.z - edge.z; + shieldingDepth += Math.sqrt(xyDiff * xyDiff + zDiff * zDiff); + edgeTemp = edge; + } - final double lastEdgeSourceXYDiff = midPoint.distance(edgeTemp); - final double lastEdgeSourceZDiff = GROUND_HEIGHT - edgeTemp.z; - double lastEdgeToSourceDistance = Math.sqrt(lastEdgeSourceXYDiff * lastEdgeSourceXYDiff - + lastEdgeSourceZDiff * lastEdgeSourceZDiff); + final double lastEdgeSourceXYDiff = midPoint.distance(edgeTemp); + final double lastEdgeSourceZDiff = GROUND_HEIGHT - edgeTemp.z; + double lastEdgeToSourceDistance = Math.sqrt(lastEdgeSourceXYDiff * lastEdgeSourceXYDiff + + lastEdgeSourceZDiff * lastEdgeSourceZDiff); - correctionTermShielding = shieldingCorrection.calculateShieldingCorrection( - rpPoint.distance(midPoint), lastEdgeToSourceDistance, receiverToFirstEdgeDistance, shieldingDepth); - } + correctionTermShielding = shieldingCorrection.calculateShieldingCorrection( + rpPoint.distance(midPoint), lastEdgeToSourceDistance, receiverToFirstEdgeDistance, shieldingDepth); return correctionTermShielding; } @@ -170,7 +157,6 @@ private ConcurrentSkipListMap getObstructionEdges(Coordinate //using intersects() and intersection() directly on the jts geometry. nkuehnel, aug '20 final Set intersections = intersection((Polygon) noiseBarrier.getGeometry().getGeometry(), directLineOfSight.getCoordinates()); - for (Coordinate coordinate : intersections) { coordinate.z = noiseBarrier.getHeight(); final double distance = receiver.distance(coordinate); @@ -226,25 +212,7 @@ private LineString constructLineOfSight(Coordinate receiver, Coordinate source) private Set intersection(Polygon polygon, Coordinate[] coords) { - - Set externalIntersections = intersection(polygon.getExteriorRing(), coords); - -// Set internalIntersections = null; -// for (int i = 0; i < polygon.getNumInteriorRing(); i++) { -// Set intersects = intersection(polygon.getInteriorRingN(i), coords); -// if (!intersects.isEmpty()) { -// if (internalIntersections == null) { -// internalIntersections = new HashSet<>(); -// } -// internalIntersections.addAll(intersects); -// } -// } - -// if(internalIntersections != null) { -// externalIntersections.addAll(internalIntersections); -// } - - return externalIntersections; + return intersection(polygon.getExteriorRing(), coords); } private Set intersection(LineString ring, Coordinate[] coords) { @@ -285,7 +253,6 @@ private static boolean intersects(Polygon polygon, LineString string) { } - /** * determines the shielding value z for a receiver point for a given link emission source */ @@ -305,70 +272,68 @@ private static boolean intersects(Polygon polygon, LineString string) { NavigableMap edgeCandidates = getObstructionEdges(rpPoint, projectedPoint, projectedLineOfSight, fromLineOfSight, toLineOfSight); edgeCandidates.put(projectedLineOfSight.getLength(), projectedPoint.getCoordinate()); - if (!edgeCandidates.isEmpty()) { - Coordinate lastFixedEdge = rpPoint.getCoordinate(); - Coordinate tmpEdge = rpPoint.getCoordinate(); - double currentHeight = GROUND_HEIGHT; + Coordinate lastFixedEdge = rpPoint.getCoordinate(); + Coordinate tmpEdge = rpPoint.getCoordinate(); + double currentHeight = GROUND_HEIGHT; - List consideredEdges = new ArrayList<>(); + List consideredEdges = new ArrayList<>(); - double distToCurrentEdge = 0; - while (lastFixedEdge != projectedPoint.getCoordinate()) { - if (edgeCandidates.isEmpty()) { - logger.warn("Skipping obstacle as distance appears to be 0."); - return correctionTermShielding; - } - Iterator edgesIterator = edgeCandidates.values().iterator(); - double maxSlope = Double.NEGATIVE_INFINITY; - double tmpDistance = 0; - while (edgesIterator.hasNext()) { - Coordinate edge = edgesIterator.next(); - double distance = lastFixedEdge.distance(edge); - double slope = (edge.z - currentHeight) / distance; - if (slope >= maxSlope) { - maxSlope = slope; - tmpEdge = edge; - tmpDistance = distance; - } + double distToCurrentEdge = 0; + while (lastFixedEdge != projectedPoint.getCoordinate()) { + if (edgeCandidates.isEmpty()) { + logger.warn("Skipping obstacle as distance appears to be 0."); + return correctionTermShielding; + } + Iterator edgesIterator = edgeCandidates.values().iterator(); + double maxSlope = Double.NEGATIVE_INFINITY; + double tmpDistance = 0; + while (edgesIterator.hasNext()) { + Coordinate edge = edgesIterator.next(); + double distance = lastFixedEdge.distance(edge); + double slope = (edge.z - currentHeight) / distance; + if (slope >= maxSlope) { + maxSlope = slope; + tmpEdge = edge; + tmpDistance = distance; } - lastFixedEdge = tmpEdge; - distToCurrentEdge += tmpDistance; - currentHeight = tmpEdge.z; - consideredEdges.add(lastFixedEdge); - edgeCandidates = edgeCandidates.tailMap(distToCurrentEdge, false); } + lastFixedEdge = tmpEdge; + distToCurrentEdge += tmpDistance; + currentHeight = tmpEdge.z; + consideredEdges.add(lastFixedEdge); + edgeCandidates = edgeCandidates.tailMap(distToCurrentEdge, false); + } - consideredEdges.remove(projectedPoint.getCoordinate()); + consideredEdges.remove(projectedPoint.getCoordinate()); - if (consideredEdges.isEmpty()) { - return correctionTermShielding; - } + if (consideredEdges.isEmpty()) { + return correctionTermShielding; + } - final double firstEdgeYDiff = GROUND_HEIGHT - consideredEdges.get(0).z; - double firstEdgeDistance = rpPoint.getCoordinate().distance(consideredEdges.get(0)); - double receiverToFirstEdgeDistance - = Math.sqrt(firstEdgeYDiff * firstEdgeYDiff + firstEdgeDistance * firstEdgeDistance); - - double shieldingDepth = 0; - - Iterator it = consideredEdges.iterator(); - Coordinate edgeTemp = it.next(); - while (it.hasNext()) { - Coordinate edge = it.next(); - double xyDiff = edgeTemp.distance(edge); - double zDiff = edgeTemp.z - edge.z; - shieldingDepth += Math.sqrt(xyDiff * xyDiff + zDiff * zDiff); - edgeTemp = edge; - } + final double firstEdgeYDiff = GROUND_HEIGHT - consideredEdges.getFirst().z; + double firstEdgeDistance = rpPoint.getCoordinate().distance(consideredEdges.getFirst()); + double receiverToFirstEdgeDistance + = Math.sqrt(firstEdgeYDiff * firstEdgeYDiff + firstEdgeDistance * firstEdgeDistance); + + double shieldingDepth = 0; + + Iterator it = consideredEdges.iterator(); + Coordinate edgeTemp = it.next(); + while (it.hasNext()) { + Coordinate edge = it.next(); + double xyDiff = edgeTemp.distance(edge); + double zDiff = edgeTemp.z - edge.z; + shieldingDepth += Math.sqrt(xyDiff * xyDiff + zDiff * zDiff); + edgeTemp = edge; + } - final double lastEdgeSourceXYDiff = projectedPoint.getCoordinate().distance(edgeTemp); - final double lastEdgeSourceZDiff = GROUND_HEIGHT - edgeTemp.z; - double lastEdgeToSourceDistance = Math.sqrt(lastEdgeSourceXYDiff * lastEdgeSourceXYDiff - + lastEdgeSourceZDiff * lastEdgeSourceZDiff); + final double lastEdgeSourceXYDiff = projectedPoint.getCoordinate().distance(edgeTemp); + final double lastEdgeSourceZDiff = GROUND_HEIGHT - edgeTemp.z; + double lastEdgeToSourceDistance = Math.sqrt(lastEdgeSourceXYDiff * lastEdgeSourceXYDiff + + lastEdgeSourceZDiff * lastEdgeSourceZDiff); - correctionTermShielding = shieldingCorrection.calculateShieldingCorrection( - rpPoint.distance(projectedPoint), lastEdgeToSourceDistance, receiverToFirstEdgeDistance, shieldingDepth); - } + correctionTermShielding = shieldingCorrection.calculateShieldingCorrection( + rpPoint.distance(projectedPoint), lastEdgeToSourceDistance, receiverToFirstEdgeDistance, shieldingDepth); return correctionTermShielding; } } From 2c26b6ab612995f6cec658b26ee9d49853d8517b Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 12:40:52 +0100 Subject: [PATCH 24/39] add getId() and getDemand() to interface --- .../matsim/freight/carriers/CarrierJob.java | 6 +++- .../freight/carriers/CarrierService.java | 29 ++++++++++++------- .../freight/carriers/CarrierShipment.java | 23 +++++++++++---- 3 files changed, 42 insertions(+), 16 deletions(-) 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 index 1dc1cd32f8d..926c5ae379f 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierJob.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/CarrierJob.java @@ -1,5 +1,6 @@ package org.matsim.freight.carriers; +import org.matsim.api.core.v01.Id; import org.matsim.utils.objectattributes.attributable.Attributable; /** @@ -16,4 +17,7 @@ * 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 {} +public interface CarrierJob extends Attributable { + Id getId(); + int getDemand(); +} 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 69a5ce75e42..244c95dd409 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 @@ -23,7 +23,6 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; -import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; @@ -41,7 +40,7 @@ public static Builder newInstance(Id id, Id locationLinkId private double serviceTime = 0.0; private TimeWindow timeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - private int capacityDemand = 0; + private int demand = 0; private Builder(Id id, Id locationLinkId) { super(); @@ -84,7 +83,7 @@ public CarrierService build(){ } public Builder setCapacityDemand(int value) { - this.capacityDemand = value; + this.demand = value; return this; } @@ -92,17 +91,11 @@ public Builder setCapacityDemand(int value) { private final Id id; - private final Id locationId; - private final String name; - private final double serviceDuration; - private final TimeWindow timeWindow; - private final int demand; - private final Attributes attributes = new AttributesImpl(); private CarrierService(Builder builder){ @@ -110,14 +103,17 @@ private CarrierService(Builder builder){ locationId = builder.locationLinkId; serviceDuration = builder.serviceTime; timeWindow = builder.timeWindow; - demand = builder.capacityDemand; + demand = builder.demand; name = builder.name; } + @Override public Id getId() { return id; } + + public Id getLocationLinkId() { return locationId; } @@ -130,10 +126,23 @@ public TimeWindow getServiceStartTimeWindow(){ return timeWindow; } + /** + * @deprecated please inline and use {@link #getDemand()} instead + */ + @Deprecated(since = "dez 2024") public int getCapacityDemand() { + return getDemand(); + } + + /** + * @return the demand (size; capacity needed) of the service. + */ + @Override + public int getDemand() { return demand; } + @Override public Attributes getAttributes() { return attributes; 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 01c8b873e70..3cb62a59182 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 @@ -23,7 +23,6 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; -import org.matsim.utils.objectattributes.attributable.Attributable; import org.matsim.utils.objectattributes.attributable.Attributes; import org.matsim.utils.objectattributes.attributable.AttributesImpl; @@ -136,7 +135,7 @@ public CarrierShipment build(){ private final Id id; private final Id from; private final Id to; - private final int size; + private final int demand; private final TimeWindow pickupTimeWindow; private final TimeWindow deliveryTimeWindow; private double pickupServiceTime; @@ -148,7 +147,7 @@ private CarrierShipment(Builder builder) { id = builder.id; from = builder.from; to = builder.to; - size = builder.size; + demand = builder.size; pickupServiceTime = builder.pickServiceTime; deliveryServiceTime = builder.delServiceTime; pickupTimeWindow = builder.pickTW; @@ -171,9 +170,11 @@ public void setDeliveryServiceTime(double deliveryServiceTime) { this.deliveryServiceTime = deliveryServiceTime; } + @Override public Id getId() { return id; } + public Id getFrom() { return from; } @@ -182,8 +183,20 @@ public Id getTo() { return to; } + /** + * @deprecated please inline and use {@link #getDemand()} instead + */ + @Deprecated(since = "dez 2024") public int getSize() { - return size; + return getDemand(); + } + + /** + * @return the demand (size; capacity needed) of the shipment. + */ + @Override + public int getDemand() { + return demand; } public TimeWindow getPickupTimeWindow() { @@ -201,7 +214,7 @@ public Attributes getAttributes() { @Override public String toString() { - return "[id= "+ id.toString() + "][hash=" + this.hashCode() + "][from=" + from.toString() + "][to=" + to.toString() + "][size=" + size + "][pickupServiceTime=" + pickupServiceTime + "]" + + return "[id= "+ id.toString() + "][hash=" + this.hashCode() + "][from=" + from.toString() + "][to=" + to.toString() + "][size=" + demand + "][pickupServiceTime=" + pickupServiceTime + "]" + "[deliveryServiceTime="+deliveryServiceTime+"][pickupTimeWindow="+pickupTimeWindow+"][deliveryTimeWindow="+deliveryTimeWindow+"]"; } From 9e964e0c937bec769766c15c8c039545b219e166 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 12:44:21 +0100 Subject: [PATCH 25/39] replace getSize() and getCapacityDemand() by new method getDemand() --- .../DemandReaderFromCSV.java | 4 +- .../DemandReaderFromCSVTest.java | 98 ++++++++++--------- .../carriers/CarrierPlanXmlWriterV2_1.java | 6 +- .../freight/carriers/CarriersUtils.java | 2 +- .../analysis/CarrierPlanAnalysis.java | 8 +- .../events/CarrierServiceStartEvent.java | 2 +- .../CarrierShipmentDeliveryEndEvent.java | 2 +- .../CarrierShipmentDeliveryStartEvent.java | 2 +- .../events/CarrierShipmentPickupEndEvent.java | 2 +- .../CarrierShipmentPickupStartEvent.java | 2 +- .../carriers/jsprit/MatsimJspritFactory.java | 6 +- .../multipleChains/MultipleChainsUtils.java | 2 +- .../freight/carriers/CarriersUtilsTest.java | 2 +- .../jsprit/MatsimTransformerTest.java | 4 +- .../utils/CarrierControllerUtilsTest.java | 16 +-- .../CollectionTrackerTest.java | 3 +- .../CollectionLSPSchedulingTest.java | 4 +- .../CompleteLSPSchedulingTest.java | 16 +-- .../FirstReloadLSPSchedulingTest.java | 6 +- .../MainRunLSPSchedulingTest.java | 10 +- ...eShipmentsCollectionLSPSchedulingTest.java | 4 +- ...pleShipmentsCompleteLSPSchedulingTest.java | 16 +-- ...ShipmentsFirstReloadLSPSchedulingTest.java | 6 +- ...ipleShipmentsMainRunLSPSchedulingTest.java | 16 +-- ...hipmentsSecondReloadLSPSchedulingTest.java | 18 ++-- .../SecondReloadLSPSchedulingTest.java | 12 +-- ...iverTriggersCarrierReplanningListener.java | 2 +- 27 files changed, 137 insertions(+), 134 deletions(-) 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 63179128cc4..3f7c9c242e0 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -1200,7 +1200,7 @@ private static void combineSimilarJobs(Scenario scenario) { double serviceTimePickup = 0; double serviceTimeDelivery = 0; for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { - demandForThisLink = demandForThisLink + carrierShipment.getSize(); + demandForThisLink = demandForThisLink + carrierShipment.getDemand(); serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); @@ -1245,7 +1245,7 @@ private static void combineSimilarJobs(Scenario scenario) { int demandForThisLink = 0; double serviceTimeService = 0; for (CarrierService carrierService : servicesToConnect.values()) { - demandForThisLink = demandForThisLink + carrierService.getCapacityDemand(); + demandForThisLink = demandForThisLink + carrierService.getDemand(); serviceTimeService = serviceTimeService + carrierService.getServiceDuration(); servicesToRemove.put(carrierService.getId(), carrierService); } 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 9cd21c16d9d..0658741aacd 100644 --- a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java +++ b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java @@ -101,9 +101,9 @@ void demandCreationWithSampleWithChangeNumberOfLocations() throws IOException { 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(5, shipment.getSize()); + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + Assertions.assertEquals(5, shipment.getDemand()); Assertions.assertEquals(2000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(1250, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); @@ -168,9 +168,9 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { 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()); + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + Assertions.assertEquals(10, shipment.getDemand()); Assertions.assertEquals(4000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(2500, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); @@ -235,9 +235,9 @@ void demandCreationWithSampleWithDemandOnLocationWithCombiningJobs() throws IOEx 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()); + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + Assertions.assertEquals(10, shipment.getDemand()); Assertions.assertEquals(4000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(2500, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); @@ -305,9 +305,9 @@ void demandCreationNoSampling() throws IOException { 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()); + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + Assertions.assertEquals(10, shipment.getDemand()); Assertions.assertEquals(4000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(2500, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); @@ -474,25 +474,27 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt 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) { + countServicesWithCertainDemand.merge((Integer) service.getDemand(), 1, Integer::sum); + countDemand = countDemand + service.getDemand(); + if (service.getDemand() == 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 if (service.getCapacityDemand() == 1) { + } else if (service.getDemand() == 1) { Assertions.assertEquals(100, service.getServiceDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) .add(service.getLocationLinkId().toString()); - } else if (service.getCapacityDemand() == 2) { - Assertions.assertEquals(200, service.getServiceDuration(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); - locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) - .add(service.getLocationLinkId().toString()); - } else - Assertions.fail("Service has a wrong demand."); + } else { + if (service.getDemand() == 2) { + Assertions.assertEquals(200, service.getServiceDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); + locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) + .add(service.getLocationLinkId().toString()); + } else + Assertions.fail("Service has a wrong demand."); + } } Assertions.assertEquals(12, countDemand); Assertions.assertEquals(4, countServicesWithCertainDemand.getInt(0)); @@ -520,9 +522,9 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt 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) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + if (shipment.getDemand() == 0) { Assertions.assertEquals(300, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(350, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupTimeWindow()); @@ -531,7 +533,7 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) .add(shipment.getTo().toString()); - } else if (shipment.getSize() == 2) { + } else if (shipment.getDemand() == 2) { Assertions.assertEquals(400, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(400, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); @@ -540,17 +542,19 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) .add(shipment.getTo().toString()); - } else if (shipment.getSize() == 3) { - Assertions.assertEquals(600, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(600, 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()); - } else - Assertions.fail("Shipment has an unexpected demand."); + } else { + if (shipment.getDemand() == 3) { + Assertions.assertEquals(600, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(600, 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()); + } else + Assertions.fail("Shipment has an unexpected demand."); + } } Assertions.assertEquals(15, countDemand); Assertions.assertEquals(4, countShipmentsWithCertainDemand.getInt(0)); @@ -579,15 +583,15 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ 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) { + countServicesWithCertainDemand.merge((Integer) service.getDemand(), 1, Integer::sum); + countDemand = countDemand + service.getDemand(); + if (service.getDemand() == 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(service.getDemand() * 100, service.getServiceDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) .add(service.getLocationLinkId().toString()); @@ -617,9 +621,9 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ 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) { + countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); + countDemand = countDemand + shipment.getDemand(); + if (shipment.getDemand() == 0) { Assertions.assertEquals(300, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(350, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupTimeWindow()); @@ -629,8 +633,8 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ 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(shipment.getDemand() * 200, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(shipment.getDemand() * 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<>()) 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 6195fb3834f..421ef4b2754 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 @@ -157,11 +157,11 @@ private void writeShipments(Carrier carrier, BufferedWriter writer) { } private void writeShipment(CarrierShipment s, Id shipmentId, boolean closeElement, boolean lineBreak) { - this.writeStartTag(SHIPMENT, List.of( + this.writeStartTag(SHIPMENT, List.of( createTuple(ID, shipmentId.toString()), createTuple(FROM, s.getFrom().toString()), createTuple(TO, s.getTo().toString()), - createTuple(SIZE, s.getSize()), + createTuple(SIZE, s.getDemand()), createTuple(START_PICKUP, getTime(s.getPickupTimeWindow().getStart())), createTuple(END_PICKUP, getTime(s.getPickupTimeWindow().getEnd())), createTuple(START_DELIVERY, getTime(s.getDeliveryTimeWindow().getStart())), @@ -191,7 +191,7 @@ private void writeService(CarrierService s, boolean closeElement, boolean lineBr this.writeStartTag(SERVICE, List.of( createTuple(ID, s.getId().toString()), createTuple(TO, s.getLocationLinkId().toString()), - createTuple(CAPACITY_DEMAND, s.getCapacityDemand()), + createTuple(CAPACITY_DEMAND, s.getDemand()), createTuple(EARLIEST_START, getTime(s.getServiceStartTimeWindow().getStart())), createTuple(LATEST_END, getTime(s.getServiceStartTimeWindow().getEnd())), createTuple(SERVICE_DURATION, getTime(s.getServiceDuration()))), closeElement, lineBreak 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 1b6a270e65e..ed8267d89b0 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 @@ -431,7 +431,7 @@ private static void createShipmentsFromServices(Carrier carrierWS, Carrier carri CarrierShipment carrierShipment = CarrierShipment.Builder .newInstance(Id.create(carrierService.getId().toString(), CarrierShipment.class), depotServiceIsDeliveredFrom.get(carrierService.getId()), carrierService.getLocationLinkId(), - carrierService.getCapacityDemand()) + carrierService.getDemand()) .setDeliveryServiceTime(carrierService.getServiceDuration()) // .setPickupServiceTime(pickupServiceTime) //Not set yet, because in service we // have now time for that. Maybe change it later, kmt sep18 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 362dfaf8793..7c73cb9b551 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 @@ -101,16 +101,16 @@ public void runAnalysisAndWriteStats(String analysisOutputDirectory) throws IOEx int numberOfHandledDemandSize; int notHandledJobs; if (numberOfPlanedShipments > 0) { - numberOfPlanedDemandSize = carrier.getShipments().values().stream().mapToInt(CarrierShipment::getSize).sum(); + numberOfPlanedDemandSize = carrier.getShipments().values().stream().mapToInt(carrierShipment -> carrierShipment.getDemand()).sum(); numberOfHandledDemandSize = carrier.getSelectedPlan().getScheduledTours().stream().mapToInt( t -> t.getTour().getTourElements().stream().filter(te -> te instanceof Tour.Pickup).mapToInt( - te -> (((Tour.Pickup) te).getShipment().getSize())).sum()).sum(); + te -> ((Tour.Pickup) te).getShipment().getDemand()).sum()).sum(); notHandledJobs = numberOfPlanedShipments - numberOfHandledPickups; } else { - numberOfPlanedDemandSize = carrier.getServices().values().stream().mapToInt(CarrierService::getCapacityDemand).sum(); + numberOfPlanedDemandSize = carrier.getServices().values().stream().mapToInt(carrierService -> carrierService.getDemand()).sum(); numberOfHandledDemandSize = carrier.getSelectedPlan().getScheduledTours().stream().mapToInt( t -> t.getTour().getTourElements().stream().filter(te -> te instanceof Tour.ServiceActivity).mapToInt( - te -> ((Tour.ServiceActivity) te).getService().getCapacityDemand()).sum()).sum(); + te -> ((Tour.ServiceActivity) te).getService().getDemand()).sum()).sum(); notHandledJobs = numberOfPlanedServices - nuOfServiceHandled; } 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 d1b4d816ace..2bf7829807e 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 @@ -47,7 +47,7 @@ public CarrierServiceStartEvent(double time, Id carrierId, CarrierServi super(time, carrierId, service.getLocationLinkId(), vehicleId); this.serviceId = service.getId(); this.serviceDuration = service.getServiceDuration(); - this.capacityDemand = service.getCapacityDemand(); + this.capacityDemand = service.getDemand(); } @Override 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 8f60260a067..35fe77cdea6 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 @@ -47,7 +47,7 @@ public CarrierShipmentDeliveryEndEvent(double time, Id carrierId, Carri super(time, carrierId, shipment.getTo(), vehicleId); this.shipmentId = shipment.getId(); this.deliveryDuration = shipment.getDeliveryServiceTime(); - this.capacityDemand = shipment.getSize(); + this.capacityDemand = shipment.getDemand(); } @Override 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 a30035968c0..300590482df 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 @@ -48,7 +48,7 @@ public CarrierShipmentDeliveryStartEvent(double time, Id carrierId, Car super(time, carrierId, shipment.getTo(), vehicleId); this.shipmentId = shipment.getId(); this.deliveryDuration = shipment.getDeliveryServiceTime(); - this.capacityDemand = shipment.getSize(); + this.capacityDemand = shipment.getDemand(); } @Override 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 4316e6f4dfe..1a80be89293 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 @@ -49,7 +49,7 @@ public CarrierShipmentPickupEndEvent(double time, Id carrierId, Carrier super(time, carrierId, shipment.getFrom(), vehicleId); this.shipmentId = shipment.getId(); this.pickupDuration = shipment.getPickupServiceTime(); - this.capacityDemand = shipment.getSize(); + this.capacityDemand = shipment.getDemand(); } 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 fe851a10138..bbc912645fb 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 @@ -47,7 +47,7 @@ public CarrierShipmentPickupStartEvent(double time, Id carrierId, Carri super(time, carrierId, shipment.getFrom(), vehicleId); this.shipmentId = shipment.getId(); this.pickupDuration = shipment.getPickupServiceTime(); - this.capacityDemand = shipment.getSize(); + this.capacityDemand = shipment.getDemand(); } 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 00cf9347716..5ec272cc6c2 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 @@ -118,7 +118,7 @@ static Shipment createJspritShipment(CarrierShipment carrierShipment) { .setPickupTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( carrierShipment.getPickupTimeWindow().getStart(), carrierShipment.getPickupTimeWindow().getEnd())) - .addSizeDimension(0, carrierShipment.getSize()); + .addSizeDimension(0, carrierShipment.getDemand()); for (String skill : CarriersUtils.getSkills(carrierShipment)) { shipmentBuilder.addRequiredSkill(skill); } @@ -149,7 +149,7 @@ static Shipment createJspritShipment(CarrierShipment carrierShipment, Coord from .setPickupTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( carrierShipment.getPickupTimeWindow().getStart(), carrierShipment.getPickupTimeWindow().getEnd())) - .addSizeDimension(0, carrierShipment.getSize()); + .addSizeDimension(0, carrierShipment.getDemand()); for (String skill : CarriersUtils.getSkills(carrierShipment)) { shipmentBuilder.addRequiredSkill(skill); } @@ -165,7 +165,7 @@ static Service createJspritService(CarrierService carrierService, Coord location Location location = locationBuilder.build(); Builder serviceBuilder = Builder.newInstance(carrierService.getId().toString()); - serviceBuilder.addSizeDimension(0, carrierService.getCapacityDemand()); + serviceBuilder.addSizeDimension(0, carrierService.getDemand()); serviceBuilder.setLocation(location).setServiceTime(carrierService.getServiceDuration()) .setTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( carrierService.getServiceStartTimeWindow().getStart(), 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 index 30517805da5..cc19c5c2064 100644 --- 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 @@ -59,7 +59,7 @@ public static Collection createLSPShipmentsFromCarrierShipments(Car LspShipmentUtils.LspShipmentBuilder builder = LspShipmentUtils.LspShipmentBuilder.newInstance( Id.create(shipment.getId().toString(), LspShipment.class)); - builder.setCapacityDemand(shipment.getSize()); + builder.setCapacityDemand(shipment.getDemand()); builder.setFromLinkId(shipment.getFrom()); builder.setToLinkId(shipment.getTo()); builder.setStartTimeWindow(shipment.getPickupTimeWindow()); 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 fe0428621e0..6f4ac797052 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 @@ -105,7 +105,7 @@ void testAddAndGetShipmentToCarrier() { Assertions.assertEquals(shipmentId, carrierShipment1b.getId()); Assertions.assertEquals(service1.getId(), carrierShipment1b.getId()); Assertions.assertEquals(Id.createLinkId("link0"), carrierShipment1b.getFrom()); - Assertions.assertEquals(20, carrierShipment1b.getSize(), EPSILON); + Assertions.assertEquals(20, carrierShipment1b.getDemand(), EPSILON); } @Test 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 5025334cc5e..08929c96408 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 @@ -148,7 +148,7 @@ void whenTransforming_jspritService2matsimService_isMadeCorrectly() { assertNotNull(service); assertEquals("locationId", service.getLocationLinkId().toString()); assertEquals(30.0, service.getServiceDuration(), 0.01); - assertEquals(50, service.getCapacityDemand()); + assertEquals(50, service.getDemand()); assertEquals(10.0, service.getServiceStartTimeWindow().getStart(), 0.01); CarrierService service2 = MatsimJspritFactory.createCarrierService(carrierService); @@ -201,7 +201,7 @@ void whenTransforming_jspritShipment2matsimShipment_isMadeCorrectly() { assertEquals(40.0, carrierShipment.getDeliveryServiceTime(), 0.01); assertEquals(50.0, carrierShipment.getDeliveryTimeWindow().getStart(), 0.01); assertEquals(60.0, carrierShipment.getDeliveryTimeWindow().getEnd(), 0.01); - assertEquals(50, carrierShipment.getSize()); + assertEquals(50, carrierShipment.getDemand()); CarrierShipment carrierShipment2 = MatsimJspritFactory.createCarrierShipment(shipment); assertNotSame(carrierShipment, carrierShipment2); 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 1896021e805..f6bb1b42ee0 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 @@ -165,7 +165,7 @@ void numberOfInitialServicesIsCorrect() { int demandServices = 0; for (CarrierService carrierService : carrierWServices.getServices().values()) { - demandServices += carrierService.getCapacityDemand(); + demandServices += carrierService.getDemand(); } Assertions.assertEquals(4, demandServices); @@ -180,7 +180,7 @@ void numberOfInitialShipmentsIsCorrect() { Assertions.assertEquals(2, carrierWShipments.getShipments().size()); int demandShipments = 0; for (CarrierShipment carrierShipment : carrierWShipments.getShipments().values()) { - demandShipments += carrierShipment.getSize(); + demandShipments += carrierShipment.getDemand(); } Assertions.assertEquals(3, demandShipments); } @@ -192,7 +192,7 @@ void numberOfShipmentsFromCopiedShipmentsIsCorrect() { Assertions.assertEquals(2, carrierWShipmentsOnlyFromCarrierWShipments.getShipments().size()); int demandShipments = 0; for (CarrierShipment carrierShipment : carrierWShipmentsOnlyFromCarrierWServices.getShipments().values()) { - demandShipments += carrierShipment.getSize(); + demandShipments += carrierShipment.getDemand(); } Assertions.assertEquals(4, demandShipments); } @@ -204,7 +204,7 @@ void numberOfShipmentsFromConvertedServicesIsCorrect() { Assertions.assertEquals(2, carrierWShipmentsOnlyFromCarrierWServices.getShipments().size()); int demandShipments = 0; for (CarrierShipment carrierShipment : carrierWShipmentsOnlyFromCarrierWServices.getShipments().values()) { - demandShipments += carrierShipment.getSize(); + demandShipments += carrierShipment.getDemand(); } Assertions.assertEquals(4, demandShipments); } @@ -246,7 +246,7 @@ void copyingOfShipmentsIsDoneCorrectly() { foundShipment1 = true; Assertions.assertEquals(Id.createLinkId("i(1,0)"), carrierShipment1.getFrom()); Assertions.assertEquals(Id.createLinkId("i(7,6)R"), carrierShipment1.getTo()); - Assertions.assertEquals(1, carrierShipment1.getSize()); + Assertions.assertEquals(1, carrierShipment1.getDemand()); Assertions.assertEquals(30.0, carrierShipment1.getDeliveryServiceTime(), 0); Assertions.assertEquals(3600.0, carrierShipment1.getDeliveryTimeWindow().getStart(), 0); Assertions.assertEquals(36000.0, carrierShipment1.getDeliveryTimeWindow().getEnd(), 0); @@ -261,7 +261,7 @@ void copyingOfShipmentsIsDoneCorrectly() { foundShipment2 = true; Assertions.assertEquals(Id.createLinkId("i(3,0)"), carrierShipment2.getFrom()); Assertions.assertEquals(Id.createLinkId("i(3,7)"), carrierShipment2.getTo()); - Assertions.assertEquals(2, carrierShipment2.getSize()); + Assertions.assertEquals(2, carrierShipment2.getDemand()); Assertions.assertEquals(30.0, carrierShipment2.getDeliveryServiceTime(), 0); Assertions.assertEquals(3600.0, carrierShipment2.getDeliveryTimeWindow().getStart(), 0); Assertions.assertEquals(36000.0, carrierShipment2.getDeliveryTimeWindow().getEnd(), 0); @@ -284,7 +284,7 @@ void convertionOfServicesIsDoneCorrectly() { 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()); + Assertions.assertEquals(2, carrierShipment1.getDemand()); Assertions.assertEquals(31.0, carrierShipment1.getDeliveryServiceTime(), 0); Assertions.assertEquals(3601.0, carrierShipment1.getDeliveryTimeWindow().getStart(), 0); Assertions.assertEquals(36001.0, carrierShipment1.getDeliveryTimeWindow().getEnd(), 0); @@ -298,7 +298,7 @@ void convertionOfServicesIsDoneCorrectly() { foundService2 = true; Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment2.getFrom()); Assertions.assertEquals(Id.createLinkId("i(4,9)"), carrierShipment2.getTo()); - Assertions.assertEquals(2, carrierShipment2.getSize()); + Assertions.assertEquals(2, carrierShipment2.getDemand()); Assertions.assertEquals(31.0, carrierShipment2.getDeliveryServiceTime(), 0); Assertions.assertEquals(3601.0, carrierShipment2.getDeliveryTimeWindow().getStart(), 0); Assertions.assertEquals(36001.0, carrierShipment2.getDeliveryTimeWindow().getEnd(), 0); 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 index e72394b24ea..b1d60e9665a 100644 --- 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 @@ -56,7 +56,6 @@ 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; @@ -238,7 +237,7 @@ public void testCollectionTracker() { if (element instanceof ServiceActivity activity) { scheduledCosts += activity.getService().getServiceDuration() * scheduledTour.getVehicle().getType().getCostInformation().getCostsPerSecond(); totalScheduledCosts += scheduledCosts; - totalScheduledWeight += activity.getService().getCapacityDemand(); + totalScheduledWeight += activity.getService().getDemand(); totalNumberOfScheduledShipments++; } } 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 index 5e071b894d4..d031c5f6d1d 100644 --- 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 @@ -197,7 +197,7 @@ public void testCollectionLSPScheduling() { 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().getDemand(), 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); @@ -212,7 +212,7 @@ public void testCollectionLSPScheduling() { 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().getDemand(), 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); 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 index c4fd34c0fd3..3a6a13e629a 100644 --- 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 @@ -434,7 +434,7 @@ public void testCompletedLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -461,7 +461,7 @@ public void testCompletedLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), toLinkId); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -485,7 +485,7 @@ public void testCompletedLSPScheduling() { 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().getDemand(), 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); @@ -503,7 +503,7 @@ public void testCompletedLSPScheduling() { 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().getDemand(), 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); @@ -522,7 +522,7 @@ public void testCompletedLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -540,7 +540,7 @@ public void testCompletedLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); @@ -558,7 +558,7 @@ public void testCompletedLSPScheduling() { 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(lspTourStartEventHandler.getCarrierService().getDemand(), 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()); @@ -576,7 +576,7 @@ public void testCompletedLSPScheduling() { 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(distributionServiceHandler.getCarrierService().getDemand(), 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()); 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 index 3cead4c873c..5b724cf6a80 100644 --- 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 @@ -260,7 +260,7 @@ public void testFirstReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -284,7 +284,7 @@ public void testFirstReloadLSPScheduling() { 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().getDemand(), 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); @@ -297,7 +297,7 @@ public void testFirstReloadLSPScheduling() { 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().getDemand(), 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); 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 index 4a39f6c6170..8d653d8e171 100644 --- 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 @@ -325,7 +325,7 @@ public void testMainRunLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -351,7 +351,7 @@ public void testMainRunLSPScheduling() { 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().getDemand(), 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); @@ -369,7 +369,7 @@ public void testMainRunLSPScheduling() { 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().getDemand(), 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); @@ -388,7 +388,7 @@ public void testMainRunLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -406,7 +406,7 @@ public void testMainRunLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); 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 index d30d608f985..dd51e2d4e4a 100644 --- 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 @@ -199,7 +199,7 @@ public void testCollectionLSPScheduling() { 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().getDemand(), 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); @@ -212,7 +212,7 @@ public void testCollectionLSPScheduling() { 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().getDemand(), 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); 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 index f27a1e08219..481c48ec6ba 100644 --- 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 @@ -437,7 +437,7 @@ public void testCompletedLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -464,7 +464,7 @@ public void testCompletedLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), toLinkId); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -488,7 +488,7 @@ public void testCompletedLSPScheduling() { 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().getDemand(), 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); @@ -506,7 +506,7 @@ public void testCompletedLSPScheduling() { 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().getDemand(), 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); @@ -525,7 +525,7 @@ public void testCompletedLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -543,7 +543,7 @@ public void testCompletedLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); @@ -561,7 +561,7 @@ public void testCompletedLSPScheduling() { 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(lspTourStartEventHandler.getCarrierService().getDemand(), 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()); @@ -579,7 +579,7 @@ public void testCompletedLSPScheduling() { 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(distributionServiceHandler.getCarrierService().getDemand(), 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()); 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 index e1661887039..eb6af700893 100644 --- 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 @@ -259,7 +259,7 @@ public void testFirstReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -283,7 +283,7 @@ public void testFirstReloadLSPScheduling() { 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().getDemand(), 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); @@ -296,7 +296,7 @@ public void testFirstReloadLSPScheduling() { 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().getDemand(), 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); 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 index c9811f9e03d..f82bde886c8 100644 --- 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 @@ -222,16 +222,16 @@ public void initialize() { @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(); + System.out.println(); }*/ @@ -325,7 +325,7 @@ public void testMainRunLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -351,7 +351,7 @@ public void testMainRunLSPScheduling() { 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().getDemand(), 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); @@ -369,7 +369,7 @@ public void testMainRunLSPScheduling() { 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().getDemand(), 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); @@ -388,7 +388,7 @@ public void testMainRunLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -406,7 +406,7 @@ public void testMainRunLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); 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 index 23ee9f61e86..403bf619d90 100644 --- 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 @@ -251,14 +251,14 @@ public void initialize() { @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(element.getSolutionElement().getId() + " " + element.getResourceId() + " " + element.getElementType() + " " + element.getStartTime() + " " + element.getEndTime()); + } System.out.println(); }*/ @@ -369,7 +369,7 @@ public void testSecondReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : @@ -401,7 +401,7 @@ public void testSecondReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), toLinkId); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : reloadEventHandler.getTranshipmentHub().getClientElements()) { @@ -431,7 +431,7 @@ public void testSecondReloadLSPScheduling() { 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().getDemand(), 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); @@ -450,7 +450,7 @@ public void testSecondReloadLSPScheduling() { 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().getDemand(), 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); @@ -470,7 +470,7 @@ public void testSecondReloadLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -489,7 +489,7 @@ public void testSecondReloadLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); 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 index 6a37cd65697..08dbac36e8b 100644 --- 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 @@ -369,7 +369,7 @@ public void testSecondReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), shipment.getFrom()); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : @@ -407,7 +407,7 @@ public void testSecondReloadLSPScheduling() { LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; assertSame(service.getLocationLinkId(), toLinkId); - assertEquals(service.getCapacityDemand(), shipment.getSize()); + assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; for (LogisticChainElement clientElement : @@ -438,7 +438,7 @@ public void testSecondReloadLSPScheduling() { 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().getDemand(), 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); @@ -457,7 +457,7 @@ public void testSecondReloadLSPScheduling() { 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().getDemand(), 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); @@ -477,7 +477,7 @@ public void testSecondReloadLSPScheduling() { 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(mainRunStartHandler.getCarrierService().getDemand(), 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()); @@ -496,7 +496,7 @@ public void testSecondReloadLSPScheduling() { 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(mainRunEndHandler.getCarrierService().getDemand(), 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()); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java index 2b8c4a6dfb9..cf7b07dd8bd 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java @@ -86,7 +86,7 @@ public void notifyIterationStarts(IterationStartsEvent event) { // TODO This only looks at the FIRST time window. This may need revision once we handle multiple // time windows. .build(); - if (newShipment.getSize() != 0) { + if (newShipment.getDemand() != 0) { receiverOrder.getCarrier().getShipments().put(newShipment.getId(), newShipment ); } } From 91a19fb404f8bfdaff398ff350178e13f0dd0504 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 12:51:09 +0100 Subject: [PATCH 26/39] remove field name from CarrierService, incl. Builder --- .../org/matsim/freight/carriers/CarrierService.java | 13 ------------- .../main/java/org/matsim/freight/carriers/Tour.java | 2 +- .../matsim/freight/carriers/CarriersUtilsTest.java | 2 +- 3 files changed, 2 insertions(+), 15 deletions(-) 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 244c95dd409..94cd241d2b1 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 @@ -36,7 +36,6 @@ public static Builder newInstance(Id id, Id locationLinkId private final Id id; private final Id locationLinkId; - private String name = "service"; private double serviceTime = 0.0; private TimeWindow timeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); @@ -48,10 +47,6 @@ private Builder(Id id, Id locationLinkId) { this.locationLinkId = locationLinkId; } - public Builder setName(String name){ - this.name = name; - return this; - } /** * By default, it is [0.0,Integer.MaxValue]. @@ -92,7 +87,6 @@ public Builder setCapacityDemand(int value) { private final Id id; private final Id locationId; - private final String name; private final double serviceDuration; private final TimeWindow timeWindow; private final int demand; @@ -104,7 +98,6 @@ private CarrierService(Builder builder){ serviceDuration = builder.serviceTime; timeWindow = builder.timeWindow; demand = builder.demand; - name = builder.name; } @Override @@ -148,12 +141,6 @@ public Attributes getAttributes() { return attributes; } - /** - * @return the name - */ - public String getType() { - return name; - } @Override public String toString() { 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 55f72325237..aaf05ebbecc 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 @@ -374,7 +374,7 @@ public CarrierService getService(){ @Override public String getActivityType() { - return service.getType(); + return CarrierConstants.SERVICE; } @Override 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 6f4ac797052..9353d4d4034 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 @@ -68,7 +68,7 @@ void testAddAndGetServiceToCarrier() { Carrier carrier = new CarrierImpl(Id.create("carrier", Carrier.class)); Id serviceId = Id.create("testVehicle", CarrierService.class); CarrierService service1 = CarrierService.Builder.newInstance(serviceId,Id.createLinkId("link0") ) - .setName("service1").setCapacityDemand(15).setServiceDuration(30).build(); + .setCapacityDemand(15).setServiceDuration(30).build(); //add Service CarriersUtils.addService(carrier, service1); From 701b615f6e995ec5d5331b81d8ff893dad4a508a Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 12:54:55 +0100 Subject: [PATCH 27/39] reorder variables --- .../freight/carriers/CarrierService.java | 12 +++++++----- .../freight/carriers/CarrierShipment.java | 19 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) 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 94cd241d2b1..3b66fbfb657 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 @@ -35,11 +35,11 @@ public static Builder newInstance(Id id, Id locationLinkId } private final Id id; - private final Id locationLinkId; + private int demand = 0; - private double serviceTime = 0.0; + private final Id locationLinkId; private TimeWindow timeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - private int demand = 0; + private double serviceTime = 0.0; private Builder(Id id, Id locationLinkId) { super(); @@ -86,10 +86,12 @@ public Builder setCapacityDemand(int value) { private final Id id; + private final int demand; + private final Id locationId; - private final double serviceDuration; private final TimeWindow timeWindow; - private final int demand; + private final double serviceDuration; + private final Attributes attributes = new AttributesImpl(); private CarrierService(Builder builder){ 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 3cb62a59182..22d11824e3f 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 @@ -49,7 +49,6 @@ public static class Builder { * @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()]. * @@ -65,7 +64,6 @@ public static Builder newInstance(Id from, Id to, int size){ /** * 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()]. * @@ -80,12 +78,14 @@ public static Builder newInstance(Id id, Id from, Id id; - final Id from; - final Id to; final int size; + + final Id from; TimeWindow pickTW = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - TimeWindow delTW = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); double pickServiceTime = 0.0; + + final Id to; + TimeWindow delTW = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); double delServiceTime = 0.0; /** @@ -133,13 +133,16 @@ public CarrierShipment build(){ } private final Id id; - private final Id from; - private final Id to; private final int demand; + + private final Id from; private final TimeWindow pickupTimeWindow; - private final TimeWindow deliveryTimeWindow; private double pickupServiceTime; + + private final Id to; + private final TimeWindow deliveryTimeWindow; private double deliveryServiceTime; + private final Attributes attributes = new AttributesImpl(); From e700fea5075f89a5fbe577fdcaf4cbc9635569b7 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 12:59:14 +0100 Subject: [PATCH 28/39] rename internal variables --- .../freight/carriers/CarrierService.java | 40 ++++---- .../freight/carriers/CarrierShipment.java | 97 ++++++++++--------- 2 files changed, 68 insertions(+), 69 deletions(-) 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 3b66fbfb657..aeb26ce729f 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 @@ -30,21 +30,21 @@ public final class CarrierService implements CarrierJob { public static class Builder { - public static Builder newInstance(Id id, Id locationLinkId){ - return new Builder(id,locationLinkId); - } - private final Id id; private int demand = 0; - private final Id locationLinkId; - private TimeWindow timeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - private double serviceTime = 0.0; + private final Id serviceLinkId; + private TimeWindow serviceStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); + private double serviceDuration = 0.0; + + public static Builder newInstance(Id id, Id locationLinkId){ + return new Builder(id,locationLinkId); + } - private Builder(Id id, Id locationLinkId) { + private Builder(Id id, Id serviceLinkId) { super(); this.id = id; - this.locationLinkId = locationLinkId; + this.serviceLinkId = serviceLinkId; } @@ -55,7 +55,7 @@ private Builder(Id id, Id locationLinkId) { * @return the builder */ public Builder setServiceDuration(double serviceDuration){ - this.serviceTime = serviceDuration; + this.serviceDuration = serviceDuration; return this; } @@ -69,7 +69,7 @@ public Builder setServiceDuration(double serviceDuration){ * @return the builder */ public Builder setServiceStartTimeWindow(TimeWindow startTimeWindow){ - this.timeWindow = startTimeWindow; + this.serviceStartsTimeWindow = startTimeWindow; return this; } @@ -88,17 +88,17 @@ public Builder setCapacityDemand(int value) { private final Id id; private final int demand; - private final Id locationId; - private final TimeWindow timeWindow; + private final Id serviceLinkId; + private final TimeWindow serviceStartsTimeWindow; private final double serviceDuration; private final Attributes attributes = new AttributesImpl(); private CarrierService(Builder builder){ id = builder.id; - locationId = builder.locationLinkId; - serviceDuration = builder.serviceTime; - timeWindow = builder.timeWindow; + serviceLinkId = builder.serviceLinkId; + serviceDuration = builder.serviceDuration; + serviceStartsTimeWindow = builder.serviceStartsTimeWindow; demand = builder.demand; } @@ -107,10 +107,8 @@ public Id getId() { return id; } - - public Id getLocationLinkId() { - return locationId; + return serviceLinkId; } public double getServiceDuration() { @@ -118,7 +116,7 @@ public double getServiceDuration() { } public TimeWindow getServiceStartTimeWindow(){ - return timeWindow; + return serviceStartsTimeWindow; } /** @@ -146,7 +144,7 @@ public Attributes getAttributes() { @Override public String toString() { - return "[id=" + id + "][locationId=" + locationId + "][capacityDemand=" + demand + "][serviceDuration=" + serviceDuration + "][startTimeWindow=" + timeWindow + "]"; + return "[id=" + id + "][locationId=" + serviceLinkId + "][capacityDemand=" + demand + "][serviceDuration=" + serviceDuration + "][startTimeWindow=" + serviceStartsTimeWindow + "]"; } /* (non-Javadoc) 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 22d11824e3f..a9975bd7213 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 @@ -45,6 +45,18 @@ public final class CarrierShipment implements CarrierJob { */ public static class Builder { + Id id; + final int demand; + + final Id pickupLinkId; + TimeWindow pickupStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); + double pickupDuration = 0.0; + + final Id deliveryLinkId; + TimeWindow deliveryStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); + double deliveryDuration = 0.0; + + /** * @deprecated Please use Builder newInstance(Id id, Id from, Id to, int size) instead. *

@@ -77,53 +89,42 @@ public static Builder newInstance(Id id, Id from, Id id; - final int size; - - final Id from; - TimeWindow pickTW = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - double pickServiceTime = 0.0; - - final Id to; - TimeWindow delTW = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - double delServiceTime = 0.0; - /** * @deprecated Please use Builder (Id id, Id from, Id to, int size) instead. */ @Deprecated - public Builder(Id from, Id to, int size) { + public Builder(Id pickupLinkId, Id deliveryLinkId, int demand) { super(); - this.from = from; - this.to = to; - this.size = size; + this.pickupLinkId = pickupLinkId; + this.deliveryLinkId = deliveryLinkId; + this.demand = demand; } - public Builder(Id id, Id from, Id to, int size) { + public Builder(Id id, Id pickupLinkId, Id deliveryLinkId, int demand) { super(); this.id = id; - this.from = from; - this.to = to; - this.size = size; + this.pickupLinkId = pickupLinkId; + this.deliveryLinkId = deliveryLinkId; + this.demand = demand; } public Builder setPickupTimeWindow(TimeWindow pickupTW){ - this.pickTW = pickupTW; + this.pickupStartsTimeWindow = pickupTW; return this; } public Builder setDeliveryTimeWindow(TimeWindow deliveryTW){ - this.delTW = deliveryTW; + this.deliveryStartsTimeWindow = deliveryTW; return this; } public Builder setPickupServiceTime(double pickupServiceTime){ - this.pickServiceTime = pickupServiceTime; + this.pickupDuration = pickupServiceTime; return this; } public Builder setDeliveryServiceTime(double deliveryServiceTime){ - this.delServiceTime = deliveryServiceTime; + this.deliveryDuration = deliveryServiceTime; return this; } @@ -135,42 +136,42 @@ public CarrierShipment build(){ private final Id id; private final int demand; - private final Id from; - private final TimeWindow pickupTimeWindow; - private double pickupServiceTime; + private final Id pickupLinkId; + private final TimeWindow pickupStartsTimeWindow; + private double pickupDuration; - private final Id to; - private final TimeWindow deliveryTimeWindow; - private double deliveryServiceTime; + private final Id deliveryLinkId; + private final TimeWindow deliveryStartsTimeWindow; + private double deliveryDuration; private final Attributes attributes = new AttributesImpl(); private CarrierShipment(Builder builder) { id = builder.id; - from = builder.from; - to = builder.to; - demand = builder.size; - pickupServiceTime = builder.pickServiceTime; - deliveryServiceTime = builder.delServiceTime; - pickupTimeWindow = builder.pickTW; - deliveryTimeWindow = builder.delTW; + pickupLinkId = builder.pickupLinkId; + deliveryLinkId = builder.deliveryLinkId; + demand = builder.demand; + pickupDuration = builder.pickupDuration; + deliveryDuration = builder.deliveryDuration; + pickupStartsTimeWindow = builder.pickupStartsTimeWindow; + deliveryStartsTimeWindow = builder.deliveryStartsTimeWindow; } public double getPickupServiceTime() { - return pickupServiceTime; + return pickupDuration; } - public void setPickupServiceTime(double pickupServiceTime) { - this.pickupServiceTime = pickupServiceTime; + public void setPickupServiceTime(double pickupDuration) { + this.pickupDuration = pickupDuration; } public double getDeliveryServiceTime() { - return deliveryServiceTime; + return deliveryDuration; } - public void setDeliveryServiceTime(double deliveryServiceTime) { - this.deliveryServiceTime = deliveryServiceTime; + public void setDeliveryServiceTime(double deliveryDuration) { + this.deliveryDuration = deliveryDuration; } @Override @@ -179,11 +180,11 @@ public Id getId() { } public Id getFrom() { - return from; + return pickupLinkId; } public Id getTo() { - return to; + return deliveryLinkId; } /** @@ -203,11 +204,11 @@ public int getDemand() { } public TimeWindow getPickupTimeWindow() { - return pickupTimeWindow; + return pickupStartsTimeWindow; } public TimeWindow getDeliveryTimeWindow() { - return deliveryTimeWindow; + return deliveryStartsTimeWindow; } @Override @@ -217,8 +218,8 @@ public Attributes getAttributes() { @Override public String toString() { - return "[id= "+ id.toString() + "][hash=" + this.hashCode() + "][from=" + from.toString() + "][to=" + to.toString() + "][size=" + demand + "][pickupServiceTime=" + pickupServiceTime + "]" + - "[deliveryServiceTime="+deliveryServiceTime+"][pickupTimeWindow="+pickupTimeWindow+"][deliveryTimeWindow="+deliveryTimeWindow+"]"; + return "[id= "+ id.toString() + "][hash=" + this.hashCode() + "][from=" + pickupLinkId.toString() + "][to=" + deliveryLinkId.toString() + "][size=" + demand + "][pickupServiceTime=" + pickupDuration + "]" + + "[deliveryServiceTime="+ deliveryDuration +"][pickupTimeWindow="+ pickupStartsTimeWindow +"][deliveryTimeWindow="+ deliveryStartsTimeWindow +"]"; } /* (non-Javadoc) From 27984fad5eb186a2db2ff38a542367e7c5523fd7 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:04:34 +0100 Subject: [PATCH 29/39] make vars in Builder private --- .../matsim/freight/carriers/CarrierShipment.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 a9975bd7213..dd12b8957b8 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 @@ -45,16 +45,16 @@ public final class CarrierShipment implements CarrierJob { */ public static class Builder { - Id id; - final int demand; + private Id id; + private final int demand; - final Id pickupLinkId; - TimeWindow pickupStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - double pickupDuration = 0.0; + private final Id pickupLinkId; + private TimeWindow pickupStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); + private double pickupDuration = 0.0; - final Id deliveryLinkId; - TimeWindow deliveryStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); - double deliveryDuration = 0.0; + private final Id deliveryLinkId; + private TimeWindow deliveryStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); + private double deliveryDuration = 0.0; /** From 5d71e55677941b55c7307e3aada600845fcf0b14 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:09:44 +0100 Subject: [PATCH 30/39] make id final --- .../java/org/matsim/freight/carriers/CarrierShipment.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 dd12b8957b8..93e9dc590fe 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 @@ -45,7 +45,7 @@ public final class CarrierShipment implements CarrierJob { */ public static class Builder { - private Id id; + private final Id id; private final int demand; private final Id pickupLinkId; @@ -71,7 +71,8 @@ public static class Builder { */ @Deprecated public static Builder newInstance(Id from, Id to, int size){ - return new Builder(from,to,size); + var id = Id.create(CarrierConstants.SHIPMENT +"_" + from.toString() + "_" + to.toString(), CarrierShipment.class); + return new Builder(id, from,to,size); } /** @@ -95,6 +96,7 @@ public static Builder newInstance(Id id, Id from, Id pickupLinkId, Id deliveryLinkId, int demand) { super(); + this.id = Id.create(CarrierConstants.SHIPMENT +"_" + pickupLinkId.toString() + "_" + deliveryLinkId.toString(), CarrierShipment.class); this.pickupLinkId = pickupLinkId; this.deliveryLinkId = deliveryLinkId; this.demand = demand; From da488beb20239c73efbf4c4bc80f1d2dccbf448e Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:11:14 +0100 Subject: [PATCH 31/39] make Builder constructor private, use available Builder.newInstance method instead --- .../main/java/org/matsim/freight/carriers/CarrierShipment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 93e9dc590fe..3955d7b1756 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 @@ -102,7 +102,7 @@ public Builder(Id pickupLinkId, Id deliveryLinkId, int demand) { this.demand = demand; } - public Builder(Id id, Id pickupLinkId, Id deliveryLinkId, int demand) { + private Builder(Id id, Id pickupLinkId, Id deliveryLinkId, int demand) { super(); this.id = id; this.pickupLinkId = pickupLinkId; From 10071dbd742eb80ccc5d80e0e94fea8e4686c8a4 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:29:16 +0100 Subject: [PATCH 32/39] rename setters in Builder to make it more consistent. old setters remain as deprecated --- .../freight/carriers/CarrierService.java | 33 ++++--- .../freight/carriers/CarrierShipment.java | 96 ++++++++++++++++--- 2 files changed, 103 insertions(+), 26 deletions(-) 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 aeb26ce729f..a8f59daad9e 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 @@ -47,35 +47,40 @@ private Builder(Id id, Id serviceLinkId) { this.serviceLinkId = serviceLinkId; } + public CarrierService build(){ + return new CarrierService(this); + } + /** - * By default, it is [0.0,Integer.MaxValue]. + * Sets a time-window for the beginning of the service + * When not set, it is by default [0.0., Integer.MAX_VALUE]. + *

+ * 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 serviceDuration duration of the service + * @param startTimeWindow time-window for the beginning of the service acti * @return the builder */ - public Builder setServiceDuration(double serviceDuration){ - this.serviceDuration = serviceDuration; + public Builder setServiceStartTimeWindow(TimeWindow startTimeWindow){ + this.serviceStartsTimeWindow = startTimeWindow; return this; } /** - * Sets a time-window for the service. - * - *

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(). + * Sets the duration for the pickup activity. + * When not set, it is by default 0.0. * - * @param startTimeWindow time-window for the service + * @param serviceDuration duration of the service * @return the builder */ - public Builder setServiceStartTimeWindow(TimeWindow startTimeWindow){ - this.serviceStartsTimeWindow = startTimeWindow; + public Builder setServiceDuration(double serviceDuration){ + this.serviceDuration = serviceDuration; return this; } - public CarrierService build(){ - return new CarrierService(this); - } + + public Builder setCapacityDemand(int value) { this.demand = value; 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 3955d7b1756..f6af6a28d55 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 @@ -77,17 +77,17 @@ public static Builder newInstance(Id from, Id to, int size){ /** * Returns a new shipment builder. - *

The builder is init with the shipment's origin (from), destination (to) and with the shipment's size. + *

The builder is init with the shipment's origin (from), destination (to) and with the shipment's demand. * The default-value for serviceTime is 0.0. The default-value for a timeWindow is [start=0.0, end=Double.maxValue()]. * * @param id the id of the shipment * @param from the origin * @param to the destination - * @param size size of the shipment + * @param demand demand 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); + public static Builder newInstance(Id id, Id from, Id to, int demand){ + return new Builder(id, from, to, demand); } /** @@ -110,29 +110,101 @@ private Builder(Id id, Id pickupLinkId, Id delivery this.demand = demand; } - public Builder setPickupTimeWindow(TimeWindow pickupTW){ - this.pickupStartsTimeWindow = pickupTW; + /** + * Sets a time-window for the beginning of the pickup + * When not set, it is by default [0.0., Integer.MAX_VALUE]. + *

+ * Note that the time-window restricts the start-time of the shipment's pickup . If one works with hard time-windows (which means that + * time-windows must be met) than the pickup is allowed to start between startTimeWindow.getStart() and startTimeWindow.getEnd(). + * + * @param pickupStartsTimeWindow time-window for the beginning of the pickup activity + * @return the builder + */ + public Builder setPickupStartsTimeWindow(TimeWindow pickupStartsTimeWindow){ + this.pickupStartsTimeWindow = pickupStartsTimeWindow; return this; } - public Builder setDeliveryTimeWindow(TimeWindow deliveryTW){ - this.deliveryStartsTimeWindow = deliveryTW; + /** + * Sets the duration for the pickup activity. + * When not set, it is by default 0.0. + * + * @param pickupDuration Duration of the pickup activity (in seconds). + * @return the Builder + */ + public Builder setPickupDuration(double pickupDuration){ + this.pickupDuration = pickupDuration; return this; } - public Builder setPickupServiceTime(double pickupServiceTime){ - this.pickupDuration = pickupServiceTime; + /** + * Sets a time-window for the beginning of the delivery + * When not set, it is by default [0.0., Integer.MAX_VALUE]. + *

+ * Note that the time-window restricts the start-time of the shipment's delivery . If one works with hard time-windows (which means that + * time-windows must be met) than the delivery is allowed to start between startTimeWindow.getStart() and startTimeWindow.getEnd(). + * + * @param deliveryStartsTimeWindow time-window for the beginning of the delivery activity + * @return the builder + */ + public Builder setDeliveryStartsTimeWindow(TimeWindow deliveryStartsTimeWindow){ + this.deliveryStartsTimeWindow = deliveryStartsTimeWindow; return this; } - public Builder setDeliveryServiceTime(double deliveryServiceTime){ - this.deliveryDuration = deliveryServiceTime; + /** + * Sets the duration for the delivery activity. + * When not set, it is by default 0.0. + * + * @param deliveryDuration Duration of the delivery activity (in seconds). + * @return the Builder + */ + public Builder setDeliveryDuration(double deliveryDuration){ + this.deliveryDuration = deliveryDuration; return this; } public CarrierShipment build(){ return new CarrierShipment(this); } + + //*** deprecated methods *** + + + /** + * @deprecated please inline and use {@link #setPickupStartsTimeWindow(TimeWindow)} instead + */ + @Deprecated(since = "dez 2024") + public Builder setPickupTimeWindow(TimeWindow pickupTW){ + return setPickupStartsTimeWindow(pickupTW); + } + + /** + * @deprecated please inline and use {@link #setPickupDuration(double)} instead + */ + @Deprecated(since = "dez 2024") + public Builder setPickupServiceTime(double pickupServiceTime){ + return setPickupDuration(pickupServiceTime); + } + + /** + * @deprecated please inline and use {@link #setDeliveryStartsTimeWindow(TimeWindow)} instead + */ + @Deprecated(since = "dez 2024") + public Builder setDeliveryTimeWindow(TimeWindow deliveryTW){ + return setDeliveryStartsTimeWindow(deliveryTW); + } + + /** + * @deprecated please inline and use {@link #setDeliveryDuration(double)} instead + */ + @Deprecated(since = "dez 2024") + public Builder setDeliveryServiceTime(double deliveryServiceTime){ + return setDeliveryDuration(deliveryServiceTime); + } + + + } private final Id id; From cbe5a12d92c35542f04022518866f05e246f18d7 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:42:37 +0100 Subject: [PATCH 33/39] comments and javadoc --- .../freight/carriers/CarrierService.java | 22 ++++++++++++---- .../freight/carriers/CarrierShipment.java | 25 +++++++++++++------ 2 files changed, 34 insertions(+), 13 deletions(-) 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 a8f59daad9e..016b16638e2 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 @@ -33,6 +33,9 @@ public static class Builder { private final Id id; private int demand = 0; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id serviceLinkId; private TimeWindow serviceStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); private double serviceDuration = 0.0; @@ -59,7 +62,7 @@ public CarrierService build(){ * 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 time-window for the beginning of the service acti + * @param startTimeWindow time-window for the beginning of the service activity * @return the builder */ public Builder setServiceStartTimeWindow(TimeWindow startTimeWindow){ @@ -79,9 +82,15 @@ public Builder setServiceDuration(double serviceDuration){ return this; } - - - + /** + * Sets the demand (size; capacity needed) of the service. + * When not set, it is by default 0. + *

+ * IMO we can put this into the Builder directly instead of a separate method? kturner dec'24 + * + * @param value the demand (size; capacity needed) of the service + * @return the builder + */ public Builder setCapacityDemand(int value) { this.demand = value; return this; @@ -93,6 +102,9 @@ public Builder setCapacityDemand(int value) { private final Id id; private final int demand; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id serviceLinkId; private final TimeWindow serviceStartsTimeWindow; private final double serviceDuration; @@ -127,7 +139,7 @@ public TimeWindow getServiceStartTimeWindow(){ /** * @deprecated please inline and use {@link #getDemand()} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public int getCapacityDemand() { return getDemand(); } 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 f6af6a28d55..e39b82afa5a 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 @@ -48,10 +48,16 @@ public static class Builder { private final Id id; private final int demand; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id pickupLinkId; private TimeWindow pickupStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); private double pickupDuration = 0.0; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id deliveryLinkId; private TimeWindow deliveryStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); private double deliveryDuration = 0.0; @@ -174,7 +180,7 @@ public CarrierShipment build(){ /** * @deprecated please inline and use {@link #setPickupStartsTimeWindow(TimeWindow)} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public Builder setPickupTimeWindow(TimeWindow pickupTW){ return setPickupStartsTimeWindow(pickupTW); } @@ -182,7 +188,7 @@ public Builder setPickupTimeWindow(TimeWindow pickupTW){ /** * @deprecated please inline and use {@link #setPickupDuration(double)} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public Builder setPickupServiceTime(double pickupServiceTime){ return setPickupDuration(pickupServiceTime); } @@ -190,7 +196,7 @@ public Builder setPickupServiceTime(double pickupServiceTime){ /** * @deprecated please inline and use {@link #setDeliveryStartsTimeWindow(TimeWindow)} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public Builder setDeliveryTimeWindow(TimeWindow deliveryTW){ return setDeliveryStartsTimeWindow(deliveryTW); } @@ -198,22 +204,25 @@ public Builder setDeliveryTimeWindow(TimeWindow deliveryTW){ /** * @deprecated please inline and use {@link #setDeliveryDuration(double)} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public Builder setDeliveryServiceTime(double deliveryServiceTime){ return setDeliveryDuration(deliveryServiceTime); } - - - } private final Id id; private final int demand; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id pickupLinkId; private final TimeWindow pickupStartsTimeWindow; private double pickupDuration; + //IMO we could build a general class (CarrierActivity ???), containing the location, StartTimeWindow and Duration. + //This could be used for both, CarrierService and CarrierShipment (Pickup and Delivery). + //kturner dec'24 private final Id deliveryLinkId; private final TimeWindow deliveryStartsTimeWindow; private double deliveryDuration; @@ -264,7 +273,7 @@ public Id getTo() { /** * @deprecated please inline and use {@link #getDemand()} instead */ - @Deprecated(since = "dez 2024") + @Deprecated(since = "dec'24") public int getSize() { return getDemand(); } From b8c6da6dbb8679cbc2eea3044e6c3f3a03f40774 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 13:45:58 +0100 Subject: [PATCH 34/39] rename setter in Builder to make it more consistent. old setter remain as deprecated --- .../freight/carriers/CarrierService.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) 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 016b16638e2..7a140a5b386 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 @@ -82,18 +82,35 @@ public Builder setServiceDuration(double serviceDuration){ return this; } + /** + * Sets the demand (size; capacity needed) of the service. + * When not set, it is by default 0. + *

+ * IMO we can put this into the Builder directly instead of a separate method? kturner dec'24 + * + * @param demand the demand (size; capacity needed) of the service + * @return the builder + */ + public Builder setDemand(int demand) { + this.demand = demand; + return this; + } + + /** * Sets the demand (size; capacity needed) of the service. * When not set, it is by default 0. *

* IMO we can put this into the Builder directly instead of a separate method? kturner dec'24 * + * @deprecated please use {@link #setDemand(int)} instead + * * @param value the demand (size; capacity needed) of the service * @return the builder */ + @Deprecated(since = "dec'24") public Builder setCapacityDemand(int value) { - this.demand = value; - return this; + return setDemand(value); } } From 80cc5df4e395411d5742f322e5975b406dd0862c Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 14:23:00 +0100 Subject: [PATCH 35/39] use new method names --- .../DemandReaderFromCSV.java | 20 ++++++------ .../DefaultCommercialJobGenerator.java | 2 +- .../freight/carriers/CarrierPlanReaderV1.java | 10 +++--- .../carriers/CarrierPlanXmlParserV2.java | 10 +++--- .../carriers/CarrierPlanXmlParserV2_1.java | 10 +++--- .../freight/carriers/CarriersUtils.java | 6 ++-- .../events/CarrierServiceStartEvent.java | 2 +- .../CarrierShipmentDeliveryEndEvent.java | 2 +- .../CarrierShipmentDeliveryStartEvent.java | 2 +- .../events/CarrierShipmentPickupEndEvent.java | 2 +- .../CarrierShipmentPickupStartEvent.java | 2 +- .../carriers/jsprit/MatsimJspritFactory.java | 10 +++--- .../chessboard/FreightScenarioCreator.java | 2 +- .../CollectionCarrierScheduler.java | 2 +- .../DistributionCarrierScheduler.java | 4 +-- .../MainRunCarrierScheduler.java | 2 +- .../freight/carriers/CarriersUtilsTest.java | 2 +- ...istanceConstraintFromVehiclesFileTest.java | 6 ++-- .../jsprit/DistanceConstraintTest.java | 10 +++--- .../carriers/jsprit/FixedCostsTest.java | 2 +- .../jsprit/MatsimTransformerTest.java | 18 +++++------ .../freight/carriers/jsprit/SkillsIT.java | 32 +++++++++---------- .../utils/CarrierControllerUtilsIT.java | 11 +++---- .../utils/CarrierControllerUtilsTest.java | 10 +++--- ...iverTriggersCarrierReplanningListener.java | 4 +-- .../ReceiverChessboardScenario.java | 4 +-- 26 files changed, 93 insertions(+), 94 deletions(-) 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 3f7c9c242e0..4355e7b938b 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -655,7 +655,7 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { createJobId(scenario, newDemandInformationElement, link.getId(), null), CarrierService.class); CarrierService thisService = CarrierService.Builder.newInstance(idNewService, link.getId()) - .setCapacityDemand(demandForThisLink).setServiceDuration(serviceTime) + .setDemand(demandForThisLink).setServiceDuration(serviceTime) .setServiceStartTimeWindow(newDemandInformationElement.getFirstJobElementTimeWindow()) .build(); CarriersUtils.getCarriers(scenario).getCarriers() @@ -696,7 +696,7 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { CarrierService.class); if (demandToDistribute > 0 && singleDemandForThisLink > 0) { CarrierService thisService = CarrierService.Builder.newInstance(idNewService, link.getId()) - .setCapacityDemand(singleDemandForThisLink).setServiceDuration(serviceTime) + .setDemand(singleDemandForThisLink).setServiceDuration(serviceTime) .setServiceStartTimeWindow(newDemandInformationElement.getFirstJobElementTimeWindow()) .build(); thisCarrier.getServices().put(thisService.getId(), thisService); @@ -747,7 +747,7 @@ else if (samplingOption.equals("changeNumberOfLocationsWithDemand")) { createJobId(scenario, newDemandInformationElement, link.getId(), null), CarrierService.class); if ((demandToDistribute > 0 && singleDemandForThisLink > 0) || demandToDistribute == 0) { CarrierService thisService = CarrierService.Builder.newInstance(idNewService, link.getId()) - .setCapacityDemand(singleDemandForThisLink).setServiceDuration(serviceTime) + .setDemand(singleDemandForThisLink).setServiceDuration(serviceTime) .setServiceStartTimeWindow(newDemandInformationElement.getFirstJobElementTimeWindow()) .build(); CarriersUtils.getCarriers(scenario).getCarriers() @@ -1051,8 +1051,8 @@ private static void createSingleShipment(Scenario scenario, DemandInformationEle CarrierShipment thisShipment = CarrierShipment.Builder .newInstance(idNewShipment, linkPickup.getId(), linkDelivery.getId(), singleDemandForThisLink) - .setPickupServiceTime(serviceTimePickup).setPickupTimeWindow(timeWindowPickup) - .setDeliveryServiceTime(serviceTimeDelivery).setDeliveryTimeWindow(timeWindowDelivery) + .setPickupDuration(serviceTimePickup).setPickupStartsTimeWindow(timeWindowPickup) + .setDeliveryDuration(serviceTimeDelivery).setDeliveryStartsTimeWindow(timeWindowDelivery) .build(); thisCarrier.getShipments().put(thisShipment.getId(), thisShipment); if (demandForThisLink == 0) @@ -1207,10 +1207,10 @@ private static void combineSimilarJobs(Scenario scenario) { } CarrierShipment newShipment = CarrierShipment.Builder .newInstance(idNewShipment, baseShipment.getFrom(), baseShipment.getTo(), demandForThisLink) - .setPickupServiceTime(serviceTimePickup) - .setPickupTimeWindow(baseShipment.getPickupTimeWindow()) - .setDeliveryServiceTime(serviceTimeDelivery) - .setDeliveryTimeWindow(baseShipment.getDeliveryTimeWindow()).build(); + .setPickupDuration(serviceTimePickup) + .setPickupStartsTimeWindow(baseShipment.getPickupTimeWindow()) + .setDeliveryDuration(serviceTimeDelivery) + .setDeliveryStartsTimeWindow(baseShipment.getDeliveryTimeWindow()).build(); shipmentsToAdd.add(newShipment); } } @@ -1253,7 +1253,7 @@ private static void combineSimilarJobs(Scenario scenario) { .newInstance(idNewService, baseService.getLocationLinkId()) .setServiceDuration(serviceTimeService) .setServiceStartTimeWindow(baseService.getServiceStartTimeWindow()) - .setCapacityDemand(demandForThisLink).build(); + .setDemand(demandForThisLink).build(); servicesToAdd.add(newService); } } diff --git a/contribs/commercialTrafficApplications/src/main/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/DefaultCommercialJobGenerator.java b/contribs/commercialTrafficApplications/src/main/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/DefaultCommercialJobGenerator.java index 3327f46292c..2891b802294 100644 --- a/contribs/commercialTrafficApplications/src/main/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/DefaultCommercialJobGenerator.java +++ b/contribs/commercialTrafficApplications/src/main/java/org/matsim/contrib/commercialTrafficApplications/jointDemand/DefaultCommercialJobGenerator.java @@ -329,7 +329,7 @@ public void generateIterationServices(Carriers carriers, Population population) double latestStart = Double.parseDouble(commercialJobProperties.get(COMMERCIALJOB_ATTRIBUTE_END_IDX)); CarrierService.Builder serviceBuilder = CarrierService.Builder.newInstance(serviceId, PopulationUtils.decideOnLinkIdForActivity(activity,scenario)); - serviceBuilder.setCapacityDemand(Integer.parseInt(commercialJobProperties.get(COMMERCIALJOB_ATTRIBUTE_AMOUNT_IDX))); + serviceBuilder.setDemand(Integer.parseInt(commercialJobProperties.get(COMMERCIALJOB_ATTRIBUTE_AMOUNT_IDX))); serviceBuilder.setServiceDuration(Double.parseDouble(commercialJobProperties.get(COMMERCIALJOB_ATTRIBUTE_DURATION_IDX))); serviceBuilder.setServiceStartTimeWindow(TimeWindow.newInstance(earliestStart,latestStart)); 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 4bb90047d86..42b2317a6cb 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 @@ -116,19 +116,19 @@ public void startTag(String name, Attributes attributes, Stack context) CarrierShipment.Builder shipmentBuilder = CarrierShipment.Builder.newInstance( Id.create( id, CarrierShipment.class ), Id.create( from, Link.class ), Id.create( to, Link.class ), size ); if( startPickup == null ){ - shipmentBuilder.setPickupTimeWindow( TimeWindow.newInstance( 0.0, Integer.MAX_VALUE ) ).setDeliveryTimeWindow( + shipmentBuilder.setPickupStartsTimeWindow( TimeWindow.newInstance( 0.0, Integer.MAX_VALUE ) ).setDeliveryStartsTimeWindow( TimeWindow.newInstance( 0.0, Integer.MAX_VALUE ) ); } else{ - shipmentBuilder.setPickupTimeWindow( TimeWindow.newInstance( getDouble( startPickup ), getDouble( endPickup ) ) ). - setDeliveryTimeWindow( + shipmentBuilder.setPickupStartsTimeWindow( TimeWindow.newInstance( getDouble( startPickup ), getDouble( endPickup ) ) ). + setDeliveryStartsTimeWindow( TimeWindow.newInstance( getDouble( startDelivery ), getDouble( endDelivery ) ) ); } - if( pickupServiceTime != null ) shipmentBuilder.setPickupServiceTime( getDouble( pickupServiceTime ) ); - if( deliveryServiceTime != null ) shipmentBuilder.setDeliveryServiceTime( getDouble( deliveryServiceTime ) ); + if( pickupServiceTime != null ) shipmentBuilder.setPickupDuration( getDouble( pickupServiceTime ) ); + if( deliveryServiceTime != null ) shipmentBuilder.setDeliveryDuration( getDouble( deliveryServiceTime ) ); CarrierShipment shipment = shipmentBuilder.build(); currentShipments.put( attributes.getValue( ID ), shipment ); CarriersUtils.addShipment(currentCarrier, shipment); 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 271871b0970..599c48a3886 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 @@ -117,7 +117,7 @@ public void startTag(String name, Attributes atts, Stack context) { Id to = Id.create(toLocation, Link.class); CarrierService.Builder serviceBuilder = CarrierService.Builder.newInstance(id, to); String capDemandString = atts.getValue("capacityDemand"); - if (capDemandString != null) serviceBuilder.setCapacityDemand(getInt(capDemandString)); + if (capDemandString != null) serviceBuilder.setDemand(getInt(capDemandString)); String startString = atts.getValue("earliestStart"); double start = parseTimeToDouble(startString); double end; @@ -157,13 +157,13 @@ public void startTag(String name, Attributes atts, Stack context) { String deliveryServiceTime = atts.getValue("deliveryServiceTime"); if (startPickup != null && endPickup != null) - shipmentBuilder.setPickupTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startPickup), parseTimeToDouble(endPickup))); + shipmentBuilder.setPickupStartsTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startPickup), parseTimeToDouble(endPickup))); if (startDelivery != null && endDelivery != null) - shipmentBuilder.setDeliveryTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startDelivery), parseTimeToDouble(endDelivery))); + shipmentBuilder.setDeliveryStartsTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startDelivery), parseTimeToDouble(endDelivery))); if (pickupServiceTime != null) - shipmentBuilder.setPickupServiceTime(parseTimeToDouble(pickupServiceTime)); + shipmentBuilder.setPickupDuration(parseTimeToDouble(pickupServiceTime)); if (deliveryServiceTime != null) - shipmentBuilder.setDeliveryServiceTime(parseTimeToDouble(deliveryServiceTime)); + shipmentBuilder.setDeliveryDuration(parseTimeToDouble(deliveryServiceTime)); currentShipment = shipmentBuilder.build(); currentShipments.put(atts.getValue(ID), currentShipment); 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 9c3f2b7a1e6..a9f06abb1f4 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 @@ -115,7 +115,7 @@ public void startTag(String name, Attributes atts, Stack context) { Id to = Id.create(toLocation, Link.class); CarrierService.Builder serviceBuilder = CarrierService.Builder.newInstance(id, to); String capDemandString = atts.getValue("capacityDemand"); - if (capDemandString != null) serviceBuilder.setCapacityDemand(getInt(capDemandString)); + if (capDemandString != null) serviceBuilder.setDemand(getInt(capDemandString)); String startString = atts.getValue("earliestStart"); double start = parseTimeToDouble(startString); double end; @@ -155,13 +155,13 @@ public void startTag(String name, Attributes atts, Stack context) { String deliveryServiceTime = atts.getValue("deliveryServiceTime"); if (startPickup != null && endPickup != null) - shipmentBuilder.setPickupTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startPickup), parseTimeToDouble(endPickup))); + shipmentBuilder.setPickupStartsTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startPickup), parseTimeToDouble(endPickup))); if (startDelivery != null && endDelivery != null) - shipmentBuilder.setDeliveryTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startDelivery), parseTimeToDouble(endDelivery))); + shipmentBuilder.setDeliveryStartsTimeWindow(TimeWindow.newInstance(parseTimeToDouble(startDelivery), parseTimeToDouble(endDelivery))); if (pickupServiceTime != null) - shipmentBuilder.setPickupServiceTime(parseTimeToDouble(pickupServiceTime)); + shipmentBuilder.setPickupDuration(parseTimeToDouble(pickupServiceTime)); if (deliveryServiceTime != null) - shipmentBuilder.setDeliveryServiceTime(parseTimeToDouble(deliveryServiceTime)); + shipmentBuilder.setDeliveryDuration(parseTimeToDouble(deliveryServiceTime)); currentShipment = shipmentBuilder.build(); currentShipments.put(atts.getValue(ID), currentShipment); 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 ed8267d89b0..61a7ff0c27b 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 @@ -432,12 +432,12 @@ private static void createShipmentsFromServices(Carrier carrierWS, Carrier carri .newInstance(Id.create(carrierService.getId().toString(), CarrierShipment.class), depotServiceIsDeliveredFrom.get(carrierService.getId()), carrierService.getLocationLinkId(), carrierService.getDemand()) - .setDeliveryServiceTime(carrierService.getServiceDuration()) + .setDeliveryDuration(carrierService.getServiceDuration()) // .setPickupServiceTime(pickupServiceTime) //Not set yet, because in service we // have now time for that. Maybe change it later, kmt sep18 - .setDeliveryTimeWindow(carrierService.getServiceStartTimeWindow()) + .setDeliveryStartsTimeWindow(carrierService.getServiceStartTimeWindow()) // Limited to end of delivery timeWindow (pickup later than the latest delivery is not useful). - .setPickupTimeWindow(TimeWindow.newInstance(0.0, carrierService.getServiceStartTimeWindow().getEnd())) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, carrierService.getServiceStartTimeWindow().getEnd())) .build(); addShipment(carrierWS, carrierShipment); } 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 2bf7829807e..02b24c5d56c 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 @@ -85,7 +85,7 @@ public static CarrierServiceStartEvent convert(GenericEvent event) { Id locationLinkId = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); CarrierService service = CarrierService.Builder.newInstance(carrierServiceId, locationLinkId) .setServiceDuration(Double.parseDouble(attributes.get(CarrierEventAttributes.ATTRIBUTE_SERVICE_DURATION))) - .setCapacityDemand(Integer.parseInt(attributes.get(CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND))) + .setDemand(Integer.parseInt(attributes.get(CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND))) .build(); Id vehicleId = Id.create(attributes.get(ATTRIBUTE_VEHICLE), Vehicle.class); return new CarrierServiceStartEvent(time, carrierId, service, vehicleId); 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 35fe77cdea6..672d959dc36 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 @@ -83,7 +83,7 @@ public static CarrierShipmentDeliveryEndEvent convert(GenericEvent event) { Id shipmentTo = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); int size = Integer.parseInt(attributes.get(CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND)); CarrierShipment shipment = CarrierShipment.Builder.newInstance(shipmentId, null, shipmentTo, size) - .setDeliveryServiceTime(Double.parseDouble(attributes.get(CarrierEventAttributes.ATTRIBUTE_DROPOFF_DURATION))) + .setDeliveryDuration(Double.parseDouble(attributes.get(CarrierEventAttributes.ATTRIBUTE_DROPOFF_DURATION))) .build(); Id vehicleId = Id.createVehicleId(attributes.get(ATTRIBUTE_VEHICLE)); return new CarrierShipmentDeliveryEndEvent(time, carrierId, shipment, vehicleId); 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 300590482df..4635c159d5d 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 @@ -84,7 +84,7 @@ public static CarrierShipmentDeliveryStartEvent convert(GenericEvent event) { Id shipmentTo = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); int size = Integer.parseInt(attributes.get(ATTRIBUTE_CAPACITYDEMAND)); CarrierShipment shipment = CarrierShipment.Builder.newInstance(shipmentId, null, shipmentTo, size) - .setDeliveryServiceTime(Double.parseDouble(attributes.get(ATTRIBUTE_DROPOFF_DURATION))) + .setDeliveryDuration(Double.parseDouble(attributes.get(ATTRIBUTE_DROPOFF_DURATION))) .build(); Id vehicleId = Id.createVehicleId(attributes.get(ATTRIBUTE_VEHICLE)); return new CarrierShipmentDeliveryStartEvent(time, carrierId, shipment, vehicleId); 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 1a80be89293..601b39bbd37 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 @@ -79,7 +79,7 @@ public static CarrierShipmentPickupEndEvent convert(GenericEvent event) { Id shipmentFrom = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); int shipmentSize = Integer.parseInt(attributes.get(ATTRIBUTE_CAPACITYDEMAND)); CarrierShipment shipment = CarrierShipment.Builder.newInstance(shipmentId, shipmentFrom, null, shipmentSize) - .setPickupServiceTime(Double.parseDouble(attributes.get(ATTRIBUTE_PICKUP_DURATION))) + .setPickupDuration(Double.parseDouble(attributes.get(ATTRIBUTE_PICKUP_DURATION))) .build(); Id vehicleId = Id.createVehicleId(attributes.get(ATTRIBUTE_VEHICLE)); return new CarrierShipmentPickupEndEvent(time, carrierId, shipment, vehicleId); 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 bbc912645fb..7154e2dba12 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 @@ -77,7 +77,7 @@ public static CarrierShipmentPickupStartEvent convert(GenericEvent event) { Id shipmentFrom = Id.createLinkId(attributes.get(ATTRIBUTE_LINK)); int shipmentSize = Integer.parseInt(attributes.get(CarrierEventAttributes.ATTRIBUTE_CAPACITYDEMAND)); CarrierShipment shipment = CarrierShipment.Builder.newInstance(shipmentId, shipmentFrom, null, shipmentSize) - .setPickupServiceTime(Double.parseDouble(attributes.get(CarrierEventAttributes.ATTRIBUTE_PICKUP_DURATION))) + .setPickupDuration(Double.parseDouble(attributes.get(CarrierEventAttributes.ATTRIBUTE_PICKUP_DURATION))) .build(); Id vehicleId = Id.createVehicleId(attributes.get(ATTRIBUTE_VEHICLE)); return new CarrierShipmentPickupStartEvent(time, carrierId, shipment, vehicleId); 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 5ec272cc6c2..0a056523f88 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 @@ -88,11 +88,11 @@ static CarrierShipment createCarrierShipment(Shipment jspritShipment) { .newInstance(Id.create(jspritShipment.getId(), CarrierShipment.class), Id.createLinkId(jspritShipment.getPickupLocation().getId()), Id.createLinkId(jspritShipment.getDeliveryLocation().getId()), jspritShipment.getSize().get(0)) - .setDeliveryServiceTime(jspritShipment.getDeliveryServiceTime()) - .setDeliveryTimeWindow(org.matsim.freight.carriers.TimeWindow.newInstance(jspritShipment.getDeliveryTimeWindow().getStart(), + .setDeliveryDuration(jspritShipment.getDeliveryServiceTime()) + .setDeliveryStartsTimeWindow(org.matsim.freight.carriers.TimeWindow.newInstance(jspritShipment.getDeliveryTimeWindow().getStart(), jspritShipment.getDeliveryTimeWindow().getEnd())) - .setPickupServiceTime(jspritShipment.getPickupServiceTime()) - .setPickupTimeWindow(org.matsim.freight.carriers.TimeWindow.newInstance(jspritShipment.getPickupTimeWindow().getStart(), + .setPickupDuration(jspritShipment.getPickupServiceTime()) + .setPickupStartsTimeWindow(org.matsim.freight.carriers.TimeWindow.newInstance(jspritShipment.getPickupTimeWindow().getStart(), jspritShipment.getPickupTimeWindow().getEnd())) .build(); CarriersUtils.setSkills(carrierShipment, jspritShipment.getRequiredSkills().values()); @@ -184,7 +184,7 @@ static Service createJspritService(CarrierService carrierService, Coord location static CarrierService createCarrierService(Service jspritService) { CarrierService.Builder serviceBuilder = CarrierService.Builder.newInstance( Id.create(jspritService.getId(), CarrierService.class), Id.create(jspritService.getLocation().getId(), Link.class)); - serviceBuilder.setCapacityDemand(jspritService.getSize().get(0)); + serviceBuilder.setDemand(jspritService.getSize().get(0)); serviceBuilder.setServiceDuration(jspritService.getServiceDuration()); serviceBuilder.setServiceStartTimeWindow( org.matsim.freight.carriers.TimeWindow.newInstance(jspritService.getTimeWindow().getStart(), jspritService.getTimeWindow().getEnd())); 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 3d291829b77..44a4dda7a5f 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 @@ -101,7 +101,7 @@ private static void createCustomers(Carrier carrier, Network network) { for(int i=0;i<20;i++){ CarrierService.Builder serviceBuilder = CarrierService.Builder.newInstance(Id.create((i + 1),CarrierService.class), drawLocationLinkId(innerCityLinks, outerCityLinks)); - serviceBuilder.setCapacityDemand(1); + serviceBuilder.setDemand(1); serviceBuilder.setServiceDuration(5*60); serviceBuilder.setServiceStartTimeWindow(TimeWindow.newInstance(6*60*60, 15*60*60)); CarrierService carrierService = serviceBuilder.build(); 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 index d91bf1c94f5..f6473a6fcad 100644 --- 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 @@ -84,7 +84,7 @@ 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()) + .setDemand(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 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 index 90abf00ea67..f3814a036e6 100644 --- 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 @@ -184,7 +184,7 @@ private CarrierService convertToCarrierService(LspShipment lspShipment) { 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()) + .setDemand(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 @@ -207,7 +207,7 @@ private CarrierShipment convertToCarrierShipment(LspShipment lspShipment) { 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()) + .setDeliveryDuration(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())) { 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 index 99f49186e11..abcc023fa20 100644 --- 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 @@ -229,7 +229,7 @@ private CarrierService convertToCarrierService(LspShipment lspShipment) { Id.create(lspShipment.getId().toString(), CarrierService.class); CarrierService.Builder builder = CarrierService.Builder.newInstance(serviceId, resource.getEndLinkId()); - builder.setCapacityDemand(lspShipment.getSize()); + builder.setDemand(lspShipment.getSize()); builder.setServiceDuration(lspShipment.getDeliveryServiceTime()); return builder.build(); } 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 9353d4d4034..7a784b4351d 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 @@ -68,7 +68,7 @@ void testAddAndGetServiceToCarrier() { Carrier carrier = new CarrierImpl(Id.create("carrier", Carrier.class)); Id serviceId = Id.create("testVehicle", CarrierService.class); CarrierService service1 = CarrierService.Builder.newInstance(serviceId,Id.createLinkId("link0") ) - .setCapacityDemand(15).setServiceDuration(30).build(); + .setDemand(15).setServiceDuration(30).build(); //add Service CarriersUtils.addService(carrier, service1); 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 43557b37a2a..e729e5360d6 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 @@ -421,14 +421,14 @@ private static Carrier addTwoServicesToCarrier(Carrier carrier) { CarrierService service1 = CarrierService.Builder .newInstance(Id.create("Service1", CarrierService.class), Id.createLinkId("j(3,8)")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service1); // Service 2 CarrierService service2 = CarrierService.Builder .newInstance(Id.create("Service2", CarrierService.class), Id.createLinkId("j(0,3)R")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service2); return carrier; @@ -442,7 +442,7 @@ private static Carrier addThreeServicesToCarrier(Carrier carrier) { CarrierService service3 = CarrierService.Builder .newInstance(Id.create("Service3", CarrierService.class), Id.createLinkId("j(9,2)")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service3); return carrier; 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 a375cceac46..3747a98a882 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 @@ -614,14 +614,14 @@ private static Carrier addTwoServicesToCarrier(Carrier carrier) { CarrierService service1 = CarrierService.Builder .newInstance(Id.create("Service1", CarrierService.class), Id.createLinkId("j(3,8)")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service1); // Service 2 CarrierService service2 = CarrierService.Builder .newInstance(Id.create("Service2", CarrierService.class), Id.createLinkId("j(0,3)R")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service2); return carrier; @@ -631,14 +631,14 @@ private static Carrier addTwoShipmentsToCarrier(Carrier carrier) { // Shipment 1 CarrierShipment shipment1 = CarrierShipment.Builder .newInstance(Id.create("Shipment1", CarrierShipment.class), Id.createLinkId("i(1,8)"), Id.createLinkId("j(3,8)"), 40) - .setDeliveryServiceTime(20).setDeliveryTimeWindow(TimeWindow.newInstance(8 * 3600, 12 * 3600)) + .setDeliveryDuration(20).setDeliveryStartsTimeWindow(TimeWindow.newInstance(8 * 3600, 12 * 3600)) .build(); CarriersUtils.addShipment(carrier, shipment1); // Shipment 2 CarrierShipment shipment2 = CarrierShipment.Builder .newInstance(Id.create("Shipment2", CarrierShipment.class),Id.createLinkId("i(1,8)"), Id.createLinkId("j(0,3)R"), 40) - .setDeliveryServiceTime(20).setDeliveryTimeWindow(TimeWindow.newInstance(8 * 3600, 12 * 3600)) + .setDeliveryDuration(20).setDeliveryStartsTimeWindow(TimeWindow.newInstance(8 * 3600, 12 * 3600)) .build(); CarriersUtils.addShipment(carrier, shipment2); @@ -653,7 +653,7 @@ private static Carrier addThreeServicesToCarrier(Carrier carrier) { CarrierService service3 = CarrierService.Builder .newInstance(Id.create("Service3", CarrierService.class), Id.createLinkId("j(9,2)")) .setServiceDuration(20).setServiceStartTimeWindow(TimeWindow.newInstance(8 * 3600, 10 * 3600)) - .setCapacityDemand(40).build(); + .setDemand(40).build(); CarriersUtils.addService(carrier, service3); return carrier; 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 cf5060bf772..494c9f106e6 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 @@ -200,7 +200,7 @@ final void test_carrier3CostsAreCorrectly() { private static CarrierService createMatsimService(String id, String to, int size) { return CarrierService.Builder.newInstance(Id.create(id, CarrierService.class), Id.create(to, Link.class)) - .setCapacityDemand(size) + .setDemand(size) .setServiceDuration(31.0) .setServiceStartTimeWindow(TimeWindow.newInstance(3601.0, 36001.0)) .build(); 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 08929c96408..a2f8130db57 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 @@ -122,7 +122,7 @@ void whenTransforming_matsimVehicle2jspritVehicle_itIsMadeCorrectly() { void whenTransforming_matsimService2jspritService_isMadeCorrectly() { CarrierService carrierService = CarrierService.Builder .newInstance(Id.create("serviceId", CarrierService.class), Id.create("locationId", Link.class)) - .setCapacityDemand(50).setServiceDuration(30.0) + .setDemand(50).setServiceDuration(30.0) .setServiceStartTimeWindow(TimeWindow.newInstance(10.0, 20.0)).build(); Service service = MatsimJspritFactory.createJspritService(carrierService, null); assertNotNull(service); @@ -161,8 +161,8 @@ void whenTransforming_matsimShipment2jspritShipment_isMadeCorrectly() { CarrierShipment carrierShipment = CarrierShipment.Builder .newInstance(Id.create("ShipmentId", CarrierShipment.class), Id.createLinkId("PickupLocationId"), Id.createLinkId("DeliveryLocationId"), 50) - .setPickupServiceTime(30.0).setPickupTimeWindow(TimeWindow.newInstance(10.0, 20.0)) - .setDeliveryServiceTime(40.0).setDeliveryTimeWindow(TimeWindow.newInstance(50.0, 60.0)).build(); + .setPickupDuration(30.0).setPickupStartsTimeWindow(TimeWindow.newInstance(10.0, 20.0)) + .setDeliveryDuration(40.0).setDeliveryStartsTimeWindow(TimeWindow.newInstance(50.0, 60.0)).build(); Shipment shipment = MatsimJspritFactory.createJspritShipment(carrierShipment); assertNotNull(shipment); assertEquals("PickupLocationId", shipment.getPickupLocation().getId()); @@ -333,10 +333,10 @@ void whenTransforming_matsimPlan2vehicleRouteSolution_itIsMadeCorrectly() { private ScheduledTour getMatsimServiceTour() { CarrierService s1 = CarrierService.Builder .newInstance(Id.create("serviceId", CarrierService.class), Id.create("to1", Link.class)) - .setCapacityDemand(20).build(); + .setDemand(20).build(); CarrierService s2 = CarrierService.Builder .newInstance(Id.create("serviceId2", CarrierService.class), Id.create("to2", Link.class)) - .setCapacityDemand(10).build(); + .setDemand(10).build(); CarrierVehicle matsimVehicle = getMatsimVehicle("matsimVehicle", "loc", getMatsimVehicleType()); double startTime = 15.0; Tour.Builder sTourBuilder = Tour.Builder.newInstance(Id.create("testTour", Tour.class)); @@ -391,8 +391,8 @@ private CarrierShipment getMatsimShipment(String id, String from, String to, int return CarrierShipment.Builder .newInstance(Id.create(id, CarrierShipment.class), Id.create(from, Link.class), Id.create(to, Link.class), size) - .setDeliveryServiceTime(30.0).setDeliveryTimeWindow(TimeWindow.newInstance(10.0, 20.0)) - .setPickupServiceTime(15.0).setPickupTimeWindow(TimeWindow.newInstance(1.0, 5.0)).build(); + .setDeliveryDuration(30.0).setDeliveryStartsTimeWindow(TimeWindow.newInstance(10.0, 20.0)) + .setPickupDuration(15.0).setPickupStartsTimeWindow(TimeWindow.newInstance(1.0, 5.0)).build(); } @Test @@ -503,11 +503,11 @@ private Carrier createCarrierWithServices() { carrier.setCarrierCapabilities(ccBuilder.build()); CarrierService carrierService1 = CarrierService.Builder .newInstance(Id.create("serviceId", CarrierService.class), Id.create("i(7,4)R", Link.class)) - .setCapacityDemand(20).setServiceDuration(10.0).build(); + .setDemand(20).setServiceDuration(10.0).build(); CarriersUtils.addService(carrier, carrierService1); CarrierService carrierService2 = CarrierService.Builder .newInstance(Id.create("serviceId2", CarrierService.class), Id.create("i(3,9)", Link.class)) - .setCapacityDemand(10).setServiceDuration(20.0).build(); + .setDemand(10).setServiceDuration(20.0).build(); CarriersUtils.addService(carrier, carrierService2); return carrier; } 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 7da556872c2..379fb15486c 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 @@ -161,10 +161,10 @@ private void addShipmentsRequiringDifferentSkills(Scenario scenario) { carrierLocation, Id.createLinkId("i(10,10)R"), 1) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setPickupServiceTime(Time.parseTime("00:05:00")) - .setDeliveryTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setDeliveryServiceTime(Time.parseTime("00:05:00")) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setPickupDuration(Time.parseTime("00:05:00")) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setDeliveryDuration(Time.parseTime("00:05:00")) .build(); CarriersUtils.addSkill(shipmentOne, "skill 1"); CarriersUtils.addShipment(carrier, shipmentOne); @@ -174,10 +174,10 @@ private void addShipmentsRequiringDifferentSkills(Scenario scenario) { carrierLocation, Id.createLinkId("i(10,10)R"), 1) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setPickupServiceTime(Time.parseTime("00:05:00")) - .setDeliveryTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setDeliveryServiceTime(Time.parseTime("00:05:00")) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setPickupDuration(Time.parseTime("00:05:00")) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setDeliveryDuration(Time.parseTime("00:05:00")) .build(); CarriersUtils.addSkill(shipmentTwo, "skill 2"); CarriersUtils.addShipment(carrier, shipmentTwo); @@ -190,10 +190,10 @@ private void addShipmentsRequiringSameSkills(Scenario scenario) { carrierLocation, Id.createLinkId("i(10,10)R"), 1) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setPickupServiceTime(Time.parseTime("00:05:00")) - .setDeliveryTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setDeliveryServiceTime(Time.parseTime("00:05:00")) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setPickupDuration(Time.parseTime("00:05:00")) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setDeliveryDuration(Time.parseTime("00:05:00")) .build(); CarriersUtils.addSkill(shipmentOne, "skill 1"); CarriersUtils.addShipment(carrier, shipmentOne); @@ -203,10 +203,10 @@ private void addShipmentsRequiringSameSkills(Scenario scenario) { carrierLocation, Id.createLinkId("i(10,10)R"), 1) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setPickupServiceTime(Time.parseTime("00:05:00")) - .setDeliveryTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) - .setDeliveryServiceTime(Time.parseTime("00:05:00")) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setPickupDuration(Time.parseTime("00:05:00")) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(0.0, Time.parseTime("24:00:00"))) + .setDeliveryDuration(Time.parseTime("00:05:00")) .build(); CarriersUtils.addSkill(shipmentTwo, "skill 1"); CarriersUtils.addShipment(carrier, shipmentTwo); 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 d7127bc80bf..249da6bf44b 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 @@ -44,7 +44,6 @@ import org.matsim.freight.carriers.jsprit.NetworkRouter; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.*; -import org.matsim.vehicles.EngineInformation.FuelType; //TODO: length of routes (legs) AND end time of route are missing. /** @@ -286,16 +285,16 @@ private static CarrierShipment createMatsimShipment(String id, String from, Stri } return CarrierShipment.Builder.newInstance(shipmentId, fromLinkId, toLinkId, size) - .setDeliveryServiceTime(30.0) - .setDeliveryTimeWindow(TimeWindow.newInstance(0.0, 36000.0)) - .setPickupServiceTime(5.0) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, 7200.0)) + .setDeliveryDuration(30.0) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(0.0, 36000.0)) + .setPickupDuration(5.0) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, 7200.0)) .build(); } private static CarrierService createMatsimService(String id, String to, int size) { return CarrierService.Builder.newInstance(Id.create(id, CarrierService.class), Id.create(to, Link.class)) - .setCapacityDemand(size) + .setDemand(size) .setServiceDuration(31.0) .setServiceStartTimeWindow(TimeWindow.newInstance(0.0, 36001.0)) .build(); 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 f6bb1b42ee0..46c783e197c 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 @@ -343,16 +343,16 @@ private static CarrierShipment createMatsimShipment(String id, String from, Stri } return CarrierShipment.Builder.newInstance(shipmentId, fromLinkId, toLinkId, size) - .setDeliveryServiceTime(30.0) - .setDeliveryTimeWindow(TimeWindow.newInstance(3600.0, 36000.0)) - .setPickupServiceTime(5.0) - .setPickupTimeWindow(TimeWindow.newInstance(0.0, 7200.0)) + .setDeliveryDuration(30.0) + .setDeliveryStartsTimeWindow(TimeWindow.newInstance(3600.0, 36000.0)) + .setPickupDuration(5.0) + .setPickupStartsTimeWindow(TimeWindow.newInstance(0.0, 7200.0)) .build(); } private static CarrierService createMatsimService(String id, String to, int size) { return CarrierService.Builder.newInstance(Id.create(id, CarrierService.class), Id.create(to, Link.class)) - .setCapacityDemand(size) + .setDemand(size) .setServiceDuration(31.0) .setServiceStartTimeWindow(TimeWindow.newInstance(3601.0, 36001.0)) .build(); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java index cf7b07dd8bd..28820157125 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverTriggersCarrierReplanningListener.java @@ -81,8 +81,8 @@ public void notifyIterationStarts(IterationStartsEvent event) { order.getReceiver().getLinkId(), (int) (Math.round(order.getDailyOrderQuantity()*order.getProduct().getProductType().getRequiredCapacity())) ); CarrierShipment newShipment = builder - .setDeliveryServiceTime( order.getServiceDuration() ) - .setDeliveryTimeWindow( receiverPlan.getTimeWindows().get( 0 ) ) + .setDeliveryDuration( order.getServiceDuration() ) + .setDeliveryStartsTimeWindow( receiverPlan.getTimeWindows().get( 0 ) ) // TODO This only looks at the FIRST time window. This may need revision once we handle multiple // time windows. .build(); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java index fd036695370..34b74c242d4 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/run/chessboard/ReceiverChessboardScenario.java @@ -228,8 +228,8 @@ public static void convertReceiverOrdersToInitialCarrierShipments(Carriers carri LOG.warn("Multiple time windows set. Only the first is used"); } - CarrierShipment shipment = shpBuilder.setDeliveryServiceTime(order.getServiceDuration()) - .setDeliveryTimeWindow(receiverPlan.getTimeWindows().get(0)) + CarrierShipment shipment = shpBuilder.setDeliveryDuration(order.getServiceDuration()) + .setDeliveryStartsTimeWindow(receiverPlan.getTimeWindows().get(0)) .build(); carriers.getCarriers().get(receiverOrder.getCarrierId()).getShipments().put(shipment.getId(), shipment); } From 8c5e2aacb1c9175f82c05ab1bfd4e58e93c99667 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 14:51:31 +0100 Subject: [PATCH 36/39] rename getters and setters to make it more consistent. old setters remain as deprecated --- .../DemandReaderFromCSV.java | 17 +-- .../DemandReaderFromCSVTest.java | 72 ++++++------- .../carriers/CarrierPlanXmlWriterV2_1.java | 14 +-- .../freight/carriers/CarrierShipment.java | 101 +++++++++++++++--- .../org/matsim/freight/carriers/Tour.java | 8 +- .../CarrierShipmentDeliveryEndEvent.java | 2 +- .../CarrierShipmentDeliveryStartEvent.java | 2 +- .../events/CarrierShipmentPickupEndEvent.java | 2 +- .../CarrierShipmentPickupStartEvent.java | 2 +- .../carriers/jsprit/MatsimJspritFactory.java | 24 ++--- .../multipleChains/MultipleChainsUtils.java | 8 +- .../jsprit/MatsimTransformerTest.java | 12 +-- .../utils/CarrierControllerUtilsTest.java | 48 ++++----- .../FreightAnalysisShipmentTracking.java | 20 ++-- 14 files changed, 203 insertions(+), 129 deletions(-) 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 4355e7b938b..2ebf3060e2e 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -1189,10 +1189,11 @@ private static void combineSimilarJobs(Scenario scenario) { 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); + && baseShipment.getTo() == thisShipment.getTo()) { + if (baseShipment.getPickupStartsTimeWindow() == thisShipment.getPickupStartsTimeWindow()) { + if (baseShipment.getDeliveryStartsTimeWindow() == thisShipment.getDeliveryStartsTimeWindow()) shipmentsToConnect.put(thisShipmentId, thisShipment); + } + } } } Id idNewShipment = baseShipment.getId(); @@ -1201,16 +1202,16 @@ private static void combineSimilarJobs(Scenario scenario) { double serviceTimeDelivery = 0; for (CarrierShipment carrierShipment : shipmentsToConnect.values()) { demandForThisLink = demandForThisLink + carrierShipment.getDemand(); - serviceTimePickup = serviceTimePickup + carrierShipment.getPickupServiceTime(); - serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryServiceTime(); + serviceTimePickup = serviceTimePickup + carrierShipment.getPickupDuration(); + serviceTimeDelivery = serviceTimeDelivery + carrierShipment.getDeliveryDuration(); shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); } CarrierShipment newShipment = CarrierShipment.Builder .newInstance(idNewShipment, baseShipment.getFrom(), baseShipment.getTo(), demandForThisLink) .setPickupDuration(serviceTimePickup) - .setPickupStartsTimeWindow(baseShipment.getPickupTimeWindow()) + .setPickupStartsTimeWindow(baseShipment.getPickupStartsTimeWindow()) .setDeliveryDuration(serviceTimeDelivery) - .setDeliveryStartsTimeWindow(baseShipment.getDeliveryTimeWindow()).build(); + .setDeliveryStartsTimeWindow(baseShipment.getDeliveryStartsTimeWindow()).build(); shipmentsToAdd.add(newShipment); } } 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 0658741aacd..d27e5d5a202 100644 --- a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java +++ b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java @@ -104,10 +104,10 @@ void demandCreationWithSampleWithChangeNumberOfLocations() throws IOException { countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); Assertions.assertEquals(5, shipment.getDemand()); - Assertions.assertEquals(2000, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(1250, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupTimeWindow()); - Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryTimeWindow()); + Assertions.assertEquals(2000, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(1250, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) @@ -171,10 +171,10 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); Assertions.assertEquals(10, shipment.getDemand()); - 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()); + Assertions.assertEquals(4000, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2500, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) @@ -238,10 +238,10 @@ void demandCreationWithSampleWithDemandOnLocationWithCombiningJobs() throws IOEx countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); Assertions.assertEquals(10, shipment.getDemand()); - 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()); + Assertions.assertEquals(4000, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2500, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) @@ -308,10 +308,10 @@ void demandCreationNoSampling() throws IOException { countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); Assertions.assertEquals(10, shipment.getDemand()); - 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()); + Assertions.assertEquals(4000, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(2500, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) @@ -525,29 +525,29 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); if (shipment.getDemand() == 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()); + Assertions.assertEquals(300, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(350, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) .add(shipment.getTo().toString()); } else if (shipment.getDemand() == 2) { - Assertions.assertEquals(400, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(400, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); - Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryTimeWindow()); + Assertions.assertEquals(400, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(400, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) .add(shipment.getTo().toString()); } else { if (shipment.getDemand() == 3) { - Assertions.assertEquals(600, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(600, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); - Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryTimeWindow()); + Assertions.assertEquals(600, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(600, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) @@ -624,19 +624,19 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ countShipmentsWithCertainDemand.merge((Integer) shipment.getDemand(), 1, Integer::sum); countDemand = countDemand + shipment.getDemand(); if (shipment.getDemand() == 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()); + Assertions.assertEquals(300, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(350, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryStartsTimeWindow()); 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.getDemand() * 200, shipment.getPickupServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(shipment.getDemand() * 200, shipment.getDeliveryServiceTime(), MatsimTestUtils.EPSILON); - Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupTimeWindow()); - Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryTimeWindow()); + Assertions.assertEquals(shipment.getDemand() * 200, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(shipment.getDemand() * 200, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); + Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); + Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) .add(shipment.getFrom().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) 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 421ef4b2754..5641fbc85f9 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 @@ -157,17 +157,17 @@ private void writeShipments(Carrier carrier, BufferedWriter writer) { } private void writeShipment(CarrierShipment s, Id shipmentId, boolean closeElement, boolean lineBreak) { - this.writeStartTag(SHIPMENT, List.of( + this.writeStartTag(SHIPMENT, List.of( createTuple(ID, shipmentId.toString()), createTuple(FROM, s.getFrom().toString()), createTuple(TO, s.getTo().toString()), createTuple(SIZE, s.getDemand()), - createTuple(START_PICKUP, getTime(s.getPickupTimeWindow().getStart())), - createTuple(END_PICKUP, getTime(s.getPickupTimeWindow().getEnd())), - createTuple(START_DELIVERY, getTime(s.getDeliveryTimeWindow().getStart())), - createTuple(END_DELIVERY, getTime(s.getDeliveryTimeWindow().getEnd())), - createTuple(PICKUP_SERVICE_TIME, getTime(s.getPickupServiceTime())), - createTuple(DELIVERY_SERVICE_TIME, getTime(s.getDeliveryServiceTime()))), closeElement, lineBreak + createTuple(START_PICKUP, getTime(s.getPickupStartsTimeWindow().getStart())), + createTuple(END_PICKUP, getTime(s.getPickupStartsTimeWindow().getEnd())), + createTuple(START_DELIVERY, getTime(s.getDeliveryStartsTimeWindow().getStart())), + createTuple(END_DELIVERY, getTime(s.getDeliveryStartsTimeWindow().getEnd())), + createTuple(PICKUP_SERVICE_TIME, getTime(s.getPickupDuration())), + createTuple(DELIVERY_SERVICE_TIME, getTime(s.getDeliveryDuration()))), closeElement, lineBreak ); } 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 e39b82afa5a..1bdb0d390e2 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 @@ -241,19 +241,35 @@ private CarrierShipment(Builder builder) { deliveryStartsTimeWindow = builder.deliveryStartsTimeWindow; } - public double getPickupServiceTime() { + //* getters and setters + + public double getPickupDuration() { return pickupDuration; } - public void setPickupServiceTime(double pickupDuration) { - this.pickupDuration = pickupDuration; + public double getDeliveryDuration() { + return deliveryDuration; } - public double getDeliveryServiceTime() { - return deliveryDuration; + /** + * Do we really need the setter? We do have it in the builder. + * I do not see, why we should be able to update it, since most of the values are immutable. + * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable.. + * kturner, dec'24 + */ + @Deprecated(since = "dec'24") + public void setPickupDuration(double pickupDuration) { + this.pickupDuration = pickupDuration; } - public void setDeliveryServiceTime(double deliveryDuration) { + /** + * Do we really need the setter? We do have it in the builder. + * I do not see, why we should be able to update it, since most of the values are immutable. + * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable.. + * kturner, dec'24 + */ + @Deprecated(since = "dec'24") + public void setDeliveryDuration(double deliveryDuration) { this.deliveryDuration = deliveryDuration; } @@ -270,14 +286,6 @@ public Id getTo() { return deliveryLinkId; } - /** - * @deprecated please inline and use {@link #getDemand()} instead - */ - @Deprecated(since = "dec'24") - public int getSize() { - return getDemand(); - } - /** * @return the demand (size; capacity needed) of the shipment. */ @@ -286,11 +294,11 @@ public int getDemand() { return demand; } - public TimeWindow getPickupTimeWindow() { + public TimeWindow getPickupStartsTimeWindow() { return pickupStartsTimeWindow; } - public TimeWindow getDeliveryTimeWindow() { + public TimeWindow getDeliveryStartsTimeWindow() { return deliveryStartsTimeWindow; } @@ -299,6 +307,67 @@ public Attributes getAttributes() { return attributes; } + //*** deprecated methods *** + + /** + * @deprecated please inline and use {@link #getDemand()} instead + */ + @Deprecated(since = "dec'24") + public int getSize() { + return getDemand(); + } + + /** + * @deprecated please inline and use {@link #getPickupStartsTimeWindow()} instead + */ + @Deprecated(since = "dec'24") + public TimeWindow getPickupTimeWindow() { + return getPickupStartsTimeWindow(); + } + + + /** + * @deprecated please inline and use {@link #getDeliveryStartsTimeWindow()} instead + */ + @Deprecated(since = "dec'24") + public TimeWindow getDeliveryTimeWindow() { + return getDeliveryStartsTimeWindow(); + } + + /** + * @deprecated please inline and use {@link #getPickupDuration()} instead + */ + @Deprecated(since = "dec'24") + public double getPickupServiceTime() { + return getPickupDuration(); + } + + /** + * @deprecated please inline and use {@link #setPickupDuration(double)} instead + */ + @Deprecated(since = "dec'24") + public void setPickupServiceTime(double pickupDuration) { + setPickupDuration(pickupDuration); + } + + /** + * @deprecated please inline and use {@link #getDeliveryDuration()} instead + */ + @Deprecated(since = "dec'24") + public double getDeliveryServiceTime() { + return getDeliveryDuration(); + } + + /** + * @deprecated please inline and use {@link #setDeliveryDuration(double)} instead + */ + @Deprecated(since = "dec'24") + public void setDeliveryServiceTime(double deliveryDuration) { + setDeliveryDuration(deliveryDuration); + } + + // *** general methods *** + @Override public String toString() { return "[id= "+ id.toString() + "][hash=" + this.hashCode() + "][from=" + pickupLinkId.toString() + "][to=" + deliveryLinkId.toString() + "][size=" + demand + "][pickupServiceTime=" + pickupDuration + "]" + 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 aaf05ebbecc..41325eb3920 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 @@ -539,7 +539,7 @@ public String getActivityType() { @Override public TimeWindow getTimeWindow() { - return shipment.getPickupTimeWindow(); + return shipment.getPickupStartsTimeWindow(); } @Override @@ -549,7 +549,7 @@ public Id getLocation() { @Override public double getDuration() { - return shipment.getPickupServiceTime(); + return shipment.getPickupDuration(); } @Override @@ -592,7 +592,7 @@ public Delivery(CarrierShipment shipment) { @Override public TimeWindow getTimeWindow() { - return shipment.getDeliveryTimeWindow(); + return shipment.getDeliveryStartsTimeWindow(); } @Override @@ -607,7 +607,7 @@ public Id getLocation() { @Override public double getDuration() { - return shipment.getDeliveryServiceTime(); + return shipment.getDeliveryDuration(); } @Override 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 672d959dc36..fbd9e4ddff8 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 @@ -46,7 +46,7 @@ public class CarrierShipmentDeliveryEndEvent extends AbstractCarrierEvent { public CarrierShipmentDeliveryEndEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { super(time, carrierId, shipment.getTo(), vehicleId); this.shipmentId = shipment.getId(); - this.deliveryDuration = shipment.getDeliveryServiceTime(); + this.deliveryDuration = shipment.getDeliveryDuration(); this.capacityDemand = shipment.getDemand(); } 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 4635c159d5d..355b76782b0 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 @@ -47,7 +47,7 @@ public class CarrierShipmentDeliveryStartEvent extends AbstractCarrierEvent { public CarrierShipmentDeliveryStartEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { super(time, carrierId, shipment.getTo(), vehicleId); this.shipmentId = shipment.getId(); - this.deliveryDuration = shipment.getDeliveryServiceTime(); + this.deliveryDuration = shipment.getDeliveryDuration(); this.capacityDemand = shipment.getDemand(); } 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 601b39bbd37..1f669809087 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 @@ -48,7 +48,7 @@ public class CarrierShipmentPickupEndEvent extends AbstractCarrierEvent { public CarrierShipmentPickupEndEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { super(time, carrierId, shipment.getFrom(), vehicleId); this.shipmentId = shipment.getId(); - this.pickupDuration = shipment.getPickupServiceTime(); + this.pickupDuration = shipment.getPickupDuration(); this.capacityDemand = shipment.getDemand(); } 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 7154e2dba12..9e9bb519ae1 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 @@ -46,7 +46,7 @@ public class CarrierShipmentPickupStartEvent extends AbstractCarrierEvent { public CarrierShipmentPickupStartEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { super(time, carrierId, shipment.getFrom(), vehicleId); this.shipmentId = shipment.getId(); - this.pickupDuration = shipment.getPickupServiceTime(); + this.pickupDuration = shipment.getPickupDuration(); this.capacityDemand = shipment.getDemand(); } 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 0a056523f88..986eb953391 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 @@ -109,15 +109,15 @@ static CarrierShipment createCarrierShipment(Shipment jspritShipment) { static Shipment createJspritShipment(CarrierShipment carrierShipment) { Shipment.Builder shipmentBuilder = Shipment.Builder.newInstance(carrierShipment.getId().toString()) .setDeliveryLocation(Location.newInstance(carrierShipment.getTo().toString())) - .setDeliveryServiceTime(carrierShipment.getDeliveryServiceTime()) + .setDeliveryServiceTime(carrierShipment.getDeliveryDuration()) .setDeliveryTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow - .newInstance(carrierShipment.getDeliveryTimeWindow().getStart(), - carrierShipment.getDeliveryTimeWindow().getEnd())) - .setPickupServiceTime(carrierShipment.getPickupServiceTime()) + .newInstance(carrierShipment.getDeliveryStartsTimeWindow().getStart(), + carrierShipment.getDeliveryStartsTimeWindow().getEnd())) + .setPickupServiceTime(carrierShipment.getPickupDuration()) .setPickupLocation(Location.newInstance(carrierShipment.getFrom().toString())) .setPickupTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( - carrierShipment.getPickupTimeWindow().getStart(), - carrierShipment.getPickupTimeWindow().getEnd())) + carrierShipment.getPickupStartsTimeWindow().getStart(), + carrierShipment.getPickupStartsTimeWindow().getEnd())) .addSizeDimension(0, carrierShipment.getDemand()); for (String skill : CarriersUtils.getSkills(carrierShipment)) { shipmentBuilder.addRequiredSkill(skill); @@ -141,14 +141,14 @@ static Shipment createJspritShipment(CarrierShipment carrierShipment, Coord from Location toLocation = toLocationBuilder.build(); Shipment.Builder shipmentBuilder = Shipment.Builder.newInstance(carrierShipment.getId().toString()) - .setDeliveryLocation(toLocation).setDeliveryServiceTime(carrierShipment.getDeliveryServiceTime()) + .setDeliveryLocation(toLocation).setDeliveryServiceTime(carrierShipment.getDeliveryDuration()) .setDeliveryTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow - .newInstance(carrierShipment.getDeliveryTimeWindow().getStart(), - carrierShipment.getDeliveryTimeWindow().getEnd())) - .setPickupServiceTime(carrierShipment.getPickupServiceTime()).setPickupLocation(fromLocation) + .newInstance(carrierShipment.getDeliveryStartsTimeWindow().getStart(), + carrierShipment.getDeliveryStartsTimeWindow().getEnd())) + .setPickupServiceTime(carrierShipment.getPickupDuration()).setPickupLocation(fromLocation) .setPickupTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( - carrierShipment.getPickupTimeWindow().getStart(), - carrierShipment.getPickupTimeWindow().getEnd())) + carrierShipment.getPickupStartsTimeWindow().getStart(), + carrierShipment.getPickupStartsTimeWindow().getEnd())) .addSizeDimension(0, carrierShipment.getDemand()); for (String skill : CarriersUtils.getSkills(carrierShipment)) { shipmentBuilder.addRequiredSkill(skill); 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 index cc19c5c2064..70abe3fedd8 100644 --- 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 @@ -62,10 +62,10 @@ public static Collection createLSPShipmentsFromCarrierShipments(Car builder.setCapacityDemand(shipment.getDemand()); builder.setFromLinkId(shipment.getFrom()); builder.setToLinkId(shipment.getTo()); - builder.setStartTimeWindow(shipment.getPickupTimeWindow()); - builder.setEndTimeWindow(shipment.getDeliveryTimeWindow()); - builder.setPickupServiceTime(shipment.getPickupServiceTime()); - builder.setDeliveryServiceTime(shipment.getDeliveryServiceTime()); + builder.setStartTimeWindow(shipment.getPickupStartsTimeWindow()); + builder.setEndTimeWindow(shipment.getDeliveryStartsTimeWindow()); + builder.setPickupServiceTime(shipment.getPickupDuration()); + builder.setDeliveryServiceTime(shipment.getDeliveryDuration()); shipmentList.add(builder.build()); } return shipmentList; 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 a2f8130db57..705f4290980 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 @@ -194,13 +194,13 @@ void whenTransforming_jspritShipment2matsimShipment_isMadeCorrectly() { CarrierShipment carrierShipment = MatsimJspritFactory.createCarrierShipment(shipment); assertNotNull(carrierShipment); assertEquals("PickupLocationId", carrierShipment.getFrom().toString()); - assertEquals(30.0, carrierShipment.getPickupServiceTime(), 0.01); - assertEquals(10.0, carrierShipment.getPickupTimeWindow().getStart(), 0.01); - assertEquals(20.0, carrierShipment.getPickupTimeWindow().getEnd(), 0.01); + assertEquals(30.0, carrierShipment.getPickupDuration(), 0.01); + assertEquals(10.0, carrierShipment.getPickupStartsTimeWindow().getStart(), 0.01); + assertEquals(20.0, carrierShipment.getPickupStartsTimeWindow().getEnd(), 0.01); assertEquals("DeliveryLocationId", carrierShipment.getTo().toString()); - assertEquals(40.0, carrierShipment.getDeliveryServiceTime(), 0.01); - assertEquals(50.0, carrierShipment.getDeliveryTimeWindow().getStart(), 0.01); - assertEquals(60.0, carrierShipment.getDeliveryTimeWindow().getEnd(), 0.01); + assertEquals(40.0, carrierShipment.getDeliveryDuration(), 0.01); + assertEquals(50.0, carrierShipment.getDeliveryStartsTimeWindow().getStart(), 0.01); + assertEquals(60.0, carrierShipment.getDeliveryStartsTimeWindow().getEnd(), 0.01); assertEquals(50, carrierShipment.getDemand()); CarrierShipment carrierShipment2 = MatsimJspritFactory.createCarrierShipment(shipment); 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 46c783e197c..110ed45f27e 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 @@ -247,12 +247,12 @@ void copyingOfShipmentsIsDoneCorrectly() { Assertions.assertEquals(Id.createLinkId("i(1,0)"), carrierShipment1.getFrom()); Assertions.assertEquals(Id.createLinkId("i(7,6)R"), carrierShipment1.getTo()); Assertions.assertEquals(1, carrierShipment1.getDemand()); - Assertions.assertEquals(30.0, carrierShipment1.getDeliveryServiceTime(), 0); - Assertions.assertEquals(3600.0, carrierShipment1.getDeliveryTimeWindow().getStart(), 0); - Assertions.assertEquals(36000.0, carrierShipment1.getDeliveryTimeWindow().getEnd(), 0); - Assertions.assertEquals(5.0, carrierShipment1.getPickupServiceTime(), 0); - Assertions.assertEquals(0.0, carrierShipment1.getPickupTimeWindow().getStart(), 0); - Assertions.assertEquals(7200.0, carrierShipment1.getPickupTimeWindow().getEnd(), 0); + Assertions.assertEquals(30.0, carrierShipment1.getDeliveryDuration(), 0); + Assertions.assertEquals(3600.0, carrierShipment1.getDeliveryStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36000.0, carrierShipment1.getDeliveryStartsTimeWindow().getEnd(), 0); + Assertions.assertEquals(5.0, carrierShipment1.getPickupDuration(), 0); + Assertions.assertEquals(0.0, carrierShipment1.getPickupStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(7200.0, carrierShipment1.getPickupStartsTimeWindow().getEnd(), 0); } CarrierShipment carrierShipment2 = CarriersUtils.getShipment(carrierWShipmentsOnlyFromCarrierWShipments, Id.create("shipment2", CarrierShipment.class)); assert carrierShipment2 != null; @@ -262,12 +262,12 @@ void copyingOfShipmentsIsDoneCorrectly() { Assertions.assertEquals(Id.createLinkId("i(3,0)"), carrierShipment2.getFrom()); Assertions.assertEquals(Id.createLinkId("i(3,7)"), carrierShipment2.getTo()); Assertions.assertEquals(2, carrierShipment2.getDemand()); - Assertions.assertEquals(30.0, carrierShipment2.getDeliveryServiceTime(), 0); - Assertions.assertEquals(3600.0, carrierShipment2.getDeliveryTimeWindow().getStart(), 0); - Assertions.assertEquals(36000.0, carrierShipment2.getDeliveryTimeWindow().getEnd(), 0); - Assertions.assertEquals(5.0, carrierShipment2.getPickupServiceTime(), 0); - Assertions.assertEquals(0.0, carrierShipment2.getPickupTimeWindow().getStart(), 0); - Assertions.assertEquals(7200.0, carrierShipment2.getPickupTimeWindow().getEnd(), 0); + Assertions.assertEquals(30.0, carrierShipment2.getDeliveryDuration(), 0); + Assertions.assertEquals(3600.0, carrierShipment2.getDeliveryStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36000.0, carrierShipment2.getDeliveryStartsTimeWindow().getEnd(), 0); + Assertions.assertEquals(5.0, carrierShipment2.getPickupDuration(), 0); + Assertions.assertEquals(0.0, carrierShipment2.getPickupStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(7200.0, carrierShipment2.getPickupStartsTimeWindow().getEnd(), 0); } Assertions.assertTrue(foundShipment1, "Not found Shipment1 after copying"); Assertions.assertTrue(foundShipment2, "Not found Shipment2 after copying"); @@ -285,12 +285,12 @@ void convertionOfServicesIsDoneCorrectly() { Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment1.getFrom()); Assertions.assertEquals(Id.createLinkId("i(3,9)"), carrierShipment1.getTo()); Assertions.assertEquals(2, carrierShipment1.getDemand()); - Assertions.assertEquals(31.0, carrierShipment1.getDeliveryServiceTime(), 0); - Assertions.assertEquals(3601.0, carrierShipment1.getDeliveryTimeWindow().getStart(), 0); - Assertions.assertEquals(36001.0, carrierShipment1.getDeliveryTimeWindow().getEnd(), 0); - Assertions.assertEquals(0.0, carrierShipment1.getPickupServiceTime(), 0); - Assertions.assertEquals(0.0, carrierShipment1.getPickupTimeWindow().getStart(), 0); - Assertions.assertEquals(36001.0, carrierShipment1.getPickupTimeWindow().getEnd(), 0); + Assertions.assertEquals(31.0, carrierShipment1.getDeliveryDuration(), 0); + Assertions.assertEquals(3601.0, carrierShipment1.getDeliveryStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36001.0, carrierShipment1.getDeliveryStartsTimeWindow().getEnd(), 0); + Assertions.assertEquals(0.0, carrierShipment1.getPickupDuration(), 0); + Assertions.assertEquals(0.0, carrierShipment1.getPickupStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36001.0, carrierShipment1.getPickupStartsTimeWindow().getEnd(), 0); } CarrierShipment carrierShipment2 = CarriersUtils.getShipment(carrierWShipmentsOnlyFromCarrierWServices, Id.create("Service2", CarrierShipment.class)); assert carrierShipment2 != null; @@ -299,12 +299,12 @@ void convertionOfServicesIsDoneCorrectly() { Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment2.getFrom()); Assertions.assertEquals(Id.createLinkId("i(4,9)"), carrierShipment2.getTo()); Assertions.assertEquals(2, carrierShipment2.getDemand()); - Assertions.assertEquals(31.0, carrierShipment2.getDeliveryServiceTime(), 0); - Assertions.assertEquals(3601.0, carrierShipment2.getDeliveryTimeWindow().getStart(), 0); - Assertions.assertEquals(36001.0, carrierShipment2.getDeliveryTimeWindow().getEnd(), 0); - Assertions.assertEquals(0.0, carrierShipment2.getPickupServiceTime(), 0); - Assertions.assertEquals(0.0, carrierShipment2.getPickupTimeWindow().getStart(), 0); - Assertions.assertEquals(36001.0, carrierShipment2.getPickupTimeWindow().getEnd(), 0); + Assertions.assertEquals(31.0, carrierShipment2.getDeliveryDuration(), 0); + Assertions.assertEquals(3601.0, carrierShipment2.getDeliveryStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36001.0, carrierShipment2.getDeliveryStartsTimeWindow().getEnd(), 0); + Assertions.assertEquals(0.0, carrierShipment2.getPickupDuration(), 0); + Assertions.assertEquals(0.0, carrierShipment2.getPickupStartsTimeWindow().getStart(), 0); + Assertions.assertEquals(36001.0, carrierShipment2.getPickupStartsTimeWindow().getEnd(), 0); } Assertions.assertTrue(foundService1, "Not found converted Service1 after converting"); Assertions.assertTrue(foundService2, "Not found converted Service2 after converting"); diff --git a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java index e7126cca05e..91613aa1d34 100644 --- a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java +++ b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java @@ -57,12 +57,14 @@ public void trackDeliveryActivity(ActivityStartEvent activityStartEvent) { for (ShipmentTracker shipment: shipments.values()){ if (shipment.to==activityStartEvent.getLinkId() ){ if(shipment.driverId == null){ - if(shipment.shipment.getDeliveryTimeWindow().getStart()<=activityStartEvent.getTime() && activityStartEvent.getTime()<=shipment.shipment.getDeliveryTimeWindow().getEnd()){ - if (shipment.possibleDrivers.contains(activityStartEvent.getPersonId().toString())) { - shipment.driverIdGuess = activityStartEvent.getPersonId(); - shipment.deliveryTimeGuess=activityStartEvent.getTime(); - } - } + if(shipment.shipment.getDeliveryStartsTimeWindow().getStart() <= activityStartEvent.getTime()) { + if (activityStartEvent.getTime()<= shipment.shipment.getDeliveryStartsTimeWindow().getEnd()) { + if (shipment.possibleDrivers.contains(activityStartEvent.getPersonId().toString())) { + shipment.driverIdGuess = activityStartEvent.getPersonId(); + shipment.deliveryTimeGuess=activityStartEvent.getTime(); + } + } + } } else if (shipment.driverId.toString().equals(activityStartEvent.getPersonId().toString())){ shipment.deliveryTime=activityStartEvent.getTime(); } @@ -75,8 +77,10 @@ public void trackPickupActivity(ActivityStartEvent activityStartEvent) { for (ShipmentTracker shipmentTracker: shipments.values()){ if (shipmentTracker.from==activityStartEvent.getLinkId()){ if (shipmentTracker.driverId==null){ - if(shipmentTracker.shipment.getPickupTimeWindow().getStart()<=activityStartEvent.getTime() && activityStartEvent.getTime()<=shipmentTracker.shipment.getPickupTimeWindow().getEnd()){ - shipmentTracker.possibleDrivers.add(activityStartEvent.getPersonId().toString()); + if(shipmentTracker.shipment.getPickupStartsTimeWindow().getStart() <= activityStartEvent.getTime()) { + if (activityStartEvent.getTime()<= shipmentTracker.shipment.getPickupStartsTimeWindow().getEnd()) { + shipmentTracker.possibleDrivers.add(activityStartEvent.getPersonId().toString()); + } } } } From 1eac34488d393021d4012f8e8f98e1894cde2c55 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 14:55:31 +0100 Subject: [PATCH 37/39] rename getters and setters to make it more consistent. old setters remain as deprecated --- .../DemandReaderFromCSV.java | 10 ++-- .../FreightDemandGenerationUtils.java | 12 ++--- .../DemandReaderFromCSVTest.java | 46 +++++++++---------- .../freight/carriers/CarrierPlanReaderV1.java | 8 ++-- .../carriers/CarrierPlanXmlParserV2.java | 12 ++--- .../carriers/CarrierPlanXmlParserV2_1.java | 12 ++--- .../carriers/CarrierPlanXmlWriterV2_1.java | 6 +-- .../freight/carriers/CarrierService.java | 10 +++- .../freight/carriers/CarrierShipment.java | 20 +++++++- .../freight/carriers/CarriersUtils.java | 2 +- .../org/matsim/freight/carriers/Tour.java | 6 +-- .../events/CarrierServiceEndEvent.java | 2 +- .../events/CarrierServiceStartEvent.java | 2 +- .../CarrierShipmentDeliveryEndEvent.java | 2 +- .../CarrierShipmentDeliveryStartEvent.java | 2 +- .../events/CarrierShipmentPickupEndEvent.java | 2 +- .../CarrierShipmentPickupStartEvent.java | 2 +- .../carriers/jsprit/MatsimJspritFactory.java | 34 +++++++------- .../multipleChains/MultipleChainsUtils.java | 4 +- .../freight/carriers/CarriersUtilsTest.java | 8 ++-- .../jsprit/MatsimTransformerTest.java | 8 ++-- .../utils/CarrierControllerUtilsTest.java | 16 +++---- .../CollectionLSPSchedulingTest.java | 4 +- .../CompleteLSPSchedulingTest.java | 16 +++---- .../FirstReloadLSPSchedulingTest.java | 6 +-- .../MainRunLSPSchedulingTest.java | 10 ++-- ...eShipmentsCollectionLSPSchedulingTest.java | 4 +- ...pleShipmentsCompleteLSPSchedulingTest.java | 16 +++---- ...ShipmentsFirstReloadLSPSchedulingTest.java | 6 +-- ...ipleShipmentsMainRunLSPSchedulingTest.java | 10 ++-- ...hipmentsSecondReloadLSPSchedulingTest.java | 12 ++--- .../SecondReloadLSPSchedulingTest.java | 12 ++--- .../receiver/ReceiverControlerListener.java | 2 +- ...tingTrafficToSmallScaleCommercialImpl.java | 10 ++-- .../DefaultUnhandledServicesSolution.java | 2 +- .../analysis/FreightAnalysisEventHandler.java | 4 +- .../FreightAnalysisServiceTracking.java | 2 +- .../FreightAnalysisShipmentTracking.java | 4 +- 38 files changed, 185 insertions(+), 161 deletions(-) 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 2ebf3060e2e..6b2d6c10784 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/DemandReaderFromCSV.java @@ -1188,8 +1188,8 @@ private static void combineSimilarJobs(Scenario scenario) { if (!shipmentsToRemove.containsKey(thisShipmentId)) { CarrierShipment thisShipment = thisCarrier.getShipments().get(thisShipmentId); if (baseShipment.getId() != thisShipment.getId() - && baseShipment.getFrom() == thisShipment.getFrom() - && baseShipment.getTo() == thisShipment.getTo()) { + && baseShipment.getPickupLinkId() == thisShipment.getPickupLinkId() + && baseShipment.getDeliveryLinkId() == thisShipment.getDeliveryLinkId()) { if (baseShipment.getPickupStartsTimeWindow() == thisShipment.getPickupStartsTimeWindow()) { if (baseShipment.getDeliveryStartsTimeWindow() == thisShipment.getDeliveryStartsTimeWindow()) shipmentsToConnect.put(thisShipmentId, thisShipment); } @@ -1207,7 +1207,7 @@ private static void combineSimilarJobs(Scenario scenario) { shipmentsToRemove.put(carrierShipment.getId(), carrierShipment); } CarrierShipment newShipment = CarrierShipment.Builder - .newInstance(idNewShipment, baseShipment.getFrom(), baseShipment.getTo(), demandForThisLink) + .newInstance(idNewShipment, baseShipment.getPickupLinkId(), baseShipment.getDeliveryLinkId(), demandForThisLink) .setPickupDuration(serviceTimePickup) .setPickupStartsTimeWindow(baseShipment.getPickupStartsTimeWindow()) .setDeliveryDuration(serviceTimeDelivery) @@ -1237,7 +1237,7 @@ private static void combineSimilarJobs(Scenario scenario) { if (!servicesToRemove.containsKey(thisServiceId)) { CarrierService thisService = thisCarrier.getServices().get(thisServiceId); if (baseService.getId() != thisService.getId() - && baseService.getLocationLinkId() == thisService.getLocationLinkId() && baseService + && baseService.getServiceLinkId() == thisService.getServiceLinkId() && baseService .getServiceStartTimeWindow() == thisService.getServiceStartTimeWindow()) servicesToConnect.put(thisServiceId, thisService); } @@ -1251,7 +1251,7 @@ private static void combineSimilarJobs(Scenario scenario) { servicesToRemove.put(carrierService.getId(), carrierService); } CarrierService newService = CarrierService.Builder - .newInstance(idNewService, baseService.getLocationLinkId()) + .newInstance(idNewService, baseService.getServiceLinkId()) .setServiceDuration(serviceTimeService) .setServiceStartTimeWindow(baseService.getServiceStartTimeWindow()) .setDemand(demandForThisLink).build(); 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 ede28ace76d..235789535db 100644 --- a/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java +++ b/contribs/application/src/main/java/org/matsim/freightDemandGeneration/FreightDemandGenerationUtils.java @@ -130,23 +130,23 @@ static void createDemandLocationsFile(Controler controler) { for (Carrier thisCarrier : CarriersUtils.getCarriers(controler.getScenario()).getCarriers().values()) { for (CarrierService thisService : thisCarrier.getServices().values()) { Coord coord = FreightDemandGenerationUtils - .getCoordOfMiddlePointOfLink(network.getLinks().get(thisService.getLocationLinkId())); + .getCoordOfMiddlePointOfLink(network.getLinks().get(thisService.getServiceLinkId())); writer.write(thisCarrier.getId().toString() + thisService.getId().toString() + " " + coord.getX() + " " + coord.getY() + " " + "Service" + " " - + thisService.getLocationLinkId().toString() + " " + "\n"); + + thisService.getServiceLinkId().toString() + " " + "\n"); } for (CarrierShipment thisShipment : thisCarrier.getShipments().values()) { Coord coordFrom = FreightDemandGenerationUtils - .getCoordOfMiddlePointOfLink(network.getLinks().get(thisShipment.getFrom())); + .getCoordOfMiddlePointOfLink(network.getLinks().get(thisShipment.getPickupLinkId())); Coord coordTo = FreightDemandGenerationUtils - .getCoordOfMiddlePointOfLink(network.getLinks().get(thisShipment.getTo())); + .getCoordOfMiddlePointOfLink(network.getLinks().get(thisShipment.getDeliveryLinkId())); writer.write(thisCarrier.getId().toString() + thisShipment.getId().toString() + " " + coordFrom.getX() + " " + coordFrom.getY() + " " + "Pickup" + " " - + thisShipment.getFrom().toString() + " " + thisShipment.getTo().toString() + "\n"); + + thisShipment.getPickupLinkId().toString() + " " + thisShipment.getDeliveryLinkId().toString() + "\n"); writer.write(thisCarrier.getId().toString() + thisShipment.getId() + " " + coordTo.getX() + " " + coordTo.getY() + " " + "Delivery" + " " - + thisShipment.getFrom() + " " + thisShipment.getTo() + "\n"); + + thisShipment.getPickupLinkId() + " " + thisShipment.getDeliveryLinkId() + "\n"); } } writer.flush(); 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 d27e5d5a202..32972385d8a 100644 --- a/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java +++ b/contribs/application/src/test/java/org/matsim/freightDemandGeneration/DemandReaderFromCSVTest.java @@ -109,9 +109,9 @@ void demandCreationWithSampleWithChangeNumberOfLocations() throws IOException { Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } Assertions.assertEquals(20, countDemand); Assertions.assertEquals(4, countShipmentsWithCertainDemand.getInt(5)); @@ -176,9 +176,9 @@ void demandCreationWithSampleWithDemandOnLocation() throws IOException { Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } Assertions.assertEquals(20, countDemand); Assertions.assertEquals(2, countShipmentsWithCertainDemand.getInt(10)); @@ -243,9 +243,9 @@ void demandCreationWithSampleWithDemandOnLocationWithCombiningJobs() throws IOEx Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } Assertions.assertEquals(20, countDemand); Assertions.assertEquals(2, countShipmentsWithCertainDemand.getInt(10)); @@ -313,9 +313,9 @@ void demandCreationNoSampling() throws IOException { Assertions.assertEquals(TimeWindow.newInstance(8000, 50000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(10000, 60000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } Assertions.assertEquals(20, countDemand); Assertions.assertEquals(2, countShipmentsWithCertainDemand.getInt(10)); @@ -480,18 +480,18 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt 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()); + .add(service.getServiceLinkId().toString()); } else if (service.getDemand() == 1) { Assertions.assertEquals(100, service.getServiceDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) - .add(service.getLocationLinkId().toString()); + .add(service.getServiceLinkId().toString()); } else { if (service.getDemand() == 2) { Assertions.assertEquals(200, service.getServiceDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) - .add(service.getLocationLinkId().toString()); + .add(service.getServiceLinkId().toString()); } else Assertions.fail("Service has a wrong demand."); } @@ -530,18 +530,18 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } else if (shipment.getDemand() == 2) { Assertions.assertEquals(400, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(400, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } else { if (shipment.getDemand() == 3) { Assertions.assertEquals(600, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); @@ -549,9 +549,9 @@ private static void checkCarrier1and2(Scenario scenario, Network network, ShpOpt Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } else Assertions.fail("Shipment has an unexpected demand."); } @@ -589,12 +589,12 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ 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()); + .add(service.getServiceLinkId().toString()); } else { Assertions.assertEquals(service.getDemand() * 100, service.getServiceDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(5000, 20000), service.getServiceStartTimeWindow()); locationsPerServiceElement.computeIfAbsent("serviceElement2", (k) -> new HashSet<>()) - .add(service.getLocationLinkId().toString()); + .add(service.getServiceLinkId().toString()); } } Assertions.assertEquals(12, countDemand); @@ -629,18 +629,18 @@ private static void checkCarrier1and2WithCombiningJobs(Scenario scenario, Networ Assertions.assertEquals(TimeWindow.newInstance(10000, 45000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement1_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } else { Assertions.assertEquals(shipment.getDemand() * 200, shipment.getPickupDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(shipment.getDemand() * 200, shipment.getDeliveryDuration(), MatsimTestUtils.EPSILON); Assertions.assertEquals(TimeWindow.newInstance(11000, 44000), shipment.getPickupStartsTimeWindow()); Assertions.assertEquals(TimeWindow.newInstance(20000, 40000), shipment.getDeliveryStartsTimeWindow()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_pickup", (k) -> new HashSet<>()) - .add(shipment.getFrom().toString()); + .add(shipment.getPickupLinkId().toString()); locationsPerShipmentElement.computeIfAbsent("ShipmentElement2_delivery", (k) -> new HashSet<>()) - .add(shipment.getTo().toString()); + .add(shipment.getDeliveryLinkId().toString()); } } Assertions.assertEquals(15, countDemand); 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 42b2317a6cb..c22b5928899 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 @@ -208,16 +208,16 @@ public void startTag(String name, Attributes attributes, Stack context) case "pickup" -> { String id = attributes.getValue(SHIPMENT_ID); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getFrom()); + finishLeg(s.getPickupLinkId()); currentTourBuilder.schedulePickup(s); - previousActLoc = s.getFrom(); + previousActLoc = s.getPickupLinkId(); } case "delivery" -> { String id = attributes.getValue(SHIPMENT_ID); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getTo()); + finishLeg(s.getDeliveryLinkId()); currentTourBuilder.scheduleDelivery(s); - previousActLoc = s.getTo(); + previousActLoc = s.getDeliveryLinkId(); } case "end" -> { finishLeg(currentVehicle.getLinkId()); 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 599c48a3886..7bbc83c9479 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 @@ -261,26 +261,26 @@ public void startTag(String name, Attributes atts, Stack context) { String id = atts.getValue(SHIPMENT_ID); if (id == null) throw new IllegalStateException("pickup.shipmentId is missing."); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getFrom()); + finishLeg(s.getPickupLinkId()); currentTourBuilder.schedulePickup(s); - previousActLoc = s.getFrom(); + previousActLoc = s.getPickupLinkId(); } case "delivery" -> { String id = atts.getValue(SHIPMENT_ID); if (id == null) throw new IllegalStateException("delivery.shipmentId is missing."); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getTo()); + finishLeg(s.getDeliveryLinkId()); currentTourBuilder.scheduleDelivery(s); - previousActLoc = s.getTo(); + previousActLoc = s.getDeliveryLinkId(); } case "service" -> { String id = atts.getValue("serviceId"); if (id == null) throw new IllegalStateException("act.serviceId is missing."); CarrierService s = serviceMap.get(Id.create(id, CarrierService.class)); if (s == null) throw new IllegalStateException("serviceId is not known."); - finishLeg(s.getLocationLinkId()); + finishLeg(s.getServiceLinkId()); currentTourBuilder.scheduleService(s); - previousActLoc = s.getLocationLinkId(); + previousActLoc = s.getServiceLinkId(); } case "end" -> { finishLeg(currentVehicle.getLinkId()); 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 a9f06abb1f4..f439d323ddd 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 @@ -263,26 +263,26 @@ public void startTag(String name, Attributes atts, Stack context) { String id = atts.getValue(SHIPMENT_ID); if (id == null) throw new IllegalStateException("pickup.shipmentId is missing."); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getFrom()); + finishLeg(s.getPickupLinkId()); currentTourBuilder.schedulePickup(s); - previousActLoc = s.getFrom(); + previousActLoc = s.getPickupLinkId(); } case "delivery" -> { String id = atts.getValue(SHIPMENT_ID); if (id == null) throw new IllegalStateException("delivery.shipmentId is missing."); CarrierShipment s = currentShipments.get(id); - finishLeg(s.getTo()); + finishLeg(s.getDeliveryLinkId()); currentTourBuilder.scheduleDelivery(s); - previousActLoc = s.getTo(); + previousActLoc = s.getDeliveryLinkId(); } case "service" -> { String id = atts.getValue("serviceId"); if (id == null) throw new IllegalStateException("act.serviceId is missing."); CarrierService s = serviceMap.get(Id.create(id, CarrierService.class)); if (s == null) throw new IllegalStateException("serviceId is not known."); - finishLeg(s.getLocationLinkId()); + finishLeg(s.getServiceLinkId()); currentTourBuilder.scheduleService(s); - previousActLoc = s.getLocationLinkId(); + previousActLoc = s.getServiceLinkId(); } case "end" -> { finishLeg(currentVehicle.getLinkId()); 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 5641fbc85f9..811153ead21 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 @@ -159,8 +159,8 @@ private void writeShipments(Carrier carrier, BufferedWriter writer) { private void writeShipment(CarrierShipment s, Id shipmentId, boolean closeElement, boolean lineBreak) { this.writeStartTag(SHIPMENT, List.of( createTuple(ID, shipmentId.toString()), - createTuple(FROM, s.getFrom().toString()), - createTuple(TO, s.getTo().toString()), + createTuple(FROM, s.getPickupLinkId().toString()), + createTuple(TO, s.getDeliveryLinkId().toString()), createTuple(SIZE, s.getDemand()), createTuple(START_PICKUP, getTime(s.getPickupStartsTimeWindow().getStart())), createTuple(END_PICKUP, getTime(s.getPickupStartsTimeWindow().getEnd())), @@ -190,7 +190,7 @@ private void writeServices(Carrier carrier, BufferedWriter writer) { private void writeService(CarrierService s, boolean closeElement, boolean lineBreak) { this.writeStartTag(SERVICE, List.of( createTuple(ID, s.getId().toString()), - createTuple(TO, s.getLocationLinkId().toString()), + createTuple(TO, s.getServiceLinkId().toString()), createTuple(CAPACITY_DEMAND, s.getDemand()), createTuple(EARLIEST_START, getTime(s.getServiceStartTimeWindow().getStart())), createTuple(LATEST_END, getTime(s.getServiceStartTimeWindow().getEnd())), 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 7a140a5b386..99be9a2f21f 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 @@ -141,10 +141,18 @@ public Id getId() { return id; } - public Id getLocationLinkId() { + public Id getServiceLinkId() { return serviceLinkId; } + /** + * @deprecated please inline and use {@link #getServiceLinkId()} instead + */ + @Deprecated(since = "dec'24") + public Id getLocationLinkId() { + return getServiceLinkId(); + } + public double getServiceDuration() { return serviceDuration; } 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 1bdb0d390e2..a78e636ee49 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 @@ -278,11 +278,11 @@ public Id getId() { return id; } - public Id getFrom() { + public Id getPickupLinkId() { return pickupLinkId; } - public Id getTo() { + public Id getDeliveryLinkId() { return deliveryLinkId; } @@ -317,6 +317,22 @@ public int getSize() { return getDemand(); } + /** + * @deprecated please inline and use {@link #getPickupLinkId()} instead + */ + @Deprecated(since = "dec'24") + public Id getFrom() { + return getPickupLinkId(); + } + + /** + * @deprecated please inline and use {@link #getDeliveryLinkId()} instead + */ + @Deprecated(since = "dec'24") + public Id getTo() { + return getDeliveryLinkId(); + } + /** * @deprecated please inline and use {@link #getPickupStartsTimeWindow()} instead */ 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 61a7ff0c27b..d82e2e0ba46 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 @@ -430,7 +430,7 @@ private static void createShipmentsFromServices(Carrier carrierWS, Carrier carri log.debug("Converting CarrierService to CarrierShipment: {}", carrierService.getId()); CarrierShipment carrierShipment = CarrierShipment.Builder .newInstance(Id.create(carrierService.getId().toString(), CarrierShipment.class), - depotServiceIsDeliveredFrom.get(carrierService.getId()), carrierService.getLocationLinkId(), + depotServiceIsDeliveredFrom.get(carrierService.getId()), carrierService.getServiceLinkId(), carrierService.getDemand()) .setDeliveryDuration(carrierService.getServiceDuration()) // .setPickupServiceTime(pickupServiceTime) //Not set yet, because in service we 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 41325eb3920..fec5bc60655 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 @@ -379,7 +379,7 @@ public String getActivityType() { @Override public Id getLocation() { - return service.getLocationLinkId(); + return service.getServiceLinkId(); } @Override @@ -544,7 +544,7 @@ public TimeWindow getTimeWindow() { @Override public Id getLocation() { - return shipment.getFrom(); + return shipment.getPickupLinkId(); } @Override @@ -602,7 +602,7 @@ public String getActivityType() { @Override public Id getLocation() { - return shipment.getTo(); + return shipment.getDeliveryLinkId(); } @Override 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 f806248471c..17907fe74eb 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 @@ -42,7 +42,7 @@ public final class CarrierServiceEndEvent extends AbstractCarrierEvent { private final double serviceDuration; public CarrierServiceEndEvent(double time, Id carrierId, CarrierService service, Id vehicleId) { - super(time, carrierId, service.getLocationLinkId(), vehicleId); + super(time, carrierId, service.getServiceLinkId(), vehicleId); this.serviceId = service.getId(); this.serviceDuration = service.getServiceDuration(); } 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 02b24c5d56c..f0a2cc0fde6 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 @@ -44,7 +44,7 @@ public final class CarrierServiceStartEvent extends AbstractCarrierEvent { private final int capacityDemand; public CarrierServiceStartEvent(double time, Id carrierId, CarrierService service, Id vehicleId) { - super(time, carrierId, service.getLocationLinkId(), vehicleId); + super(time, carrierId, service.getServiceLinkId(), vehicleId); this.serviceId = service.getId(); this.serviceDuration = service.getServiceDuration(); this.capacityDemand = service.getDemand(); 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 fbd9e4ddff8..2687b550387 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 @@ -44,7 +44,7 @@ public class CarrierShipmentDeliveryEndEvent extends AbstractCarrierEvent { private final double deliveryDuration; private final int capacityDemand; public CarrierShipmentDeliveryEndEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { - super(time, carrierId, shipment.getTo(), vehicleId); + super(time, carrierId, shipment.getDeliveryLinkId(), vehicleId); this.shipmentId = shipment.getId(); this.deliveryDuration = shipment.getDeliveryDuration(); this.capacityDemand = shipment.getDemand(); 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 355b76782b0..ca4a2ec4767 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 @@ -45,7 +45,7 @@ public class CarrierShipmentDeliveryStartEvent extends AbstractCarrierEvent { private final double deliveryDuration; private final int capacityDemand; public CarrierShipmentDeliveryStartEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { - super(time, carrierId, shipment.getTo(), vehicleId); + super(time, carrierId, shipment.getDeliveryLinkId(), vehicleId); this.shipmentId = shipment.getId(); this.deliveryDuration = shipment.getDeliveryDuration(); this.capacityDemand = shipment.getDemand(); 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 1f669809087..97da9f70817 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 @@ -46,7 +46,7 @@ public class CarrierShipmentPickupEndEvent extends AbstractCarrierEvent { public CarrierShipmentPickupEndEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { - super(time, carrierId, shipment.getFrom(), vehicleId); + super(time, carrierId, shipment.getPickupLinkId(), vehicleId); this.shipmentId = shipment.getId(); this.pickupDuration = shipment.getPickupDuration(); this.capacityDemand = shipment.getDemand(); 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 9e9bb519ae1..7334a9fa8a6 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 @@ -44,7 +44,7 @@ public class CarrierShipmentPickupStartEvent extends AbstractCarrierEvent { public CarrierShipmentPickupStartEvent(double time, Id carrierId, CarrierShipment shipment, Id vehicleId) { - super(time, carrierId, shipment.getFrom(), vehicleId); + super(time, carrierId, shipment.getPickupLinkId(), vehicleId); this.shipmentId = shipment.getId(); this.pickupDuration = shipment.getPickupDuration(); this.capacityDemand = shipment.getDemand(); 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 986eb953391..11776d0152b 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 @@ -108,13 +108,13 @@ static CarrierShipment createCarrierShipment(Shipment jspritShipment) { */ static Shipment createJspritShipment(CarrierShipment carrierShipment) { Shipment.Builder shipmentBuilder = Shipment.Builder.newInstance(carrierShipment.getId().toString()) - .setDeliveryLocation(Location.newInstance(carrierShipment.getTo().toString())) + .setDeliveryLocation(Location.newInstance(carrierShipment.getDeliveryLinkId().toString())) .setDeliveryServiceTime(carrierShipment.getDeliveryDuration()) .setDeliveryTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow .newInstance(carrierShipment.getDeliveryStartsTimeWindow().getStart(), carrierShipment.getDeliveryStartsTimeWindow().getEnd())) .setPickupServiceTime(carrierShipment.getPickupDuration()) - .setPickupLocation(Location.newInstance(carrierShipment.getFrom().toString())) + .setPickupLocation(Location.newInstance(carrierShipment.getPickupLinkId().toString())) .setPickupTimeWindow(com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow.newInstance( carrierShipment.getPickupStartsTimeWindow().getStart(), carrierShipment.getPickupStartsTimeWindow().getEnd())) @@ -127,14 +127,14 @@ static Shipment createJspritShipment(CarrierShipment carrierShipment) { static Shipment createJspritShipment(CarrierShipment carrierShipment, Coord fromCoord, Coord toCoord) { Location.Builder fromLocationBuilder = Location.Builder.newInstance(); - fromLocationBuilder.setId(carrierShipment.getFrom().toString()); + fromLocationBuilder.setId(carrierShipment.getPickupLinkId().toString()); if (fromCoord != null) { fromLocationBuilder.setCoordinate(Coordinate.newInstance(fromCoord.getX(), fromCoord.getY())); } Location fromLocation = fromLocationBuilder.build(); Location.Builder toLocationBuilder = Location.Builder.newInstance(); - toLocationBuilder.setId(carrierShipment.getTo().toString()); + toLocationBuilder.setId(carrierShipment.getDeliveryLinkId().toString()); if (toCoord != null) { toLocationBuilder.setCoordinate(Coordinate.newInstance(toCoord.getX(), toCoord.getY())); } @@ -158,7 +158,7 @@ static Shipment createJspritShipment(CarrierShipment carrierShipment, Coord from static Service createJspritService(CarrierService carrierService, Coord locationCoord) { Location.Builder locationBuilder = Location.Builder.newInstance(); - locationBuilder.setId(carrierService.getLocationLinkId().toString()); + locationBuilder.setId(carrierService.getServiceLinkId().toString()); if (locationCoord != null) { locationBuilder.setCoordinate(Coordinate.newInstance(locationCoord.getX(), locationCoord.getY())); } @@ -515,11 +515,11 @@ public static VehicleRoutingProblem createRoutingProblem(Carrier carrier, Networ Coord coordinate = null; if (network != null) { - Link link = network.getLinks().get(service.getLocationLinkId()); + Link link = network.getLinks().get(service.getServiceLinkId()); if (link != null) { coordinate = link.getCoord(); } else - log.warn("cannot find linkId {}", service.getLocationLinkId()); + log.warn("cannot find linkId {}", service.getServiceLinkId()); } vrpBuilder.addJob(createJspritService(service, coordinate)); } @@ -530,8 +530,8 @@ public static VehicleRoutingProblem createRoutingProblem(Carrier carrier, Networ Coord fromCoordinate = null; Coord toCoordinate = null; if (network != null) { - Link fromLink = network.getLinks().get(carrierShipment.getFrom()); - Link toLink = network.getLinks().get(carrierShipment.getTo()); + Link fromLink = network.getLinks().get(carrierShipment.getPickupLinkId()); + Link toLink = network.getLinks().get(carrierShipment.getDeliveryLinkId()); if (fromLink != null && toLink != null) { // Shipment to be delivered from specified location to // specified location @@ -540,8 +540,8 @@ public static VehicleRoutingProblem createRoutingProblem(Carrier carrier, Networ vrpBuilder.addJob(createJspritShipment(carrierShipment, fromCoordinate, toCoordinate)); } else throw new IllegalStateException( - "cannot create shipment since neither fromLinkId " + carrierShipment.getTo() - + " nor toLinkId " + carrierShipment.getTo() + " exists in network."); + "cannot create shipment since neither fromLinkId " + carrierShipment.getDeliveryLinkId() + + " nor toLinkId " + carrierShipment.getDeliveryLinkId() + " exists in network."); } vrpBuilder.addJob(createJspritShipment(carrierShipment, fromCoordinate, toCoordinate)); @@ -611,9 +611,9 @@ public static VehicleRoutingProblem.Builder createRoutingProblemBuilder(Carrier log.debug("Handle CarrierService: {}", service.toString()); Coord coordinate = null; if (network != null) { - Link link = network.getLinks().get(service.getLocationLinkId()); + Link link = network.getLinks().get(service.getServiceLinkId()); if (link == null) { - throw new IllegalStateException("cannot create service since linkId " + service.getLocationLinkId() + throw new IllegalStateException("cannot create service since linkId " + service.getServiceLinkId() + " does not exists in network."); } else coordinate = link.getCoord(); @@ -628,8 +628,8 @@ public static VehicleRoutingProblem.Builder createRoutingProblemBuilder(Carrier Coord fromCoordinate = null; Coord toCoordinate = null; if (network != null) { - Link fromLink = network.getLinks().get(carrierShipment.getFrom()); - Link toLink = network.getLinks().get(carrierShipment.getTo()); + Link fromLink = network.getLinks().get(carrierShipment.getPickupLinkId()); + Link toLink = network.getLinks().get(carrierShipment.getDeliveryLinkId()); if (fromLink != null && toLink != null) { // Shipment to be delivered from specified location to // specified location @@ -638,8 +638,8 @@ public static VehicleRoutingProblem.Builder createRoutingProblemBuilder(Carrier toCoordinate = toLink.getCoord(); } else throw new IllegalStateException("cannot create shipment " + carrierShipment.getId().toString() - + " since either fromLinkId " + carrierShipment.getFrom() + " or toLinkId " - + carrierShipment.getTo() + " exists in network."); + + " since either fromLinkId " + carrierShipment.getPickupLinkId() + " or toLinkId " + + carrierShipment.getDeliveryLinkId() + " exists in network."); } vrpBuilder.addJob(createJspritShipment(carrierShipment, fromCoordinate, toCoordinate)); 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 index 70abe3fedd8..8670ad977ea 100644 --- 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 @@ -60,8 +60,8 @@ public static Collection createLSPShipmentsFromCarrierShipments(Car LspShipmentUtils.LspShipmentBuilder.newInstance( Id.create(shipment.getId().toString(), LspShipment.class)); builder.setCapacityDemand(shipment.getDemand()); - builder.setFromLinkId(shipment.getFrom()); - builder.setToLinkId(shipment.getTo()); + builder.setFromLinkId(shipment.getPickupLinkId()); + builder.setToLinkId(shipment.getDeliveryLinkId()); builder.setStartTimeWindow(shipment.getPickupStartsTimeWindow()); builder.setEndTimeWindow(shipment.getDeliveryStartsTimeWindow()); builder.setPickupServiceTime(shipment.getPickupDuration()); 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 7a784b4351d..839f2cceaef 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 @@ -75,14 +75,14 @@ void testAddAndGetServiceToCarrier() { Assertions.assertEquals(1, carrier.getServices().size()); CarrierService cs1a = (CarrierService) carrier.getServices().values().toArray()[0]; Assertions.assertEquals(service1, cs1a); - Assertions.assertEquals(Id.createLinkId("link0"), cs1a.getLocationLinkId()); + Assertions.assertEquals(Id.createLinkId("link0"), cs1a.getServiceLinkId()); //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()); + Assertions.assertEquals(Id.createLinkId("link0"), cs1b.getServiceLinkId()); Assertions.assertEquals(30, cs1b.getServiceDuration(), EPSILON); } @@ -97,14 +97,14 @@ void testAddAndGetShipmentToCarrier() { Assertions.assertEquals(1, carrier.getShipments().size()); CarrierShipment carrierShipment1a = (CarrierShipment) carrier.getShipments().values().toArray()[0]; Assertions.assertEquals(service1, carrierShipment1a); - Assertions.assertEquals(Id.createLinkId("link0"), carrierShipment1a.getFrom()); + Assertions.assertEquals(Id.createLinkId("link0"), carrierShipment1a.getPickupLinkId()); //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()); + Assertions.assertEquals(Id.createLinkId("link0"), carrierShipment1b.getPickupLinkId()); Assertions.assertEquals(20, carrierShipment1b.getDemand(), EPSILON); } 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 705f4290980..2882cec1336 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 @@ -146,7 +146,7 @@ void whenTransforming_jspritService2matsimService_isMadeCorrectly() { CarrierService service = MatsimJspritFactory.createCarrierService(carrierService); assertNotNull(service); - assertEquals("locationId", service.getLocationLinkId().toString()); + assertEquals("locationId", service.getServiceLinkId().toString()); assertEquals(30.0, service.getServiceDuration(), 0.01); assertEquals(50, service.getDemand()); assertEquals(10.0, service.getServiceStartTimeWindow().getStart(), 0.01); @@ -193,11 +193,11 @@ void whenTransforming_jspritShipment2matsimShipment_isMadeCorrectly() { CarrierShipment carrierShipment = MatsimJspritFactory.createCarrierShipment(shipment); assertNotNull(carrierShipment); - assertEquals("PickupLocationId", carrierShipment.getFrom().toString()); + assertEquals("PickupLocationId", carrierShipment.getPickupLinkId().toString()); assertEquals(30.0, carrierShipment.getPickupDuration(), 0.01); assertEquals(10.0, carrierShipment.getPickupStartsTimeWindow().getStart(), 0.01); assertEquals(20.0, carrierShipment.getPickupStartsTimeWindow().getEnd(), 0.01); - assertEquals("DeliveryLocationId", carrierShipment.getTo().toString()); + assertEquals("DeliveryLocationId", carrierShipment.getDeliveryLinkId().toString()); assertEquals(40.0, carrierShipment.getDeliveryDuration(), 0.01); assertEquals(50.0, carrierShipment.getDeliveryStartsTimeWindow().getStart(), 0.01); assertEquals(60.0, carrierShipment.getDeliveryStartsTimeWindow().getEnd(), 0.01); @@ -234,7 +234,7 @@ private Collection getJobsFrom(ScheduledTour sTour) { CarrierService carrierService = ((Tour.ServiceActivity) e) .getService(); Service service = Service.Builder.newInstance(carrierService.getId().toString()) - .setLocation(Location.newInstance(carrierService.getLocationLinkId().toString())).build(); + .setLocation(Location.newInstance(carrierService.getServiceLinkId().toString())).build(); services.add(service); } } 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 110ed45f27e..393f73088a3 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 @@ -244,8 +244,8 @@ void copyingOfShipmentsIsDoneCorrectly() { if (carrierShipment1.getId() == Id.create("shipment1", CarrierShipment.class)) { System.out.println("Found Shipment1"); foundShipment1 = true; - Assertions.assertEquals(Id.createLinkId("i(1,0)"), carrierShipment1.getFrom()); - Assertions.assertEquals(Id.createLinkId("i(7,6)R"), carrierShipment1.getTo()); + Assertions.assertEquals(Id.createLinkId("i(1,0)"), carrierShipment1.getPickupLinkId()); + Assertions.assertEquals(Id.createLinkId("i(7,6)R"), carrierShipment1.getDeliveryLinkId()); Assertions.assertEquals(1, carrierShipment1.getDemand()); Assertions.assertEquals(30.0, carrierShipment1.getDeliveryDuration(), 0); Assertions.assertEquals(3600.0, carrierShipment1.getDeliveryStartsTimeWindow().getStart(), 0); @@ -259,8 +259,8 @@ void copyingOfShipmentsIsDoneCorrectly() { if (carrierShipment2.getId() == Id.create("shipment2", CarrierShipment.class)) { System.out.println("Found Shipment2"); foundShipment2 = true; - Assertions.assertEquals(Id.createLinkId("i(3,0)"), carrierShipment2.getFrom()); - Assertions.assertEquals(Id.createLinkId("i(3,7)"), carrierShipment2.getTo()); + Assertions.assertEquals(Id.createLinkId("i(3,0)"), carrierShipment2.getPickupLinkId()); + Assertions.assertEquals(Id.createLinkId("i(3,7)"), carrierShipment2.getDeliveryLinkId()); Assertions.assertEquals(2, carrierShipment2.getDemand()); Assertions.assertEquals(30.0, carrierShipment2.getDeliveryDuration(), 0); Assertions.assertEquals(3600.0, carrierShipment2.getDeliveryStartsTimeWindow().getStart(), 0); @@ -282,8 +282,8 @@ void convertionOfServicesIsDoneCorrectly() { assert carrierShipment1 != null; if (carrierShipment1.getId() == Id.create("Service1", CarrierShipment.class)) { foundService1 = true; - Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment1.getFrom()); - Assertions.assertEquals(Id.createLinkId("i(3,9)"), carrierShipment1.getTo()); + Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment1.getPickupLinkId()); + Assertions.assertEquals(Id.createLinkId("i(3,9)"), carrierShipment1.getDeliveryLinkId()); Assertions.assertEquals(2, carrierShipment1.getDemand()); Assertions.assertEquals(31.0, carrierShipment1.getDeliveryDuration(), 0); Assertions.assertEquals(3601.0, carrierShipment1.getDeliveryStartsTimeWindow().getStart(), 0); @@ -296,8 +296,8 @@ void convertionOfServicesIsDoneCorrectly() { assert carrierShipment2 != null; if (carrierShipment2.getId() == Id.create("Service2", CarrierShipment.class)) { foundService2 = true; - Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment2.getFrom()); - Assertions.assertEquals(Id.createLinkId("i(4,9)"), carrierShipment2.getTo()); + Assertions.assertEquals(Id.createLinkId("i(6,0)"), carrierShipment2.getPickupLinkId()); + Assertions.assertEquals(Id.createLinkId("i(4,9)"), carrierShipment2.getDeliveryLinkId()); Assertions.assertEquals(2, carrierShipment2.getDemand()); Assertions.assertEquals(31.0, carrierShipment2.getDeliveryDuration(), 0); Assertions.assertEquals(3601.0, carrierShipment2.getDeliveryStartsTimeWindow().getStart(), 0); 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 index d031c5f6d1d..ba6d1fd35e7 100644 --- 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 @@ -196,7 +196,7 @@ public void testCollectionLSPScheduling() { { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -211,7 +211,7 @@ public void testCollectionLSPScheduling() { { assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); 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 index 3a6a13e629a..11d49bd6c0b 100644 --- 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 @@ -433,7 +433,7 @@ public void testCompletedLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -460,7 +460,7 @@ public void testCompletedLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), toLinkId); + assertSame(service.getServiceLinkId(), toLinkId); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -484,7 +484,7 @@ public void testCompletedLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -502,7 +502,7 @@ public void testCompletedLSPScheduling() { //CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -520,7 +520,7 @@ public void testCompletedLSPScheduling() { //MainRunStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -538,7 +538,7 @@ public void testCompletedLSPScheduling() { //MainRunEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -556,7 +556,7 @@ public void testCompletedLSPScheduling() { //DistributionRunStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(4)); LSPTourStartEventHandler lspTourStartEventHandler = (LSPTourStartEventHandler) eventHandlers.get(4); - assertSame(lspTourStartEventHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertSame(lspTourStartEventHandler.getCarrierService().getServiceLinkId(), shipment.getTo()); assertEquals(lspTourStartEventHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(lspTourStartEventHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -574,7 +574,7 @@ public void testCompletedLSPScheduling() { //DistributionServiceStart assertInstanceOf(DistributionServiceStartEventHandler.class, eventHandlers.get(5)); DistributionServiceStartEventHandler distributionServiceHandler = (DistributionServiceStartEventHandler) eventHandlers.get(5); - assertSame(distributionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertSame(distributionServiceHandler.getCarrierService().getServiceLinkId(), shipment.getTo()); assertEquals(distributionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(distributionServiceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); 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 index 5b724cf6a80..76191192a70 100644 --- 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 @@ -259,7 +259,7 @@ public void testFirstReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -283,7 +283,7 @@ public void testFirstReloadLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -296,7 +296,7 @@ public void testFirstReloadLSPScheduling() { assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); 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 index 8d653d8e171..ce0a83639a8 100644 --- 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 @@ -324,7 +324,7 @@ public void testMainRunLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -350,7 +350,7 @@ public void testMainRunLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -368,7 +368,7 @@ public void testMainRunLSPScheduling() { //CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -386,7 +386,7 @@ public void testMainRunLSPScheduling() { //MainRunTourStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -404,7 +404,7 @@ public void testMainRunLSPScheduling() { //MainRunTourEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); 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 index dd51e2d4e4a..d3fe9b5214d 100644 --- 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 @@ -198,7 +198,7 @@ public void testCollectionLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -211,7 +211,7 @@ public void testCollectionLSPScheduling() { assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); 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 index 481c48ec6ba..1a584b463b5 100644 --- 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 @@ -436,7 +436,7 @@ public void testCompletedLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -463,7 +463,7 @@ public void testCompletedLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), toLinkId); + assertSame(service.getServiceLinkId(), toLinkId); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -487,7 +487,7 @@ public void testCompletedLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -505,7 +505,7 @@ public void testCompletedLSPScheduling() { //CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -523,7 +523,7 @@ public void testCompletedLSPScheduling() { //MainRunTourStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -541,7 +541,7 @@ public void testCompletedLSPScheduling() { //MainRunTourEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -559,7 +559,7 @@ public void testCompletedLSPScheduling() { //DistributionTourStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(4)); LSPTourStartEventHandler lspTourStartEventHandler = (LSPTourStartEventHandler) eventHandlers.get(4); - assertSame(lspTourStartEventHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertSame(lspTourStartEventHandler.getCarrierService().getServiceLinkId(), shipment.getTo()); assertEquals(lspTourStartEventHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(lspTourStartEventHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, lspTourStartEventHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -577,7 +577,7 @@ public void testCompletedLSPScheduling() { //DistributionServiceStart assertInstanceOf(DistributionServiceStartEventHandler.class, eventHandlers.get(5)); DistributionServiceStartEventHandler distributionServiceHandler = (DistributionServiceStartEventHandler) eventHandlers.get(5); - assertSame(distributionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getTo()); + assertSame(distributionServiceHandler.getCarrierService().getServiceLinkId(), shipment.getTo()); assertEquals(distributionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(distributionServiceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, distributionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); 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 index eb6af700893..4d41d635e10 100644 --- 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 @@ -258,7 +258,7 @@ public void testFirstReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -282,7 +282,7 @@ public void testFirstReloadLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -295,7 +295,7 @@ public void testFirstReloadLSPScheduling() { assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); 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 index f82bde886c8..b63c6d854d4 100644 --- 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 @@ -324,7 +324,7 @@ public void testMainRunLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -350,7 +350,7 @@ public void testMainRunLSPScheduling() { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler endHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(endHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(endHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(endHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(endHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(endHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -368,7 +368,7 @@ public void testMainRunLSPScheduling() { //CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler serviceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(serviceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(serviceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(serviceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(serviceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(serviceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -386,7 +386,7 @@ public void testMainRunLSPScheduling() { //MainRunTourStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -404,7 +404,7 @@ public void testMainRunLSPScheduling() { //MainRunEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); 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 index 403bf619d90..03f374b15f0 100644 --- 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 @@ -368,7 +368,7 @@ public void testSecondReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -400,7 +400,7 @@ public void testSecondReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), toLinkId); + assertSame(service.getServiceLinkId(), toLinkId); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -430,7 +430,7 @@ public void testSecondReloadLSPScheduling() { { assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler collectionEndHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(collectionEndHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(collectionEndHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(collectionEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(collectionEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -449,7 +449,7 @@ public void testSecondReloadLSPScheduling() { {//CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler collectionServiceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(collectionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(collectionServiceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(collectionServiceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(collectionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -468,7 +468,7 @@ public void testSecondReloadLSPScheduling() { {//MainRunStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -487,7 +487,7 @@ public void testSecondReloadLSPScheduling() { {//MainRunEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); 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 index 08dbac36e8b..66a30fa10d4 100644 --- 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 @@ -368,7 +368,7 @@ public void testSecondReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), shipment.getFrom()); + assertSame(service.getServiceLinkId(), shipment.getFrom()); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -406,7 +406,7 @@ public void testSecondReloadLSPScheduling() { CarrierService service = entry.getKey(); LspShipment shipment = entry.getValue().lspShipment; LogisticChainElement element = entry.getValue().logisticChainElement; - assertSame(service.getLocationLinkId(), toLinkId); + assertSame(service.getServiceLinkId(), toLinkId); assertEquals(service.getDemand(), shipment.getSize()); assertEquals(service.getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); boolean handledByTranshipmentHub = false; @@ -437,7 +437,7 @@ public void testSecondReloadLSPScheduling() { {//CollectionTourEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.getFirst()); LSPTourEndEventHandler collectionEndHandler = (LSPTourEndEventHandler) eventHandlers.getFirst(); - assertSame(collectionEndHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(collectionEndHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(collectionEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(collectionEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(collectionEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -456,7 +456,7 @@ public void testSecondReloadLSPScheduling() { {//CollectionServiceEnd assertInstanceOf(CollectionServiceEndEventHandler.class, eventHandlers.get(1)); CollectionServiceEndEventHandler collectionServiceHandler = (CollectionServiceEndEventHandler) eventHandlers.get(1); - assertSame(collectionServiceHandler.getCarrierService().getLocationLinkId(), shipment.getFrom()); + assertSame(collectionServiceHandler.getCarrierService().getServiceLinkId(), shipment.getFrom()); assertEquals(collectionServiceHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(collectionServiceHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(collectionServiceHandler.getCarrierService().getServiceStartTimeWindow().getStart(), shipment.getPickupTimeWindow().getStart(), 0.0); @@ -475,7 +475,7 @@ public void testSecondReloadLSPScheduling() { {//MainRunStart assertInstanceOf(LSPTourStartEventHandler.class, eventHandlers.get(2)); LSPTourStartEventHandler mainRunStartHandler = (LSPTourStartEventHandler) eventHandlers.get(2); - assertSame(mainRunStartHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunStartHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunStartHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunStartHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunStartHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); @@ -494,7 +494,7 @@ public void testSecondReloadLSPScheduling() { {//MainRunEnd assertInstanceOf(LSPTourEndEventHandler.class, eventHandlers.get(3)); LSPTourEndEventHandler mainRunEndHandler = (LSPTourEndEventHandler) eventHandlers.get(3); - assertSame(mainRunEndHandler.getCarrierService().getLocationLinkId(), toLinkId); + assertSame(mainRunEndHandler.getCarrierService().getServiceLinkId(), toLinkId); assertEquals(mainRunEndHandler.getCarrierService().getServiceDuration(), shipment.getDeliveryServiceTime(), 0.0); assertEquals(mainRunEndHandler.getCarrierService().getDemand(), shipment.getSize()); assertEquals(0, mainRunEndHandler.getCarrierService().getServiceStartTimeWindow().getStart(), 0.0); diff --git a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java index 852452663a6..a35dddecc24 100644 --- a/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java +++ b/contribs/freightreceiver/src/main/java/org/matsim/freight/receiver/ReceiverControlerListener.java @@ -178,7 +178,7 @@ private void linkReceiverTimeWindowToCarrierTourPosition() throws IOException { String shipmentId = act.getShipment().getId().toString(); if (act.getActivityType().equalsIgnoreCase("delivery")) { - Id linkId = act.getShipment().getTo(); + Id linkId = act.getShipment().getDeliveryLinkId(); if (!receiverLinkMap.containsKey(linkId)) { LOG.error("Woops, the carrier is delivering a shipment to an unknown receiver!"); throw new RuntimeException("Don't know to whom delivery is."); 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 index 6652c17b955..052fb62b9f1 100644 --- 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 @@ -372,8 +372,8 @@ public void reduceDemandBasedOnExistingCarriers(Scenario scenario, Map createListOfCarrierWithUnhandledJobs(Scenario scenario){ private void redrawAllServiceDurations(Carrier carrier, GenerateSmallScaleCommercialTrafficDemand.CarrierAttributes carrierAttributes, int additionalTravelBufferPerIterationInMinutes) { for (CarrierService service : carrier.getServices().values()) { double newServiceDuration = generator.getServiceTimePerStop(carrier, carrierAttributes, additionalTravelBufferPerIterationInMinutes); - CarrierService redrawnService = CarrierService.Builder.newInstance(service.getId(), service.getLocationLinkId()) + CarrierService redrawnService = CarrierService.Builder.newInstance(service.getId(), service.getServiceLinkId()) .setServiceDuration(newServiceDuration).setServiceStartTimeWindow(service.getServiceStartTimeWindow()).build(); carrier.getServices().put(redrawnService.getId(), redrawnService); } diff --git a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventHandler.java b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventHandler.java index 2f322e8640f..3b159189bda 100644 --- a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventHandler.java +++ b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisEventHandler.java @@ -391,8 +391,8 @@ public void exportShipmentInfo(String path, Boolean exportGuesses) { if (shipmentTracker == null) { continue; } - Id from = shipment.getFrom(); - Id toLink = shipment.getTo(); + Id from = shipment.getPickupLinkId(); + Id toLink = shipment.getDeliveryLinkId(); // if info is not certain, export the guess if that is wanted. String carrierIdString = id2String(carrier.getId()); String shipmentIdString = id2String(shipment.getId()); diff --git a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisServiceTracking.java b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisServiceTracking.java index 88ee09b7b5c..b0e668fdc2f 100644 --- a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisServiceTracking.java +++ b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisServiceTracking.java @@ -57,7 +57,7 @@ public void addTracker(CarrierService service, Id id) { public void trackServiceActivityStart(ActivityStartEvent activityStartEvent) { for (ServiceTracker.CarrierServiceTracker cst: carrierServiceTrackers.values()) { for (ServiceTracker service : cst.serviceTrackers.values()) { - if (service.service.getLocationLinkId().equals(activityStartEvent.getLinkId())) { + if (service.service.getServiceLinkId().equals(activityStartEvent.getLinkId())) { if (service.driverId == null) { // if there is no driver, but there is a service which is to be performed at the moment at this place, we guess this could be the event for it. // (Does not work well obviously as soon as there are multiple services at a location that have generous time windows, like e.g. at stores). diff --git a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java index 91613aa1d34..5673a46b530 100644 --- a/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java +++ b/contribs/vsp/src/main/java/org/matsim/freight/carriers/analysis/FreightAnalysisShipmentTracking.java @@ -128,8 +128,8 @@ class ShipmentTracker { public ShipmentTracker(CarrierShipment shipment) { this.id = shipment.getId(); - this.from = shipment.getFrom(); - this.to=shipment.getTo(); + this.from = shipment.getPickupLinkId(); + this.to=shipment.getDeliveryLinkId(); this.shipment=shipment; } From 9e65b096c6e722847ad7bae721285083d6e2ff9d Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 14:56:49 +0100 Subject: [PATCH 38/39] reorganisation of code --- .../freight/carriers/CarrierShipment.java | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) 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 a78e636ee49..748b9f0a412 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 @@ -254,7 +254,7 @@ public double getDeliveryDuration() { /** * Do we really need the setter? We do have it in the builder. * I do not see, why we should be able to update it, since most of the values are immutable. - * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable.. + * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable. * kturner, dec'24 */ @Deprecated(since = "dec'24") @@ -265,7 +265,7 @@ public void setPickupDuration(double pickupDuration) { /** * Do we really need the setter? We do have it in the builder. * I do not see, why we should be able to update it, since most of the values are immutable. - * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable.. + * @deprecated Consider setting it using the Builder. This will maybe be removed and the field gets immutable. * kturner, dec'24 */ @Deprecated(since = "dec'24") @@ -317,6 +317,7 @@ public int getSize() { return getDemand(); } + /** * @deprecated please inline and use {@link #getPickupLinkId()} instead */ @@ -325,14 +326,6 @@ public Id getFrom() { return getPickupLinkId(); } - /** - * @deprecated please inline and use {@link #getDeliveryLinkId()} instead - */ - @Deprecated(since = "dec'24") - public Id getTo() { - return getDeliveryLinkId(); - } - /** * @deprecated please inline and use {@link #getPickupStartsTimeWindow()} instead */ @@ -341,13 +334,12 @@ public TimeWindow getPickupTimeWindow() { return getPickupStartsTimeWindow(); } - /** - * @deprecated please inline and use {@link #getDeliveryStartsTimeWindow()} instead + * @deprecated please inline and use {@link #setPickupDuration(double)} instead */ @Deprecated(since = "dec'24") - public TimeWindow getDeliveryTimeWindow() { - return getDeliveryStartsTimeWindow(); + public void setPickupServiceTime(double pickupDuration) { + setPickupDuration(pickupDuration); } /** @@ -358,12 +350,21 @@ public double getPickupServiceTime() { return getPickupDuration(); } + /** - * @deprecated please inline and use {@link #setPickupDuration(double)} instead + * @deprecated please inline and use {@link #getDeliveryLinkId()} instead */ @Deprecated(since = "dec'24") - public void setPickupServiceTime(double pickupDuration) { - setPickupDuration(pickupDuration); + public Id getTo() { + return getDeliveryLinkId(); + } + + /** + * @deprecated please inline and use {@link #getDeliveryStartsTimeWindow()} instead + */ + @Deprecated(since = "dec'24") + public TimeWindow getDeliveryTimeWindow() { + return getDeliveryStartsTimeWindow(); } /** From 060dde94b39a58dd20f6c0f3200229bc54cebc9d Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Fri, 20 Dec 2024 15:19:33 +0100 Subject: [PATCH 39/39] remove long-time deprecated constructor / newInstance(...)-method in CarrierShipment.Builder --- .../freight/carriers/CarrierShipment.java | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) 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 748b9f0a412..a74177246d5 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 @@ -62,28 +62,10 @@ public static class Builder { private TimeWindow deliveryStartsTimeWindow = TimeWindow.newInstance(0.0, Integer.MAX_VALUE); private double deliveryDuration = 0.0; - /** - * @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 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){ - var id = Id.create(CarrierConstants.SHIPMENT +"_" + from.toString() + "_" + to.toString(), CarrierShipment.class); - return new Builder(id, from,to,size); - } - - /** - * Returns a new shipment builder. - *

The builder is init with the shipment's origin (from), destination (to) and with the shipment's demand. + *

+ * The builder is init with the shipment's origin (from), destination (to) and with the shipment's demand. * The default-value for serviceTime is 0.0. The default-value for a timeWindow is [start=0.0, end=Double.maxValue()]. * * @param id the id of the shipment @@ -96,18 +78,6 @@ public static Builder newInstance(Id id, Id from, Id id, Id from, Id to, int size) instead. - */ - @Deprecated - public Builder(Id pickupLinkId, Id deliveryLinkId, int demand) { - super(); - this.id = Id.create(CarrierConstants.SHIPMENT +"_" + pickupLinkId.toString() + "_" + deliveryLinkId.toString(), CarrierShipment.class); - this.pickupLinkId = pickupLinkId; - this.deliveryLinkId = deliveryLinkId; - this.demand = demand; - } - private Builder(Id id, Id pickupLinkId, Id deliveryLinkId, int demand) { super(); this.id = id;