TM-PAM Connector Documentation¶
Purpose¶
The TM_PAM_connector bridges the Trade Module (TM) and Plant Agent Model (PAM) by translating trade optimization results into operational parameters for individual furnace groups. It propagates costs through supply chains and updates furnace group attributes (utilization rates, bill of materials, emissions) based on actual trade flows.
Location: src/steelo/domain/trade_modelling/TM_PAM_connector.py
Role in Simulation¶
The Trade Module solves an LP optimization to determine:
Which furnace groups should produce how much
Where products should be shipped
Optimal allocation of feedstocks (scrap, DRI, iron ore, etc.)
The TM-PAM Connector then:
Converts optimization results → NetworkX graph representing the supply chain
Propagates costs from raw materials through processing stages to final products
Updates furnace groups with their allocated production volumes, material costs, and emissions
When it runs: After every Trade Module optimization, before PAM makes strategic decisions.
Key Concepts¶
1. Supply Chain as a Directed Graph¶
The connector models the entire steel production supply chain as a NetworkX MultiDiGraph:
[Iron Ore] ──→ [BF Furnace] ──→ [BOF Furnace] ──→ [Demand]
[Scrap] ──────────→ [EAF Furnace] ──→ [Demand]
Nodes: Process centers (furnace groups, supply sources, demand sinks)
Edges: Material flows with volumes, costs, and efficiencies
2. Cost Propagation¶
Costs accumulate as materials move through the supply chain:
Raw Material Cost
+ Transport Cost (from supplier to furnace)
+ Processing Energy Cost (electricity, gas, etc.)
↓
Intermediate Product Cost
+ Transport Cost (from intermediate to final furnace)
+ Processing Energy Cost
↓
Final Product Cost
Algorithm: Breadth-first traversal starting from raw material sources (iron ore, scrap), accumulating costs at each processing stage.
3. Allocations vs Volumes¶
Volume: Amount of material shipped/produced (output quantity)
Allocation: Amount of material required as input (accounts for process inefficiency)
Formula:
Allocation = Volume / Process Efficiency
Example: If EAF has 95% yield, producing 100t steel requires 100/0.95 = 105.3t of scrap input.
Main Workflow¶
Stage 1: Graph Construction¶
Method: create_graph(solved_trade_allocations)
Extracts all non-zero allocations from LP solution:
(from_pc, to_pc, commodity) → volumeCreates nodes for each process center (furnace group)
Creates edges for each material flow, storing:
volume: Shipped quantitytransport_cost: Cost to move material between locationsprocessing_energy_cost: Energy cost at source (electricity, gas, etc.)process: Process identifier (e.g., “eaf_scrap_electricity”)process_efficiency: Yield/conversion rateoutput: Primary product of this process
Result: self.G populated with nodes and edges representing the trade network.
Stage 2: Input Allocation Calculation¶
Method: calculate_allocations_for_graph()
Converts output volumes to input requirements using process efficiencies:
allocation = edge['volume'] / edge['process_efficiency']
For each edge, updates the allocations attribute with the computed input requirement.
Result: Each edge now has both volume (output) and allocations (input) attributes.
Stage 3: Cost Propagation¶
Method: propage_cost_forward_by_layers_and_normalize()
Propagates costs forward through the graph using breadth-first search:
Identify roots: Nodes with no incoming edges (raw material sources)
BFS traversal: Process nodes layer by layer
For each edge (u → v):
Get base cost from source node
u(raw material cost or accumulated upstream cost)Add processing energy cost at destination
vAdd transport cost for this shipment
Multiply by volume shipped
Accumulate total cost at destination node
v
Normalize: Divide total cost by total outgoing volume to get per-unit cost
Result: Each node has:
product_cost: Total accumulated cost by commodityunit_cost: Cost per tonne by commodityallocations: Volume and cost breakdown by commodity
Stage 4: Update Furnace Groups¶
After cost propagation, the connector updates furnace group attributes:
4a. Update Utilization Rates¶
Method: update_furnace_group_utilisation(furnace_groups)
allocated_volumes = sum(outgoing_edge_volumes)
utilization_rate = allocated_volumes / capacity
Sets fg.utilization_rate based on actual production assigned by Trade Module.
4b. Update Bill of Materials¶
Method: update_bill_of_materials(furnace_groups)
For each furnace group, extracts from the graph:
Materials (from node allocations):
{
"scrap": {
"demand": 105.3, # tonnes required
"total_cost": 31590, # USD
"unit_cost": 300 # USD/t
},
"dri": { ... }
}
Energy (from edge processing costs):
{
"electricity": {
"demand": 100.0, # production volume
"total_cost": 6000, # USD
"unit_cost": 60 # USD/t
}
}
Sets fg.bill_of_materials = {"materials": {...}, "energy": {...}}
4c. Update Emissions¶
Method: update_furnace_group_emissions(furnace_groups)
Calls fg.set_emissions_based_on_allocated_volumes() for each furnace group if it has a valid BOM. This calculates emissions from material consumption and technology emission factors.
Sets fg.emissions with structure:
{
"plant_boundary": {"scope_1": 500, "scope_2": 200},
"supply_chain": {"scope_3": 1000}
}
Key Methods Reference¶
Initialization¶
__init__(dynamic_feedstocks_classes, plants, transport_kpis)
Creates connector and populates lookup tables:
flat_feedstocks_dict: O(1) feedstock lookup by namefeedstock_energy_requirements: Energy requirements per feedstockprocessing_energy_cost: Energy costs by furnace group and commoditychosen_reductant: Reductant choice for each furnacetransport_costs: Transport cost lookup(from_iso, to_iso, commodity) → costiron_furnaces,steel_furnaces: Lists of furnace group IDs by product type
Graph Construction & Cost Propagation¶
set_up_network_and_propagate_costs(solved_trade_allocations)
High-level orchestration method that calls in sequence:
create_graph()- Build NetworkX graph from trade resultscalculate_allocations_for_graph()- Convert volumes to input requirementsvalidate_edge_attributes()- Check graph structurepropage_cost_forward_by_layers_and_normalize()- Propagate costs through network
Furnace Group Updates¶
update_furnace_group_utilisation(furnace_groups)
Sets fg.utilization_rate = allocated_volumes / capacity
update_bill_of_materials(furnace_groups)
Sets fg.bill_of_materials with material and energy costs from graph
update_furnace_group_emissions(furnace_groups)
Calculates and sets fg.emissions based on BOM and emission factors
Utility Methods¶
get_transport_cost(from_iso, to_iso, commodity)
Returns transport cost between two countries for a commodity (USD/t)
extract_transportation_costs(furnace_groups)
Returns detailed transport cost breakdown for each furnace group’s incoming shipments
Integration Points¶
Called By¶
update_furnace_utilization_rates handler (in handlers.py:241):
tmpc = TM_PAM_connector(
dynamic_feedstocks_classes=env.dynamic_feedstocks,
plants=uow.plants,
transport_kpis=env.transport_kpis,
)
tmpc.set_up_network_and_propagate_costs(solved_trade_allocations=trade_allocations)
tmpc.update_furnace_group_utilisation(fgs)
tmpc.update_bill_of_materials(fgs)
tmpc.update_furnace_group_emissions(fgs)
env.allocation_and_transportation_costs = tmpc.extract_transportation_costs(fgs)
Dependencies¶
Inputs:
Allocationsobject from Trade Module LP solverPlantInMemoryRepositoryfor accessing all plants and furnace groupsdynamic_feedstocksdict mapping technologies to feedstock optionsTransportKPIlist with transportation costs
Updates:
FurnaceGroup.utilization_rateFurnaceGroup.allocated_volumesFurnaceGroup.bill_of_materialsFurnaceGroup.emissions
Used By:
PAM decision-making (uses updated costs and utilization)
Balance sheet calculations (uses updated BOM costs)
Emissions reporting (uses updated emissions)
Data Flow Through Connector¶
Trade Module LP Solver
↓
Allocations: (from_pc, to_pc, commodity) → volume
↓
TM_PAM_connector.set_up_network_and_propagate_costs()
↓
1. create_graph()
→ NetworkX MultiDiGraph with nodes (furnaces) and edges (flows)
↓
2. calculate_allocations_for_graph()
→ Add input allocations (volume / efficiency) to edges
↓
3. propage_cost_forward_by_layers_and_normalize()
→ BFS cost accumulation from raw materials to final products
→ Each node gets: product_cost, unit_cost, allocations
↓
4. update_furnace_group_utilisation()
→ fg.utilization_rate = sum(outgoing_volumes) / capacity
↓
5. update_bill_of_materials()
→ fg.bill_of_materials = {materials: {...}, energy: {...}}
↓
6. update_furnace_group_emissions()
→ fg.emissions = {boundary: {scope: value}}
↓
PAM uses updated FurnaceGroup attributes for decision-making
Known Limitations¶
Assumes DAG Structure: Cost propagation assumes no cycles in the supply chain graph. This is determined by the structure of the dynamic bill of materials and legal process connectors given to the Trade Module.
No Transport Mode Differentiation: All transport costs treated equally - no distinction between rail, sea, truck, etc.
Zero-Volume Edge Handling: Edges with volume < LP_TOLERANCE are skipped, which may lose some small flows.
Summary¶
The TM-PAM Connector serves as the critical bridge between optimization and simulation:
Input: Trade optimization results (allocations)
Process: Graph-based cost propagation through supply chains
Output: Updated furnace group parameters (utilization, BOM, emissions)
Purpose: Ensures PAM makes decisions based on actual trade-optimized costs and production levels
This two-way integration enables:
Trade → PAM: Operational parameters reflect optimized production schedules
PAM → Trade: Strategic decisions (technology switches, expansions) feed back into future trade optimizations