Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dvrp): generic loads and changeable capacities #3627

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification;
import org.matsim.contrib.dvrp.fleet.FleetWriter;
import org.matsim.contrib.dvrp.fleet.ImmutableDvrpVehicleSpecification;
import org.matsim.contrib.dvrp.fleet.dvrp_load.DefaultDvrpLoadSerializer;
import org.matsim.contrib.dvrp.fleet.dvrp_load.DefaultIntegerLoadType;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.gbl.MatsimRandom;
import org.matsim.core.network.io.MatsimNetworkReader;
Expand Down Expand Up @@ -77,7 +79,7 @@ public static void main(String[] args) {
.build());

}
new FleetWriter(vehicles.stream()).write(taxisFile);
new FleetWriter(vehicles.stream(), new DefaultDvrpLoadSerializer(new DefaultIntegerLoadType())).write(taxisFile);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
package org.matsim.contrib.drt.extension.companions;

import static org.matsim.contrib.drt.extension.companions.DrtCompanionUtils.DRT_COMPANION_AGENT_PREFIX;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -29,7 +29,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Id;
Expand All @@ -43,6 +43,7 @@
import org.matsim.contrib.drt.extension.DrtWithExtensionsConfigGroup;
import org.matsim.contrib.dvrp.fleet.DvrpVehicleSpecification;
import org.matsim.contrib.dvrp.fleet.FleetSpecification;
import org.matsim.contrib.dvrp.fleet.dvrp_load.IntegerLoad;
import org.matsim.contrib.dvrp.passenger.PassengerGroupIdentifier;
import org.matsim.core.controler.events.AfterMobsimEvent;
import org.matsim.core.controler.events.BeforeMobsimEvent;
Expand All @@ -51,14 +52,14 @@
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.utils.objectattributes.attributable.AttributesUtils;

import com.google.common.base.Preconditions;

/**
* @author Steffen Axer
*/
final class DrtCompanionRideGenerator implements BeforeMobsimListener, AfterMobsimListener {

private static final Logger LOG = LogManager.getLogger(DrtCompanionRideGenerator.class);
public static final String DRT_COMPANION_TYPE = "drtCompanion";
private final Scenario scenario;
Expand All @@ -67,32 +68,36 @@ final class DrtCompanionRideGenerator implements BeforeMobsimListener, AfterMobs
private final Set<Id<Person>> companionAgentIds = new HashSet<>();
private final Set<Leg> drtLegs = new HashSet<>();
private WeightedRandomSelection<Integer> sampler;

private final Map<Id<PassengerGroupIdentifier.PassengerGroup>, List<GroupLeg>> passengerGroups = new HashMap<>();

private int passengerGroupIdentifier = 0; // Should be unique over the entire simulation

private final AtomicInteger personIdentifierSuffix = new AtomicInteger(0);

DrtCompanionRideGenerator(final String drtMode,
final FleetSpecification fleet,
final Scenario scenario,
final DrtWithExtensionsConfigGroup drtWithExtensionsConfigGroup) {
this.scenario = scenario;
this.drtMode = drtMode;
//TODO[Sebastian]. I guess this functionality will only be used with the ScalarVehicleLoad implementation of the DvrpVehicleLoad. So I will just filter the vehicle capacities. Tarek.
this.maxCapacity = fleet.getVehicleSpecifications()
.values()
.stream()
.mapToInt(DvrpVehicleSpecification::getCapacity)
.map(DvrpVehicleSpecification::getCapacity)
.filter(dvrpVehicleLoad -> dvrpVehicleLoad instanceof IntegerLoad)
.map(dvrpVehicleLoad -> (IntegerLoad) dvrpVehicleLoad)
.mapToInt(IntegerLoad::getLoad)
.max()
.orElse(0);
installSampler(drtWithExtensionsConfigGroup);
}

private String getCompanionPrefix(String drtMode) {
return DRT_COMPANION_AGENT_PREFIX + "_" + drtMode;
}

private void installSampler(DrtWithExtensionsConfigGroup drtWithExtensionsConfigGroup) {
if (!drtWithExtensionsConfigGroup.getDrtCompanionParams().orElseThrow().getDrtCompanionSamplingWeights()
.isEmpty()) {
Expand All @@ -104,44 +109,44 @@ private void installSampler(DrtWithExtensionsConfigGroup drtWithExtensionsConfig
"drtCompanionSamplingWeights are empty, please check your DrtCompanionParams");
}
}

private Id<PassengerGroupIdentifier.PassengerGroup> getGroupIdentifier() {
return Id.create(this.passengerGroupIdentifier, PassengerGroupIdentifier.PassengerGroup.class);
}

record GroupLeg(Leg leg, Id<Person> personId) {
}

private void addCompanionAgents() {
Collection<Person> companions = new ArrayList<>();
for (Person person : this.scenario.getPopulation().getPersons().values()) {
for (TripStructureUtils.Trip trip : TripStructureUtils.getTrips(person.getSelectedPlan())) {
int additionalCompanions = sampler.select();

for (Leg leg : trip.getLegsOnly()) {
if (leg.getMode().equals(this.drtMode)) {
this.drtLegs.add(leg);
// Initial person travels now in a group
Id<PassengerGroupIdentifier.PassengerGroup> currentGroupIdentifier = getGroupIdentifier();
DrtCompanionUtils.setPassengerGroupIdentifier(leg, currentGroupIdentifier);

// Add person to group map
this.passengerGroups.computeIfAbsent(currentGroupIdentifier, k -> new ArrayList<>())
.add(new GroupLeg(leg, person.getId()));

int groupSize = additionalCompanions + 1;
int currentGroupSize = 1; // Initial person

// Add companions
for (int i = 0; i < additionalCompanions; i++) {

// currentGroupSize+1 exceeds maxCapacity, create a new passengerGroupIdentifier
if (currentGroupSize + 1 > this.maxCapacity) {
passengerGroupIdentifier++; // increment due to vehicle capacity
currentGroupSize = 0;
currentGroupIdentifier = getGroupIdentifier();
}

// Bypass passengerGroupIdentifierId to each group member
companions.add(createCompanionAgent(this.drtMode, person, leg, trip.getOriginActivity(),
trip.getDestinationActivity(), i, groupSize,
Expand All @@ -157,110 +162,109 @@ private void addCompanionAgents() {
this.scenario.getPopulation().addPerson(p);
this.companionAgentIds.add(p.getId());
});

validateGroups();
LOG.info("Added # {} drt companion agents for mode {}", companions.size(), this.drtMode);
}

private void validateGroups() {
this.passengerGroups.values().forEach(g -> {
GroupLeg representative = g.get(0);

Id<Link> fromLinkId = representative.leg.getRoute().getStartLinkId();
Id<Link> toLinkId = representative.leg.getRoute().getEndLinkId();
double departureTime = representative.leg.getDepartureTime().seconds();

Preconditions.checkNotNull(fromLinkId);
Preconditions.checkNotNull(toLinkId);

Preconditions.checkArgument(g.stream().allMatch(
a -> a.leg.getRoute().getStartLinkId().equals(fromLinkId)));

Preconditions.checkArgument(g.stream().allMatch(
a -> a.leg.getRoute().getEndLinkId().equals(toLinkId)));

Preconditions.checkArgument(g.stream().allMatch(
a -> a.leg.getDepartureTime().seconds() == departureTime));

Preconditions.checkArgument(g.size() <= this.maxCapacity);
});
}

private Person createCompanionAgent(final String drtMode, final Person originalPerson, final Leg leg,
final Activity fromActivity, final Activity toActivity, final int groupPart, final int groupSize,
final int personIdentifier, final Id<PassengerGroupIdentifier.PassengerGroup> passengerGroupIdentifierId) {
String prefix = getCompanionPrefix(drtMode);
String companionId = prefix + "_" + originalPerson.getId().toString() + "_" + personIdentifier;
Person person = PopulationUtils.getFactory().createPerson(Id.createPersonId(companionId));
Leg legCopy = PopulationUtils.createLeg(leg);

DrtCompanionUtils.setDRTCompanionType(person, DRT_COMPANION_TYPE);

// Copy attributes from person
AttributesUtils.copyAttributesFromTo(originalPerson, person);
AttributesUtils.copyAttributesFromTo(leg, legCopy); // bypass all leg attributes

// Ensure that we have a timed end
Activity copyFromActivity = PopulationUtils.createActivity(fromActivity);
Activity copyToActivity = PopulationUtils.createActivity(toActivity);
copyFromActivity.setEndTime(leg.getDepartureTime().seconds());

// Ensure drt leg starts/ends at the correct links
copyFromActivity.setLinkId(legCopy.getRoute().getStartLinkId());
copyToActivity.setLinkId(legCopy.getRoute().getEndLinkId());

copyFromActivity.setCoord(null);
copyToActivity.setCoord(null);

copyFromActivity.setFacilityId(null);
copyToActivity.setFacilityId(null);

Plan plan = PopulationUtils.createPlan();
plan.getPlanElements().add(copyFromActivity);
plan.getPlanElements().add(legCopy);
plan.getPlanElements().add(copyToActivity);

person.addPlan(plan);

// Add group information to leg
DrtCompanionUtils.setAdditionalGroupPart(person, groupPart);
DrtCompanionUtils.setAdditionalGroupSize(person, groupSize);
DrtCompanionUtils.setPassengerGroupIdentifier(legCopy, passengerGroupIdentifierId);

// Add companion to group map
this.passengerGroups.computeIfAbsent(passengerGroupIdentifierId, k -> new ArrayList<>())
.add(new GroupLeg(legCopy, person.getId()));
return person;
}

private void removeCompanionAgents() {
int counter = 0;

for (Id<Person> drtCompanion : companionAgentIds) {
this.scenario.getPopulation().getPersons().remove(drtCompanion);
counter++;
}

// Reset
companionAgentIds.clear();
passengerGroups.clear();
personIdentifierSuffix.set(0);
LOG.info("Removed # {} drt companion agents", counter);

// Remove attribute from legs of initial drt riders
this.drtLegs.stream().forEach(DrtCompanionUtils::removePassengerGroupIdentifier);
this.drtLegs.clear();
}

@Override
public void notifyAfterMobsim(AfterMobsimEvent event) {
this.removeCompanionAgents();
}

@Override
public void notifyBeforeMobsim(BeforeMobsimEvent event) {
this.addCompanionAgents();
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public boolean checkInsertion(DrtRequest drtRequest, Insertion insertion, Detour

private boolean isValidInsertionForExclusiveRequest(DrtRequest drtRequest, Insertion insertion,
DetourTimeInfo detourTimeInfo) {
if (insertion.pickup.previousWaypoint.getOutgoingOccupancy() > 0) {
if (!insertion.pickup.previousWaypoint.getOutgoingOccupancy().isEmpty()) {
// attempt to attach pickup to existing trip
return false;
}
Expand Down Expand Up @@ -67,4 +67,4 @@ private boolean isValidInsertionForStandardRequest(DrtRequest drtRequest, Insert
static public interface ExclusivityVoter {
boolean isExclusive(DrtRequest request);
}
}
}
Loading
Loading