PAM Classes Overview - Domain Models¶
Purpose¶
This document provides a high-level overview of the core domain model classes in models.py that are used by the Plant Agent Model (PAM). It focuses on understanding what each class represents and how they relate to each other.
Core Agent Hierarchy¶
PAM uses a three-tier hierarchy of decision-making agents:
PlantGroup (Company/Owner)
└── Plant (Physical facility)
└── FurnaceGroup (Production unit)
└── Technology (Process definition)
Decision-Making by Level¶
PlantGroup: Decides where to expand capacity across all owned plants
Plant: Coordinates strategy across all furnace groups at a location
FurnaceGroup: Decides when to renovate, switch technology, or close
Core Classes¶
1. FurnaceGroup (models.py:898)¶
What it represents: A single production unit (furnace or production line) with a specific technology.
Core concept: The primary decision-making agent in PAM. Each furnace group evaluates its own profitability and decides whether to continue operating, renovate, switch to a new technology, or close.
Key relationships:
Belongs to one
PlantUses one
TechnologyTracks
PointInTimefor renovation cyclesHas a
bill_of_materials(materials and energy inputs)
Economic attributes:
capacity,utilization_rate,productionbalance(annual profit/loss),historic_balance(cumulative)equity_share,cost_of_debt,total_investmentunit_production_cost(total cost per tonne)
2. Plant (models.py:2692)¶
What it represents: A physical production facility at a specific geographic location.
Core concept: A collection of furnace groups that share a location and infrastructure. Coordinates strategy decisions across all its furnace groups and aggregates their financial performance.
Key relationships:
Belongs to one
PlantGroupContains multiple
FurnaceGroupobjectsLocated at one
Location
Coordination role:
Evaluates strategy for each furnace group
Aggregates balance sheets from all furnaces
Handles technology switches, renovations, and closures
Creates new furnace groups for expansions
3. PlantGroup (models.py:4121)¶
What it represents: A company or ownership entity that owns multiple plants.
Core concept: Makes strategic investment decisions about where to expand capacity across all owned facilities. Represents the highest level of decision-making in PAM.
Key relationships:
Contains multiple
PlantobjectsIdentified by
plant_group_id(typically from GEM database)Aggregates
total_balanceacross all plants
Strategic role:
Evaluates expansion options across all plants
Selects best plant and technology for new capacity
Checks affordability and capacity limits
Generates new plants for greenfield investments
4. Technology (models.py:821)¶
What it represents: A production process (e.g., BF, BOF, EAF, DRI).
Core concept: Defines the production characteristics, costs, and feedstock options for a specific technology.
Key relationships:
Used by
FurnaceGroupContains multiple
PrimaryFeedstockoptions
Key attributes:
name(e.g., “BF”, “EAF”, “EAF”)product(“steel” or “iron”)capex,capex_no_subsidycapex_type(“greenfield” or “brownfield”)dynamic_business_case(list of feedstock options)
5. PrimaryFeedstock (models.py:747)¶
What it represents: A specific input combination for a technology (metallic charge + reductant).
Core concept: Defines one way to operate a technology. For example, an EAF can use scrap+electricity or DRI+electricity as different feedstock options.
Key relationships:
Belongs to a
Technology(viadynamic_business_case)Has
secondary_feedstock(additional materials)Has
energy_requirements(by energy type)
Key attributes:
metallic_charge(e.g., “scrap”, “dri”, “hot_metal”)reductant(e.g., “coke”, “hydrogen”, “natural_gas”)required_quantity_per_ton_of_productoutputs(products and by-products)
Supporting Classes¶
6. PointInTime (models.py:131)¶
What it represents: Lifetime tracking for renovation cycles.
Core concept: Plants don’t have absolute ages - they undergo renovation cycles every N years (default 20). This class tracks position within the current cycle.
Key relationships:
Used by
FurnaceGroup(aslifetimeattribute)Contains a
TimeFrame(start and end years)
Key computation:
For a 116-year-old plant with 20-year lifetime: 116 mod 20 = 16 years elapsed → 4 years remaining until renovation
7. Location (models.py:254)¶
What it represents: Geographic coordinates and country identification.
Key relationships:
Used by
PlantContains pre-calculated distances to other countries
Key attributes:
lat,lon(coordinates)iso3(country code)distance_to_other_iso3(for transport costs)
8. Subsidy (models.py:5479)¶
What it represents: Financial incentive for technology adoption.
Key relationships:
Applied to
FurnaceGroup(stored inapplied_subsidies)Filtered by year and technology
Key attributes:
iso3(country),technology_name,cost_item(capex/opex/debt)start_year,end_year(time-bounded)absolute_subsidy(fixed amount)relative_subsidy(percentage reduction)
9. TechnologyEmissionFactors (models.py:383)¶
What it represents: Emission intensities for a specific technology-feedstock combination.
Key relationships:
Used by
FurnaceGroupto calculate emissionsMatched with
bill_of_materialsentries
Key attributes:
technology,metallic_charge,reductantboundary(emission scope)direct_ghg_factor,indirect_ghg_factor
Class Relationship Diagram¶
PlantGroup
│
├── plant_group_id: str
├── total_balance: float
└── plants: list[Plant] ────────────────┐
│
▼
Plant
│
├── plant_id: str
├── location: Location
├── balance: float
├── technology_unit_fopex: dict
├── carbon_cost_series: dict[Year, float]
└── furnace_groups: list[FurnaceGroup] ─────┐
│
▼
FurnaceGroup
│
├── furnace_group_id: str
├── capacity: Volumes
├── status: str
├── utilization_rate: float
├── balance: float
├── historic_balance: float
├── equity_share: float
├── cost_of_debt: float
├── legacy_debt_schedule: list[float]
├── applied_subsidies: dict[str, list[Subsidy]]
│
├── lifetime: PointInTime
│ └── time_frame: TimeFrame
│
├── technology: Technology
│ ├── name: str
│ ├── product: str
│ ├── capex: float
│ ├── capex_type: str
│ ├── bill_of_materials: dict
│ └── dynamic_business_case: list[PrimaryFeedstock]
│ │
│ ├── metallic_charge: str
│ ├── reductant: str
│ ├── secondary_feedstock: dict
│ ├── energy_requirements: dict
│ └── outputs: dict
│
└── bill_of_materials: dict
├── materials: dict
└── energy: dict
Key Concepts¶
1. Debt Accumulation¶
When a furnace group switches technologies before its debt is fully repaid:
Old technology’s remaining debt is stored in
legacy_debt_scheduleNew technology creates new debt based on its CAPEX
Total debt = new debt + legacy debt (for overlapping years)
This makes early switches expensive and affects COSA calculations
2. Renovation Cycles¶
Plants don’t retire after N years - they renovate:
First cycle (age < 20 years): Uses greenfield CAPEX (full cost)
Subsequent cycles (age >= 20 years): Uses brownfield CAPEX (~30% of greenfield)
Renovation resets the lifetime clock but keeps the same technology
Position within cycle:
actual_age mod plant_lifetime
3. Cost Normalization¶
All costs are normalized to per-unit-of-production basis (USD/tonne):
CAPEX → divided by production over lifetime
OPEX → inherently per tonne
Debt repayment → annual payment divided by annual production
Carbon costs → emissions per tonne × carbon price
4. Subsidies¶
Three types, each with absolute and relative components:
CAPEX: Reduces upfront investment → affects NPV and affordability
OPEX: Reduces operating costs → affects profitability
Debt: Reduces interest rates → affects debt repayment costs
Time-bounded: Only applied if start_year <= current_year <= end_year
5. Probabilistic Decisions¶
When enabled, technology switches and expansions use probabilistic acceptance:
P(accept) = exp(-investment_cost / NPV)
Higher cost relative to benefit → Lower acceptance probability
Models real-world hesitation and risk aversion
Integration with Other Modules¶
Cost Calculation Module (calculate_costs.py)¶
Provides functions for NPV, OPEX, debt repayment, COSA, and subsidies.
Called by: FurnaceGroup.optimal_technology_name(), Plant.evaluate_furnace_group_strategy(), PlantGroup.evaluate_expansion()
Emissions Module (calculate_emissions.py)¶
Calculates emissions from bill of materials and technology emission factors.
Called by: FurnaceGroup.set_emissions_based_on_allocated_volumes(), FurnaceGroup.optimal_technology_name()
Trade Module (trade_modelling/)¶
Optimizes production and trade flows based on costs and demand.
Reads: FurnaceGroup.capacity, unit_production_cost
Updates: FurnaceGroup.allocated_volumes, utilization_rate
Summary¶
The PAM domain model consists of:
Three-tier agent hierarchy: PlantGroup → Plant → FurnaceGroup
Economic decision-making: NPV-based with debt accumulation and subsidies
Renovation cycles: Plants renovate every N years rather than retiring
Flexible feedstocks: Each technology can use multiple input combinations
Event sourcing: All state changes recorded as domain events