Heat generators package
Annuity Calculation Module
Economic evaluation module for technical installations according to VDI 2067.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
This module provides comprehensive economic analysis capabilities for district heating systems following the German VDI 2067 standard for economic evaluation of technical installations. It implements standardized methodology for calculating annuities considering capital costs, operational expenses, and revenue streams over the entire system lifecycle.
The implementation supports lifecycle cost analysis for various district heating technologies including heat pumps, thermal storage systems, solar thermal installations, and conventional heating equipment. It provides standardized economic evaluation suitable for investment decisions, subsidy calculations, and economic optimization of district heating systems.
Features:
VDI 2067 compliant annuity calculations
Lifecycle cost analysis with inflation and interest rate considerations
Capital-bound, demand-bound, and operation-bound cost components
Residual value calculations for asset replacement cycles
Revenue integration for economic optimization
Support for multiple replacement cycles over analysis period
Mathematical Foundation:
The module implements the VDI 2067 methodology for economic evaluation:
- Annuity Factor:
a = (q - 1) / [1 - q^(-T)]
Where: - q = interest rate factor (1 + interest rate) - T = consideration time period [years]
- Price-Dynamic Present Value Factor:
b = [1 - (r/q)^T] / (q - r)
Where: - r = inflation rate factor (1 + inflation rate) - q = interest rate factor - T = consideration time period [years]
- Total Annuity:
A_N = A_N_K + A_N_V + A_N_B + A_N_S - A_N_E
Where: - A_N_K = Capital-bound costs annuity - A_N_V = Demand-bound costs annuity - A_N_B = Operation-bound costs annuity - A_N_S = Other costs annuity - A_N_E = Revenue annuity
Cost Categories:
- Capital-Bound Costs (A_N_K):
Investment costs, replacement costs, and residual value considerations
- Demand-Bound Costs (A_N_V):
Energy costs (electricity, gas, fuel) varying with system operation
- Operation-Bound Costs (A_N_B):
Maintenance, inspection, insurance, and labor costs
- Other Costs (A_N_S):
Additional system-specific costs not covered by other categories
- districtheatingsim.heat_generators.annuity.annuity(initial_investment_cost: float, asset_lifespan_years: int, installation_factor: float, maintenance_inspection_factor: float, operational_effort_h: float = 0, interest_rate_factor: float = 1.05, inflation_rate_factor: float = 1.03, consideration_time_period_years: int = 20, annual_energy_demand: float = 0, energy_cost_per_unit: float = 0, annual_revenue: float = 0, hourly_rate: float = 45) float[source]
Calculate annuity for technical installations according to VDI 2067.
- Parameters:
initial_investment_cost (float) – Initial capital investment cost [€]
asset_lifespan_years (int) – Technical lifetime [years]
installation_factor (float) – Installation cost factor [%]
maintenance_inspection_factor (float) – Annual maintenance cost factor [%]
operational_effort_h (float) – Annual operational effort [hours/year], defaults to 0
interest_rate_factor (float) – Interest rate factor (1 + rate), defaults to 1.05
inflation_rate_factor (float) – Inflation rate factor (1 + rate), defaults to 1.03
consideration_time_period_years (int) – Economic analysis period [years], defaults to 20
annual_energy_demand (float) – Annual energy consumption [MWh/year], defaults to 0
energy_cost_per_unit (float) – Energy cost [€/MWh], defaults to 0
annual_revenue (float) – Annual revenue [€/year], defaults to 0
hourly_rate (float) – Labor cost rate [€/hour], defaults to 45
- Returns:
Total annual equivalent cost [€/year]
- Return type:
Note
Implements VDI 2067 methodology for lifecycle cost analysis including capital-bound, demand-bound, and operation-bound costs with revenue integration.
- Raises:
ValueError – If
asset_lifespan_yearsis zero or negative, or ifinterest_rate_factor<= 1 /inflation_rate_factor< 1 (a rate such as 0.05 was passed where a factor such as 1.05 is required — see BACKLOG C5).ZeroDivisionError – If interest and inflation factors are equal (mathematical singularity).
- districtheatingsim.heat_generators.annuity.infrastructure_annuity(initial_investment_cost: float, asset_lifespan_years: int, installation_factor: float, maintenance_inspection_factor: float, operational_effort_h: float, economic_parameters: dict) float[source]
Annuity for one infrastructure cost row from a GUI
economic_parametersmapping.Adapts
economic_parameters(capital_interest_rate/inflation_rateas VDI 2067 factors,time_period,hourly_rate) toannuity(). Returns0.0for a zero lifespan (a not-yet-configured row), avoiding a division by zero. Lives here, not in the cost tab, so the economic mapping is testable and the GUI holds no VDI 2067 logic (BACKLOG B2).- Parameters:
initial_investment_cost – Initial capital investment cost [€].
asset_lifespan_years – Technical lifetime [years];
0→ returns0.0.installation_factor – Installation cost factor [%].
maintenance_inspection_factor – Annual maintenance cost factor [%].
operational_effort_h – Annual operational effort [hours/year].
economic_parameters – Mapping with
capital_interest_rate,inflation_rate,time_period,hourly_rate.
- Returns:
The annuity [€/year].
AqvaHeat Heat Pump Module
Vacuum ice slurry generator with heat pump.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.aqvaheat_heat_pump.AqvaHeat(name, nominal_power=100, temperature_difference=0)[source]
Bases:
HeatPumpAqvaHeat vacuum ice slurry heat pump system.
- Parameters:
- calculate(economic_parameters, duration, load_profile, **kwargs)[source]
Calculate AqvaHeat system performance.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Simulation duration [h]
load_profile (numpy.ndarray) – Load profile [kW]
kwargs – VLT_L (flow temperatures), COP_data (COP interpolation data)
- Returns:
Performance metrics and results
- Return type:
- set_parameters(variables, variables_order, idx)[source]
Set optimization parameters for the heat generator (abstract).
Base Heat Generator Module
Abstract base classes for heat generation technologies.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.base_heat_generator.BaseHeatGenerator(name: str)[source]
Bases:
objectAbstract base class for heat generators.
- Parameters:
name (str) – Unique identifier
Note
Derived classes must implement: calculate(), set_parameters(), add_optimization_parameters()
- __init__(name: str) None[source]
Initialize the base heat generator.
- Parameters:
name (str) – Unique identifier for the heat generator instance
- annuity(*args, **kwargs) float[source]
VDI 2067 compliant economic evaluation wrapper.
- Parameters:
args – Positional arguments for annuity function
kwargs – Keyword arguments for annuity function
- Returns:
Annual equivalent cost [€/year]
- Return type:
Note
See annuity.py for complete parameter documentation.
- generate(t: int, **kwargs) tuple[source]
Generate heat for a single time step (used in storage-coupled dispatch).
- Parameters:
t (int) – Time step index
kwargs – Technology-specific context (remaining_load, VLT_L, RLT_L, etc.)
- Returns:
(heat_output_kW, electricity_output_kW)
- Return type:
- Raises:
NotImplementedError – Must be implemented by derived classes that support STES coupling.
- calculate(economic_parameters: dict[str, Any], duration: float, load_profile, **kwargs) dict[str, Any][source]
Full-profile calculation including economic and environmental analysis (abstract).
- Parameters:
economic_parameters (dict) – Economic parameters (electricity_price, gas_price, etc.)
duration (float) – Time step duration [hours]
load_profile (numpy.ndarray) – Remaining heat demand profile [kW]
kwargs – Technology-specific parameters
- Returns:
Results dict with Wärmemenge, WGK, spec_co2_total, etc.
- Return type:
- Raises:
NotImplementedError – Must be implemented by derived classes.
- load_economic_parameters(economic_parameters: dict[str, Any]) None[source]
Extract and store common economic parameters from the shared parameters dict.
- Parameters:
economic_parameters (dict) – Dict with keys electricity_price, gas_price, wood_price, capital_interest_rate, inflation_rate, time_period, subsidy_eligibility, hourly_rate.
Note
Call this at the start of calculate_heat_generation_cost() in each subclass instead of repeating the same 7-8 assignment lines.
- set_parameters(variables: list[float], variables_order: list[str], idx: int) None[source]
Set optimization parameters for the heat generator (abstract).
- add_optimization_parameters(idx: int) dict[str, Any][source]
Define optimization variables and constraints for the technology (abstract).
- Parameters:
idx (int) – Technology index in the system list
- Returns:
Dict with ‘variables’, ‘bounds’, ‘constraints’ keys
- Return type:
- Raises:
NotImplementedError – Must be implemented by derived classes
- update_parameters(optimized_values: list[float], variables_order: list[str]) None[source]
Update technology parameters from optimization results.
- get_plot_data() dict[str, list | ndarray][source]
Extract time-series data for visualization.
- Returns:
Dict mapping variable names to time-series arrays
- Return type:
- to_dict() dict[str, Any][source]
Convert heat generator to dictionary for serialization.
- Returns:
Dictionary representation excluding non-serializable attributes
- Return type:
Note
Numpy arrays are converted to lists for JSON compatibility.
- class districtheatingsim.heat_generators.base_heat_generator.BaseStrategy(charge_on: float, charge_off: float)[source]
Bases:
objectBase control strategy with hysteresis logic.
- Parameters:
- __init__(charge_on: float, charge_off: float) None[source]
Initialize control strategy with temperature thresholds.
- decide_operation(current_state: bool, upper_storage_temp: float, lower_storage_temp: float, remaining_demand: float) bool[source]
Decide heat generator operation based on storage conditions and demand.
- Parameters:
- Returns:
True to operate, False to stop
- Return type:
Note
ON: Continue if lower_temp < charge_off AND demand > 0. OFF: Start if upper_temp ≤ charge_on AND demand > 0.
- to_dict() dict[str, Any][source]
Convert strategy to dictionary for serialization.
- Returns:
Dictionary representation of the strategy
- Return type:
- classmethod from_dict(data: dict[str, Any]) BaseStrategy[source]
Create strategy from dictionary representation.
Looks up the concrete subclass via the
_strategy_classkey written byto_dict()so the correctdecide_operation()override is preserved. Falls back to cls (typicallyBaseStrategy) for legacy JSON files that do not contain the key.- Parameters:
data (dict) – Dictionary containing strategy attributes
- Returns:
New strategy object
- Return type:
Base Heat Pump Classes
Base classes for heat pump modeling with COP calculations and economic analysis.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.base_heat_pumps.HeatPump(name: str, spezifische_Investitionskosten_WP: float = 1000, active: bool = True)[source]
Bases:
BaseHeatGeneratorComprehensive heat pump model for district heating applications.
- Parameters:
Note
Supports geothermal, waste heat, wastewater, and river sources with BEW subsidy (40%).
- __init__(name: str, spezifische_Investitionskosten_WP: float = 1000, active: bool = True) None[source]
Initialize heat pump system.
- init_operation(hours: int) None[source]
Initialize operational arrays for simulation period.
- Parameters:
hours (int) – Number of simulation hours
- calculate_COP(VLT_L: ndarray, QT: float | ndarray, COP_data: ndarray) tuple[ndarray, ndarray][source]
Calculate Coefficient of Performance using manufacturer data interpolation.
- Parameters:
VLT_L (numpy.ndarray) – Flow temperature array [°C]
QT (float or numpy.ndarray) – Source temperature(s) [°C]
COP_data (numpy.ndarray) – COP lookup table
- Returns:
(COP_L, VLT_L_adjusted)
- Return type:
- class districtheatingsim.heat_generators.base_heat_pumps.HeatPumpStrategy(charge_on: float, charge_off: float)[source]
Bases:
BaseStrategyControl strategy for heat pump operation with hysteresis.
- Parameters:
Biomass Boiler System Module
Biomass boiler system with storage integration, economic analysis and BEW subsidy support.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.biomass_boiler.BiomassBoiler(name: str, thermal_capacity_kW: float, Größe_Holzlager: float = 40, spez_Investitionskosten: float = 200, spez_Investitionskosten_Holzlager: float = 400, Nutzungsgrad_BMK: float = 0.8, min_Teillast: float = 0.3, speicher_aktiv: bool = False, Speicher_Volumen: float = 20, T_vorlauf: float = 90, T_ruecklauf: float = 60, initial_fill: float = 0.0, min_fill: float = 0.2, max_fill: float = 0.8, spez_Investitionskosten_Speicher: float = 750, active: bool = True, opt_BMK_min: float = 0, opt_BMK_max: float = 1000, opt_Speicher_min: float = 0, opt_Speicher_max: float = 100)[source]
Bases:
BaseHeatGeneratorBiomass boiler system with storage and efficiency modeling.
- Parameters:
name (str) – Unique identifier
thermal_capacity_kW (float) – Nominal thermal power [°kW]
Größe_Holzlager (float, optional) – Wood storage capacity [tons], defaults to 40
spez_Investitionskosten (float, optional) – Specific investment costs [€/kW], defaults to 200
Nutzungsgrad_BMK (float, optional) – Thermal efficiency [-], defaults to 0.8
speicher_aktiv (bool, optional) – Enable thermal storage, defaults to False
Speicher_Volumen (float, optional) – Storage volume [m³], defaults to 20
Note
Supports BEW subsidy calculation and part-load operation constraints.
- __init__(name: str, thermal_capacity_kW: float, Größe_Holzlager: float = 40, spez_Investitionskosten: float = 200, spez_Investitionskosten_Holzlager: float = 400, Nutzungsgrad_BMK: float = 0.8, min_Teillast: float = 0.3, speicher_aktiv: bool = False, Speicher_Volumen: float = 20, T_vorlauf: float = 90, T_ruecklauf: float = 60, initial_fill: float = 0.0, min_fill: float = 0.2, max_fill: float = 0.8, spez_Investitionskosten_Speicher: float = 750, active: bool = True, opt_BMK_min: float = 0, opt_BMK_max: float = 1000, opt_Speicher_min: float = 0, opt_Speicher_max: float = 100)[source]
Initialize the base heat generator.
- Parameters:
name (str) – Unique identifier for the heat generator instance
- init_operation(hours: int) None[source]
Initialize operational arrays.
- Parameters:
hours (int) – Simulation hours
- simulate_operation(Last_L: ndarray) None[source]
Simulate boiler operation without storage.
- Parameters:
Last_L (numpy.ndarray) – Thermal load [kW]
Note
Considers minimum part-load constraints.
- simulate_storage(Last_L: ndarray, duration: float) None[source]
Simulate boiler with thermal buffer storage (backed by ThermalStorage1D).
- Parameters:
Last_L (numpy.ndarray) – Thermal load [kW]
duration (float) – Time step [hours]
Note
Boiler runs at full nominal load; excess heat charges the buffer. Hysteresis control (min_fill / max_fill SOC thresholds) decides when to switch on/off. Buffer provides discharge when boiler is off.
- calculate_results(duration: float) None[source]
Calculate operational metrics.
- Parameters:
duration (float) – Time step [hours]
- calculate_heat_generation_costs(economic_parameters: dict) float[source]
Calculate heat generation costs with BEW subsidies.
- Parameters:
economic_parameters (dict) – Economic parameters (prices, rates, subsidies)
- Returns:
Heat generation cost [€/MWh]
- Return type:
Note
Includes BEW subsidy (40%) if eligible.
- calculate_environmental_impact() None[source]
Calculate environmental impact metrics.
Note
Biomass: 0.036 tCO2/MWh, primary energy factor 0.2
- calculate(economic_parameters: dict, duration: float, load_profile: ndarray, **kwargs) dict[source]
Comprehensive system analysis.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Time step [hours]
load_profile (numpy.ndarray) – Load profile [kW]
- Returns:
Results dictionary with thermal, economic and environmental data
- Return type:
Note
Includes thermal simulation, economic and environmental analysis.
- set_parameters(variables: list[float], variables_order: list[str], idx: int) None[source]
Set optimization parameters.
- add_optimization_parameters(idx: int) tuple[list[float], list[str], list[tuple[float, float]]][source]
Define optimization parameters for system sizing.
- Parameters:
idx (int) – Technology index
- Returns:
(initial_values, variables_order, bounds)
- Return type:
Note
Includes boiler capacity and storage volume (if active).
- class districtheatingsim.heat_generators.biomass_boiler.BiomassBoilerStrategy(charge_on: float, charge_off: float)[source]
Bases:
BaseStrategyControl strategy for biomass boiler with storage.
- Parameters:
Combined Heat and Power (CHP) System Module
CHP system modeling with thermal/electrical efficiency, storage integration and electricity revenue calculation.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.chp.CHP(name: str, th_Leistung_kW: float, spez_Investitionskosten_GBHKW: float = 1500, spez_Investitionskosten_HBHKW: float = 1850, el_Wirkungsgrad: float = 0.33, KWK_Wirkungsgrad: float = 0.9, min_Teillast: float = 0.7, speicher_aktiv: bool = False, Speicher_Volumen_BHKW: float = 20, T_vorlauf: float = 90, T_ruecklauf: float = 60, initial_fill: float = 0.0, min_fill: float = 0.2, max_fill: float = 0.8, spez_Investitionskosten_Speicher: float = 750, active: bool = True, opt_BHKW_min: float = 0, opt_BHKW_max: float = 1000, opt_BHKW_Speicher_min: float = 0, opt_BHKW_Speicher_max: float = 100, fuel_type: str | None = None)[source]
Bases:
BaseHeatGeneratorCombined Heat and Power system with storage.
- Parameters:
name (str) – Unique identifier (prefix “BHKW” for gas, “Holzgas-BHKW” for biomass)
th_Leistung_kW (float) – Nominal thermal power [kW]
spez_Investitionskosten_GBHKW (float, optional) – Gas CHP investment costs [€/kW], defaults to 1500
el_Wirkungsgrad (float, optional) – Electrical efficiency [-], defaults to 0.33
KWK_Wirkungsgrad (float, optional) – Combined efficiency [-], defaults to 0.9
speicher_aktiv (bool, optional) – Enable thermal storage, defaults to False
Note
Supports BEW/KWKG subsidies and electricity revenue calculations.
- __init__(name: str, th_Leistung_kW: float, spez_Investitionskosten_GBHKW: float = 1500, spez_Investitionskosten_HBHKW: float = 1850, el_Wirkungsgrad: float = 0.33, KWK_Wirkungsgrad: float = 0.9, min_Teillast: float = 0.7, speicher_aktiv: bool = False, Speicher_Volumen_BHKW: float = 20, T_vorlauf: float = 90, T_ruecklauf: float = 60, initial_fill: float = 0.0, min_fill: float = 0.2, max_fill: float = 0.8, spez_Investitionskosten_Speicher: float = 750, active: bool = True, opt_BHKW_min: float = 0, opt_BHKW_max: float = 1000, opt_BHKW_Speicher_min: float = 0, opt_BHKW_Speicher_max: float = 100, fuel_type: str | None = None)[source]
Initialize the base heat generator.
- Parameters:
name (str) – Unique identifier for the heat generator instance
- init_operation(hours: int) None[source]
Initialize operational arrays.
- Parameters:
hours (int) – Simulation hours
- simulate_operation(Last_L: ndarray) None[source]
Simulate CHP operation without storage (heat-led mode).
- Parameters:
Last_L (numpy.ndarray) – Thermal load [kW]
Note
Heat-led with minimum part-load constraints.
- simulate_storage(Last_L: ndarray, duration: float) None[source]
Simulate CHP with thermal buffer storage (backed by ThermalStorage1D).
- Parameters:
Last_L (numpy.ndarray) – Thermal load [kW]
duration (float) – Time step [hours]
Note
CHP runs at full nominal load; excess heat charges the buffer. Hysteresis control (min_fill / max_fill SOC thresholds) decides when to switch on/off. Buffer provides discharge when CHP is off.
- generate(t: int, **kwargs) tuple[float, float][source]
Generate heat and electricity for time step.
- calculate_results(duration: float) None[source]
Calculate cogeneration metrics.
- Parameters:
duration (float) – Time step [hours]
- calculate_heat_generation_costs(economic_parameters: dict) float[source]
Calculate net heat generation costs with electricity revenue.
- Parameters:
economic_parameters (dict) – Economic parameters
- Returns:
Net heat generation cost [€/MWh]
- Return type:
Note
Includes KWKG/BEW subsidies and electricity revenue offset.
- calculate_environmental_impact() None[source]
Calculate environmental impact with CO2 savings.
Note
CO2 balance: fuel emissions minus grid displacement savings. Gas: 0.201 tCO2/MWh, Biomass: 0.036 tCO2/MWh
- calculate(economic_parameters: dict, duration: float, load_profile: ndarray, **kwargs) dict[source]
Comprehensive CHP analysis.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Time step [hours]
load_profile (numpy.ndarray) – Load profile [kW]
- Returns:
Results with heat, electricity, economic and environmental data
- Return type:
Note
Includes cogeneration simulation with electricity revenue.
- set_parameters(variables: list[float], variables_order: list[str], idx: int) None[source]
Set optimization parameters.
- add_optimization_parameters(idx: int) tuple[list[float], list[str], list[tuple[float, float]]][source]
Define optimization parameters for CHP sizing.
- Parameters:
idx (int) – Technology index
- Returns:
(initial_values, variables_order, bounds)
- Return type:
Note
Includes thermal capacity and storage volume (if active).
- class districtheatingsim.heat_generators.chp.CHPStrategy(charge_on: float, charge_off: float)[source]
Bases:
BaseStrategyControl strategy for CHP with storage.
- Parameters:
Energy System Module
Multi-technology energy system modeling with optimization and visualization.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.energy_system.EnergySystem(time_steps: ndarray, load_profile: ndarray, VLT_L: ndarray, RLT_L: ndarray, TRY_data: object, COP_data: object, economic_parameters: dict)[source]
Bases:
objectMulti-technology district heating system integration.
- Parameters:
time_steps (numpy.ndarray) – Simulation time steps
load_profile (numpy.ndarray) – Hourly thermal load [kW]
VLT_L (numpy.ndarray) – Supply temperature profile [°C]
RLT_L (numpy.ndarray) – Return temperature profile [°C]
TRY_data (object) – Test Reference Year meteorological data
COP_data (object) – Heat pump performance data
economic_parameters (dict) – Economic parameters dict
Note
Supports multi-technology dispatch, storage integration and optimization.
- __init__(time_steps: ndarray, load_profile: ndarray, VLT_L: ndarray, RLT_L: ndarray, TRY_data: object, COP_data: object, economic_parameters: dict)[source]
Initialize energy system.
- Parameters:
time_steps (numpy.ndarray) – Time steps for simulation
load_profile (numpy.ndarray) – Hourly thermal load [kW]
VLT_L (numpy.ndarray) – Supply temperature [°C]
RLT_L (numpy.ndarray) – Return temperature [°C]
TRY_data (object) – Test Reference Year data
COP_data (object) – Heat pump performance data
economic_parameters (dict) – Economic parameters
- add_technology(tech) None[source]
Add a heat generation technology to the energy system.
- Parameters:
tech (BaseHeatGenerator) – Technology object to add.
Note
Technologies operate based on priority and control strategies.
- add_storage(storage) None[source]
Add a seasonal thermal energy storage system to the energy system.
- Parameters:
storage (ThermalStorageAdapter) – Seasonal Thermal Energy Storage object.
Note
Enables temporal decoupling of generation and demand for improved efficiency.
- initialize_results() None[source]
Initialize the results dictionary for energy system calculations.
Note
Sets up structure for energy balance, economic, environmental, and performance results.
- set_optimization_variables(variables: list, variables_order: list) None[source]
Set optimization variables for technologies.
- aggregate_results(tech_results: dict) None[source]
Aggregate technology results into system-level metrics.
- Parameters:
tech_results (dict) – Technology results dictionary
- calculate_mix(variables: list | None = None, variables_order: list | None = None) dict[source]
Calculate energy generation mix with technology dispatch and storage.
- optimize_mix(weights: dict, num_restarts: int = 5, unmet_demand_penalty: float = 1000000.0, seed=None)[source]
Optimize energy mix for multi-objective performance.
- Parameters:
weights (dict) – Optimization weights (WGK_Gesamt, specific_emissions_Gesamt, primärenergiefaktor_Gesamt)
num_restarts (int) – Number of random restarts, defaults to 5
unmet_demand_penalty (float) – Penalty weight on the uncovered-demand fraction added to the objective, defaults to 1e6 (see EnergySystemOptimizer for the rationale)
seed (int or None) – Seed for the random-restart draws;
None(default) is non-deterministic, an int makesoptimize_mixreproducible.
- Returns:
Optimized energy system
- Return type:
- getInitialPlotData() tuple[source]
Extract and prepare data for visualization.
- Returns:
(extracted_data, initial_vars)
- Return type:
- plot_stack_plot(figure=None, selected_vars=None, second_y_axis=False) None[source]
Create stack plot visualization of energy system operation.
- plot_pie_chart(figure=None) None[source]
Create pie chart visualization of technology contributions.
- Parameters:
figure (matplotlib.figure.Figure, optional) – Figure object, defaults to None
- copy()[source]
Create deep copy of EnergySystem instance.
- Returns:
Deep copy of energy system
- Return type:
- to_dict() dict[source]
Convert EnergySystem to dictionary for serialization and storage.
- Returns:
Dictionary representation of the complete energy system.
- Return type:
- classmethod from_dict(data: dict)[source]
Recreate EnergySystem instance from dictionary representation.
- Parameters:
data (dict) – Dictionary representation of the EnergySystem.
- Returns:
Fully initialized EnergySystem object.
- Return type:
- save_to_csv(file_path: str) None[source]
Save energy system results to CSV file.
- Parameters:
file_path (str) – Path for CSV output
- save_to_json(file_path: str) None[source]
Save complete EnergySystem object to JSON file for persistence.
- Parameters:
file_path (str) – Path for JSON file output.
- class districtheatingsim.heat_generators.energy_system.EnergySystemOptimizer(initial_energy_system: EnergySystem, weights: dict[str, float], num_restarts: int = 5, unmet_demand_penalty: float = 1000000.0, seed=None)[source]
Bases:
objectMulti-objective optimizer for energy system configuration.
- Parameters:
initial_energy_system (EnergySystem) – Initial system configuration
weights (dict) – Optimization weights dict with ‘WGK_Gesamt’, ‘specific_emissions_Gesamt’, ‘primärenergiefaktor_Gesamt’
num_restarts (int, optional) – Number of random restart runs, defaults to 5
Note
Uses SLSQP with random restarts for multi-objective optimization.
- __init__(initial_energy_system: EnergySystem, weights: dict[str, float], num_restarts: int = 5, unmet_demand_penalty: float = 1000000.0, seed=None)[source]
Initialize multi-objective optimizer.
- Parameters:
initial_energy_system (EnergySystem) – Initial system configuration
weights (dict) – Optimization weights
num_restarts (int) – Number of random restarts, defaults to 5
unmet_demand_penalty (float) – Penalty weight applied to the uncovered-demand fraction (Restwärmebedarf / Jahreswärmebedarf) and added to the objective, defaults to 1e6. Without it the objective (WGK + emissions + primary-energy, all divided by the full annual demand) is minimised by shrinking generators: less generation → the uncovered load lands in the cost-free “Ungedeckter Bedarf” row → every term falls toward 0, so the optimum is an empty/non-covering system (verified: a CHP collapses to 0 kW / 0 % coverage). A large penalty makes covering demand strictly dominate the cost saving from undersizing.
- Raises:
ValueError – If required weights missing or negative
- optimize() EnergySystem[source]
Perform multi-objective optimization with random restarts.
- Returns:
Optimized energy system
- Return type:
- Raises:
ValueError – If no optimization parameters available
RuntimeError – If optimization fails in all restarts
Gas Boiler System Module
Gas-fired boiler system with economic analysis and environmental assessment.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.gas_boiler.GasBoiler(name: str, thermal_capacity_kW: float, spez_Investitionskosten: float = 30, Nutzungsgrad: float = 0.9, active: bool = True)[source]
Bases:
BaseHeatGeneratorGas-fired boiler system for backup and peak load.
- Parameters:
name (str) – Unique identifier
thermal_capacity_kW (float) – Nominal thermal power [kW]
spez_Investitionskosten (float, optional) – Specific investment costs [€/kW], defaults to 30
Nutzungsgrad (float, optional) – Thermal efficiency [-], defaults to 0.9
active (bool, optional) – Initial operational state, defaults to True
Note
Simple load-following operation without minimum load constraints.
- __init__(name: str, thermal_capacity_kW: float, spez_Investitionskosten: float = 30, Nutzungsgrad: float = 0.9, active: bool = True)[source]
Initialize gas boiler system.
- init_operation(hours: int) None[source]
Initialize operational arrays.
- Parameters:
hours (int) – Simulation hours
- calculate_operation(Last_L: ndarray) None[source]
Simulate gas boiler with load-following strategy.
- Parameters:
Last_L (numpy.ndarray) – Thermal load [kW]
Note
Simple on/off without minimum load constraints.
- calculate_results(duration: float) None[source]
Calculate operational metrics.
- Parameters:
duration (float) – Time step [hours]
- calculate_heat_generation_cost(economic_parameters: dict) None[source]
Calculate heat generation costs.
- Parameters:
economic_parameters (dict) – Economic parameters (prices, rates)
Note
Low investment costs but high fuel costs.
- calculate_environmental_impact() None[source]
Calculate environmental impact metrics.
Note
Natural gas: 0.201 tCO2/MWh, primary energy factor 1.1
- calculate(economic_parameters: dict, duration: float, load_profile: ndarray, **kwargs) dict[source]
Comprehensive system analysis.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Time step [hours]
load_profile (numpy.ndarray) – Load profile [kW]
- Returns:
Results dictionary
- Return type:
Note
Includes thermal simulation, economic and environmental analysis.
- set_parameters(variables: list[float], variables_order: list[str], idx: int) None[source]
Set optimization parameters.
Note
Gas boiler typically has no optimization parameters (fixed capacity).
- add_optimization_parameters(idx: int) tuple[list[float], list[str], list[tuple[float, float]]][source]
Define optimization parameters.
- class districtheatingsim.heat_generators.gas_boiler.GasBoilerStrategy(charge_on: float, charge_off: float | None = None)[source]
Bases:
BaseStrategyControl strategy for gas boiler backup operation.
- Parameters:
- decide_operation(current_state: float, upper_storage_temp: float, lower_storage_temp: float, remaining_demand: float) bool[source]
Decide gas boiler operation based on storage and demand.
- Parameters:
- Returns:
True if boiler should operate
- Return type:
Note
Activates if storage temp < threshold AND demand exists.
Geothermal Heat Pump System Module
Geothermal heat pump modeling with borehole field design and drilling cost analysis.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.geothermal_heat_pump.Geothermal(name: str, Fläche: float, Bohrtiefe: float, Temperatur_Geothermie: float, spez_Bohrkosten: float = 100, spez_Entzugsleistung: float = 50, Vollbenutzungsstunden: float = 2400, Abstand_Sonden: float = 10, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, min_area_geothermal: float = 0, max_area_geothermal: float = 5000, min_depth_geothermal: float = 0, max_depth_geothermal: float = 400)[source]
Bases:
HeatPumpGeothermal heat pump with borehole field modeling.
- Parameters:
name (str) – Unique identifier
Fläche (float) – Borehole field area [m²]
Bohrtiefe (float) – Drilling depth [m]
Temperatur_Geothermie (float) – Ground temperature [°C]
spez_Bohrkosten (float, optional) – Drilling costs [€/m], defaults to 100
spez_Entzugsleistung (float, optional) – Heat extraction [W/m], defaults to 50
Note
Stable source temperature for high seasonal efficiency.
- __init__(name: str, Fläche: float, Bohrtiefe: float, Temperatur_Geothermie: float, spez_Bohrkosten: float = 100, spez_Entzugsleistung: float = 50, Vollbenutzungsstunden: float = 2400, Abstand_Sonden: float = 10, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, min_area_geothermal: float = 0, max_area_geothermal: float = 5000, min_depth_geothermal: float = 0, max_depth_geothermal: float = 400) None[source]
Initialize geothermal heat pump.
- Parameters:
- calculate_operation(Last_L: ndarray, VLT_L: ndarray, COP_data: ndarray) None[source]
Calculate operation with thermal sustainability constraints.
- Parameters:
Last_L (numpy.ndarray) – Heat load [kW]
VLT_L (numpy.ndarray) – Flow temperature [°C]
COP_data (numpy.ndarray) – COP lookup table
Note
Uses iterative method to balance thermal extraction with sustainability.
- generate(t: int, **kwargs) tuple[float, float][source]
Generate heat for time step.
- Parameters:
- Returns:
(heat_output [kW], electricity_consumption [kW])
- Return type:
Note
Checks sustainable extraction limits and temperature constraints.
- calculate_results(duration: float) None[source]
Calculate performance metrics.
- Parameters:
duration (float) – Time step [hours]
- calculate(economic_parameters: dict[str, Any], duration: float, load_profile: ndarray, **kwargs) dict[str, Any][source]
Comprehensive geothermal heat pump analysis.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Time step [hours]
load_profile (numpy.ndarray) – Load profile [kW]
- Returns:
Results with performance, economic and environmental data
- Return type:
Note
Includes borehole field modeling and thermal sustainability.
- set_parameters(variables: list, variables_order: list, idx: int) None[source]
Set optimization parameters.
- add_optimization_parameters(idx: int) tuple[list, list, list][source]
Define optimization parameters for borehole field sizing.
- Parameters:
idx (int) – Technology index
- Returns:
(initial_values, variables_order, bounds)
- Return type:
Note
Optimizes area and drilling depth.
JSON encoder for energy-system serialization.
GUI-free json.JSONEncoder that handles the non-standard types produced by the
domain core (numpy scalars/arrays, pandas DataFrames, heat-generator/storage
objects). Lives here — not in the gui package — so that
energy_system.save_to_json does not drag PyQt6 into the GUI-free domain core
(BACKLOG B5). The GUI re-exports it from EnergySystemTab/_10_utilities.py.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.json_encoder.CustomJSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]
Bases:
JSONEncoderCustom JSON Encoder for handling numpy arrays, pandas DataFrames, and custom objects.
- default(obj)[source]
Implement this method in a subclass such that it returns a serializable object for
o, or calls the base implementation (to raise aTypeError).For example, to support arbitrary iterators, you could implement default like this:
def default(self, o): try: iterable = iter(o) except TypeError: pass else: return list(iterable) # Let the base class default method raise the TypeError return super().default(o)
Photovoltaics Module
Photovoltaic power generation modeling based on EU PVGIS methodology.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- districtheatingsim.heat_generators.photovoltaics.Calculate_PV(TRY_data: str, Gross_area: float, Longitude: float, STD_Longitude: float, Latitude: float, Albedo: float, East_West_collector_azimuth_angle: float, Collector_tilt_angle: float) tuple[float, float, ndarray][source]
Calculate photovoltaic power output based on EU PVGIS methodology.
- Parameters:
TRY_data (str) – Path to Test Reference Year data
Gross_area (float) – PV system area [m²]
Longitude (float) – Geographic longitude [degrees]
STD_Longitude (float) – Standard longitude for time zone [degrees]
Latitude (float) – Geographic latitude [degrees]
Albedo (float) – Ground reflection coefficient [-]
East_West_collector_azimuth_angle (float) – Azimuth angle [degrees]
Collector_tilt_angle (float) – Tilt angle from horizontal [degrees]
- Returns:
(yield_kWh, P_max, P_L)
- Return type:
- districtheatingsim.heat_generators.photovoltaics.azimuth_angle(direction: str) float | None[source]
Convert cardinal direction to azimuth angle.
- districtheatingsim.heat_generators.photovoltaics.calculate_building(TRY_data: str, building_data: str, output_filename: str) None[source]
Calculate photovoltaic yield for multiple buildings.
Power-to-Heat System Module
Electric heating system modeling with storage integration and control strategies.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.power_to_heat.PowerToHeat(name: str, thermal_capacity_kW: float = 1000, spez_Investitionskosten: float = 30, Nutzungsgrad: float = 0.9, active: bool = True)[source]
Bases:
BaseHeatGeneratorElectric heating system with grid integration.
- Parameters:
Note
Near-instantaneous response for demand response and grid services.
- __init__(name: str, thermal_capacity_kW: float = 1000, spez_Investitionskosten: float = 30, Nutzungsgrad: float = 0.9, active: bool = True) None[source]
Initialize power-to-heat system.
- Parameters:
name (str) – Unique identifier
thermal_capacity_kW (float) – Thermal capacity [kW], defaults to 1000
spez_Investitionskosten (float) – Specific investment costs [€/kW], defaults to 30
Nutzungsgrad (float) – Electric heating efficiency [-], defaults to 0.9
active (bool) – Activation status, defaults to True
- init_operation(hours: int) None[source]
Initialize operational data arrays for simulation.
- Parameters:
hours (int) – Number of simulation hours.
Note
Initializes time-series arrays and resets calculation flags.
- simulate_operation(Last_L: ndarray) None[source]
Simulate power-to-heat system operation for given load profile.
- Parameters:
Last_L (numpy.ndarray) – Thermal load demand time series [kW].
Note
System operates when demand exists, limited by thermal capacity. Electrical consumption calculated using efficiency factor.
- generate(t: int, **kwargs) tuple[float, float][source]
Generate thermal power for specific time step.
- Parameters:
- Returns:
Heat generation [kW] and electricity consumption [kW].
- Return type:
Note
Heat output limited by thermal_capacity_kW and remaining demand.
- calculate_results(duration: float) None[source]
Calculate aggregated performance metrics.
- Parameters:
duration (float) – Time step duration [hours]
- calculate_heat_generation_cost(economic_parameters: dict[str, Any]) None[source]
Calculate heat generation costs using VDI 2067 methodology.
- Parameters:
economic_parameters (dict) – Economic analysis parameters.
Note
Includes capital costs, electricity costs, and operational expenses. Uses annuity method for levelized cost calculation.
- calculate_environmental_impact() None[source]
Calculate environmental impact of power-to-heat operation.
Note
CO2 emissions from electricity grid and primary energy consumption. Uses grid emission factor and primary energy factor.
- calculate(economic_parameters: dict[str, Any], duration: float, load_profile: ndarray, **kwargs) dict[str, Any][source]
Comprehensive calculation of power-to-heat performance and economics.
- Parameters:
economic_parameters (dict) – Economic analysis parameters.
duration (float) – Simulation time step duration [hours].
load_profile (numpy.ndarray) – Thermal load demand time series [kW].
kwargs (dict) – Additional parameters.
- Returns:
Performance, economic, and environmental results.
- Return type:
Note
Performs operational simulation, economic evaluation, and environmental assessment.
- set_parameters(variables: list, variables_order: list, idx: int) None[source]
Set optimization parameters (interface compatibility).
- add_optimization_parameters(idx: int) tuple[list, list, list][source]
Define optimization parameters for power-to-heat system.
- Parameters:
idx (int) – Technology index.
- Returns:
Empty lists for initial values, variable names, and bounds.
- Return type:
Note
No optimization parameters for basic power-to-heat systems.
- class districtheatingsim.heat_generators.power_to_heat.PowerToHeatStrategy(charge_on: float, charge_off: float | None = None)[source]
Bases:
BaseStrategyControl strategy for power-to-heat with storage.
- Parameters:
- __init__(charge_on: float, charge_off: float | None = None) None[source]
Initialize power-to-heat control strategy.
- decide_operation(current_state: float, upper_storage_temp: float, lower_storage_temp: float, remaining_demand: float) bool[source]
Decide whether to operate power-to-heat system based on control strategy.
- Parameters:
- Returns:
True if system should operate, False otherwise.
- Return type:
Note
Operates if temperature below charge_on threshold and demand exists.
Energy-system result records.
One TechnologyResult per row of the energy-system result, replacing the
eight hand-maintained parallel lists in energy_system.py (BACKLOG C4). The
record is the single source of truth; the legacy German results lists
(techs, Wärmemengen, Anteile …) are projected from it for the GUI and
serialization. Appending one record keeps every projected list in lockstep, so the
divergence bugs that motivated this are structurally impossible.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.results.TechnologyResult(name: str, heat_output_kW: ndarray, heat_amount_MWh: float, share: float, heat_generation_cost: float, specific_co2: float, primary_energy: float, color: str)[source]
Bases:
objectA single technology’s (or storage/unmet-demand row’s) contribution.
Field → legacy
resultslist it projects to:name→techsheat_output_kW→Wärmeleistung_Lheat_amount_MWh→Wärmemengenshare→Anteileheat_generation_cost→WGKspecific_co2→specific_emissions_Lprimary_energy→primärenergie_Lcolor→colors
River Water Heat Pump System Module
River water heat pump modeling with temperature-dependent performance and intake costs.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.river_heat_pump.RiverHeatPump(name: str, Wärmeleistung_FW_WP: float, Temperatur_FW_WP: float | ndarray, dT: float = 0, spez_Investitionskosten_Flusswasser: float = 1000, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, opt_power_min: float = 0, opt_power_max: float = 500)[source]
Bases:
HeatPumpRiver water heat pump with intake infrastructure.
- Parameters:
name (str) – Unique identifier
Wärmeleistung_FW_WP (float) – Thermal capacity [kW]
Temperatur_FW_WP (float or numpy.ndarray) – River water temperature [°C], constant or time-series
spez_Investitionskosten_Flusswasser (float, optional) – River system costs [€/kW], defaults to 1000
Note
Supports variable river temperature profiles for seasonal analysis.
- __init__(name: str, Wärmeleistung_FW_WP: float, Temperatur_FW_WP: float | ndarray, dT: float = 0, spez_Investitionskosten_Flusswasser: float = 1000, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, opt_power_min: float = 0, opt_power_max: float = 500) None[source]
Initialize river water heat pump.
- Parameters:
name (str) – System identifier
Wärmeleistung_FW_WP (float) – Thermal capacity [kW]
Temperatur_FW_WP (float or numpy.ndarray) – River water temperature [°C]
spez_Investitionskosten_Flusswasser (float) – River system costs [€/kW], defaults to 1000
- calculate_heat_pump(VLT_L: ndarray, COP_data: ndarray) tuple[ndarray, ndarray, ndarray, ndarray][source]
Calculate heat pump performance.
- Parameters:
VLT_L (numpy.ndarray) – Required flow temperature [°C]
COP_data (numpy.ndarray) – COP lookup table
- Returns:
(cooling_power, electric_power, achievable_temp, COP)
- Return type:
Note
Uses river water temperature as heat source.
- calculate_operation(Last_L: ndarray, VLT_L: ndarray, COP_data: ndarray) None[source]
Calculate operation with load and temperature constraints.
- Parameters:
Last_L (numpy.ndarray) – Heat load [kW]
VLT_L (numpy.ndarray) – Flow temperature [°C]
COP_data (numpy.ndarray) – COP lookup table
- calculate_results(duration: float) None[source]
Calculate performance metrics.
- Parameters:
duration (float) – Time step [hours]
- calculate(economic_parameters: dict[str, Any], duration: float, load_profile: ndarray, **kwargs) dict[str, Any][source]
Comprehensive river heat pump analysis.
- Parameters:
economic_parameters (dict) – Economic parameters
duration (float) – Time step [hours]
load_profile (numpy.ndarray) – Load profile [kW]
- Returns:
Results dictionary
- Return type:
Note
Includes performance, economic and environmental analysis.
- set_parameters(variables: list, variables_order: list, idx: int) None[source]
Set optimization parameters.
- add_optimization_parameters(idx: int) tuple[list, list, list][source]
Define optimization parameters for capacity sizing.
Solar Radiation Calculation Module
Solar radiation calculations for tilted collectors using Test Reference Year data.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- districtheatingsim.heat_generators.solar_radiation.calculate_solar_radiation(time_steps: ndarray, global_radiation: ndarray, direct_radiation: ndarray, Longitude: float, STD_Longitude: float, Latitude: float, Albedo: float, East_West_collector_azimuth_angle: float, Collector_tilt_angle: float, IAM_W: dict[float, float] | None = None, IAM_N: dict[float, float] | None = None) tuple[ndarray, ndarray | None, ndarray, ndarray][source]
Calculate solar radiation components for tilted collectors using Test Reference Year data.
- Parameters:
time_steps (numpy.ndarray) – Time series as datetime64 array [hours]
global_radiation (numpy.ndarray) – Global horizontal irradiance [W/m²]
direct_radiation (numpy.ndarray) – Direct normal irradiance [W/m²]
Longitude (float) – Site longitude [degrees], range -180° to +180°
STD_Longitude (float) – Standard time zone longitude [degrees] (e.g., 15° for CET)
Latitude (float) – Site latitude [degrees], range -90° to +90°
Albedo (float) – Ground reflectance factor [-], typical values 0.2 (grass), 0.8 (snow)
East_West_collector_azimuth_angle (float) – Collector azimuth [degrees], 0° = south
Collector_tilt_angle (float) – Collector tilt from horizontal [degrees], 0-90°
IAM_W (Optional[Dict[float, float]]) – Incidence Angle Modifier lookup table for East-West direction {angle: factor}
IAM_N (Optional[Dict[float, float]]) – Incidence Angle Modifier lookup table for North-South direction {angle: factor}
- Returns:
(GT_total[W/m²], K_beam[-], Gb_tilted[W/m²], Gd_tilted[W/m²])
- Return type:
Tuple[np.ndarray, Optional[np.ndarray], np.ndarray, np.ndarray]
Note
Implements comprehensive solar geometry, atmospheric effects, and collector-specific IAM corrections. Total radiation GT = beam + diffuse sky + ground-reflected components.
Solar Thermal Collector System Module
Solar thermal collector modeling with flat-plate and vacuum tube technologies.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
Note
Based on Scenocalc 2.0 solar thermal model (https://www.scfw.de)
- class districtheatingsim.heat_generators.solar_thermal.SolarThermal(name: str, bruttofläche_STA: float, vs: float, Typ: str, kosten_speicher_spez: float = 750, kosten_fk_spez: float = 430, kosten_vrk_spez: float = 590, Tsmax: float = 90, Longitude: float = -14.4222, STD_Longitude: float = -15, Latitude: float = 51.1676, East_West_collector_azimuth_angle: float = 0, Collector_tilt_angle: float = 36, Tm_rl: float = 60, Qsa: float = 0, Vorwärmung_K: float = 8, DT_WT_Solar_K: float = 5, DT_WT_Netz_K: float = 5, opt_volume_min: float = 0, opt_volume_max: float = 200, opt_area_min: float = 0, opt_area_max: float = 2000, active: bool = True)[source]
Bases:
BaseHeatGeneratorSolar thermal collector system with storage.
- Parameters:
name (str) – Unique identifier
bruttofläche_STA (float) – Gross collector area [m²]
vs (float) – Storage volume [m³]
Typ (str) – Collector type (“Flachkollektor” or “Vakuumröhrenkollektor”)
kosten_speicher_spez (float, optional) – Storage costs [€/m³], defaults to 750
kosten_fk_spez (float, optional) – Flat-plate costs [€/m²], defaults to 430
Note
Includes detailed solar radiation calculations and efficiency modeling.
- __init__(name: str, bruttofläche_STA: float, vs: float, Typ: str, kosten_speicher_spez: float = 750, kosten_fk_spez: float = 430, kosten_vrk_spez: float = 590, Tsmax: float = 90, Longitude: float = -14.4222, STD_Longitude: float = -15, Latitude: float = 51.1676, East_West_collector_azimuth_angle: float = 0, Collector_tilt_angle: float = 36, Tm_rl: float = 60, Qsa: float = 0, Vorwärmung_K: float = 8, DT_WT_Solar_K: float = 5, DT_WT_Netz_K: float = 5, opt_volume_min: float = 0, opt_volume_max: float = 200, opt_area_min: float = 0, opt_area_max: float = 2000, active: bool = True)[source]
Initialize solar thermal collector system with technical and economic parameters.
- Parameters:
name (str) – Unique identifier
bruttofläche_STA (float) – Gross collector area [m²]
vs (float) – Storage volume [m³]
Typ (str) – Collector type (“Flachkollektor” or “Vakuumröhrenkollektor”)
kosten_speicher_spez (float) – Storage costs [€/m³], defaults to 750
kosten_fk_spez (float) – Flat-plate costs [€/m²], defaults to 430
kosten_vrk_spez (float) – Vacuum tube costs [€/m²], defaults to 590
- init_calculation_constants() None[source]
Initialize technology-specific calculation constants for collector performance modeling.
Note
Sets efficiency parameters, heat loss coefficients, IAM data, and geometric factors based on collector type. Flat-plate: η0=0.763, c1=1.969 W/(m²·K). Vacuum tube: η0=0.693, c1=0.583 W/(m²·K).
- init_operation(hours: int) None[source]
Initialize operational arrays for annual simulation.
- Parameters:
hours (int) – Number of simulation hours (typically 8760)
- calculate_heat_generation_costs(economic_parameters: dict) float[source]
Calculate levelized heat generation costs with subsidy integration.
- Parameters:
economic_parameters (Dict) – Economic parameters (interest_rate, inflation_rate, subsidy_eligibility, etc.)
- Returns:
Heat generation cost [€/MWh]
- Return type:
Note
Includes BEW program: 40% investment cost reduction and 10 €/MWh operational incentive for 10 years.
- calculate_environmental_impact() None[source]
Calculate environmental impact metrics (zero CO2 emissions, zero primary energy factor).
Note
Solar thermal has zero direct emissions and no fossil fuel dependency.
- calculate_solar_thermal_with_storage(Last_L: ndarray, VLT_L: ndarray, RLT_L: ndarray, TRY_data: tuple, time_steps: ndarray, duration: float) None[source]
Hourly solar thermal simulation with storage integration.
- Parameters:
Last_L (numpy.ndarray) – Heat demand profile [kW]
VLT_L (numpy.ndarray) – Supply temperature [°C]
RLT_L (numpy.ndarray) – Return temperature [°C]
TRY_data (Tuple) – Weather data (air_temp, wind_speed, direct_rad, global_rad)
time_steps (numpy.ndarray) – Time step array
duration (float) – Time step duration [hours]
Note
Calculates solar radiation, collector efficiency, storage stratification, and heat generation.
- generate(t: int, **kwargs) tuple[float, float][source]
Generate instantaneous heat output with detailed collector and storage modeling.
- Parameters:
t (int) – Current time step index
kwargs – Simulation parameters (remaining_load, storage temps, TRY_data, time_steps, etc.)
- Returns:
(heat_output[kW], electrical_output[kW]=0)
- Return type:
Note
Implements dual collector A/B approach, temperature stratification, and stagnation prevention.
- calculate(economic_parameters: dict[str, float | str], duration: float, load_profile: ndarray, **kwargs) dict[str, str | float | ndarray][source]
Comprehensive system analysis including performance and economic evaluation.
- Parameters:
economic_parameters (Dict[str, Union[float, str]]) – Economic parameters (interest_rate, inflation_rate, subsidies, etc.)
duration (float) – Time step duration [hours]
load_profile (numpy.ndarray) – Heat demand profile [kW]
kwargs – VLT_L, RLT_L, TRY_data, time_steps
- Returns:
Results dict with Wärmemenge, Wärmeleistung_L, WGK, operational stats, environmental data
- Return type:
Note
Performs thermal simulation, operational analysis, economic cost assessment, and environmental evaluation.
- set_parameters(variables: list[float], variables_order: list[str], idx: int) None[source]
Set optimization parameters from optimizer variable list.
- Parameters:
Note
Updates bruttofläche_STA and vs from variables with names f”bruttofläche_STA_{idx}” and f”vs_{idx}”.
- add_optimization_parameters(idx: int) tuple[list[float], list[str], list[tuple[float, float]]][source]
Define optimization parameters for solar thermal system sizing.
- Parameters:
idx (int) – Technology index for unique parameter names
- Returns:
(initial_values, variables_order, bounds)
- Return type:
Note
Returns [bruttofläche_STA, vs] with bounds from opt_area_min/max and opt_volume_min/max.
- get_display_text() str[source]
Generate formatted display text for GUI representation.
- Returns:
Formatted text with key system parameters
- Return type:
- extract_tech_data() tuple[str, str, str, str][source]
Extract technology data for reporting and documentation.
- classmethod from_dict(data: dict[str, Any]) SolarThermal[source]
Create SolarThermal object from dictionary representation.
- Parameters:
data (Dict[str, Any]) – Dictionary containing SolarThermal attributes
- Returns:
Restored SolarThermal object
- Return type:
Note
Ensures IAM dictionaries are properly restored when loading saved objects.
- class districtheatingsim.heat_generators.solar_thermal.SolarThermalStrategy(charge_on: int, charge_off: int | None = None)[source]
Bases:
BaseStrategyControl strategy for solar thermal systems.
- Parameters:
Note
Operates continuously when solar irradiation available.
- __init__(charge_on: int, charge_off: int | None = None)[source]
Initialize solar thermal control strategy.
Thermal Storage Adapter Module
Wrapper around ThermalStorage1D from the thermal-energy-storage-1d package, exposing the interface required by EnergySystem and the GUI.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.thermal_storage.ThermalStorageAdapter(name: str, volume: float = 1000.0, height: float = 10.0, T_min: float = 40.0, T_max: float = 95.0, initial_temp: float = 60.0, n_nodes: int = 50, geometry_type: str = 'cylinder', loss_model_type: str = 'constant', U_loss: float = 0.3, U_top: float = 0.3, U_side: float = 0.06, U_bottom: float = 0.4, T_ambient: float = 10.0, z_ground: float = 2.0, fluid_type: str = 'water', rho: float = 977.8, cp: float = 4187.0, lambda_fluid: float = 0.663, solver: str = 'implicit', advection_scheme: str = 'tvd', buoyancy: bool = True, lambda_eff_factor: float = 5.0, spez_Investitionskosten: float = 50.0, Nutzungsdauer: int = 30, f_Inst: float = 1.0, f_W_Insp: float = 1.0, Bedienaufwand: float = 0.0, hours: int = 8760, T_charge: float = 90.0, T_discharge_return: float = 50.0)[source]
Bases:
BaseHeatGeneratorSeasonal / large-scale thermal storage backed by ThermalStorage1D.
Exposes the interface expected by EnergySystem.calculate_mix() and the GUI, while delegating all physics to the 1D stratified model.
- Parameters:
name (str) – Display name.
volume (float) – Tank volume [m³].
height (float) – Tank height [m].
T_min (float) – Minimum useful temperature for SOC calculation [°C].
T_max (float) – Maximum operating temperature [°C].
initial_temp (float) – Uniform initial temperature [°C].
n_nodes (int) – Number of vertical nodes (default 50).
geometry_type (str) –
"cylinder","truncated_cone", or"truncated_pyramid".loss_model_type (str) –
"constant","split", or"ground".U_loss (float) – Overall heat-loss coefficient [W/m²K] (used for
"constant").U_top (float) – Surface-specific U-values [W/m²K] (used for
"split").U_side (float) – Surface-specific U-values [W/m²K] (used for
"split").U_bottom (float) – Surface-specific U-values [W/m²K] (used for
"split").T_ambient (float) – Ambient / ground-surface temperature [°C].
z_ground (float) – Depth of tank bottom below ground [m] (used for
"ground").fluid_type (str) –
"water"(temperature-dependent) or"constant".rho (float) – Constant fluid properties (used when
fluid_type="constant").cp (float) – Constant fluid properties (used when
fluid_type="constant").lambda_fluid (float) – Constant fluid properties (used when
fluid_type="constant").solver (str) –
"implicit"(default, unconditionally stable) or"explicit".advection_scheme (str) –
"tvd"(default) or"upwind".buoyancy (bool) – Enable convective mixing correction (default True).
spez_Investitionskosten (float) – Specific investment cost [€/m³] for cost calculation.
hours (int) – Simulation horizon [h] (default 8760).
- __init__(name: str, volume: float = 1000.0, height: float = 10.0, T_min: float = 40.0, T_max: float = 95.0, initial_temp: float = 60.0, n_nodes: int = 50, geometry_type: str = 'cylinder', loss_model_type: str = 'constant', U_loss: float = 0.3, U_top: float = 0.3, U_side: float = 0.06, U_bottom: float = 0.4, T_ambient: float = 10.0, z_ground: float = 2.0, fluid_type: str = 'water', rho: float = 977.8, cp: float = 4187.0, lambda_fluid: float = 0.663, solver: str = 'implicit', advection_scheme: str = 'tvd', buoyancy: bool = True, lambda_eff_factor: float = 5.0, spez_Investitionskosten: float = 50.0, Nutzungsdauer: int = 30, f_Inst: float = 1.0, f_W_Insp: float = 1.0, Bedienaufwand: float = 0.0, hours: int = 8760, T_charge: float = 90.0, T_discharge_return: float = 50.0)[source]
Initialize the base heat generator.
- Parameters:
name (str) – Unique identifier for the heat generator instance
- simulate_stratified_temperature_mass_flows(t: int, Q_in: float, Q_out: float, T_Q_in_flow: float, T_Q_out_return: float) None[source]
Advance storage by one timestep (dt = 3600 s).
- Parameters:
t (int) – Current simulation timestep index.
Q_in (float) – Total heat delivered by all generators [kW].
Q_out (float) – Total network heat demand [kW].
T_Q_in_flow (float) – Network supply temperature passed by EnergySystem [°C]. Not used for mass-flow calculation — the fixed
self.T_charge(generator-side temperature) is used instead, so that a variable network supply curve (“Gleitung”) does not inadvertently cool the storage in summer.T_Q_out_return (float) – Network return temperature passed by EnergySystem [°C]. Not used directly —
self.T_discharge_returnis used instead.
Notes
The storage is either charging or discharging in a given timestep:
Charging (generators over-produce): excess
Q_in − Q_outenters the storage at the top atself.T_charge(fixed generator supply temperature, e.g. 90 °C).Discharging (demand exceeds generation): deficit
Q_out − Q_inis drawn from the storage top; cold return enters at the bottom atself.T_discharge_return.
- Port assignments (StorageInputs.two_port):
charge_in : z = height (top), m_dot > 0, T_in = T_charge
charge_out : z = 0 (bottom), m_dot < 0 → outlet T = T_bottom
discharge_in : z = 0 (bottom), m_dot > 0, T_in = T_discharge_return
discharge_out : z = height (top), m_dot < 0 → outlet T = T_top
- property Q_net_storage_flow: ndarray
positive = discharge, negative = charge.
- Type:
Net heat flow [kW]
- current_storage_temperatures(t: int) tuple[source]
Return (upper_temp, lower_temp) [°C] at timestep t, used by generator control strategies via EnergySystem.calculate_mix().
upper_temp = T_top (hot side – used for charge_on threshold). lower_temp = T_middle (middle node – strategy turn-off threshold,
better indicator of overall charge state than T_bottom).
- current_storage_state(t: int, T_Q_out_return: float, T_Q_in_flow: float) tuple[source]
Return (storage_fraction, available_energy_kWh, max_energy_kWh) at timestep t.
- calculate_efficiency(Q_in_array: ndarray) None[source]
Compute round-trip efficiency and store on self.efficiency.
- calculate_costs(Wärmemenge_MWh: float, economic_parameters: dict) None[source]
Compute the storage’s annuity and heat-generation cost (VDI 2067).
Capital-bound costs come from the tank investment (
volume×spez_Investitionskosten); the annual maintenance share is thef_W_Inspfactor folded into the annuity. There are no demand-bound (fuel) costs – the energy to cover the storage losses is paid for on the generator side, so charging it here too would double-count.- Parameters:
Wärmemenge_MWh – Annual heat discharged from the storage [MWh].
economic_parameters – Shared economic-parameters dict.
- to_dict() dict[source]
Convert heat generator to dictionary for serialization.
- Returns:
Dictionary representation excluding non-serializable attributes
- Return type:
Note
Numpy arrays are converted to lists for JSON compatibility.
- classmethod from_dict(data: dict) ThermalStorageAdapter | None[source]
Deserialize from a saved dict.
Returns None and logs a warning when an old-format config is detected, so the caller can inform the user to re-configure the storage.
- class districtheatingsim.heat_generators.thermal_storage.BufferStorage(volume: float, T_flow: float = 90.0, T_return: float = 60.0, U_loss: float = 0.5, T_ambient: float = 15.0)[source]
Bases:
objectSimple buffer tank backed by ThermalStorage1D.
Replaces the inline scalar energy-bucket (speicher_fill / speicher_kapazitaet) previously embedded in CHP and BiomassBoiler dispatch loops.
- Parameters:
volume (float) – Tank volume [m³].
T_flow (float) – Generator supply temperature [°C] (sets T_max for SOC).
T_return (float) – Generator return temperature [°C] (sets T_min for SOC).
U_loss (float) – Heat-loss coefficient [W/m²K] (default 0.5, well-insulated steel tank).
T_ambient (float) – Ambient temperature [°C] (default 15).
- __init__(volume: float, T_flow: float = 90.0, T_return: float = 60.0, U_loss: float = 0.5, T_ambient: float = 15.0)[source]
Waste Heat Pump Module
Waste heat pump modeling with variable source temperatures and heat recovery.
- author:
Dipl.-Ing. (FH) Jonas Pfeiffer
- class districtheatingsim.heat_generators.waste_heat_pump.WasteHeatPump(name: str, Kühlleistung_Abwärme: float, Temperatur_Abwärme: float, spez_Investitionskosten_Abwärme: float = 500, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, opt_cooling_min: float = 0, opt_cooling_max: float = 500)[source]
Bases:
HeatPumpWaste heat pump utilizing industrial/data center waste heat.
- Parameters:
Note
High COP due to elevated source temperatures.
- __init__(name: str, Kühlleistung_Abwärme: float, Temperatur_Abwärme: float, spez_Investitionskosten_Abwärme: float = 500, spezifische_Investitionskosten_WP: float = 1000, min_Teillast: float = 0.2, opt_cooling_min: float = 0, opt_cooling_max: float = 500) None[source]
Initialize waste heat pump system.
- Parameters:
name (str) – Unique identifier for the waste heat pump system.
Kühlleistung_Abwärme (float) – Waste heat cooling capacity available for extraction [kW].
Temperatur_Abwärme (float) – Waste heat source temperature [°C].
spez_Investitionskosten_Abwärme (float, optional) – Specific investment costs for waste heat recovery system [€/kW]. Default is 500.
spezifische_Investitionskosten_WP (float, optional) – Specific investment costs for heat pump unit [€/kW]. Default is 1000.
min_Teillast (float, optional) – Minimum part-load ratio [-]. Default is 0.2.
opt_cooling_min (float, optional) – Minimum cooling capacity for optimization [kW]. Default is 0.
opt_cooling_max (float, optional) – Maximum cooling capacity for optimization [kW]. Default is 500.
- calculate_heat_pump(VLT_L: ndarray, COP_data: ndarray) tuple[ndarray, ndarray, ndarray, ndarray][source]
Calculate heat pump performance for waste heat operation.
- Parameters:
VLT_L (numpy.ndarray) – Required flow temperature array [°C].
COP_data (numpy.ndarray) – COP lookup table for performance interpolation.
- Returns:
Heat output [kW], electrical power [kW], achievable flow temps [°C], COP [-].
- Return type:
Note
Uses waste heat temperature as source for COP calculation.
- calculate_operation(Last_L: ndarray, VLT_L: ndarray, COP_data: ndarray) None[source]
Calculate operational performance considering waste heat availability.
- Parameters:
Last_L (numpy.ndarray) – Heat load demand time series [kW].
VLT_L (numpy.ndarray) – Required flow temperature time series [°C].
COP_data (numpy.ndarray) – COP lookup table for performance interpolation.
Note
Heat output limited by waste heat capacity and load demand. Updates time-series attributes for simulation period.
- generate(t: int, **kwargs) tuple[float, float][source]
Generate heat at specific time step with waste heat constraints.
- Parameters:
- Returns:
Heat generation [kW] and electricity consumption [kW].
- Return type:
Note
Checks waste heat availability and operational constraints.
- calculate_results(duration: float) None[source]
Calculate aggregated performance metrics from simulation results.
- Parameters:
duration (float) – Time step duration [hours].
Note
Calculates energy totals, SCOP, and operational statistics.
- calculate(economic_parameters: dict[str, Any], duration: float, load_profile: ndarray, **kwargs) dict[str, Any][source]
Comprehensive calculation of waste heat pump performance and economics.
- Parameters:
economic_parameters (dict) – Economic analysis parameters.
duration (float) – Simulation time step duration [hours].
load_profile (numpy.ndarray) – Heat demand time series [kW].
kwargs (dict) – Additional parameters (VLT_L, COP_data).
- Returns:
Performance, economic, and environmental results.
- Return type:
Note
Integrates waste heat recovery with heat pump performance and lifecycle cost analysis.
- set_parameters(variables: list, variables_order: list, idx: int) None[source]
Set optimization parameters for the waste heat pump system.
- Parameters:
Note
Updates waste heat cooling capacity from optimization variables.
- add_optimization_parameters(idx: int) tuple[list, list, list][source]
Define optimization parameters for waste heat pump system.
- Parameters:
idx (int) – Technology index for unique variable identification.
- Returns:
Initial values, variable names, and bounds for optimization.
- Return type:
Note
Returns waste heat cooling capacity bounds and initial value.