|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Created on Thu Jun 16 11:19:17 2022 |
| 4 | +developed by Felix Panitz* and Peter Stange* |
| 5 | +* at Chair of Building Energy Systems and Heat Supply, Technische Universität Dresden |
| 6 | +""" |
| 7 | + |
| 8 | +import numpy as np |
| 9 | + |
| 10 | +import flixOpt as fx |
| 11 | + |
| 12 | +check_penalty = False |
| 13 | +excess_penalty = 1e5 |
| 14 | + |
| 15 | +electricity_demand = np.array([70., 80., 90., 90, 90, 90, 90, 90, 90]) |
| 16 | +heat_demand = np.array([30., 0., 90., 110, 2000, 20, 20, 20, 20]) if check_penalty else np.array([30., 0., 90., 110, 110, 20, 20, 20, 20]) |
| 17 | +electricity_price = np.array([40., 40., 40., 40, 40, 40, 40, 40, 40]) |
| 18 | + |
| 19 | +time_series = fx.create_datetime_array('2020-01-01', len(heat_demand), freq='h') |
| 20 | + |
| 21 | + |
| 22 | +# ## Bus-Definition: ## |
| 23 | +####################### |
| 24 | +# Typ Name |
| 25 | +Strom = fx.Bus('Strom', excess_penalty_per_flow_hour=excess_penalty) |
| 26 | +Fernwaerme = fx.Bus('Fernwärme', excess_penalty_per_flow_hour=excess_penalty) |
| 27 | +Gas = fx.Bus('Gas', excess_penalty_per_flow_hour=excess_penalty) |
| 28 | + |
| 29 | +# Effect-Definition: |
| 30 | +Costs = fx.Effect('costs', '€', 'Kosten', is_standard=True, is_objective=True) |
| 31 | +CO2 = fx.Effect('CO2', 'kg', 'CO2_e-Emissionen', specific_share_to_other_effects_operation={Costs: 0.2}) |
| 32 | +PE = fx.Effect('PE', 'kWh_PE', 'Primärenergie', maximum_total=3.5e3) |
| 33 | + |
| 34 | +################################ |
| 35 | +# ## definition of components ## |
| 36 | +################################ |
| 37 | + |
| 38 | +# 1. definition of boiler # |
| 39 | +Gaskessel = fx.linear_converters.Boiler( |
| 40 | + 'Kessel', eta=0.5, # efficiency ratio |
| 41 | + on_off_parameters=fx.OnOffParameters(effects_per_running_hour={Costs: 0, CO2: 1000}), # 1000 kg_CO2/h (just for testing) |
| 42 | + # defining flows: |
| 43 | + Q_th=fx.Flow(label='Q_th', # name |
| 44 | + bus=Fernwaerme, # linked bus |
| 45 | + size=fx.InvestParameters(fix_effects=1000, # 1000 € investment costs |
| 46 | + fixed_size=50, # fixed size |
| 47 | + optional=False, # forced investment |
| 48 | + specific_effects={Costs: 10, PE: 2}), # specific costs: 10 €/kW; 2 kWh_PE/kW |
| 49 | + load_factor_max=1.0, # maximal mean power 50 kW |
| 50 | + load_factor_min=0.1, # minimal mean power 5 kW |
| 51 | + relative_minimum=5 / 50, # 10 % part load |
| 52 | + relative_maximum=1, # 50 kW |
| 53 | + previous_flow_rate=50, # 50 kW is value before start |
| 54 | + flow_hours_total_max=1e6, # kWh, overall maximum "flow-work" |
| 55 | + can_be_off=fx.OnOffParameters( |
| 56 | + on_hours_total_min=0, # minimum of working hours |
| 57 | + on_hours_total_max=1000, # maximum of working hours |
| 58 | + consecutive_on_hours_max=10, # maximum of working hours in one step |
| 59 | + consecutive_off_hours_max=10, # maximum of off hours in one step |
| 60 | + # consecutive_on_hours_min = 2, # minimum on hours in one step |
| 61 | + # consecutive_off_hours_min = 4, # minimum off hours in one step |
| 62 | + effects_per_switch_on=0.01, # € per start |
| 63 | + switch_on_total_max=1000), # max nr of starts |
| 64 | + ), |
| 65 | + Q_fu=fx.Flow(label='Q_fu', # name |
| 66 | + bus=Gas, # linked bus |
| 67 | + size=200, # kW |
| 68 | + relative_minimum=0, |
| 69 | + relative_maximum=1)) |
| 70 | + |
| 71 | +# 2. defining of CHP-unit: |
| 72 | +aKWK = fx.linear_converters.CHP( |
| 73 | + 'BHKW2', eta_th=0.5, eta_el=0.4, on_off_parameters=fx.OnOffParameters(effects_per_switch_on=0.01), |
| 74 | + P_el=fx.Flow('P_el', bus=Strom, size=60, relative_minimum=5 / 60), |
| 75 | + Q_th=fx.Flow('Q_th', bus=Fernwaerme, size=1e3), |
| 76 | + Q_fu=fx.Flow('Q_fu', bus=Gas, size=1e3, previous_flow_rate=20)) # The CHP was ON previously |
| 77 | + |
| 78 | +# 3. defining a alternative CHP-unit with linear segments : |
| 79 | +# (Flows mst be defined before the segmented_conversion_factors can be defined) |
| 80 | +P_el = fx.Flow('P_el', bus=Strom, size=60, previous_flow_rate=20) |
| 81 | +Q_th = fx.Flow('Q_th', bus=Fernwaerme) |
| 82 | +Q_fu = fx.Flow('Q_fu', bus=Gas) |
| 83 | +segmented_conversion_factors = ({P_el: [(5, 30), (40, 60)], # elements can also be a time series (can change over time) |
| 84 | + Q_th: [(6, 35), (45, 100)], |
| 85 | + Q_fu: [(12, 70), (90, 200)]}) |
| 86 | + |
| 87 | +aKWK2 = fx.LinearConverter('BHKW2', inputs=[Q_fu], outputs=[P_el, Q_th], segmented_conversion_factors=segmented_conversion_factors, |
| 88 | + on_off_parameters=fx.OnOffParameters(effects_per_switch_on=0.01)) |
| 89 | + |
| 90 | +# 4. definition of storage: |
| 91 | +# segmented_investment_effects: [start1, end1, start2, end2, ...] If start and end are equal, then its a point |
| 92 | +segmented_investment_effects = ([(5, 25), (25, 100)], # size |
| 93 | + {Costs: [(50, 250), (250, 800)], # € |
| 94 | + PE: [(5, 25), (25, 100)] # kWh_PE |
| 95 | + }) |
| 96 | + |
| 97 | +aSpeicher = fx.Storage('Speicher', # defining flows: |
| 98 | + charging=fx.Flow('Q_th_load', bus=Fernwaerme, size=1e4), |
| 99 | + discharging=fx.Flow('Q_th_unload', bus=Fernwaerme, size=1e4), |
| 100 | + capacity_in_flow_hours=fx.InvestParameters( |
| 101 | + fix_effects=0, # no fix costs |
| 102 | + fixed_size=None, # variable size |
| 103 | + effects_in_segments=segmented_investment_effects, # see above |
| 104 | + optional=False, # forced invest |
| 105 | + specific_effects={Costs: 0.01, CO2: 0.01}, # €/kWh; kg_CO2/kWh |
| 106 | + minimum_size=0, maximum_size=1000), # optimizing between 0...1000 kWh |
| 107 | + initial_charge_state=0, # empty storage at beginning |
| 108 | + # minimal_final_charge_state = 3, # min charge state and end |
| 109 | + maximal_final_charge_state=10, # max charge state and end |
| 110 | + eta_charge=0.9, eta_discharge=1, # efficiency of (un)-loading |
| 111 | + relative_loss_per_hour=0.08, # loss of storage per time |
| 112 | + prevent_simultaneous_charge_and_discharge=True) # no parallel loading and unloading |
| 113 | + |
| 114 | +# 5. definition of sinks and sources: |
| 115 | +# 5.a) heat load profile: |
| 116 | +Waermelast = fx.Sink('Wärmelast', sink=fx.Flow('Q_th_Last', # name |
| 117 | + bus=Fernwaerme, # linked bus |
| 118 | + size=1, relative_maximum=max(heat_demand), fixed_relative_value=heat_demand)) # fixed values fixed_relative_value * size |
| 119 | +# 5.b) gas tarif: |
| 120 | +Gasbezug = fx.Source('Gastarif', source=fx.Flow('Q_Gas', bus=Gas, # linked bus |
| 121 | + size=1000, # defining nominal size |
| 122 | + effects_per_flow_hour={Costs: 0.04, CO2: 0.3})) |
| 123 | +# 5.c) feed-in of electricity: |
| 124 | +Stromverkauf = fx.Sink('Einspeisung', sink=fx.Flow('P_el', bus=Strom, # linked bus |
| 125 | + effects_per_flow_hour=-1 * np.array(electricity_price))) # feed-in tariff |
| 126 | + |
| 127 | +########################## |
| 128 | +# ## Build energysystem ## |
| 129 | +########################## |
| 130 | + |
| 131 | +flow_system = fx.FlowSystem(time_series, last_time_step_hours=None) # creating FlowSystem |
| 132 | + |
| 133 | +flow_system.add_effects(Costs, CO2, PE) # adding effects |
| 134 | +flow_system.add_components(Gaskessel, Waermelast, Gasbezug) # adding components |
| 135 | +flow_system.add_components(Stromverkauf) # adding components |
| 136 | +flow_system.add_components(aSpeicher) # adding components |
| 137 | +flow_system.add_components(aKWK2) # adding components |
| 138 | +#flow_system.add_components(aKWK) # adding components |
| 139 | + |
| 140 | + |
| 141 | +time_indices = None |
| 142 | +# time_indices = [1,3,5] |
| 143 | + |
| 144 | +calculation = fx.FullCalculation('Sim1', flow_system, 'pyomo', time_indices) |
| 145 | +calculation.do_modeling() |
| 146 | + |
| 147 | +print(calculation.system_model.description_of_equations()) |
| 148 | +print(calculation.system_model.description_of_variables()) |
| 149 | + |
| 150 | + |
| 151 | +calculation.solve(fx.solvers.HighsSolver(mip_gap=0.005, time_limit_seconds=30), save_results=True) |
| 152 | + |
| 153 | +results = fx.results.CalculationResults(calculation.name, folder='results') |
| 154 | + |
| 155 | +results.plot_operation('Fernwärme') |
| 156 | + |
0 commit comments