FLEX-Operation
What It Does
FLEX-Operation models the hourly energy system dispatch of a single household over a full year (8,760 hours). Given a household’s technology configuration — heating system, PV, battery storage, EV, thermal tanks — and the corresponding demand and weather inputs, it calculates how the system operates hour by hour, along with the resulting energy consumption and cost.
The model runs each scenario ID independently and produces separate result files per scenario.
Ref vs. Opt: The Central Distinction
Every scenario is run in both modes (unless disabled), and the comparison between them is typically the core research output:
Reference mode (dispatch_ref.py) simulates a household with no smart control. The code follows two distinct execution paths depending on the heating system type:
Heat pump path (
run_heatpump_ref):Space heating demand is computed via the RC thermal model; excess demand beyond HP capacity goes to the heating element.
PV surplus follows a fixed priority chain: load → battery → EV → DHW tank → grid feed-in.
DHW tank temperature is tracked iteratively; an HP power cap check ensures total HP electrical input stays within rated capacity.
Fuel boiler path (
run_fuel_boiler_ref):Space heating and DHW are supplied by the fuel boiler (gas, oil, solids, or district heating).
Fuel consumption:
\[\text{Fuel}_t = \frac{Q^{\text{boiler,heat}}_t + Q^{\text{boiler,DHW}}_t}{\eta_{\text{boiler}}}\]where \(Q^{\text{boiler,heat}}_t\) and \(Q^{\text{boiler,DHW}}_t\) are the thermal output for space heating and DHW [kWh], and \(\eta_{\text{boiler}}\) is the boiler efficiency.
The electrical load only includes base loads, the heating element, and cooling.
In both paths: the EV charges immediately when it arrives home; the battery follows a charge-from-PV / discharge-to-load rule; there is no lookahead or price awareness.
Optimization mode (dispatch_opt.py) simulates a household with a Smart Energy Management System (SEMS). A Pyomo LP is solved for the full year simultaneously:
Objective: minimize total annual energy cost:
where:
\(\text{Grid}_t\) — electricity purchased from the grid at hour \(t\) [kWh]
\(\text{Fuel}_t\) — fuel consumed (gas, oil, etc.) at hour \(t\) [kWh]
\(\text{Feed2Grid}_t\) — PV electricity fed back to the grid [kWh]
\(\lambda^{\text{elec}}_t\), \(\lambda^{\text{fuel}}_t\), \(\lambda^{\text{FiT}}_t\) — electricity price, fuel price, and feed-in tariff [€/kWh]
\(\varepsilon_t\) — tie-break penalty (see below)
The tie-break term adds tiny penalties on storage throughput and heating element use to prevent degenerate LP solutions:
with \(\epsilon_1 = 10^{-6}\), \(\epsilon_2 = 9 \times 10^{-7}\), \(\epsilon_3 = 7 \times 10^{-7}\), \(\epsilon_4 = 5 \times 10^{-7}\), \(\epsilon_5 = 3 \times 10^{-7}\). These values are small enough to never override energy cost decisions.
Key LP Constraints
Battery state of charge:
where \(\eta^{\text{bat}}_c\) and \(\eta^{\text{bat}}_d\) are charge and discharge efficiencies, and \(\text{BatSoC}_0 = 0\). The term \((2 - \eta^{\text{bat}}_d)\) is a linearized approximation of \(1/\eta^{\text{bat}}_d\).
EV state of charge:
where \(\eta^{\text{ev}}_c\) and \(\eta^{\text{ev}}_d\) are EV charge and discharge efficiencies, and \(\text{EVSoC}_0 = C_{\text{ev}}\) (EV battery starts fully charged). \(\text{EVDischarge}_t\) includes driving demand, vehicle-to-home (V2H), and vehicle-to-battery flows.
Electricity demand (load composition):
where \(\text{BaseLoad}_t\) is the appliance demand, \(E^{\text{HP,heat}}_t\) and \(E^{\text{HP,DHW}}_t\) are heat pump electrical input for space heating and DHW, \(Q^{\text{HE}}_t / \eta_{\text{HE}}\) is heating element electricity, and \(E^{\text{cool}}_t\) is cooling electricity.
Electricity supply (load balance):
PV allocation:
Thermal tank energy balance (space heating tank; DHW tank follows the same structure):
where \(Q^{\text{tank}}_t\) is the thermal energy stored [kJ], \(Q^{\text{in}}_t\) and \(Q^{\text{out}}_t\) are heat flows in/out, \(U\) is the tank heat loss coefficient, \(A\) is the tank surface area, \(M\) is the water mass, \(c_p\) is the specific heat of water, and \(T_{\text{surr}}\) is the surrounding temperature [K]. The term \(Q^{\text{tank}}_t / (M \cdot c_p)\) converts stored energy to absolute temperature.
Flexible devices (battery, EV, thermal tanks, heat pump) are scheduled optimally given these energy balance constraints, device capacity limits, and comfort bounds (room temperature ±3 °C, tank temperature min/max). The result represents the theoretical maximum value of full demand flexibility.
The difference in annual cost between Ref and Opt quantifies the economic value of SEMS. This can be computed from OperationResult_RefYear and OperationResult_OptYear (TotalCost column).
Technology Components
Each component is a dataclass defined in src/models/operation/components.py and parameterized via its own input table:
Component |
Input table |
Key parameters |
|---|---|---|
|
|
Floor area (\(A_f\)), thermal conductances (\(H_{op}\), \(H_{tr,w}\), \(H_{ve}\)), mass/area factors, window areas by orientation, supply temperature, ventilation heat recovery |
|
|
Type (heat pump / fuel boiler / district heating), Carnot efficiency factor, fuel boiler efficiency |
|
|
Backup electric resistance heater power and efficiency |
|
|
Size, thermal loss, start/min/max temperature |
|
|
Size, thermal loss, start/min/max temperature |
|
|
Cooling COP (\(\eta_{\text{cool}}\)) and rated power |
|
|
Installed capacity ( |
|
|
Capacity, charge/discharge efficiency and power limits |
|
|
Battery capacity, consumption rate, charge/discharge efficiency, V2H capability ( |
|
|
IDs selecting which electricity, feed-in, and fuel price columns to use from the price time series table |
|
|
Temperature setpoints (at-home / not-at-home), shading parameters, demand profile type ID |
All 11 component IDs in the scenario table are required — NULL / NaN values are not allowed and will cause a validation error. Instead, “technology not installed” is represented by pointing to a component row whose key capacity parameter is zero. For example, to model a household without PV, the scenario references a PV entry with size = 0; without a battery, it references a Battery entry with capacity = 0.
The model detects these zero-capacity entries via ScenarioFlags (in opt_pyomo_config.py) and responds by fixing the corresponding decision variables to zero and deactivating the related constraints. The flags are:
Flag |
Condition |
Effect when False |
|---|---|---|
|
|
PV flow variables fixed to 0 |
|
|
Battery charge/discharge/SoC fixed to 0 |
|
|
All EV variables fixed to 0 |
|
|
Cooling variables fixed to 0 |
|
|
Heating element variables fixed to 0 |
|
|
Tank variables fixed to 0, energy balance deactivated |
|
|
DHW tank variables fixed to 0, energy balance deactivated |
The RC Thermal Model
Building thermal dynamics are modeled using a 5R1C simplified resistance-capacitance (RC) model based on ISO 13790. The equations are implemented in src/models/operation/rc_equations.py and used in both Ref and Opt dispatch.
The model tracks two state variables: thermal mass temperature \(T^m_t\) and room air temperature \(T^{\text{room}}_t\).
Thermal mass update (ISO 13790 Eq. C.4):
Room air temperature (ISO 13790 Eq. C.11):
where:
\(C_m\) — building thermal mass capacity [J/K]
\(H_{tr,3}\), \(H_{tr,em}\), \(H_{tr,is}\), \(H_{ve}\) — heat transfer coefficients for different thermal paths (transmission, exterior mass, interior surface, ventilation) [W/K]
\(\Phi_{m,tot}\) — total heat flow to the thermal mass, aggregated from solar gains (\(Q_{\text{solar}}\)), internal gains (\(Q_i\)), heating/cooling input (\(Q_{hc}\)), and outdoor temperature via thermal bridges (ISO 13790 Eq. C.5)
\(T_s\) — interior surface temperature, computed from \(T^m\) and heat flows (ISO 13790 Eq. C.10)
\(T_{sup}\) — ventilation supply temperature [°C]
\(\Phi_{ia}\) — internal air heat gain [W]
\(Q_{hc}\) — net heating (+) or cooling (−) power delivered to the room [W]
In Opt mode, the thermal mass acts as an implicit thermal storage: the optimizer can pre-heat the building when electricity is cheap.
Inputs
Table |
Content |
|---|---|
|
Main scenario table — one row per scenario, links all component IDs |
|
Parameter tables for each technology (Battery, Boiler, Building, etc.) |
|
Behavior parameters: temperature setpoints, shading, demand profile type |
|
Maps scenario to price column IDs in the price time series |
|
Hourly electricity, feed-in, and fuel price time series |
|
Hourly outdoor temperature, solar irradiance, PV generation profiles |
|
Hourly behavior profiles from FLEX-Behavior (appliance demand, hot water, occupancy) |
|
EV parking and driving distance profiles |
Outputs
Results are written per scenario (suffix _S{id}) and per mode (Ref / Opt):
Table |
Resolution |
Content |
|---|---|---|
|
Hourly (8,760 rows) |
53 variables — see |
|
Monthly (12 rows) |
Summed energy flows |
|
Annual (1 row) |
Total energy and cost summary including |
Hourly results are stored as parquet (default) or CSV. Monthly and annual results are CSV and are automatically merged across scenarios into a single file (e.g. OperationResult_RefYear.csv) after all scenarios complete.
The full output variable list is defined in src/models/operation/result_registry.py. Key variables include:
Thermal:
T_Room,T_BuildingMass,Q_RoomHeating,Q_RoomCooling,Q_HeatingTank_in/out,Q_DHWTank_in/outElectrical:
Grid,Load,Feed2Grid,PV2Load,PV2Bat,PV2Grid,PV2EVStorage:
BatSoC,BatCharge,BatDischarge,EVSoC,EVCharge,EVDischargeFuel:
Fuel,FuelPriceCOP:
SpaceHeatingHourlyCOP,HotWaterHourlyCOP,CoolingHourlyCOP
Key Code Locations
File |
Role |
|---|---|
|
Entry point — |
|
Loads all component parameters into the |
|
Rule-based reference dispatch (HP path + fuel boiler path) |
|
LP optimization dispatch — calls Pyomo solver |
|
Shared physical state computation (energy flows, COP, SoC updates) |
|
Pyomo model definition: sets, variables, constraints, objective |
|
Populates Pyomo parameters from scenario data; activates/deactivates constraints |
|
Building thermal model equations (ISO 13790 5R1C) |
|
11 component dataclasses |
|
Boiler type classification (HP vs. fuel) and normalization |
|
Environment-variable-driven solver factory |
|
Defines which variables are saved and how they are aggregated |
How to Run
python -m projects.test_operation.main
Output is written to projects/test_operation/output/.