Skip to content

Commit 2529dde

Browse files
authored
Merge pull request #605 from HSLdevcom/feat/agent-based-park-and-ride-aggregated
Park and ride for agent-based model
2 parents ffe1a07 + 54f17ee commit 2529dde

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

Scripts/datatypes/purpose.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import openmatrix as omx
88
from datahandling.zonedata import ZoneData
99

10+
if TYPE_CHECKING:
11+
from datatypes.person import Person
1012
from models.park_and_ride_model import ParkAndRideModel, ParkAndRidePseudoPurpose
1113
import parameters.zone as param
1214
from parameters.destination_choice import secondary_destination_threshold, destination_choice
@@ -195,6 +197,38 @@ def calc_basic_prob(self, impedance):
195197
self.model.calc_basic_prob(impedance)
196198
self.dist = impedance["car"]["dist"]
197199

200+
def calc_pnr_demand(self, population, estimation_mode=False, log=None):
201+
"""Calculate pnr demand matrices for agent based model.
202+
203+
Returns
204+
-------
205+
dict
206+
Mode (car/transit/bike) : dict
207+
Demand matrix for whole day : Demand
208+
"""
209+
#Initiate OD matrix
210+
gen_zones = numpy.zeros_like(self.zone_numbers)
211+
attr_zones = numpy.zeros_like(self.zone_data.zone_numbers)
212+
od_matrix = numpy.zeros((gen_zones.size,attr_zones.size))
213+
#Aggregate tour to matrix
214+
for person in population:
215+
for tour in person.tours:
216+
if tour.purpose_name == self.name and tour.mode == "park_and_ride":
217+
od_matrix[self.zone_data.zone_index(tour.orig),
218+
self.zone_data.zone_index(tour.dest)] += 1
219+
log.info(f"Matrix contains {od_matrix.sum()} park and ride tours")
220+
demand = {}
221+
# if estimation_mode:
222+
# omx_file = omx.open_file(f"{self.resultdata.path}/estimation/demand_{self.name}.omx","w")
223+
# omx_file.create_mapping("zone_number",self.zone_data.all_zone_numbers)
224+
225+
car_demand, transit_demand = self.park_and_ride_model.distribute_demand(od_matrix)
226+
pnr_purpose = ParkAndRidePseudoPurpose(self)
227+
demand["pnr_car"] = Demand(pnr_purpose, "car", car_demand)
228+
demand["pnr_transit"] = Demand(pnr_purpose, "transit", transit_demand)
229+
230+
return demand
231+
198232
def calc_demand(self, estimation_mode=False, add_sec_dest: bool = True):
199233
"""Calculate purpose specific demand matrices.
200234

Scripts/modelsystem.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,22 @@ def _add_internal_demand(self, previous_iter_impedance, is_last_iteration, estim
731731
thread.join()
732732
for purpose in self.dm.tour_purposes:
733733
purpose.print_data()
734+
#Park and ride
735+
if purpose.park_and_ride_model is not None:
736+
# Apply penalty for overcrowded park and ride facilities.
737+
MAX_PNR_ITERATIONS = 5 # Maximum number of iterations. Set to 0 for no penalty
738+
for i in range(MAX_PNR_ITERATIONS):
739+
modified = purpose.park_and_ride_model.apply_crowding_penalty()
740+
purpose.calc_basic_prob(saved_pnr_impedance[purpose.name])
741+
demand = purpose.calc_pnr_demand(self.dm.population,estimation_mode=estimation_mode, log=log)
742+
log.debug(f"Park and ride crowding penalty iteration {i+1} modified {modified} facilities.")
743+
if modified < 1:
744+
break
745+
log.debug("Park and ride demand calculation completed.")
746+
#Add park and ride to time periods
747+
self.dtm.add_demand(demand["pnr_car"])
748+
self.dtm.add_demand(demand["pnr_transit"])
749+
#Add all tours to time periods
734750
for person in self.dm.population:
735751
for tour in person.tours:
736752
self.dtm.add_demand(tour)

0 commit comments

Comments
 (0)