Data Models =========== ``tfm`` defines a few key objects: - ``Network`` stores nodes and edges - ``OD`` stores origin-destination flows - ``ODFlows`` stores flows allocated to paths over a network (for each ``OD`` pair, the flow might use one or more paths to route over the network) - ``NetworkFlows`` stores flows allocated to the network in aggregate (for each node or edge in a ``Network``, multiple ``OD`` pairs might be allocated to it) Network edges ------------- Create a ``Network`` from a DataFrame with ``edge_from``, ``edge_to``, and ``edge_id`` columns. Optional columns such as ``cost`` and ``capacity`` are used later to allocate flows. >>> import pandas as pd >>> from transport_flow_model.model import Network, NetworkFlows, OD, ODFlows >>> network = Network( ... pd.DataFrame( ... { ... "edge_from": ["A", "B", "C"], ... "edge_to": ["B", "C", "D"], ... "edge_id": ["AB", "BC", "CD"], ... "cost": [1, 1, 1], ... } ... ) ... ) >>> network.to_dataframe()[["edge_from", "edge_to", "edge_id"]].to_dict("records") [{'edge_from': 'A', 'edge_to': 'B', 'edge_id': 'AB'}, {'edge_from': 'B', 'edge_to': 'C', 'edge_id': 'BC'}, {'edge_from': 'C', 'edge_to': 'D', 'edge_id': 'CD'}] OD demand --------- An ``OD`` object represents demand for flows between origin and destination nodes. >>> od = OD( ... pd.DataFrame( ... { ... "origin_id": ["A"], ... "destination_id": ["C"], ... "flow": [10], ... } ... ) ... ) >>> od.to_dataframe().to_dict("records") [{'origin_id': 'A', 'destination_id': 'C', 'flow': 10}] Allocated flows --------------- An ``ODFlows`` object stores the paths used for each allocated OD flow. The ``edge_path`` values are lists of edge IDs. >>> od_flows = ODFlows( ... pd.DataFrame( ... { ... "origin_id": ["A", "B"], ... "destination_id": ["B", "C"], ... "flow": [10, 5], ... "edge_path": [["AB"], ["BA", "AC"]], ... } ... ) ... ) >>> od_flows.to_dataframe()["edge_path"].tolist() [['AB'], ['BA', 'AC']] Edge totals ----------- ``NetworkFlows.from_network_and_od_flows`` aggregates path flows onto network edges. Unused edges are have zero flow. >>> network_flows = NetworkFlows.from_network_and_od_flows(network, od_flows) >>> network_flows.to_dataframe().set_index("edge_id")["flow"].to_dict() {'AB': 10, 'BC': 0, 'CD': 0} CSV input --------- CSV inputs can use project-specific column names. ``from_csv`` normalizes them to the model schema using a ``column_map`` dictionary. >>> import tempfile >>> with tempfile.TemporaryDirectory() as tmpdir: ... csv_path = f"{tmpdir}/network.csv" ... pd.DataFrame( ... { ... "from_id": ["A"], ... "to_id": ["B"], ... "id": ["E1"], ... "flow_capacity": [100], ... "gcost_usd_per_ton": [10.5], ... } ... ).to_csv(csv_path, index=False) ... loaded = Network.from_csv( ... csv_path, ... { ... "from_id": "edge_from", ... "to_id": "edge_to", ... "id": "edge_id", ... "flow_capacity": "capacity", ... "gcost_usd_per_ton": "cost", ... }, ... ) ... loaded.to_dataframe().to_dict("records") [{'edge_from': 'A', 'edge_to': 'B', 'edge_id': 'E1', 'capacity': 100, 'cost': 10.5}]