Skip to content

Commit

Permalink
Merge branch 'master' into feat/drt-detour-time-estimator-di
Browse files Browse the repository at this point in the history
  • Loading branch information
sebhoerl authored Feb 8, 2024
2 parents 092763c + a64d221 commit 9756f5c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

/**
* This CarrierReaderFromCSV reads all carrier information given in the read CSV
* file and creates the carriers. While the process of creating the carriers the
* file and creates the carriers. While the process of creating the carriers, the
* consistency of the information will be checked.
*
* @author Ricardo Ewert
Expand All @@ -55,11 +55,11 @@ public final class CarrierReaderFromCSV {
* file. For one carrier several CarrierInformationElement can be read in. This
* is necessary for creating different configurations of the vehicles. Not every
* parameter should be set for creating the carrier. While the process of
* creating the carriers the consistency of the information will be checked.
* creating the carriers, the consistency of the information will be checked.
*/
static class CarrierInformationElement {
/**
* Name of carrier of this information element.
* Name of the carrier of this information element.
*/
private final String carrierName;
/**
Expand Down Expand Up @@ -97,8 +97,8 @@ static class CarrierInformationElement {
private final int jspritIterations;
/**
* Sets a fixed number of vehicles per vehicleType and location. If this
* number is e.g. 3.: for each vehicleType 3 vehicles at each location will be
* created and the fleetsize is finite.
* number is e.g., 3.: for each vehicleType 3 vehicles at each location will be
* created, and the fleetsize is finite.
*/
private int fixedNumberOfVehiclePerTypeAndLocation;

Expand Down Expand Up @@ -302,7 +302,7 @@ else if (!record.get("fleetSize").isBlank())
}

/**
* Checks if the read carrier information are consistent.
* Checks if the read carrier information is consistent.
*
* @param allNewCarrierInformation
* @param freightCarriersConfigGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@
import org.apache.commons.csv.CSVRecord;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.locationtech.jts.geom.Point;
import org.matsim.api.core.v01.Coord;
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.population.Person;
import org.matsim.api.core.v01.population.Population;
import org.matsim.freight.carriers.*;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.utils.geometry.CoordinateTransformation;
import org.matsim.core.utils.geometry.geotools.MGC;
import org.matsim.freight.carriers.*;
import org.opengis.feature.simple.SimpleFeature;

import java.io.IOException;
Expand All @@ -45,7 +46,7 @@
/**
* This DemandReaderFromCSV reads all demand information given in the read CSV
* file and creates the demand for the carriers. While the process of creating
* the demand the consistency of the information will be checked.
* the demand, the consistency of the information will be checked.
*
* @author Ricardo Ewert
*/
Expand All @@ -58,9 +59,9 @@ public final class DemandReaderFromCSV {
* file. Several DemandInformationElement can be read in for one carrier. This
* is necessary for creating configurations of the demand. Not every parameter
* should be set for creating the demand. While the process of creating the
* demand the consistency of the information will be checked. If this demand
* creates a service the information for the firstJobElement should be set. If
* this demands creates a shipment the firstJobElement is the pickup and the
* demand, the consistency of the information will be checked. If this demand
* creates a service, the information for the firstJobElement should be set. If
* this demand creates a shipment, the firstJobElement is the pickup and the
* secondJobElement is the delivery.
*/
static class DemandInformationElement {
Expand Down Expand Up @@ -336,7 +337,7 @@ static void readAndCreateDemand(Scenario scenario, Path csvLocationDemand,

/**
* Reads the demand information from the csv file and checks if the information
* are consistent
* is consistent
*
* @param csvLocationDemand
* @return
Expand Down Expand Up @@ -887,7 +888,7 @@ else if (population == null)
throw new RuntimeException("The selected link " + selectedLinkIdDelivery
+ " for delivery is not part of the possible links for delivery. Please check!");

// distribute the demand over the network because no number of jobs are selected
// distribute the demand over the network because no number of jobs is selected
if (numberOfJobs == null) {
// creates shipments with a demand of 1
if (possibleLinksPickup.size() > demandToDistribute || possibleLinksDelivery.size() > demandToDistribute) {
Expand Down Expand Up @@ -1088,8 +1089,8 @@ else if (numberOfPickupLocations != null) {
}

/**
* Creates a job Id for a new job. If a certain Id is already used a number will
* be added at the end until no existing job was the same Id.
* Creates a job Id for a new job.
* If a certain Id is already used, a number will be added at the end until no existing job was the same Id.
*
* @param scenario
* @param newDemandInformationElement
Expand Down Expand Up @@ -1127,8 +1128,8 @@ private static String createJobId(Scenario scenario, DemandInformationElement ne
}

/**
* If jobs of a carrier have the same characteristics (time window, location)
* they will be combined to one job,
* If jobs of a carrier have the same characteristics (time window, location),
* they will be combined to one job.
*
* @param scenario
* @param newDemandInformationElement
Expand Down Expand Up @@ -1262,7 +1263,7 @@ private static HashMap<Id<Link>, Link> findAllPossibleLinks(Scenario scenario,
possibleLinks.put(link.getId(), link);
}
} else {
Link newPossibleLink = null;
Link newPossibleLink;
while (possibleLinks.size() < numberOfLocations) {
newPossibleLink = findPossibleLinkForDemand(possibleLinks, possiblePersons, nearestLinkPerPerson,
polygonsInShape, areasForLocations, numberOfLocations, scenario, setLocations,
Expand Down Expand Up @@ -1315,7 +1316,7 @@ private static Link findNextUsedLink(Scenario scenario, Collection<SimpleFeature
}

/**
* Finds all persons which are possible for the demand.
* Finds all persons that are possible for the demand.
*
* @param population
* @param areasForServiceLocations
Expand All @@ -1330,13 +1331,9 @@ private static HashMap<Id<Person>, Person> findPossiblePersons(Population popula
HashMap<Id<Person>, Person> possiblePersons = new HashMap<Id<Person>, Person>();

for (Person person : population.getPersons().values()) {
Point p = MGC.xy2Point((double) person.getAttributes().getAttribute("homeX"),
(double) person.getAttributes().getAttribute("homeY"));
Coord coord;
Coord coord = getHomeCoord(person);
if (crsTransformationNetworkAndShape != null)
coord = crsTransformationNetworkAndShape.transform(MGC.point2Coord(p));
else
coord = MGC.point2Coord(p);
coord = crsTransformationNetworkAndShape.transform(coord);

if (FreightDemandGenerationUtils.checkPositionInShape(null, MGC.coord2Point(coord), polygonsInShape,
areasForServiceLocations, crsTransformationNetworkAndShape))
Expand All @@ -1352,15 +1349,14 @@ private static HashMap<Id<Person>, Person> findPossiblePersons(Population popula
* @param nearestLinkPerPerson
* @param person
*/
static void findLinksForPersons(Scenario scenario,
HashMap<Id<Person>, HashMap<Double, String>> nearestLinkPerPerson, Person person) {
static void findLinksForPerson(Scenario scenario,
HashMap<Id<Person>, HashMap<Double, String>> nearestLinkPerPerson, Person person) {

for (Link link : scenario.getNetwork().getLinks().values())
if (!link.getId().toString().contains("pt") && (!link.getAttributes().getAsMap().containsKey("type")
|| !link.getAttributes().getAsMap().get("type").toString().contains("motorway"))) {

Coord homePoint = MGC.point2Coord(MGC.xy2Point((double) person.getAttributes().getAttribute("homeX"),
(double) person.getAttributes().getAttribute("homeY")));
Coord homePoint = getHomeCoord(person);
Coord middlePointLink = FreightDemandGenerationUtils.getCoordOfMiddlePointOfLink(link);
double distance = NetworkUtils.getEuclideanDistance(homePoint, middlePointLink);
if (!nearestLinkPerPerson.containsKey(person.getId())
Expand All @@ -1371,6 +1367,30 @@ static void findLinksForPersons(Scenario scenario,
}
}

/**
* Method to get the home coordinate of a person.
* The default is to get the home coordinate from one home activity of the selected plan.
* If the selected plan does not contain a home activity, the home coordinate is read from the attributes of the person.
*
* @param person The person for which the home coordinate should be returned.
* @return
*/
private static Coord getHomeCoord(Person person) {
Coord homeCoord = null;
if (person.getSelectedPlan() != null)
homeCoord = PopulationUtils.getActivities(person.getSelectedPlan(),
TripStructureUtils.StageActivityHandling.ExcludeStageActivities).stream().filter(
activity -> activity.getType().contains("home")).findFirst().get().getCoord();
if (homeCoord == null) {
double home_x = (double) person.getAttributes().getAsMap().entrySet().stream().filter(
entry -> entry.getKey().contains("home") && entry.getKey().contains("X")).findFirst().get().getValue();
double home_y = (double) person.getAttributes().getAsMap().entrySet().stream().filter(
entry -> entry.getKey().contains("home") && entry.getKey().contains("Y")).findFirst().get().getValue();
homeCoord = new Coord(home_x, home_y);
}
return homeCoord;
}

/**
* Searches a possible link for the demand.
*
Expand Down Expand Up @@ -1406,33 +1426,15 @@ private static Link findPossibleLinkForDemand(HashMap<Id<Link>, Link> possibleLi
newLink = scenario.getNetwork().getLinks().values().stream()
.skip(rand.nextInt(scenario.getNetwork().getLinks().size())).findFirst().get();
else {
Person person = possiblePersons.values().stream().skip(rand.nextInt(possiblePersons.size()))
.findFirst().get();
if (nearestLinkPerPerson.containsKey(person.getId()))
newLink = scenario.getNetwork().getLinks().get(Id
.createLinkId(nearestLinkPerPerson.get(person.getId()).values().iterator().next()));
else {
findLinksForPersons(scenario, nearestLinkPerPerson, person);
newLink = scenario.getNetwork().getLinks().get(Id
.createLinkId(nearestLinkPerPerson.get(person.getId()).values().iterator().next()));
}
newLink = getNewLinkForPerson(possiblePersons, nearestLinkPerPerson, scenario);
}
}
} else {
if (possiblePersons.isEmpty()) {
newLink = possibleLinks.values().stream().skip(rand.nextInt(possibleLinks.size())).findFirst()
.get();
} else {
Person person = possiblePersons.values().stream().skip(rand.nextInt(possiblePersons.size()))
.findFirst().get();
if (nearestLinkPerPerson.containsKey(person.getId()))
newLink = scenario.getNetwork().getLinks().get(
Id.createLinkId(nearestLinkPerPerson.get(person.getId()).values().iterator().next()));
else {
findLinksForPersons(scenario, nearestLinkPerPerson, person);
newLink = scenario.getNetwork().getLinks().get(
Id.createLinkId(nearestLinkPerPerson.get(person.getId()).values().iterator().next()));
}
newLink = getNewLinkForPerson(possiblePersons, nearestLinkPerPerson, scenario);
}
}
if (!newLink.getId().toString().contains("pt")
Expand All @@ -1444,4 +1446,17 @@ private static Link findPossibleLinkForDemand(HashMap<Id<Link>, Link> possibleLi
}
return selectedlink;
}

private static Link getNewLinkForPerson(HashMap<Id<Person>, Person> possiblePersons,
HashMap<Id<Person>, HashMap<Double, String>> nearestLinkPerPerson, Scenario scenario) {
Link newLink;
Person person = possiblePersons.values().stream().skip(rand.nextInt(possiblePersons.size()))
.findFirst().get();
if (!nearestLinkPerPerson.containsKey(person.getId())) {
findLinksForPerson(scenario, nearestLinkPerPerson, person);
}
newLink = scenario.getNetwork().getLinks().get(
Id.createLinkId(nearestLinkPerPerson.get(person.getId()).values().iterator().next()));
return newLink;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ public static void main(String[] args) {
public Integer call() throws IOException, InvalidAttributeValueException, ExecutionException, InterruptedException {

String vehicleTypesFileLocation = carrierVehicleFilePath.toString();
String carriersFileLocation = carrierFilePath.toString();
String populationFile = populationFilePath;
CoordinateTransformation crsTransformationFromNetworkToShape = null;

// create and prepare MATSim config
Expand Down Expand Up @@ -197,12 +195,12 @@ public Integer call() throws IOException, InvalidAttributeValueException, Execut
crsTransformationFromNetworkToShape = shp.createTransformation(networkCRS);
}
log.info("Start creating carriers. Selected option: " + selectedCarrierInputOption);
createCarrier(scenario, selectedCarrierInputOption, carriersFileLocation, csvCarrierPath, polygonsInShape,
createCarrier(scenario, selectedCarrierInputOption, csvCarrierPath, polygonsInShape,
defaultJspritIterations, crsTransformationFromNetworkToShape);

// create the demand
log.info("Start creating the demand. Selected option: " + selectedCarrierInputOption);
createDemand(selectedDemandGenerationOption, scenario, csvDemandPath, polygonsInShape, populationFile,
createDemand(selectedDemandGenerationOption, scenario, csvDemandPath, polygonsInShape, populationFilePath,
selectedPopulationSamplingOption, selectedPopulationOption, Boolean.getBoolean(combineSimilarJobs),
crsTransformationFromNetworkToShape);

Expand Down Expand Up @@ -238,6 +236,8 @@ private Config prepareConfig(int lastMATSimIteration, String coordinateSystem) {
FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(config, FreightCarriersConfigGroup.class);
freightCarriersConfigGroup.setTravelTimeSliceWidth(1800);
freightCarriersConfigGroup.setTimeWindowHandling(FreightCarriersConfigGroup.TimeWindowHandling.enforceBeginnings);
if (carrierFilePath != null)
freightCarriersConfigGroup.setCarriersFile(carrierFilePath.toString());

return config;
}
Expand Down Expand Up @@ -290,15 +290,14 @@ private static void prepareVehicles(Config config, String vehicleTypesFileLocati
*
* @param scenario
* @param selectedCarrierInputOption
* @param carriersFileLocation
* @param csvLocationCarrier
* @param polygonsInShape
* @param defaultJspritIterations
* @param crsTransformationNetworkAndShape
* @throws IOException
*/
private void createCarrier(Scenario scenario, CarrierInputOptions selectedCarrierInputOption,
String carriersFileLocation, Path csvLocationCarrier, Collection<SimpleFeature> polygonsInShape,
Path csvLocationCarrier, Collection<SimpleFeature> polygonsInShape,
int defaultJspritIterations, CoordinateTransformation crsTransformationNetworkAndShape) throws IOException {

FreightCarriersConfigGroup freightCarriersConfigGroup = ConfigUtils.addOrGetModule(scenario.getConfig(),
Expand All @@ -307,24 +306,22 @@ private void createCarrier(Scenario scenario, CarrierInputOptions selectedCarrie
case addCSVDataToExistingCarrierFileData -> {
// reads an existing carrier file and adds the information based on the read csv
// carrier file
if (Objects.equals(carriersFileLocation, ""))
if (freightCarriersConfigGroup.getCarriersFile() == null)
throw new RuntimeException("No path to the carrier file selected");
else {
freightCarriersConfigGroup.setCarriersFile(carriersFileLocation);
CarriersUtils.loadCarriersAccordingToFreightConfig(scenario);
log.info("Load carriers from: " + carriersFileLocation);
log.info("Load carriers from: " + freightCarriersConfigGroup.getCarriersFile());
CarrierReaderFromCSV.readAndCreateCarrierFromCSV(scenario, freightCarriersConfigGroup, csvLocationCarrier,
polygonsInShape, defaultJspritIterations, crsTransformationNetworkAndShape, shapeCategory);
}
}
case readCarrierFile -> {
// reads only a carrier file as the carrier import.
if (Objects.equals(carriersFileLocation, ""))
if (freightCarriersConfigGroup.getCarriersFile() == null)
throw new RuntimeException("No path to the carrier file selected");
else {
freightCarriersConfigGroup.setCarriersFile(carriersFileLocation);
CarriersUtils.loadCarriersAccordingToFreightConfig(scenario);
log.info("Load carriers from: " + carriersFileLocation);
log.info("Load carriers from: " + freightCarriersConfigGroup.getCarriersFile());
}
}
case createCarriersFromCSV ->
Expand All @@ -342,15 +339,15 @@ private void createCarrier(Scenario scenario, CarrierInputOptions selectedCarrie
* @param scenario
* @param csvLocationDemand
* @param polygonsInShape
* @param populationFile
* @param populationFilePath
* @param selectedSamplingOption
* @param selectedPopulationOption
* @param combineSimilarJobs
* @param crsTransformationNetworkAndShape
* @throws IOException
*/
private void createDemand(DemandGenerationOptions selectedDemandGenerationOption, Scenario scenario,
Path csvLocationDemand, Collection<SimpleFeature> polygonsInShape, String populationFile,
Path csvLocationDemand, Collection<SimpleFeature> polygonsInShape, String populationFilePath,
PopulationSamplingOption selectedSamplingOption, PopulationOptions selectedPopulationOption,
boolean combineSimilarJobs, CoordinateTransformation crsTransformationNetworkAndShape) throws IOException {

Expand All @@ -364,7 +361,7 @@ private void createDemand(DemandGenerationOptions selectedDemandGenerationOption
* Option creates the demand by using the information given in the read csv file
* and uses a population for finding demand locations
*/
Population population = PopulationUtils.readPopulation(populationFile);
Population population = PopulationUtils.readPopulation(populationFilePath);
switch (selectedSamplingOption) {
/*
* This option is important if the sample of the population and the sample of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void testLinkForPerson() throws IOException {
FreightDemandGenerationUtils.preparePopulation(population, 1.0, 1.0, "changeNumberOfLocationsWithDemand");
HashMap<Id<Person>, HashMap<Double, String>> nearestLinkPerPerson = new HashMap<>();
for (Person person : population.getPersons().values()) {
DemandReaderFromCSV.findLinksForPersons(scenario, nearestLinkPerPerson, person);
DemandReaderFromCSV.findLinksForPerson(scenario, nearestLinkPerPerson, person);
}
Assertions.assertEquals("j(1,8)",nearestLinkPerPerson.get(Id.createPersonId("person1")).values().iterator().next());
Assertions.assertEquals("j(3,3)",nearestLinkPerPerson.get(Id.createPersonId("person2")).values().iterator().next());
Expand Down

0 comments on commit 9756f5c

Please sign in to comment.