Skip to content

Commit

Permalink
Person vehicle types attribute (#2877)
Browse files Browse the repository at this point in the history
* added todos

* separate container class for vehicle types

* add vehicle type logic and test for it

* add a todo

* put vehicle types into person attributes from commercial traffic

* changes from ricardo
  • Loading branch information
rakow authored Oct 16, 2023
1 parent 3d665b5 commit 3b1b938
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.vehicles.Vehicle;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;
import org.matsim.vehicles.Vehicles;

import java.io.BufferedWriter;
import java.io.IOException;
Expand Down Expand Up @@ -169,7 +171,7 @@ private static void writeCSVWithCategoryHeader(HashMap<String, Object2DoubleMap<
writer.close();

} catch (IOException e) {
e.printStackTrace();
log.error("Could not write the csv file with the data distribution data.", e);
}
}

Expand All @@ -186,6 +188,8 @@ static void createPlansBasedOnCarrierPlans(Scenario scenario, String smallScaleC
Map<String, AtomicLong> idCounter = new HashMap<>();

Population populationFromCarrier = (Population) scenario.getScenarioElement("allpersons");
Vehicles allVehicles = VehicleUtils.getOrCreateAllvehicles(scenario);

for (Person person : populationFromCarrier.getPersons().values()) {

Plan plan = popFactory.createPlan();
Expand Down Expand Up @@ -238,11 +242,12 @@ else if (subpopulation.contains("goodsTraffic"))
if (relatedCarrier.getAttributes().getAsMap().containsKey("tourStartArea"))
newPerson.getAttributes().putAttribute("tourStartArea",
relatedCarrier.getAttributes().getAttribute("tourStartArea"));
VehicleUtils.insertVehicleIdsIntoAttributes(newPerson, (new HashMap<>() {
{
put(mode, (Id.createVehicleId(person.getId().toString())));
}
}));

Id<Vehicle> vehicleId = Id.createVehicleId(person.getId().toString());

VehicleUtils.insertVehicleIdsIntoAttributes(newPerson, Map.of(mode, vehicleId));
VehicleUtils.insertVehicleTypesIntoAttributes(newPerson, Map.of(mode, allVehicles.getVehicles().get(vehicleId).getType().getId()));

population.addPerson(newPerson);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
* *
* *********************************************************************** */

package org.matsim.core.controler;
package org.matsim.core.controler;


import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Id;
Expand Down Expand Up @@ -49,20 +51,15 @@
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.router.TripStructureUtils.Trip;
import org.matsim.core.scenario.Lockable;
import org.matsim.core.utils.collections.Tuple;
import org.matsim.core.utils.timing.TimeInterpretation;
import org.matsim.facilities.ActivityFacilities;
import org.matsim.facilities.FacilitiesFromPopulation;
import org.matsim.vehicles.Vehicle;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;

import jakarta.inject.Inject;
import jakarta.inject.Provider;

import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;

import static org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource.modeVehicleTypesFromVehiclesData;

Expand Down Expand Up @@ -230,13 +227,35 @@ private void createAndAddVehiclesForEveryNetworkMode() {

for (Person person : scenario.getPopulation().getPersons().values()) {

var modeToVehicle = modeVehicleTypes.entrySet().stream()
// map mode type to vehicle id
.map(modeType -> Tuple.of(modeType, createVehicleId(person, modeType.getKey())))
// create a corresponding vehicle
.peek(tuple -> createAndAddVehicleIfNecessary(tuple.getSecond(), tuple.getFirst().getValue()))
// write mode-string to vehicle-id into a map
.collect(Collectors.toMap(tuple -> tuple.getFirst().getKey(), Tuple::getSecond));

Map<String, Id<Vehicle>> modeToVehicle = new HashMap<>();

// optional attribute, that can be null
Map<String, Id<VehicleType>> modeTypes = VehicleUtils.getVehicleTypes(person);

for (Map.Entry<String, VehicleType> modeType : modeVehicleTypes.entrySet()) {

String mode = modeType.getKey();

Id<Vehicle> vehicleId = createVehicleId(person, mode);

// get the type
VehicleType type = modeType.getValue();

// Use the person attribute to map to a more specific vehicle type
if (modeTypes != null && modeTypes.containsKey(mode)) {
Id<VehicleType> typeId = modeTypes.get(mode);
type = scenario.getVehicles().getVehicleTypes().get(typeId);
if (type == null) {
throw new IllegalStateException("Vehicle type " + typeId + " specified for person " + person.getId() + ", but not found in scenario.");
}
}

createAndAddVehicleIfNecessary(vehicleId, type);

// write mode-string to vehicle-id into a map
modeToVehicle.put(mode, vehicleId);
}

VehicleUtils.insertVehicleIdsIntoAttributes(person, modeToVehicle);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.logging.log4j.Logger;
import org.matsim.utils.objectattributes.attributeconverters.*;
import org.matsim.api.core.v01.Coord;
import org.matsim.vehicles.PersonVehicleTypes;
import org.matsim.vehicles.PersonVehicles;

import java.util.*;
Expand Down Expand Up @@ -60,6 +61,7 @@ public ObjectAttributesConverter() {
this.converters.put(Coord.class.getName(), new CoordConverter());
this.converters.put(Coord[].class.getName(), new CoordArrayConverter());
this.converters.put(PersonVehicles.class.getName(), new PersonVehiclesAttributeConverter());
this.converters.put(PersonVehicleTypes.class.getName(), new PersonVehicleTypesAttributeConverter());
}

//this is for reading
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.matsim.utils.objectattributes.attributeconverters;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Id;
import org.matsim.utils.objectattributes.AttributeConverter;
import org.matsim.vehicles.PersonVehicleTypes;
import org.matsim.vehicles.VehicleType;

import java.util.HashMap;
import java.util.Map;

/**
* Converter to store vehicle types as person attribute.
*/
public class PersonVehicleTypesAttributeConverter implements AttributeConverter<PersonVehicleTypes> {

private final Logger logger = LogManager.getLogger(PersonVehicleTypesAttributeConverter.class);

@Override
public PersonVehicleTypes convert(String value) {
PersonVehicleTypes vehicles = new PersonVehicleTypes();
Map<String, String> stringMap = new StringStringMapConverter().convert(value);
for (Map.Entry<String, String> entry: stringMap.entrySet()) {
vehicles.addModeVehicleType(entry.getKey(), Id.create(entry.getValue(), VehicleType.class));
}
return vehicles;
}

@Override
public String convertToString(Object o) {
if(!(o instanceof PersonVehicleTypes vehicles)){
logger.error("Object is not of type PersonVehicles: " + o.getClass());
return null;
}
Map<String, String> stringMap = new HashMap<>();
for (Map.Entry<String, Id<VehicleType>> entry: vehicles.getModeVehicleTypes().entrySet()) {
stringMap.put(entry.getKey(), entry.getValue().toString());
}
return new StringStringMapConverter().convertToString(stringMap);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ public PersonVehicles convert(String value) {

@Override
public String convertToString(Object o) {
if(!(o instanceof PersonVehicles)){
logger.error("Object is not of type PersonVehicles: " + o.getClass().toString());
if(!(o instanceof PersonVehicles vehicles)){
logger.error("Object is not of type PersonVehicles: " + o.getClass());
return null;
}
PersonVehicles vehicles = (PersonVehicles)o;
Map<String, String> stringMap = new HashMap<>();
Map<String, String> stringMap = new HashMap<>();
for (Map.Entry<String, Id<Vehicle>> entry: vehicles.getModeVehicles().entrySet()) {
stringMap.put(entry.getKey(), entry.getValue().toString());
}
Expand Down
33 changes: 33 additions & 0 deletions matsim/src/main/java/org/matsim/vehicles/PersonVehicleTypes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.matsim.vehicles;

import org.matsim.api.core.v01.Id;

import java.util.HashMap;
import java.util.Map;

/**
* Container class to store mode specific person vehicle types.
*/
public final class PersonVehicleTypes {

private final Map<String, Id<VehicleType>> modeVehicleTypes = new HashMap<>();

public PersonVehicleTypes() {
}

public void addModeVehicleType(String mode, Id<VehicleType> vehicleType) {
modeVehicleTypes.put(mode, vehicleType);
}

public Id<VehicleType> getVehicleType(String mode) {
return modeVehicleTypes.get(mode);
}

public Map<String, Id<VehicleType>> getModeVehicleTypes() {
return modeVehicleTypes;
}

public void putModeVehicleTypes(Map<String, Id<VehicleType>> vehicleTypes) {
modeVehicleTypes.putAll(vehicleTypes);
}
}
35 changes: 32 additions & 3 deletions matsim/src/main/java/org/matsim/vehicles/VehicleUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class VehicleUtils {

private static final VehicleType DEFAULT_VEHICLE_TYPE = VehicleUtils.getFactory().createVehicleType(Id.create("defaultVehicleType", VehicleType.class));
private static final String VEHICLE_ATTRIBUTE_KEY = "vehicles";
private static final String VEHICLE_TYPES_ATTRIBUTE_KEY = "vehicleTypes";

// should remain under the hood --> should remain private
private static final String DOOR_OPERATION_MODE = "doorOperationMode" ;
Expand Down Expand Up @@ -117,11 +118,11 @@ public static void copyFromTo( VehicleType in, VehicleType out ) {
/**
* Checks whether a person has a vehicle id for mode - without throwing an
* exception if not.
*
*
* @param person the person one wants to check for a vehicle id
* @param mode the mode for the vehicle id to check
* @return whether person has a vehicle id for that mode
*
*
* @see {@link VehicleUtils#getVehicleId(Person, String)}
*/
public static boolean hasVehicleId(Person person, String mode) {
Expand All @@ -147,6 +148,15 @@ public static Map<String, Id<Vehicle>> getVehicleIds(Person person) {
return personVehicles.getModeVehicles();
}

/**
* Retrieve the optional vehicle types per mode that might be assigned to a person.
* Returns null if this is not defined.
*/
public static Map<String, Id<VehicleType>> getVehicleTypes(Person person) {
var personVehicles = (PersonVehicleTypes) person.getAttributes().getAttribute(VehicleUtils.VEHICLE_TYPES_ATTRIBUTE_KEY);
return personVehicles != null ? personVehicles.getModeVehicleTypes() : null;
}

/**
* Retrieves a vehicleId from the person's attributes.
*
Expand Down Expand Up @@ -179,13 +189,32 @@ public static void insertVehicleIdsIntoAttributes(Person person, Map<String, Id<
Map<String, Id<Vehicle>> modeToVehicleCopy = new HashMap<>(modeToVehicle);
PersonVehicles personVehicles;
if (attr == null) {
personVehicles = new PersonVehicles(modeToVehicleCopy);
personVehicles = new PersonVehicles();
} else {
personVehicles = (PersonVehicles) attr;
}
personVehicles.addModeVehicleList(modeToVehicleCopy);
person.getAttributes().putAttribute(VEHICLE_ATTRIBUTE_KEY, personVehicles);
}

/**
* Attaches vehicle types to a person, so that the router knows which vehicle to use for which mode and person.
* @param modeToVehicleType mode string mapped to vehicle type ids. The provided map is copied and stored as unmodifiable map.
*/
public static void insertVehicleTypesIntoAttributes(Person person, Map<String, Id<VehicleType>> modeToVehicleType) {
Object attr = person.getAttributes().getAttribute(VEHICLE_TYPES_ATTRIBUTE_KEY);

Map<String, Id<VehicleType>> modeToTypesCopy = new HashMap<>(modeToVehicleType);
PersonVehicleTypes personVehiclesTypes;
if (attr == null) {
personVehiclesTypes = new PersonVehicleTypes();
} else {
personVehiclesTypes = (PersonVehicleTypes) attr;
}
personVehiclesTypes.putModeVehicleTypes(modeToTypesCopy);
person.getAttributes().putAttribute(VEHICLE_TYPES_ATTRIBUTE_KEY, personVehiclesTypes);
}

//******** general VehicleType attributes ************

public static VehicleType.DoorOperationMode getDoorOperationMode( VehicleType vehicleType ){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@

package org.matsim.core.controler;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;

import org.junit.Assert;
import org.junit.Test;
Expand Down Expand Up @@ -55,6 +52,11 @@
import org.matsim.core.utils.timing.TimeInterpretation;

import com.google.inject.Provider;
import org.matsim.vehicles.Vehicle;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Mostly tests adaptation of old plans to routing mode and the related replacement of helper modes for access and egress
Expand Down Expand Up @@ -760,6 +762,48 @@ public void testOutdatedFallbackAndHelperModesReplacement() {
}
}

@Test
public void vehicleTypes() {

Config config = ConfigUtils.createConfig();
config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists);
Scenario scenario = ScenarioUtils.createScenario(config);
createAndAddNetwork(scenario);
Population pop = scenario.getPopulation();
PopulationFactory f = pop.getFactory();

// add truck type
VehicleType truckType = scenario.getVehicles().getFactory().createVehicleType(Id.create("truck", VehicleType.class));
scenario.getVehicles().addVehicleType(truckType);

// Create test person
Person p1 = f.createPerson(Id.createPersonId("1"));
{
VehicleUtils.insertVehicleTypesIntoAttributes(p1, Map.of(TransportMode.car, Id.create("truck", VehicleType.class)));

Plan plan = f.createPlan();
Activity act = f.createActivityFromCoord("home", new Coord(0, 0));
act.setEndTime(3600);
plan.addActivity(act);
plan.addLeg(f.createLeg(TransportMode.car));
plan.addActivity(f.createActivityFromCoord("work", new Coord(1000, 0)));
p1.addPlan(plan);
pop.addPerson(p1);
}

// run prepare
final PrepareForSimImpl prepareForSimImpl = new PrepareForSimImpl(config.global(), scenario, scenario.getNetwork(),
pop, scenario.getActivityFacilities(), new DummyTripRouterProvider(), config.qsim(), config.facilities(),
config.plans(), new MainModeIdentifierImpl(), TimeInterpretation.create(config));

prepareForSimImpl.run();

Id<Vehicle> id = VehicleUtils.getVehicleId(p1, TransportMode.car);
assertThat(scenario.getVehicles().getVehicles().get(id).getType())
.isEqualTo(truckType);

}

private class DummyTripRouterProvider implements Provider<TripRouter> {
@Override
public TripRouter get() {
Expand Down

0 comments on commit 3b1b938

Please sign in to comment.