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

Transit settings #165

Merged
merged 4 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions tm2py/components/demand/prepare_demand.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ def _prepare_demand(
demand = demand + self._read_demand(file_config, time_period, num_zones)
demand_name = f"{time_period}_{name}"
description = f"{time_period} {description} demand"
self._save_demand(demand_name, demand, description, apply_msa=True)
self._save_demand(
demand_name, demand, description, apply_msa=self.config.apply_msa_demand
)

def _read_demand(self, file_config, time_period, num_zones):
# Load demand from cross-referenced source file,
Expand Down Expand Up @@ -428,7 +430,7 @@ def create_zero_passenger_trips(
self.controller.config.household.transit_demand_file
)
.__str__()
.format(period=time_period),
.format(period=time_period, iter=self.controller.iteration),
"w",
)
# active_out_file = OMXManager(
Expand Down Expand Up @@ -691,11 +693,7 @@ def _read_demand(self, file_config, time_period, skim_set, num_zones):
).__str__()
name = file_config["name"]
return self._read(
path.format(
period=time_period,
# set=skim_set,
# iter=self.controller.iteration
),
path.format(period=time_period, iter=self.controller.iteration),
name,
num_zones,
)
25 changes: 18 additions & 7 deletions tm2py/components/network/transit/transit_assign.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,13 +711,24 @@ def _run_congested_assign(self, time_period: str) -> None:
"assignment_period": _duration,
}

_stop_criteria = {
"max_iterations": self.congested_transit_assn_max_iteration[
time_period.lower()
],
"normalized_gap": self.config.congested.normalized_gap,
"relative_gap": self.config.congested.relative_gap,
}
stop_criteria_settings = self.config.congested.stop_criteria
# get the corresponding stop criteria for the global iteration
_stop_criteria = None
for item in stop_criteria_settings:
if item["global_iteration"] == self.controller.iteration:
_stop_criteria = {
"max_iterations": [
time.max_iteration
for time in item.max_iterations
if time.time_period.lower() == time_period.lower()
][0],
"normalized_gap": item.normalized_gap,
"relative_gap": item.relative_gap,
}
if _stop_criteria is None:
raise ValueError(
f"transit.congested.stop_criteria: Must specifify stop criteria for global iteration {self.controller.iteration}"
)
add_volumes = False
assign_transit(
_tclass_specs,
Expand Down
60 changes: 55 additions & 5 deletions tm2py/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,13 @@ class TimePeriodConfig(ConfigItem):
capacites in the highway network
emme_scenario_id: scenario ID to use for Emme per-period
assignment (highway and transit) scenarios
congested_transit_assn_max_iteration: max iterations in congested
transit assignment stopping criteria
"""

name: str = Field(max_length=4)
start_period: float = Field(gt=0)
length_hours: float = Field(gt=0)
highway_capacity_factor: float = Field(gt=0)
emme_scenario_id: int = Field(ge=1)
congested_transit_assn_max_iteration: int = Field(ge=1)
description: Optional[str] = Field(default="")


Expand Down Expand Up @@ -952,6 +949,7 @@ class HighwayConfig(ConfigItem):
to the free-flow speed, capacity, and critical speed values
interchange_nodes_file: relative path to the interchange nodes file, this is
used for calculating highway reliability
apply_msa_demand: average highway demand with previous iterations'. Default to True.
reliability: bool to skim highway reliability. Default to true. If true, assignment
will be run twice in global iterations 0 (warmstart) and 1, to calculate reliability,
assignment will be run only once in global iterations 2 and 3,
Expand All @@ -973,6 +971,7 @@ class HighwayConfig(ConfigItem):
classes: Tuple[HighwayClassConfig, ...] = Field()
capclass_lookup: Tuple[HighwayCapClassConfig, ...] = Field()
interchange_nodes_file: str = Field()
apply_msa_demand: bool = True
reliability: bool = Field(default=True)

@validator("output_skim_filename_tmpl")
Expand Down Expand Up @@ -1291,13 +1290,46 @@ class EawtWeightsConfig(ConfigItem):
default_eawt_factor: float = Field(default=1)


@dataclass(frozen=True)
class CongestedTransitMaxIteration(ConfigItem):
"""Congested transit assignment time period specific max iteration parameters.

Properties:
time_period: time period string
max_iteration: max iteration specific to time period. In the design of tm2py,
congested assignment is run only for AM and PM. For EA, MD, and EV, we run
extended assignment. See code here: tm2py/components/network/transit/transit_assign.py#L465-L466
Therefore, `max_iteration` here does not impact EA, MD, and EV, this setting
is only meaningful for AM and PM.
"""

time_period: str = Field(max_length=4)
max_iteration: int = Field(ge=1, default=1)


@dataclass(frozen=True)
class CongestedTransitStopCriteria(ConfigItem):
"""Congested transit assignment stopping criteria parameters.

Properties:
global_iteration: global iteration number
normalized_gap: normalized_gap
relative_gaps: relative gap
max_iterations: max iterations config, one for each time period
"""

global_iteration: int = Field(ge=0)
normalized_gap: float = Field(gt=0)
relative_gap: float = Field(gt=0)
max_iterations: Tuple[CongestedTransitMaxIteration, ...] = Field()


@dataclass(frozen=True)
class CongestedAssnConfig(ConfigItem):
"Congested transit assignment Configuration."
trim_demand_before_congested_transit_assignment: bool = False
output_trimmed_demand_report_path: str = Field(default=None)
normalized_gap: float = Field(default=0.25)
relative_gap: float = Field(default=0.25)
stop_criteria: Tuple[CongestedTransitStopCriteria, ...] = Field()
use_peaking_factor: bool = False
am_peaking_factor: float = Field(default=1.219)
pm_peaking_factor: float = Field(default=1.262)
Expand Down Expand Up @@ -1353,6 +1385,14 @@ class TransitConfig(ConfigItem):
default_factory=TransitVehicleConfig
)

@validator("use_ccr")
def deprecate_capacitated_assignment(cls, value, values):
"""Validate use_ccr is false."""
assert (
not value
), "capacitated transit assignment is deprecated, please set use_ccr to false"
return value


@dataclass(frozen=True)
class EmmeConfig(ConfigItem):
Expand Down Expand Up @@ -1445,6 +1485,16 @@ def relative_gap_length(cls, value, values):
that includes global iteration 0 to {values['run']['end_iteration']}'"
return value

@validator("transit", always=True)
def transit_stop_criteria_length(cls, value, values):
"""Validate transit.congested.stop_criteria is a list of the same length as global iterations."""
if ("run" in values) & (value.congested_transit_assignment):
assert len(value.congested.stop_criteria) == (
values["run"]["end_iteration"]
), f"'transit.relative_gaps must be the same length as end_iteration,\
that includes global iteration 1 to {values['run']['end_iteration']}'"
return value


def _load_toml(path: str) -> dict:
"""Load config from toml file at path."""
Expand Down
Loading