You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Früher konnte man Elements beliebig oft verwenden.
Beispiel: flow_system_ohne_Eigenverbrauch.add_elements(cost_effect, bus_el, battery, source, sink) flow_system_mit_Eigenverbrauch.add_elements(cost_effect, bus_el, battery, verbraucher, source_sink)
Das scheint nicht mehr zu gehen (mindestens Konflikt mit timeseries-collection).
Es hat bei der Modellerstellung enorme Vorteile. Klar es gibt auch Nachteile für den Zugriff nachher, aber eigentlich nicht, wenn man konsequent mit dem results-Objekt arbeitet.
"""This script shows how to use the flixOpt framework to model a more complex energy system."""importnumpyasnpimportpandasaspdfromrich.prettyimportpprint# Used for pretty printingimportflixOptasfxif__name__=='__main__':
# --- Experiment Options ---# Configure options for testing various parameters and behaviorscheck_penalty=Falseexcess_penalty=1e5use_chp_with_segments=Falsetime_indices=None# Define specific time steps for custom calculations, or use the entire series# --- Define Demand and Price Profiles ---# Input data for electricity and heat demands, as well as electricity priceelectricity_demand=np.array([70, 80, 90, 90, 90, 90, 90, 90, 90])
heat_demand= (
np.array([30, 0, 90, 110, 2000, 20, 20, 20, 20])
ifcheck_penaltyelsenp.array([30, 0, 90, 110, 110, 20, 20, 20, 20])
)
electricity_price=np.array([40, 40, 40, 40, 40, 40, 40, 40, 40])
# --- Define the Flow System, that will hold all elements, and the time steps you want to model ---timesteps=pd.date_range('2020-01-01', periods=len(heat_demand), freq='h')
flow_system=fx.FlowSystem(timesteps) # Create FlowSystem# --- Define Energy Buses ---# Represent node balances (inputs=outputs) for the different energy carriers (electricity, heat, gas) in the systemflow_system.add_elements(
fx.Bus('Strom', excess_penalty_per_flow_hour=excess_penalty),
fx.Bus('Fernwärme', excess_penalty_per_flow_hour=excess_penalty),
fx.Bus('Gas', excess_penalty_per_flow_hour=excess_penalty),
)
# --- Define Effects ---# Specify effects related to costs, CO2 emissions, and primary energy consumptionCosts=fx.Effect('costs', '€', 'Kosten', is_standard=True, is_objective=True)
CO2=fx.Effect('CO2', 'kg', 'CO2_e-Emissionen', specific_share_to_other_effects_operation={Costs.label: 0.2})
PE=fx.Effect('PE', 'kWh_PE', 'Primärenergie', maximum_total=3.5e3)
# --- Define Components ---# 1. Define Boiler Component# A gas boiler that converts fuel into thermal output, with investment and on-off parametersGaskessel=fx.linear_converters.Boiler(
'Kessel',
eta=0.5, # Efficiency ratioon_off_parameters=fx.OnOffParameters(effects_per_running_hour={Costs.label: 0, CO2.label: 1000}), # CO2 emissions per hourQ_th=fx.Flow(
label='Q_th', # Thermal outputbus='Fernwärme', # Linked bussize=fx.InvestParameters(
fix_effects=1000, # Fixed investment costsfixed_size=50, # Fixed sizeoptional=False, # Forced investmentspecific_effects={Costs.label: 10, PE.label: 2}, # Specific costs
),
load_factor_max=1.0, # Maximum load factor (50 kW)load_factor_min=0.1, # Minimum load factor (5 kW)relative_minimum=5/50, # Minimum part loadrelative_maximum=1, # Maximum part loadprevious_flow_rate=50, # Previous flow rateflow_hours_total_max=1e6, # Total energy flow limiton_off_parameters=fx.OnOffParameters(
on_hours_total_min=0, # Minimum operating hourson_hours_total_max=1000, # Maximum operating hoursconsecutive_on_hours_max=10, # Max consecutive operating hoursconsecutive_on_hours_min=np.array(
[1, 1, 1, 1, 1, 2, 2, 2, 2]
), # min consecutive operation hoursconsecutive_off_hours_max=10, # Max consecutive off hourseffects_per_switch_on=0.01, # Cost per switch-onswitch_on_total_max=1000, # Max number of starts
),
),
Q_fu=fx.Flow(label='Q_fu', bus='Gas', size=200),
)
# 2. Define CHP Unit# Combined Heat and Power unit that generates both electricity and heat from fuelbhkw=fx.linear_converters.CHP(
'BHKW2',
eta_th=0.5,
eta_el=0.4,
on_off_parameters=fx.OnOffParameters(effects_per_switch_on=0.01),
P_el=fx.Flow('P_el', bus='Strom', size=60, relative_minimum=5/60),
Q_th=fx.Flow('Q_th', bus='Fernwärme', size=1e3),
Q_fu=fx.Flow('Q_fu', bus='Gas', size=1e3, previous_flow_rate=20), # The CHP was ON previously
)
# 3. Define CHP with Linear Segments# This CHP unit uses linear segments for more dynamic behavior over timeP_el=fx.Flow('P_el', bus='Strom', size=60, previous_flow_rate=20)
Q_th=fx.Flow('Q_th', bus='Fernwärme')
Q_fu=fx.Flow('Q_fu', bus='Gas')
segmented_conversion_factors= {
P_el.label: [(5, 30), (40, 60)], # Similar to eta_th, each factor here can be an arrayQ_th.label: [(6, 35), (45, 100)],
Q_fu.label: [(12, 70), (90, 200)],
}
bhkw_2=fx.LinearConverter(
'BHKW2',
inputs=[Q_fu],
outputs=[P_el, Q_th],
segmented_conversion_factors=segmented_conversion_factors,
on_off_parameters=fx.OnOffParameters(effects_per_switch_on=0.01),
)
# 4. Define Storage Component# Storage with variable size and segmented investment effectssegmented_investment_effects= (
[(5, 25), (25, 100)], # Investment size
{
Costs.label: [(50, 250), (250, 800)], # Investment costsPE.label: [(5, 25), (25, 100)], # Primary energy costs
},
)
speicher=fx.Storage(
'Speicher',
charging=fx.Flow('Q_th_load', bus='Fernwärme', size=1e4),
discharging=fx.Flow('Q_th_unload', bus='Fernwärme', size=1e4),
capacity_in_flow_hours=fx.InvestParameters(
effects_in_segments=segmented_investment_effects, # Investment effectsoptional=False, # Forced investmentminimum_size=0,
maximum_size=1000, # Optimizing between 0 and 1000 kWh
),
initial_charge_state=0, # Initial charge statemaximal_final_charge_state=10, # Maximum final charge stateeta_charge=0.9,
eta_discharge=1, # Charge/discharge efficiencyrelative_loss_per_hour=0.08, # Energy loss per hour, relative to current charge stateprevent_simultaneous_charge_and_discharge=True, # Prevent simultaneous charge/discharge
)
# 5. Define Sinks and Sources# 5.a) Heat demand profileWaermelast=fx.Sink(
'Wärmelast',
sink=fx.Flow(
'Q_th_Last', # Heat sinkbus='Fernwärme', # Linked bussize=1,
fixed_relative_profile=heat_demand, # Fixed demand profile
),
)
# 5.b) Gas tariffGasbezug=fx.Source(
'Gastarif',
source=fx.Flow(
'Q_Gas',
bus='Gas', # Gas sourcesize=1000, # Nominal sizeeffects_per_flow_hour={Costs.label: 0.04, CO2.label: 0.3},
),
)
# 5.c) Feed-in of electricityStromverkauf=fx.Sink(
'Einspeisung',
sink=fx.Flow(
'P_el',
bus='Strom', # Feed-in tariff for electricityeffects_per_flow_hour=-1*electricity_price, # Negative price for feed-in
),
)
# --- Build FlowSystem ---# Select components to be included in the flow systemflow_system.add_elements(Costs, CO2, PE, Gaskessel, Waermelast, Gasbezug, Stromverkauf, speicher)
flow_system.add_elements(bhkw_2) ifuse_chp_with_segmentselseflow_system.add_elements(bhkw)
pprint(flow_system) # Get a string representation of the FlowSystemflow_system2=fx.FlowSystem(timesteps)
flow_system2.add_elements(*list(flow_system.components.values()))
flow_system2.add_elements(*list(flow_system.buses.values()))
flow_system2.add_elements(*list(flow_system.effects.effects.values()))
# --- Solve FlowSystem ---calculation=fx.FullCalculation('complex example', flow_system, time_indices)
calculation.do_modeling()
calculation.solve(fx.solvers.HighsSolver(0.01, 60))
calculation2=fx.FullCalculation('complex example 2', flow_system2, time_indices)
calculation2.do_modeling()
calculation2.solve(fx.solvers.HighsSolver(0.01, 60))
assertnp.isclose(calculation2.results.objective, calculation.results.objective, rtol=1e-5, atol=0.1)
# --- Results ---# You can analyze results directly or save them to file and reload them later.calculation.results.to_file()
# But let's plot some results anywaycalculation.results.plot_heatmap('BHKW2(Q_th)|flow_rate')
calculation.results['BHKW2'].plot_node_balance()
calculation.results['Speicher'].plot_charge_state()
Ist das etwas was wir brauchen?
Dafür müsste man immer die _backup_data aus den timeseries rausholen wenn man Elemente zu einem neuen FlowSystem hinzufügt.
Ist das etwas was wir brauchen? Dafür müsste man immer die _backup_data aus den timeseries rausholen wenn man Elemente zu einem neuen FlowSystem hinzufügt.
Wäre denkbar umzusetzen.
@baumbude Ich nehms zurück.
Das beisst sich sehr mit dem indexing (active_timesteps).
Das beides möglich zu machen wird sehr schwierig glaube ich.
Activity
FBumann commentedon Mar 25, 2025
Gerne.
Kannst du mal ein Skript teilen damit ich weis was nicht geht?
FBumann commentedon Mar 25, 2025
In meinem ersten Test geht das auf jeden fall.
FBumann commentedon Mar 28, 2025
@baumbude kannst du hier nochmal reinschauen und sagen was nicht funktioniert?
baumbude commentedon Apr 2, 2025
Ja @FBumann , es klappt anscheinend nur nicht, wenn sich die timesteps-Reihe ändert:
Hier Minimalbeispiel:
FBumann commentedon Apr 2, 2025
Ist das etwas was wir brauchen?
Dafür müsste man immer die _backup_data aus den timeseries rausholen wenn man Elemente zu einem neuen FlowSystem hinzufügt.
Wäre denkbar umzusetzen.
FBumann commentedon Apr 2, 2025
@baumbude Ich nehms zurück.
Das beisst sich sehr mit dem indexing (active_timesteps).
Das beides möglich zu machen wird sehr schwierig glaube ich.
FBumann commentedon Oct 13, 2025
Closed by #348