Skip to content

Commit

Permalink
make first test work
Browse files Browse the repository at this point in the history
  • Loading branch information
simei94 committed Oct 9, 2024
1 parent d7baf7e commit 4a7be7e
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 111 deletions.
Binary file not shown.
Binary file not shown.
90 changes: 78 additions & 12 deletions src/main/java/org/matsim/run/DrtOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.geotools.api.feature.simple.SimpleFeature;
import org.geotools.api.feature.simple.SimpleFeatureType;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.TransportMode;
Expand All @@ -24,6 +27,7 @@
import org.matsim.core.utils.gis.GeoFileWriter;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.pt.config.TransitRouterConfigGroup;
import org.matsim.run.prepare.PrepareDrtScenarioAgents;
import org.matsim.run.prepare.PrepareNetwork;
import org.matsim.run.prepare.PrepareTransitSchedule;
import org.matsim.vehicles.Vehicle;
Expand All @@ -32,6 +36,10 @@
import org.matsim.vehicles.VehicleUtils;
import picocli.CommandLine;

import java.io.File;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

Expand All @@ -40,6 +48,7 @@
*/
public class DrtOptions {
private static final Logger log = LogManager.getLogger(DrtOptions.class);
public static final String DRT_DUMMY_ACT_TYPE = "drt-split-trip";

@CommandLine.Option(names = "--drt-shp", description = "Path to shp file for adding drt not network links as an allowed mode.", defaultValue = "./drt-area/nord-bautzen-waiting-times_utm32N.shp")
private String drtAreaShp;
Expand All @@ -65,12 +74,14 @@ public class DrtOptions {
@CommandLine.Option(names = "--intermodal", defaultValue = "INTERMODALITY_ACTIVE", description = "enable intermodality for DRT service")
private IntermodalityHandling intermodal;

@CommandLine.Option(names = "--manual-trip-conversion", defaultValue = "NOT_CONVERT_TRIPS_MANUALLY", description = "enable manual trip conversion from pt to drt " +
"(for legs with new pt line of LausitzPtScenario).")
private ManualTripConversionHandling manualTripConversion;

/**
* a helper method, which makes all necessary config changes to simulate drt.
*/
public void configureDrtConfig(Config config) {
// check if every feature of shp file has attr typ_wt for drt estimation. Add attr with standard value if not present.
checkServiceAreaShapeFile(config);
DvrpConfigGroup dvrpConfigGroup = ConfigUtils.addOrGetModule(config, DvrpConfigGroup.class);
dvrpConfigGroup.networkModes = Set.of(TransportMode.drt);

Expand All @@ -93,6 +104,11 @@ public void configureDrtConfig(Config config) {
optimizationConstraintsSet.maxWalkDistance = ConfigUtils.addOrGetModule(config, TransitRouterConfigGroup.class).getSearchRadius();
drtConfigGroup.addParameterSet(optimizationConstraints);
drtConfigGroup.addParameterSet(new ExtensiveInsertionSearchParams());

// check if every feature of shp file has attr typ_wt for drt estimation. Add attr with standard value if not present
// + set new shp file as drtServiceAreaShapeFile
checkServiceAreaShapeFile(config, drtConfigGroup);

multiModeDrtConfigGroup.addParameterSet(drtConfigGroup);
}

Expand Down Expand Up @@ -144,6 +160,15 @@ public void configureDrtConfig(Config config) {
srrConfig.addIntermodalAccessEgress(accessEgressWalkParam);

}

if (manualTripConversion == ManualTripConversionHandling.CONVERT_TRIPS_MANUALLY) {
ScoringConfigGroup.ActivityParams drtDummyScoringParams = new ScoringConfigGroup.ActivityParams();
drtDummyScoringParams.setTypicalDuration(0.);
drtDummyScoringParams.setActivityType(DRT_DUMMY_ACT_TYPE);
drtDummyScoringParams.setScoringThisActivityAtAll(false);

scoringConfigGroup.addActivityParams(drtDummyScoringParams);
}
}

/**
Expand Down Expand Up @@ -180,31 +205,67 @@ public void configureDrtScenario(Scenario scenario) {
drtDummy.getAttributes().putAttribute("serviceEndTime", 86400.);

scenario.getVehicles().addVehicle(drtDummy);
}

// tag intermodal pt stops for intermodality between pt and drt
if (intermodal == IntermodalityHandling.INTERMODALITY_ACTIVE) {
PrepareTransitSchedule.tagIntermodalStops(scenario.getTransitSchedule(), new ShpOptions(IOUtils.extendUrl(scenario.getConfig().getContext(), intermodalAreaShp).toString(), null, null));
}
// tag intermodal pt stops for intermodality between pt and drt
if (intermodal == IntermodalityHandling.INTERMODALITY_ACTIVE) {
PrepareTransitSchedule.tagIntermodalStops(scenario.getTransitSchedule(), new ShpOptions(IOUtils.extendUrl(scenario.getConfig().getContext(), intermodalAreaShp).toString(), null, null));
}

if (manualTripConversion == ManualTripConversionHandling.CONVERT_TRIPS_MANUALLY) {
PrepareDrtScenarioAgents.convertVspRegionalTrainLegsToDrt(scenario.getPopulation(), scenario.getNetwork());
}
}

private void checkServiceAreaShapeFile(Config config) {
ShpOptions shp = new ShpOptions(getDrtAreaShp(), null, null);
private void checkServiceAreaShapeFile(Config config, DrtConfigGroup drtConfigGroup) {
ShpOptions shp = new ShpOptions(IOUtils.extendUrl(config.getContext(), getDrtAreaShp()).toString(), null, null);
List<SimpleFeature> features = shp.readFeatures();
List<SimpleFeature> newFeatures = new ArrayList<>();
boolean adapted = false;
for (SimpleFeature feature : features) {
if (feature.getAttribute("typ_wt") == null) {
feature.setAttribute("typ_wt", 10 * 60.);
SimpleFeatureType existingFeatureType = feature.getFeatureType();

SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.init(existingFeatureType);

builder.add("typ_wt", Double.class);
SimpleFeatureType newFeatureType = builder.buildFeatureType();

SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(newFeatureType);

List<Object> existingAttributes = feature.getAttributes();
featureBuilder.addAll(existingAttributes);
featureBuilder.add(10 * 60.);

// Step 7: Build the new feature with a unique ID (same geometry, updated attributes)
SimpleFeature newFeature = featureBuilder.buildFeature(feature.getID());
newFeatures.add(newFeature);
adapted = true;
} else {
newFeatures.add(feature);
}
}

if (adapted) {
String newServiceAreaPath;
try {
File file = new File(Path.of(IOUtils.extendUrl(config.getContext(), getDrtAreaShp()).toURI()).getParent().toString(),
Path.of(IOUtils.extendUrl(config.getContext(), getDrtAreaShp()).toURI()).getFileName().toString().split(".shp")[0] + "-with-waiting-time.shp");
newServiceAreaPath = file.getAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}




log.warn("For drt service area shape file {}, at least one feature did not have the obligatory attribute typ_wt. " +
"The attribute is needed for drt estimation. The attribute was added with a standard value of 10min for those features.", getDrtAreaShp());
"The attribute is needed for drt estimation. The attribute was added with a standard value of 10min for those features " +
"and saved to file {}.", IOUtils.extendUrl(config.getContext(), getDrtAreaShp()), newServiceAreaPath);

GeoFileWriter.writeGeometries(features, IOUtils.extendUrl(config.getContext(), getDrtAreaShp()).toString());
log.warn("Adapted drt service area shp file written to {}.", IOUtils.extendUrl(config.getContext(), getDrtAreaShp()));
GeoFileWriter.writeGeometries(newFeatures, newServiceAreaPath);
drtConfigGroup.drtServiceAreaShapeFile = newServiceAreaPath;
}
}

Expand Down Expand Up @@ -237,4 +298,9 @@ public double getRideTimeStd() {
*/
enum IntermodalityHandling {INTERMODALITY_ACTIVE, INTERMODALITY_NOT_ACTIVE}

/**
* Defines if pt legs with new pt regional train from LausitzPtScenario are converted to drt legs manually or not.
*/
enum ManualTripConversionHandling {CONVERT_TRIPS_MANUALLY, NOT_CONVERT_TRIPS_MANUALLY}

}
119 changes: 21 additions & 98 deletions src/main/java/org/matsim/run/prepare/PrepareDrtScenarioAgents.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package org.matsim.run.prepare;

import com.google.common.collect.Lists;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.locationtech.jts.geom.Geometry;
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.*;
import org.matsim.application.MATSimAppCommand;
Expand All @@ -16,10 +13,8 @@
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.network.filter.NetworkFilterManager;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.AnalysisMainModeIdentifier;
import org.matsim.core.router.DefaultAnalysisMainModeIdentifier;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.utils.geometry.geotools.MGC;
import org.matsim.run.DrtOptions;
import picocli.CommandLine;

import java.nio.file.Files;
Expand All @@ -42,7 +37,6 @@ public class PrepareDrtScenarioAgents implements MATSimAppCommand {
@CommandLine.Mixin
private final ShpOptions shp = new ShpOptions();

private static final String PLAN_TYPE = "drtPlan";
private static final String PT_INTERACTION = "pt interaction";

public static void main(String[] args) {
Expand All @@ -64,7 +58,9 @@ public Integer call() throws Exception {
Population population = PopulationUtils.readPopulation(input.toString());
Network network = NetworkUtils.readNetwork(networkPath);

// convertPtToDrtTrips(population, network, shp);
// shp needs to include all locations, where the new pt line (from pt policy case) has a station
// thus, lausitz.shp should be chosen as an input
PrepareNetwork.prepareDrtNetwork(network, shp.getShapeFile());

// TODO: try if for 3 and 5 it is enough to delete act locations instead of searching for nearest drt link
convertVspRegionalTrainLegsToDrt(population, network);
Expand All @@ -74,12 +70,12 @@ public Integer call() throws Exception {
return 0;
}

private void convertVspRegionalTrainLegsToDrt(Population population, Network network) {
// shp needs to include all locations, where the new pt line (from pt policy case) has a station
// thus, lausitz.shp should be chosen as an input
PrepareNetwork.prepareDrtNetwork(network, shp.getShapeFile());

NetworkFilterManager manager = new NetworkFilterManager(network, new NetworkConfigGroup());
/**
* Method to convert agents, which are using the new vsp pt line (see RunLausitzPtScenario) manually to mode DRT.
* The network needs to be including DRT as an allowed mode.
*/
public static void convertVspRegionalTrainLegsToDrt(Population population, Network networkInclDrt) {
NetworkFilterManager manager = new NetworkFilterManager(networkInclDrt, new NetworkConfigGroup());
manager.addLinkFilter(l -> l.getAllowedModes().contains(TransportMode.drt));
Network filtered = manager.applyFilters();

Expand Down Expand Up @@ -121,7 +117,7 @@ private void convertVspRegionalTrainLegsToDrt(Population population, Network net
}

if (selected.getPlanElements().get(i - 2) instanceof Activity prev) {
convertToDrtInteraction(act, prev, network, filtered);
convertToDrtInteractionAndSplitTrip(act, prev, filtered);
} else {
logWrongPlanElementType(person, i);
throw new IllegalStateException();
Expand All @@ -133,6 +129,7 @@ private void convertVspRegionalTrainLegsToDrt(Population population, Network net
// pt leg with new pt line
leg.setRoute(null);
leg.setMode(TransportMode.drt);
leg.setRoutingMode(TransportMode.drt);
leg.setTravelTimeUndefined();
leg.setDepartureTimeUndefined();
leg.getAttributes().removeAttribute("enterVehicleTime");
Expand All @@ -146,7 +143,7 @@ private void convertVspRegionalTrainLegsToDrt(Population population, Network net
throw new IllegalStateException();
}
if (selected.getPlanElements().get(i + 2) instanceof Activity next) {
convertToDrtInteraction(act, next, network, filtered);
convertToDrtInteractionAndSplitTrip(act, next, filtered);
} else {
logWrongPlanElementType(person, i);
throw new IllegalStateException();
Expand Down Expand Up @@ -174,93 +171,19 @@ private static void logWrongPlanElementType(Person person, int i) {
"It seems to be a leg. Abort.", person.getId(), i);
}

private static void convertToDrtInteraction(Activity act, Activity previous, Network fullNetwork, Network filtered) {
private static void convertToDrtInteractionAndSplitTrip(Activity act, Activity previous, Network filtered) {
// TODO: test if it is enough to delete link and facility, but keep coord. Correct link shoulb be found automatically then

if (filtered.getLinks().containsKey(previous.getLinkId())) {
act.setLinkId(previous.getLinkId());
} else {
act.setLinkId(NetworkUtils.getNearestLink(filtered, fullNetwork.getLinks().get(previous.getLinkId()).getToNode().getCoord()).getId());
// The original trip has to be split up because MATSim does not allow trips with 2 different routing modes.
// for the drt subtrip, a dummy act, which is not scored, is created.
if (TripStructureUtils.isStageActivityType(previous.getType())) {
previous.setType(DrtOptions.DRT_DUMMY_ACT_TYPE);
previous.setFacilityId(null);
previous.setLinkId(null);
}
act.setLinkId(NetworkUtils.getNearestLink(filtered, previous.getCoord()).getId());
act.setFacilityId(null);
act.setCoord(null);
act.setType("drt interaction");
}

/**
* This is implemented as a separate method to be able to use it in a scenario run class.
* Additionally, it can be used to write a new output population by calling this class.
*/
public static void convertPtToDrtTrips(Population population, Network network, ShpOptions shp) {
Geometry serviceArea = shp.getGeometry();

AnalysisMainModeIdentifier identifier = new DefaultAnalysisMainModeIdentifier();

log.info("Starting to iterate through population.");

int count = 0;
for (Person person : population.getPersons().values()) {
Plan selected = person.getSelectedPlan();
// remove all unselected plans
for (Plan plan : Lists.newArrayList(person.getPlans())) {
if (plan != selected)
person.removePlan(plan);
}

for (TripStructureUtils.Trip trip : TripStructureUtils.getTrips(selected)) {

String tripMode = identifier.identifyMainMode(trip.getTripElements());

if (!tripMode.equals(TransportMode.pt)) {
continue;
}

boolean startInside = isInside(network.getLinks().get(trip.getLegsOnly().getFirst().getRoute().getStartLinkId()), serviceArea);
boolean endInside = isInside(network.getLinks().get(trip.getLegsOnly().getLast().getRoute().getEndLinkId()), serviceArea);

// we only need to change the mode for trips within the drt service area.
// All others will be handled by intermodal trips between drt and pt.
// "other" would be ending in service area but not starting and vice versa
if (startInside && endInside) {
int oldIndex = selected.getPlanElements().indexOf(trip.getLegsOnly().stream().filter(l -> l.getMode().equals(TransportMode.pt)).toList().getFirst());

// TODO: erst plan kopieren dann converten
int index = convertPtTripToLeg(trip, selected, identifier);

// copy pt plan and create drt plan. Tag it as drtPlan
Plan drtCopy = person.createCopyOfSelectedPlanAndMakeSelected();
((Leg) drtCopy.getPlanElements().get(index)).setMode(TransportMode.drt);
drtCopy.setType(PLAN_TYPE);
count++;
}
}
}
log.info("For {} trips, a copy of the selected plan with a drt trip has been created.", count);
}

private static int convertPtTripToLeg(TripStructureUtils.Trip trip, Plan selected, AnalysisMainModeIdentifier identifier) {
final List<PlanElement> planElements = selected.getPlanElements();

// TODO: test if new leg is pasted at correct index.
// TODO: index in this method is always -1. fix this

// TODO: rather use trips2LegsALgo instead of copy paste
final List<PlanElement> fullTrip =
planElements.subList(
planElements.indexOf(trip.getOriginActivity()) + 1,
planElements.indexOf(trip.getDestinationActivity()));
final String mode = identifier.identifyMainMode(fullTrip);
fullTrip.clear();
Leg leg = PopulationUtils.createLeg(mode);
TripStructureUtils.setRoutingMode(leg, mode);
int index = planElements.indexOf(leg);
fullTrip.add(leg);
if ( fullTrip.size() != 1 ) throw new IllegalArgumentException(fullTrip.toString());
return index;
}

private static boolean isInside(Link link, Geometry geometry) {
return MGC.coord2Point(link.getFromNode().getCoord()).within(geometry) ||
MGC.coord2Point(link.getToNode().getCoord()).within(geometry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class PrepareDrtScenarioAgentsTest {

@Test
void testPrepareDrtScenarioAgents() {
String inputPopulationPath = "./input/v1.1/lausitz-pt-case-test_experienced_plans_1person.xml.gz";
String inputPopulationPath = "./input/v1.1/lausitz-pt-case-test_plans_1person.xml.gz";
Population in = PopulationUtils.readPopulation(inputPopulationPath);
String networkPath = URL + String.format("lausitz-v%s-network-with-pt.xml.gz", LausitzScenario.VERSION);
String outPath = utils.getOutputDirectory() + "/drt-test-population.xml.gz";
Expand Down

0 comments on commit 4a7be7e

Please sign in to comment.