Architecture
FLEX models residential energy systems across three levels of abstraction, each handled by a dedicated module that runs in sequence:
Module |
Level |
Core question |
|---|---|---|
FLEX-Behavior |
Demand |
What do households consume, and when? |
FLEX-Operation |
Dispatch |
How does the household energy system operate, optimally or otherwise? |
FLEX-Community |
Community |
How can an aggregator profit by coordinating a group of households? |
Shared data organization. All three modules follow the same pattern:
Each module has a main scenario table where every row defines one independent configuration.
The model iterates over all rows and writes separate result files per scenario ID — e.g.,
OperationResult_RefHour_S1,_S2, …Parameter sweeps require no code changes: add rows to the scenario table, re-run, get more results.
FLEX-Community adds a second layer — each
CommunityScenarioID assembles a fixed set of operation scenarios into a community with a particular aggregator configuration (e.g., different battery sizes).
How the modules connect. Each module’s output becomes part of the next module’s input:
Behavior → Operation:
BehaviorResult_HouseholdProfilesprovides hourly appliance electricity demand, hot water demand, and occupancy, which FLEX-Operation reads as behavioral input when coupling is enabled.Operation → Community:
OperationResult_RefHour_S{id}provides hourly PV generation, grid import/export, load, and battery SoC per household scenario.OperationResult_RefYear_S{id}provides the corresponding annual cost. FLEX-Community reads only Ref mode outputs — it never re-runs household simulation, only aggregates and optimizes on top of already-computed results.
All table names are defined as enums in src/utils/tables.py. Hourly result tables are stored as parquet files; monthly and annual summaries as CSV.