Skip to content

Commit

Permalink
Replace old P&R implemantation with the new one
Browse files Browse the repository at this point in the history
  • Loading branch information
samakinen committed Dec 4, 2024
1 parent ee513a2 commit ea6eab9
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 451 deletions.
34 changes: 0 additions & 34 deletions Scripts/assignment/departure_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
from datatypes.demand import Demand
from datatypes.tour import Tour

from models.park_and_ride_logit import ParkAndRidePurpose
from transform.park_and_ride_transformer import ParkAndRideTransformer
import utils.log as log
import parameters.departure_time as param
from parameters.assignment import transport_classes, assignment_classes
Expand Down Expand Up @@ -69,38 +67,6 @@ def init_demand(self) -> Dict[str,float]:

return {"rel_gap": relative_gap, "max_gap": max_gap}

def split_park_and_ride(self, demand: Union[Demand, Tour], park_and_ride_impedance:Dict[str, numpy.ndarray], park_and_ride_facility_map: Dict[int,int], pr_purpose: ParkAndRidePurpose):
log.info("Splitting park and ride demand to cars and public transport for {} facilities".format(len(park_and_ride_facility_map)))
position2 = cast(Tuple[int,int], demand.position) #type checker hint

zone_data = pr_purpose.zone_data
share: Dict[str, Any] = param.demand_share[demand.purpose.name][demand.mode]
all_zones_len = len(zone_data.all_zone_numbers)
car_matrix = numpy.zeros((all_zones_len,all_zones_len))
transit_matrix = numpy.zeros((all_zones_len,all_zones_len))

#used_facility = park_and_ride_impedance["used_facility"]
#target_cell = park_and_ride_facility_map[used_facility]
pr_purpose.calc_park_and_ride_expsum("park_and_ride", park_and_ride_impedance, zone_data) #calculate the logsum for all facilities
used_facilities_probs = pr_purpose.get_park_and_ride_routes() #probabilities of using a facility, dict[matrix] target_cell:n*n
for target_cell in used_facilities_probs:
#move car journeys to park and ride facilities
pr_facility_demand = used_facilities_probs[target_cell] * demand.matrix #demand matrix
source_zones = [j for j in range(zone_data.nr_zones_hs15)]
target_zones = [j for j in range(zone_data.nr_zones_hs15)]

car_matrix[source_zones, target_cell] += pr_facility_demand.sum(axis=1) #for cars Park and ride is target only
transit_matrix[target_cell, target_zones] += pr_facility_demand.sum(axis=0) #for transit Park and ride is source only


for time_period in self.time_periods:
self._add_2d_demand(
share[time_period], "car_work", time_period,
car_matrix, position2)
self._add_2d_demand(
share[time_period], "transit_work", time_period,
transit_matrix, position2)

def add_demand(self, demand: Union[Demand, Tour]):
"""Add demand matrix for whole day.
Expand Down
26 changes: 24 additions & 2 deletions Scripts/datatypes/purpose.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
from datahandling.resultdata import ResultsData
from datahandling.zonedata import ZoneData

from models.park_and_ride_model import ParkAndRideModel, ParkAndRidePseudoPurpose
import parameters.zone as param
from parameters.destination_choice import secondary_destination_threshold
from parameters.destination_choice import secondary_destination_threshold, destination_choice
import models.logit as logit
import models.generation as generation
from datatypes.demand import Demand
Expand Down Expand Up @@ -59,6 +60,7 @@ def __init__(self,
self.modes: List[str] = []
self.generated_tours: Dict[str, numpy.array] = {}
self.attracted_tours: Dict[str, numpy.array] = {}
self.park_and_ride_model: ParkAndRideModel = None

@property
def zone_numbers(self):
Expand Down Expand Up @@ -124,6 +126,12 @@ def __init__(self, specification, zone_data, resultdata):
self.own_zone_aggregates = {mode: ArrayAggregator(zone_data.zone_numbers)
for mode in self.modes}
self.sec_dest_purpose = None
self.park_and_ride_model = None
if "park_and_ride" in destination_choice[self.name]:
self.park_and_ride_model = ParkAndRideModel(
zone_data, self)
else:
self.park_and_ride_model = None

def print_data(self):
Purpose.print_data(self)
Expand Down Expand Up @@ -155,6 +163,10 @@ def calc_prob(self, impedance):
Mode (car/transit/bike/walk) : dict
Type (time/cost/dist) : numpy 2d matrix
"""
if self.park_and_ride_model is not None:
pnr_utility = self.park_and_ride_model.get_logsum()
impedance['park_and_ride'] = {'utility': pnr_utility,
'dist': impedance['car']['dist']}
self.prob = self.model.calc_prob(impedance)
self.dist = impedance["car"]["dist"]

Expand All @@ -169,6 +181,10 @@ def calc_basic_prob(self, impedance):
Mode (car/transit/bike/walk) : dict
Type (time/cost/dist) : numpy 2d matrix
"""
if self.park_and_ride_model is not None:
pnr_utility = self.park_and_ride_model.get_logsum()
impedance['park_and_ride'] = {'utility': pnr_utility,
'dist': impedance['car']['dist']}
self.model.calc_basic_prob(impedance)
self.dist = impedance["car"]["dist"]

Expand All @@ -189,7 +205,13 @@ def calc_demand(self):
self.sec_dest_purpose.gen_model.add_tours(mtx, mode, self)
except AttributeError:
pass
demand[mode] = Demand(self, mode, mtx)
if mode == "park_and_ride":
car_demand, transit_demand = self.park_and_ride_model.distribute_demand(mtx)
pnr_purpose = ParkAndRidePseudoPurpose(self)
demand["pnr_car"] = Demand(pnr_purpose, "car", car_demand)
demand["pnr_transit"] = Demand(pnr_purpose, "transit", transit_demand)
else:
demand[mode] = Demand(self, mode, mtx)
self.attracted_tours[mode] = mtx.sum(0)
self.generated_tours[mode] = mtx.sum(1)
self.histograms[mode].count_tour_dists(mtx, self.dist)
Expand Down
134 changes: 0 additions & 134 deletions Scripts/models/park_and_ride_logit.py

This file was deleted.

41 changes: 22 additions & 19 deletions Scripts/modelsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from assignment.emme_assignment import EmmeAssignmentModel
from assignment.mock_assignment import MockAssignmentModel

from models.park_and_ride_logit import ParkAndRidePurpose
from transform.park_and_ride_transformer import ParkAndRideTransformer
import utils.log as log
from utils.zone_interval import ArrayAggregator
import assignment.departure_time as dt
Expand Down Expand Up @@ -89,9 +87,7 @@ def __init__(self,
self.ass_model.nr_zones, self.ass_model.time_periods)

#init Impedance transformers
pnr_transformer = ParkAndRideTransformer(self.zdata_forecast)
self.pnr_distribution = ParkAndRidePurpose(self.zdata_forecast, self.resultdata)
self.imptrans = ImpedanceTransformer(extra_transformers=[pnr_transformer],
self.imptrans = ImpedanceTransformer(extra_transformers=[],
export_path=estimation_data_path)

bounds = slice(0, self.zdata_forecast.nr_zones)
Expand Down Expand Up @@ -129,15 +125,16 @@ def _add_internal_demand(self, previous_iter_impedance, is_last_iteration):
# Mode and destination probability matrices are calculated first,
# as logsums from probability calculation are used in tour generation.
self.dm.create_population_segments()
pnr_impedances = {}
saved_pnr_impedance = {}
for purpose in self.dm.tour_purposes:
if isinstance(purpose, SecDestPurpose):
purpose.gen_model.init_tours()
else:
purpose_impedance = self.imptrans.transform(
purpose, previous_iter_impedance)
if "park_and_ride" in purpose_impedance:
pnr_impedances[purpose.name] = purpose_impedance["park_and_ride"]
if purpose.park_and_ride_model is not None:
saved_pnr_impedance[purpose.name] = purpose_impedance
purpose.park_and_ride_model.set_impedance(previous_iter_impedance)
purpose.calc_prob(purpose_impedance)
if is_last_iteration and purpose.name not in ("sop", "so"):
purpose.accessibility_model.calc_accessibility(
Expand All @@ -162,19 +159,20 @@ def _add_internal_demand(self, previous_iter_impedance, is_last_iteration):
else:
if purpose.name != "wh":
demand = purpose.calc_demand()
if purpose.park_and_ride_model is not None:
# Apply penalty for overcrowded park and ride facilities.
MAX_PNR_ITERATIONS = 5 # Maximum number of iterations. Set to 0 for no penalty
for i in range(MAX_PNR_ITERATIONS):
modified = purpose.park_and_ride_model.apply_crowding_penalty()
purpose.calc_prob(saved_pnr_impedance[purpose.name])
demand = purpose.calc_demand()
log.debug(f"Park and ride crowding penalty iteration {i+1} modified {modified} facilities.")
if modified < 1:
break

if purpose.dest != "source":
for mode in demand:
if mode == "park_and_ride":
pnr_transformer = None
for et in self.imptrans._extra_transformers:
if type(et) == ParkAndRideTransformer:
pnr_transformer = et
break
else:
log.error(f"No park and ride transformer found for {purpose.name} model")
self.dtm.split_park_and_ride(demand["park_and_ride"],pnr_impedances[purpose.name],pnr_transformer.get_pnr_map(),self.pnr_distribution)
else:
self.dtm.add_demand(demand[mode])
self.dtm.add_demand(demand[mode])
self.travel_modes[mode] = True
log.info("Demand calculation completed")

Expand Down Expand Up @@ -572,12 +570,17 @@ def _add_internal_demand(self, previous_iter_impedance, is_last_iteration):
log.info("Demand calculation started...")
random.seed(None)
self.dm.car_use_model.calc_basic_prob()
saved_pnr_impedance = {}
for purpose in self.dm.tour_purposes:
if isinstance(purpose, SecDestPurpose):
purpose.init_sums()
else:
purpose_impedance = self.imptrans.transform(
purpose, previous_iter_impedance)
if purpose.park_and_ride_model is not None:
saved_pnr_impedance[purpose.name] = purpose_impedance
purpose.park_and_ride_model.set_impedance(previous_iter_impedance)

if (purpose.area == "peripheral" or purpose.dest == "source"
or purpose.name == "oop"):
purpose.calc_prob(purpose_impedance)
Expand Down
30 changes: 16 additions & 14 deletions Scripts/parameters/destination_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@

# Destination choice (generated 2.9.2024)
destination_choice = {
"pnr": {
"park_and_ride": {
"impedance": {
"delta_time": (-0.1,-0.1),
},
"log": {
"size": 1.0
},
"attraction": {
"shops": (0.1, 0.1)
},
},
},
"hw": {
"car": {
"attraction": {
Expand Down Expand Up @@ -84,8 +71,23 @@
}
},
"park_and_ride": {
"utility": {
"facility": {
"shops": 0.01,
"cost": -0.1,
"time": -0.1
},
"car_impedance": {
"time": -0.019273809692544004,
"cost": -0.146013709792
},
"transit_impedance": {
"time": -0.146013709792,
"cost": -0.0174294749661
}
},
"impedance": {
"cost": -0.00770353464125
"utility": 0.00770353464125
},
"attraction": {
"parking_cost_work": (0.771663871487, 0.771663871487)
Expand Down
Loading

0 comments on commit ea6eab9

Please sign in to comment.