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

Update freight generation #3100

Merged
merged 7 commits into from
Feb 8, 2024
Merged
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 @@ -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
Loading