Source code for passengersim.driver._base_sim
#
# Driver program to load a simulation from YAML, run it and return results
# (c) PassengerSim LLC
#
from __future__ import annotations
import logging
import pathlib
from abc import ABC, abstractmethod
from collections.abc import Mapping
from typing import TYPE_CHECKING
import passengersim.config.rm_systems
import passengersim.core
from passengersim.config import Config
from passengersim.core import (
Market,
SimulationEngine,
)
from passengersim.utils.filenaming import timestamp_now
from passengersim.utils.tempdir import MaybeTemporaryDirectory
if TYPE_CHECKING:
pass
logger = logging.getLogger("passengersim")
[docs]
class BaseSimulation(ABC):
[docs]
@classmethod
def from_yaml(
cls,
filenames: pathlib.Path | list[pathlib.Path],
output_dir: pathlib.Path | None = None,
):
"""
Create a Simulation object from a YAML file.
Parameters
----------
filenames : pathlib.Path | list[pathlib.Path]
output_dir : pathlib.Path | None, optional
Returns
-------
Simulation
"""
config = passengersim.config.Config.from_yaml(filenames)
return cls(config, output_dir)
[docs]
def __init__(
self,
config: Config,
output_dir: pathlib.Path | None = None,
):
"""
Initialize a BaseSimulation instance.
Parameters
----------
config : Config
The simulation configuration object.
output_dir : pathlib.Path or None, optional
Directory for output files. If None, a temporary directory
will be created automatically.
"""
self.cnx = None
self.output_dir = MaybeTemporaryDirectory(output_dir)
# establish a common "timestamp" for this Simulation, which is the date
# and time the Simulation object is created. This timestamp will be
# used to potentially tag multiple output files, so having a single
# common timestamp set here allows us to synchronize output names.
self._timestamp = timestamp_now()
@property
@abstractmethod
def _eng(self) -> SimulationEngine:
"""
Access to the underlying simulation engine.
Returns
-------
SimulationEngine
The core simulation engine instance.
Notes
-----
This is an abstract property that must be implemented by subclasses.
"""
raise NotImplementedError
[docs]
def path_names(self):
"""
Get a mapping of path IDs to path names.
Returns
-------
dict
Dictionary mapping path IDs to string representations of paths.
"""
result = {}
for p in self._eng.paths:
result[p.path_id] = str(p)
return result
@property
def markets(self) -> Mapping[str, Market]:
"""
Access markets in the simulation.
Returns
-------
Mapping[str, Market]
A mapping of market names to Market objects.
"""
return self._eng.markets
@property
def paths(self):
"""
Generator of all paths in the simulation.
Returns
-------
generator
Generator yielding path objects from the simulation.
"""
return self._eng.paths
@property
def pathclasses(self):
"""
Generator of all path classes in the simulation.
Yields
------
pathclass
Path class objects from all paths in the simulation.
"""
for path in self._eng.paths:
yield from path.pathclasses
[docs]
def pathclasses_for_carrier(self, carrier: str):
"""
Generator of all path classes for a given carrier.
Parameters
----------
carrier : str
The carrier name to filter path classes by.
Yields
------
pathclass
Path class objects for the specified carrier.
"""
for path in self._eng.paths:
if path.carrier_name == carrier:
yield from path.pathclasses
@property
def demands(self):
"""
Generator of all demands in the simulation.
Returns
-------
DemandIterator
Iterator object for accessing demand data.
"""
from passengersim.iterators.demand import DemandIterator
return DemandIterator(self._eng)
@property
def fares(self):
"""
Generator of all fares in the simulation.
Returns
-------
FareIterator
Iterator object for accessing fare data.
"""
from passengersim.iterators.fare import FareIterator
return FareIterator(self._eng)