Skip to content

Commit

Permalink
Merge pull request #77 from moia-oss/master
Browse files Browse the repository at this point in the history
Update MATSim
  • Loading branch information
TomE168 authored Dec 28, 2023
2 parents 3c76710 + f8d7750 commit 7e9a980
Show file tree
Hide file tree
Showing 20 changed files with 468 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.matsim.core.config.ConfigGroup;

import java.net.URL;
import java.util.Map;

/**
* @author nkuehnel / MOIA
Expand All @@ -30,6 +29,10 @@ public class ShiftsParams extends ReflectiveConfigGroupWithConfigurableParameter
@Comment("changeover duration in [seconds]")
public double changeoverDuration = 900;

@Parameter
@Comment("maximum delay of shift assignment after start time has passed in [seconds]. If a shift can not be assigned to a vehicle until the planned start of the shift plus the defined max delay, the shift is discarded. Defaults to 0")
public double maxUnscheduledShiftDelay = 0;

@Parameter
@Comment("Time of shift assignment (i.e. which vehicle carries out a specific shift) before start of shift in [seconds]")
public double shiftScheduleLookAhead = 1800;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,13 @@ private void startShifts(double timeStep) {

private void assignShifts(double timeStep) {
// Remove elapsed shifts
unscheduledShifts.removeIf(shift -> shift.getStartTime() < timeStep);
unscheduledShifts.removeIf(shift -> {
if (shift.getStartTime() + drtShiftParams.maxUnscheduledShiftDelay < timeStep ) {
logger.warn("Shift with ID " + shift.getId() + " could not be assigned and is being removed as start time is longer in the past than defined by maxUnscheduledShiftDelay.");
return true;
}
return false;
});

// Assign shifts
Set<DrtShift> assignableShifts = new LinkedHashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,44 @@
package org.matsim.contrib.drt.extension.edrt.run;

import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.population.Plan;
import org.matsim.api.core.v01.population.Population;
import org.matsim.contrib.drt.extension.edrt.optimizer.EDrtVehicleDataEntryFactory;
import org.matsim.contrib.drt.prebooking.PrebookingParams;
import org.matsim.contrib.drt.prebooking.logic.ProbabilityBasedPrebookingLogic;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.drt.run.DrtConfigs;
import org.matsim.contrib.drt.run.DrtControlerCreator;
import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler;
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent;
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler;
import org.matsim.contrib.dvrp.passenger.*;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule;
import org.matsim.contrib.dvrp.run.DvrpConfigGroup;
import org.matsim.contrib.dvrp.run.DvrpModule;
import org.matsim.contrib.dvrp.run.DvrpQSimComponents;
import org.matsim.contrib.ev.EvConfigGroup;
import org.matsim.contrib.ev.EvModule;
import org.matsim.contrib.ev.charging.*;
import org.matsim.contrib.ev.discharging.IdleDischargingHandler;
import org.matsim.contrib.ev.temperature.TemperatureService;
import org.matsim.contrib.evrp.EvDvrpFleetQSimModule;
import org.matsim.contrib.evrp.OperatingVehicleProvider;
import org.matsim.contrib.otfvis.OTFVisLiveModule;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.mobsim.qsim.AbstractQSimModule;
import org.matsim.core.population.io.PopulationReader;
import org.matsim.core.population.io.PopulationWriter;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.examples.ExamplesUtils;
import org.matsim.vis.otfvis.OTFVisConfigGroup;
Expand All @@ -51,36 +71,82 @@ void test() {
RunEDrtScenario.run(configUrl, false);
}

@Test
void testMultiModeDrtDeterminism() {
URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_multiModeEdrt_config.xml");

Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(),
new OTFVisConfigGroup(), new EvConfigGroup());


Controler controller = RunEDrtScenario.createControler(config, false);
config.controller().setLastIteration(2);

PassengerPickUpTracker tracker = new PassengerPickUpTracker();
tracker.install(controller);

controller.run();

assertEquals(2011, tracker.passengerPickupEvents);
}


@Test
void testWithPrebooking() {
URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_edrt_config.xml");

Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(),
new OTFVisConfigGroup(), new EvConfigGroup());

DrtConfigGroup drtConfig = DrtConfigGroup.getSingleModeDrtConfig(config);
drtConfig.addParameterSet(new PrebookingParams());

Controler controller = RunEDrtScenario.createControler(config, false);
ProbabilityBasedPrebookingLogic.install(controller, drtConfig, 0.5, 4.0 * 3600.0);

PrebookingTracker tracker = new PrebookingTracker();
tracker.install(controller);

controller.run();

assertEquals(74, tracker.immediateScheduled);
assertEquals(198, tracker.prebookedScheduled);
assertEquals(116, tracker.immediateRejected);
assertEquals(7, tracker.prebookedRejected);
}


static private class PassengerPickUpTracker implements PassengerPickedUpEventHandler {
int passengerPickupEvents = 0;

void install(Controler controller) {
PassengerPickUpTracker thisTracker = this;

controller.addOverridingModule(new AbstractModule() {
@Override
public void install() {
addEventHandlerBinding().toInstance(thisTracker);
}
});
}

@Override
public void handleEvent(PassengerPickedUpEvent event) {
passengerPickupEvents++;
}

@Override
public void reset(int iteration) {
passengerPickupEvents=0;
}

}

static private class PrebookingTracker implements PassengerRequestRejectedEventHandler, PassengerRequestScheduledEventHandler {
int immediateScheduled = 0;
int prebookedScheduled = 0;
int immediateRejected = 0;
int prebookedRejected = 0;

@Override
public void handleEvent(PassengerRequestScheduledEvent event) {
if (event.getRequestId().toString().contains("prebooked")) {
Expand All @@ -98,10 +164,10 @@ public void handleEvent(PassengerRequestRejectedEvent event) {
immediateRejected++;
}
}

void install(Controler controller) {
PrebookingTracker thisTracker = this;

controller.addOverridingModule(new AbstractModule() {
@Override
public void install() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@

package org.matsim.contrib.ev.discharging;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.events.Event;
import org.matsim.api.core.v01.events.HasLinkId;
import org.matsim.api.core.v01.events.HasVehicleId;
import org.matsim.api.core.v01.events.LinkLeaveEvent;
import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent;
import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent;
Expand Down Expand Up @@ -80,7 +83,7 @@ private boolean isOnFirstLink() {
this.network = network;
this.eventsManager = eventsManager;
eVehicles = data.getElectricVehicles();
evDrives = new HashMap<>(eVehicles.size() / 10);
evDrives = new ConcurrentHashMap<>(eVehicles.size() / 10);
}

@Override
Expand All @@ -94,12 +97,16 @@ public void handleEvent(VehicleEntersTrafficEvent event) {

@Override
public void handleEvent(LinkLeaveEvent event) {
linkLeaveEvents.add(event);
if (evDrives.containsKey(event.getVehicleId())) {// handle only our EVs
linkLeaveEvents.add(event);
}
}

@Override
public void handleEvent(VehicleLeavesTrafficEvent event) {
trafficLeaveEvents.add(event);
if (evDrives.containsKey(event.getVehicleId())) {// handle only our EVs
trafficLeaveEvents.add(event);
}
}

@Override
Expand All @@ -118,40 +125,34 @@ public void setInternalInterface(InternalInterface internalInterface) {

@Override
public void doSimStep(double time) {
handleQueuedEvents(linkLeaveEvents, time, false);
handleQueuedEvents(trafficLeaveEvents, time, true);
}

private <E extends Event & HasVehicleId & HasLinkId> void handleQueuedEvents(Queue<E> queue, double time, boolean leftTraffic) {
// We want to process events in the main thread (instead of the event handling threads).
// This is to eliminate race conditions, where the battery is read/modified by many threads without proper synchronisation
var linkLeaveIterator = linkLeaveEvents.iterator();
while (linkLeaveIterator.hasNext()) {
var event = linkLeaveIterator.next();
while (!queue.isEmpty()) {
var event = queue.peek();
if (event.getTime() == time) {
// There is a potential race condition wrt processing events between doSimStep() and handleEvent().
// To ensure a deterministic behaviour, we only process events from the previous time step.
break;
}

EvDrive evDrive = dischargeVehicle(event.getVehicleId(), event.getLinkId(), event.getTime(), time);
if (evDrive != null) {
evDrive.movedOverNodeTime = event.getTime();
}
linkLeaveIterator.remove();
}

var trafficLeaveIterator = trafficLeaveEvents.iterator();
while (trafficLeaveIterator.hasNext()) {
var event = trafficLeaveIterator.next();
if (event.getTime() == time) {
break;
}

EvDrive evDrive = dischargeVehicle(event.getVehicleId(), event.getLinkId(), event.getTime(), time);
if (evDrive != null) {
var evDrive = dischargeVehicle(event.getVehicleId(), event.getLinkId(), event.getTime(), time);
if (leftTraffic) {
evDrives.remove(evDrive.vehicleId);
} else {
evDrive.movedOverNodeTime = event.getTime();
}
trafficLeaveIterator.remove();
queue.remove();
}
}

private EvDrive dischargeVehicle(Id<Vehicle> vehicleId, Id<Link> linkId, double eventTime, double now) {
EvDrive evDrive = evDrives.get(vehicleId);
if (evDrive != null && !evDrive.isOnFirstLink()) {// handle only our EVs, except for the first link
if (!evDrive.isOnFirstLink()) {// skip the first link
Link link = network.getLinks().get(linkId);
double tt = eventTime - evDrive.movedOverNodeTime;
ElectricVehicle ev = evDrive.ev;
Expand Down
Loading

0 comments on commit 7e9a980

Please sign in to comment.