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 CommunityScenario ID 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_HouseholdProfiles provides 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.