Adding vehicles to plans¶
In this example, we show how an existing set of plans can be updated to include additional vehicles.
import logging
import random
from pathlib import Path
from pprint import pprint
from pam import read, write
from pam.core import Person
from pam.vehicles import ElectricVehicle, Vehicle, VehicleType
# load up example population
data_path = Path("data/example_data/vehicles")
population = read.read_matsim(data_path / "example_plans.xml")
population.stats
{'num_households': 51, 'num_people': 51, 'num_activities': 153, 'num_legs': 102}
Giving agents vehicles¶
A simple approach is to create some vehicles and assign them to our agents
# now we randomly assign some vehicles and electric vehicles using these types
for hid, pid, p in population.people():
if random.random() < 0.2: # 20% change of having an ev
# evs have the type "small_car"
p.vehicles = {"car": ElectricVehicle(pid, type_id="small_car", battery_capacity=100)}
else:
if random.random() < 0.5: # 40% change of having a regular vehicle of type "small_car"
p.vehicles = {"car": Vehicle(pid, type_id="small_car")}
else: # 40% change of having a vehicle of type "ev"
p.vehicles = {"car": Vehicle(pid, type_id="large_car")}
# note that we specify the key as "car" as this is the transport "mode"
Pam expects each person to contain their vehicles as a dictionary, mapping the mode of the vehicle (eg "car") to the vehicle. Vehicles (both regular and electric) must minimally define a unique vehicle id (vid
) and a type (type_id
).
Please note that MATSim will not support a person having more than one vehicle for a mode. However if we plan to run a complex multi-modal MATSim simulation, then we might define multiple modes (taking care to maintain unique identifiers for each vehicle):
person = Person("0")
person.vehicles = {
"car": Vehicle("car_0", "small_car"),
"taxi": Vehicle("taxi_0", "large_car"),
"bike": Vehicle("bike_0", "pedal_bike"),
}
Electric vehicles can contain additional information about the vehicle battery state and charger access. These are designed to work with the MATSim electric vehicles extension:
person = Person("1")
person.vehicles = {
"car": ElectricVehicle(
vid="car_0",
type_id="small_car",
battery_capacity=60, # kWh
initial_soc=60, # kWh
charger_types="default", # supported charger types; comma-separated list: 'default,other'
)
}
Vehicle types¶
If we want to write our vehicles to MATSim format, then we need to also define the vehicle types. In the above examples we described three vehicle types, a small_car
, large_car
, and pedal_bike
. We define these types by adding them to the population:
# first define some vehicle types and add them to the population via the vehicles_manager
population.add_veh_type(VehicleType("small_car"))
population.add_veh_type(VehicleType("large_car", length=15, width=2))
population.add_veh_type(VehicleType("pedal_bike", length=2, width=1))
The population has a vehicles manager will be ultimately responsible for managing our vehicles and their types, including reading and writing them from MATSim format. We can check for consistency between person vehicles and population vehicle types:
assert population.check_vehicles()
So far we are using a lot of default values (especially for the ElectricVehicles). Defaults follow the same defaults as defined in MATSim's dtd files; vehicleDefinitions_v2.0.xsd and electric_vehicles_v1.dtd.
Writing to MATSim format¶
We can use the standard pam.write to write these vehicle formats to disk by providing a vehicles and, optionally, an electric vehciles path.
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO)
write.write_matsim(
population,
plans_path="./tmp/plans.xml",
vehs_path="./tmp/vehicles.xml",
evs_path="./tmp/evs.xml",
)
INFO:root:Building population vehicles output.
INFO:root:Writing vehicle types to ./tmp/vehicles.xml
INFO:root:Writing vehicles to ./tmp/vehicles.xml
INFO:root:Writing electric vehicles to ./tmp/evs.xml
Because MATSim has very strict requirements about vehicle identities and types, we also provide a "safer" interface for adding vehicles, which ensures that vehicle ids are unique and types defined:
population.add_veh("census_0", "census_0", "car", Vehicle("0", "large_car"))
try:
population.add_veh("census_1", "census_1", "car", Vehicle("0", "large_car"))
except Exception as e:
print(e)
try:
population.add_veh("census_1", "census_1", "car", Vehicle("1", "flying_car"))
except Exception as e:
print(e)
Unable to add vehicle with duplicate vehicle id (vid): 0 Unable to add vehicle with unknown type: 'flying_car'.
This interface is a little clunky and slow (it checks all existing ids each time), so we don't use in the following example.
Modifying vehicles in existing MATSim population¶
Pam can also read vehicles (and electric vehicles) from an existing MATSim population. These can then be checked and/or modified before writing a new population.
population = read.read_matsim(
plans_path=data_path / "plans.xml",
all_vehicles_path=data_path / "vehicles.xml",
electric_vehicles_path=data_path / "evs.xml",
)
pprint(population.vehicle_types)
print(
f"Population has {len([v for _, _, _, v in population.vehicles() if v.type_id == 'small_car'])} small cars."
)
print(f"Population has {len(list(population.evs()))} evs.")
{'large_car': VehicleType(id='large_car', length=15.0, width=2.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0), 'small_car': VehicleType(id='small_car', length=7.5, width=1.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0)} Population has 31 small cars. Population has 11 evs.
# 50% chance of large_car type switching to small_car
for _, pid, person in population.people():
veh = person.vehicles.get("car")
if isinstance(veh, Vehicle) and veh.type_id == "large_car":
if random.random() < 0.5:
person.vehicles["car"] = Vehicle(pid, "small_car")
pprint(population.vehicle_types)
pprint(population.random_person().vehicles)
print(
f"Population has {len([v for _, _, _, v in population.vehicles() if v.type_id == 'small_car'])} small cars."
)
print(f"Population has {len(list(population.evs()))} evs.")
{'large_car': VehicleType(id='large_car', length=15.0, width=2.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0), 'small_car': VehicleType(id='small_car', length=7.5, width=1.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0)} {'car': Vehicle(vid='census_7', type_id='small_car')} Population has 41 small cars. Population has 11 evs.
# 10% chance of small_car type switching to electric vehicle
for _, pid, person in population.people():
veh = person.vehicles.get("car")
if isinstance(veh, Vehicle) and veh.type_id == "small_car":
if random.random() < 0.5:
person.vehicles["car"] = ElectricVehicle(pid, "small_car")
pprint(population.vehicle_types)
print(
f"Population has {len([v for _, _, _, v in population.vehicles() if v.type_id == 'small_car'])} small cars."
)
print(f"Population has {len(list(population.evs()))} evs.")
{'large_car': VehicleType(id='large_car', length=15.0, width=2.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0), 'small_car': VehicleType(id='small_car', length=7.5, width=1.0, networkMode='car', capacity=CapacityType(seats=4, standingRoomInPersons=0), description='personal_vehicle', passengerCarEquivalents=1.0, flowEfficiencyFactor=1.0)} Population has 41 small cars. Population has 28 evs.
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO)
write.write_matsim(
population,
plans_path="./tmp/plans.xml",
vehs_path="./tmp/vehicles.xml",
evs_path="./tmp/evs.xml",
)
INFO:root:Building population vehicles output.
INFO:root:Writing vehicle types to ./tmp/vehicles.xml
INFO:root:Writing vehicles to ./tmp/vehicles.xml
INFO:root:Writing electric vehicles to ./tmp/evs.xml