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

Person vehicle types attribute #2877

Merged
merged 11 commits into from
Oct 16, 2023
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
Loading