Skip to content

refactor: implement energy chain with consumer, provider and energy system abstractions#1492

Draft
frodehk wants to merge 2 commits intomainfrom
refactor/energy-system
Draft

refactor: implement energy chain with consumer, provider and energy system abstractions#1492
frodehk wants to merge 2 commits intomainfrom
refactor/energy-system

Conversation

@frodehk
Copy link
Copy Markdown
Contributor

@frodehk frodehk commented Apr 18, 2026

Summary

Implements the energy chain domain model — abstractions for modeling how consumer demand (mechanical MW) is transformed through providers (motor, generator, shore) into fuel consumption (Sm³/day).

Supersedes #1486 which took a different approach (separate DriveTrain/PowerSupply hierarchies). This PR uses a unified Provider contract (supply, get_capacity_margin) implemented by both single-step nodes (ElectricMotor, Generator, Shore) and composite systems (SerialEnergySystem, PowerBus), so they can be nested freely.

Design

Three core abstractions:

Abstraction Contract Examples
Consumer get_demand() → EnergyStream RotatingEquipment, Shaft
Provider supply(demand) → EnergyStream, get_capacity_margin(demand) → float ElectricMotor, Generator, Shore, Wind
EnergySystem Provider + get_children() PowerBus, SerialEnergySystem

SerialEnergySystem chains providers sequentially — each node's output becomes the next node's input (mechanical → electrical → fuel). PowerBus distributes electrical demand across multiple sources in the order they are listed — earlier sources are used first, remaining demand spills over to the next.

EnergyChain connects a Consumer to an EnergySystem and orchestrates the full calculation via run() → EnergyChainResult.

EnergyStream carries a typed value (MECHANICAL, ELECTRICAL, FUEL) and unit (MW or Sm³/day). Each node transforms the stream type — when fuel is reached, the chain terminates.

Structure

flowchart TD
    subgraph EnergyChain["EnergyChain"]
        direction TB

        subgraph Consumer["Consumer — get_demand() → EnergyStream"]
            RE1["RotatingEquipment A"] --> SHAFT["Shaft"]
            RE2["RotatingEquipment B"] --> SHAFT
        end

        SHAFT -- "demand EnergyStream\n(MECHANICAL, MW)" --> SYSTEM

        subgraph SYSTEM["EnergySystem — supply(demand) → EnergyStream"]
            direction TB
            EM["ElectricMotor\n(Provider)"]
            EM -- "ELECTRICAL, MW" --> BUS

            subgraph BUS["PowerBus (EnergySystem)"]
                SHORE["Shore\n(Provider)"]
                GEN["Generator\n(Provider)"]
            end
        end

        BUS -- "supply EnergyStream\n(FUEL, Sm³/day)" --> RES["run() → EnergyChainResult\n• demand\n• fuel\n• capacity_margin"]
    end

    style Consumer fill:#e8f5e9,stroke:#2e7d32
    style SYSTEM fill:#e3f2fd,stroke:#1565c0
    style BUS fill:#e3f2fd,stroke:#1565c0
    style RES fill:#ffebee,stroke:#c62828
Loading

Energy flow example

flowchart LR
    A["RotatingEquipment\n1.0 MW"] --> B["Shaft\n÷ 0.95 mech. eff"]
    B -->|"1.053 MW"| C["ElectricMotor\n÷ 0.90 efficiency"]
    C -->|"1.170 MW"| D["Generator\n× 100 Sm³/day per MW"]
    D -->|"117 Sm³/day"| E["fuel"]

    style A fill:#e8f5e9
    style E fill:#ffebee
Loading

Each node transforms the stream:

  • Shaft: equipment demands 1.0 MW, but shaft loses 5% → must supply 1.0 / 0.95 = 1.053 MW mechanical
  • ElectricMotor: converts mechanical → electrical, loses 10% → 1.053 / 0.90 = 1.170 MW electrical
  • Generator: converts electrical MW → fuel Sm³/day → 1.170 × 100 = 117 Sm³/day

Type of Work

  • Patch: X.Y.Z+1. NEGLIGIBLE visible changes, does not change input or output - OR changes behaviour. Use chore:, refactor: etc
  • Minor: X.Y+1.Z. Minor changes, might ADD new input (YAML), or other backwards-compatible changes. Use feat:, fix:
  • Major: X+1.Y.Z. Major and most likely BREAKING changes, wo. backwards compatibility, or removing temporary backwards compatibility functionality. Use ! or BREAKING:.

See here (internal): https://github.com/equinor/ecalc-internal/discussions/1044

Have you remembered and considered?

  • IF FEAT: I have remembered to update documentation
  • IF FIX OR FEAT: I have remembered to update manual changelog (docs/drafts/next.draft.md)
  • IF BREAKING: I have remembered to update migration guide (docs/docs/migration_guides/)
  • IF BREAKING: I have committed with BREAKING: in footer or ! in header
  • I have added tests (if not, comment why)
  • I have used conventional commits syntax (if you squash, make sure that conventional commit is used)
  • I have included the Github issue nr in the footer!

What is this PR all about?

What else did you consider?

Between the lines?

@frodehk frodehk self-assigned this Apr 18, 2026
@frodehk frodehk requested a review from a team as a code owner April 18, 2026 12:23
@frodehk frodehk changed the title refactor: implement energy chain with consumer, provider and energy s… refactor: implement energy chain with consumer, provider and energy system abstractions Apr 18, 2026
@frodehk frodehk marked this pull request as draft April 30, 2026 10:43
@frodehk frodehk marked this pull request as draft April 30, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant