def test_equate_variables_constraint(self): """Testing the equate_variables function in the constraint module.""" bus1 = solph.Bus(label='Bus1') storage = solph.components.GenericStorage( label='storage_constraint', invest_relation_input_capacity=0.2, invest_relation_output_capacity=0.2, inputs={bus1: solph.Flow()}, outputs={bus1: solph.Flow()}, investment=solph.Investment(ep_costs=145)) sink = solph.Sink( label='Sink', inputs={ bus1: solph.Flow(investment=solph.Investment(ep_costs=500)) }) source = solph.Source( label='Source', outputs={ bus1: solph.Flow(investment=solph.Investment(ep_costs=123)) }) om = self.get_om() solph.constraints.equate_variables( om, om.InvestmentFlow.invest[source, bus1], om.InvestmentFlow.invest[bus1, sink], 2) solph.constraints.equate_variables( om, om.InvestmentFlow.invest[source, bus1], om.GenericInvestmentStorageBlock.invest[storage]) self.compare_lp_files('connect_investment.lp', my_om=om)
def test_generic_invest_limit(self): """ """ bus = solph.Bus(label='bus_1') solph.Source( label='source_0', outputs={ bus: solph.Flow(investment=solph.Investment(ep_costs=50, space=4)) }) solph.Source( label='source_1', outputs={ bus: solph.Flow(investment=solph.Investment(ep_costs=100, space=1)) }) solph.Source(label='source_2', outputs={ bus: solph.Flow(investment=solph.Investment(ep_costs=75)) }) om = self.get_om() om = solph.constraints.additional_investment_flow_limit(om, "space", limit=20) self.compare_lp_files('generic_invest_limit.lp', my_om=om)
def test_nonconvex_invest_storage_all_nonconvex(self): """All invest variables are free and nonconvex.""" b1 = solph.Bus(label='bus1') solph.components.GenericStorage( label='storage_all_nonconvex', inputs={ b1: solph.Flow(investment=solph.Investment(nonconvex=True, minimum=5, offset=10, maximum=30, ep_costs=10)) }, outputs={ b1: solph.Flow(investment=solph.Investment(nonconvex=True, minimum=8, offset=15, ep_costs=10, maximum=20)) }, investment=solph.Investment(nonconvex=True, ep_costs=20, offset=30, minimum=20, maximum=100)) self.compare_lp_files('storage_invest_all_nonconvex.lp')
def test_something_else(): date_time_index = pd.date_range('1/1/2012', periods=5, freq='H') energysystem = solph.EnergySystem(timeindex=date_time_index) bel1 = solph.Bus(label='electricity1') bel2 = solph.Bus(label='electricity2') energysystem.add(bel1, bel2) energysystem.add( solph.Transformer( label='powerline_1_2', inputs={bel1: solph.Flow()}, outputs={ bel2: solph.Flow(investment=solph.Investment(ep_costs=20)) })) energysystem.add( solph.Transformer( label='powerline_2_1', inputs={bel2: solph.Flow()}, outputs={ bel1: solph.Flow(investment=solph.Investment(ep_costs=20)) })) om = solph.Model(energysystem) line12 = energysystem.groups['powerline_1_2'] line21 = energysystem.groups['powerline_2_1'] solph.constraints.equate_variables(om, om.InvestmentFlow.invest[line12, bel2], om.InvestmentFlow.invest[line21, bel1], name="my_name")
def test_flow_classes(): with assert_raises(ValueError): solph.Flow(fixed=True) with assert_raises(ValueError): solph.Flow(investment=solph.Investment(), nominal_value=4) with assert_raises(ValueError): solph.Flow(investment=solph.Investment(), nonconvex=solph.NonConvex()) with assert_raises(AttributeError): solph.Flow(fixed_costs=34)
def test_storage_invest_2(self): """All can be free extended to their own cost. """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage2', inputs={bel: solph.Flow(investment=solph.Investment(ep_costs=99))}, outputs={bel: solph.Flow(investment=solph.Investment(ep_costs=9))}, investment=solph.Investment(ep_costs=145), initial_capacity=0.5) self.compare_lp_files('storage_invest_2.lp')
def test_storage_invest_3(self): """The storage capacity is fixed, but the Flows can be extended. e.g. PHES with a fixed basin but the pump and the turbine can be adapted """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage3', inputs={bel: solph.Flow(investment=solph.Investment(ep_costs=99))}, outputs={bel: solph.Flow(investment=solph.Investment(ep_costs=9))}, nominal_capacity=5000) self.compare_lp_files('storage_invest_3.lp')
def sink_dispatchable_optimize(model, dict_asset, **kwargs): r""" Define a dispatchable sink. The dispatchable sink is capacity-optimized, without any costs connected to the capacity of the asset. Applications of this asset type are: Feed-in sink, excess sink. See :py:func:`~.sink` for more information, including parameters. Notes ----- Tested with: - test_sink_dispatchable_single_input_bus() - test_sink_dispatchable_multiple_input_busses() Returns ------- Indirectly updated `model` and dict of asset in `kwargs` with the sink object. """ # check if the sink has multiple input busses if isinstance(dict_asset[INFLOW_DIRECTION], list): inputs = {} index = 0 for bus in dict_asset[INFLOW_DIRECTION]: inputs[kwargs[OEMOF_BUSSES][bus]] = solph.Flow( label=dict_asset[LABEL], variable_costs=dict_asset[DISPATCH_PRICE][VALUE][index], investment=solph.Investment(), ) index += 1 else: inputs = { kwargs[OEMOF_BUSSES][dict_asset[INFLOW_DIRECTION]]: solph.Flow( label=dict_asset[LABEL], variable_costs=dict_asset[DISPATCH_PRICE][VALUE], investment=solph.Investment(), ) } # create and add excess electricity sink to micro_grid_system - variable sink_dispatchable = solph.Sink( label=dict_asset[LABEL], inputs=inputs, ) model.add(sink_dispatchable) kwargs[OEMOF_SINK].update({dict_asset[LABEL]: sink_dispatchable}) logging.debug( f"Added: Dispatchable sink {dict_asset[LABEL]} (to be capacity optimized) to bus {dict_asset[INFLOW_DIRECTION]}.", )
def test_fixed_source_invest_sink(self): """ Wrong constraints for fixed source + invest sink w. `summed_max`. """ bel = solph.Bus(label='electricityBus') solph.Source(label='wind', outputs={ bel: solph.Flow(actual_value=[12, 16, 14], nominal_value=1000000, fixed=True) }) solph.Sink(label='excess', inputs={ bel: solph.Flow(summed_max=2.3, variable_costs=25, max=0.8, investment=solph.Investment(ep_costs=500, maximum=10e5, existing=50)) }) self.compare_lp_files('fixed_source_invest_sink.lp')
def test_nonconvex_investment_storage_with_offset(self): """All invest variables are coupled. The invest variables of the Flows will be created during the initialisation of the storage e.g. battery """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storagenon_convex', inputs={bel: solph.Flow(variable_costs=56)}, outputs={bel: solph.Flow(variable_costs=24)}, nominal_storage_capacity=None, loss_rate=0.13, max_storage_level=0.9, min_storage_level=0.1, invest_relation_input_capacity=1 / 6, invest_relation_output_capacity=1 / 6, inflow_conversion_factor=0.97, outflow_conversion_factor=0.86, investment=solph.Investment(ep_costs=145, minimum=19, offset=5, nonconvex=True, maximum=1454)) self.compare_lp_files('storage_invest_with_offset.lp')
def test_linear_transformer_chp_invest(self): """Constraint test of a Transformer with Investment (two outputs). """ bgas = solph.Bus(label='gasBus') bheat = solph.Bus(label='heatBus') bel = solph.Bus(label='electricityBus') solph.Transformer(label='chp_powerplant_gas', inputs={ bgas: solph.Flow(variable_costs=50, investment=solph.Investment( maximum=1000, ep_costs=20)) }, outputs={ bel: solph.Flow(), bheat: solph.Flow() }, conversion_factors={ bel: 0.4, bheat: 0.5 }) self.compare_lp_files('linear_transformer_chp_invest.lp')
def add_storage(it, labels, nodes, busd): """Adds oemof.solph.GenericStorage objects to the list of components. If attribute `invest` is *True*, the investment version of the Storage is created. Parameters ---------- it : pd.DataFrame Table of storage attributes of the producers / consumers. labels : dict Dictonary containing specifications for label-tuple. nodes : list All oemof.solph components are added to the list. busd : dict All oemof.solph.Bus objects are given by this dictionary. Returns ------- list : Updated list of nodes. """ for _, s in it.iterrows(): label_storage = oh.Label(labels['l_1'], s['bus'], s['label'], labels['l_4']) label_bus = busd[(labels['l_1'], s['bus'], 'bus', labels['l_4'])] if s['invest']: epc_s = s['capex'] nodes.append( solph.components.GenericStorage( label=label_storage, inputs={label_bus: solph.Flow()}, outputs={label_bus: solph.Flow()}, loss_rate=s['capacity_loss'], fixed_losses_relative=s['fixed_losses_relative'], invest_relation_input_capacity=s[ 'invest_relation_input_capacity'], invest_relation_output_capacity=s[ 'invest_relation_output_capacity'], inflow_conversion_factor=s['inflow_conversion_factor'], outflow_conversion_factor=s[ 'outflow_conversion_factor'], investment=solph.Investment(ep_costs=epc_s))) else: nodes.append( solph.components.GenericStorage( label=label_storage, inputs={label_bus: solph.Flow()}, outputs={label_bus: solph.Flow()}, loss_rate=s['capacity_loss'], fixed_losses_relative=s['fixed_losses_relative'], nominal_storage_capacity=s['capacity'], inflow_conversion_factor=s['inflow_conversion_factor'], outflow_conversion_factor=s[ 'outflow_conversion_factor'])) return nodes
def test_transformer_invest_with_existing(self): """Constraint test of a LinearN1Transformer with Investment. """ bgas = solph.Bus(label='gasBus') bcoal = solph.Bus(label='coalBus') bel = solph.Bus(label='electricityBus') bth = solph.Bus(label='thermalBus') solph.Transformer(label='powerplant_gas_coal', inputs={ bgas: solph.Flow(), bcoal: solph.Flow() }, outputs={ bel: solph.Flow(variable_costs=50, investment=solph.Investment( maximum=1000, ep_costs=20, existing=200)), bth: solph.Flow(variable_costs=20) }, conversion_factors={ bgas: 0.58, bcoal: 0.2, bel: 0.3, bth: 0.5 }) self.compare_lp_files('transformer_invest_with_existing.lp')
def test_investment_limit(self): """Testing the investment_limit function in the constraint module. """ bus1 = solph.Bus(label='Bus1') solph.components.GenericStorage( label='storage', nominal_input_capacity_ratio=0.2, nominal_output_capacity_ratio=0.2, inputs={bus1: solph.Flow()}, outputs={bus1: solph.Flow()}, investment=solph.Investment(ep_costs=145)) solph.Source(label='Source', outputs={bus1: solph.Flow( investment=solph.Investment(ep_costs=123))}) om = self.get_om() solph.constraints.investment_limit(om, limit=900) self.compare_lp_files('investment_limit.lp', my_om=om)
def add_heatpipes(it, labels, gd, q, b_in, b_out, nodes): """ Adds *HeatPipeline* objects with *Investment* attribute to the list of oemof.solph components. Parameters ---------- it : pd.DataFrame Table of *Heatpipeline* attributes of the district heating grid labels : dict Dictonary containing specifications for label-tuple gd : dict Settings of the investment optimisation of the ThermalNetwork q : pd.Series Specific *Pipe* of ThermalNetwork b_in : oemof.solph.Bus Bus of Inflow b_out : oemof.solph.Bus Bus of Outflow nodes : list All oemof.solph components are added to the list Returns ------- list : Updated list of nodes. """ for _, t in it.iterrows(): # definition of tag3 of label -> type of pipe labels['l_3'] = t['label_3'] epc_p = t['capex_pipes'] * q['length'] epc_fix = t['fix_costs'] * q['length'] # Heatpipe with binary variable nc = bool(t['nonconvex']) # bidirectional heatpipelines yes or no flow_bi_args = { 'bidirectional': True, 'min': -1}\ if gd['bidirectional_pipes'] else {} nodes.append(oh.HeatPipeline( label=oh.Label(labels['l_1'], labels['l_2'], labels['l_3'], labels['l_4']), inputs={b_in: solph.Flow(**flow_bi_args)}, outputs={b_out: solph.Flow( nominal_value=None, **flow_bi_args, investment=solph.Investment( ep_costs=epc_p, maximum=t['cap_max'], minimum=t['cap_min'], nonconvex=nc, offset=epc_fix, ))}, heat_loss_factor=t['l_factor'] * q['length'], heat_loss_factor_fix=t['l_factor_fix'] * q['length'], )) return nodes
def test_storage_invest_6(self): """Like test_storage_invest_5 but there can also be an investment in the basin. """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage6', inputs={ bel: solph.Flow( investment=solph.Investment(ep_costs=99, existing=110)) }, outputs={ bel: solph.Flow(investment=solph.Investment(existing=100)) }, invest_relation_input_output=1.1, investment=solph.Investment(ep_costs=145, existing=10000)) self.compare_lp_files('storage_invest_6.lp')
def test_storage_invest_4(self): """Only the storage capacity can be extended. """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage4', inputs={bel: solph.Flow(nominal_value=80)}, outputs={bel: solph.Flow(nominal_value=100)}, investment=solph.Investment(ep_costs=145, maximum=500)) self.compare_lp_files('storage_invest_4.lp')
def test_storage_invest_5(self): """The storage capacity is fixed, but the Flows can be extended. e.g. PHES with a fixed basin but the pump and the turbine can be adapted. The installed capacity of the pump is 10 % bigger than the the capacity of the turbine due to 'invest_relation_input_output=1.1'. """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage5', inputs={ bel: solph.Flow( investment=solph.Investment(ep_costs=99, existing=110)) }, outputs={ bel: solph.Flow(investment=solph.Investment(existing=100)) }, invest_relation_input_output=1.1, nominal_capacity=10000) self.compare_lp_files('storage_invest_5.lp')
def test_generic_storage_2(): """Nominal value defined with investment model.""" bel = solph.Bus() solph.components.GenericStorage( label='storage3', nominal_storage_capacity=45, inputs={bel: solph.Flow(variable_costs=10e10)}, outputs={bel: solph.Flow(variable_costs=10e10)}, loss_rate=0.00, initial_storage_level=0, invest_relation_input_capacity=1/6, invest_relation_output_capacity=1/6, inflow_conversion_factor=1, outflow_conversion_factor=0.8, investment=solph.Investment(ep_costs=23))
def test_generic_storage_1(): """Duplicate definition inflow.""" bel = solph.Bus() solph.components.GenericStorage( label='storage1', inputs={bel: solph.Flow(variable_costs=10e10)}, outputs={bel: solph.Flow(variable_costs=10e10)}, loss_rate=0.00, initial_storage_level=0, invest_relation_input_output=1, invest_relation_output_capacity=1, invest_relation_input_capacity=1, investment=solph.Investment(), inflow_conversion_factor=1, outflow_conversion_factor=0.8)
def source_non_dispatchable_optimize(model, dict_asset, **kwargs): r""" Defines a non dispatchable source with a capacity to be optimized. See :py:func:`~.source` for more information, including parameters. Notes ----- Tested with: - test_source_non_dispatchable_optimize() Returns ------- Indirectly updated `model` and dict of asset in `kwargs` with the source object. """ if MAXIMUM_ADD_CAP_NORMALIZED in dict_asset: maximum = dict_asset[MAXIMUM_ADD_CAP_NORMALIZED][VALUE] else: maximum = dict_asset[MAXIMUM_ADD_CAP][VALUE] if INSTALLED_CAP_NORMALIZED in dict_asset: existing = dict_asset[INSTALLED_CAP_NORMALIZED][VALUE] else: existing = dict_asset[INSTALLED_CAP][VALUE] outputs = { kwargs[OEMOF_BUSSES][dict_asset[OUTFLOW_DIRECTION]]: solph.Flow( label=dict_asset[LABEL], fix=dict_asset[TIMESERIES_NORMALIZED], investment=solph.Investment( ep_costs=dict_asset[SIMULATION_ANNUITY][VALUE] / dict_asset[TIMESERIES_PEAK][VALUE], maximum=maximum, existing=existing, ), # variable_costs are devided by time series peak as normalized time series are used as actual_value variable_costs=dict_asset[DISPATCH_PRICE][VALUE] / dict_asset[TIMESERIES_PEAK][VALUE], # add emission_factor for emission contraint emission_factor=dict_asset[EMISSION_FACTOR][VALUE], ) } source_non_dispatchable = solph.Source(label=dict_asset[LABEL], outputs=outputs) model.add(source_non_dispatchable) kwargs[OEMOF_SOURCE].update({dict_asset[LABEL]: source_non_dispatchable}) logging.debug( f"Added: Non-dispatchable source {dict_asset[LABEL]} (capacity to be optimized) to bus {dict_asset[OUTFLOW_DIRECTION]}." )
def test_invest_source_fixed_sink(self): """Constraint test with a fixed sink and a dispatch invest source. """ bel = solph.Bus(label='electricityBus') solph.Source(label='pv', outputs={bel: solph.Flow( max=[45, 83, 65], variable_costs=13, investment=solph.Investment(ep_costs=123))}) solph.Sink(label='excess', inputs={bel: solph.Flow( actual_value=[.5, .8, .3], nominal_value=10e4, fixed=True)}) self.compare_lp_files('invest_source_fixed_sink.lp')
def test_storage_minimum_invest(self): """All invest variables are coupled. The invest variables of the Flows will be created during the initialisation of the storage e.g. battery """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage(label='storage1', inputs={bel: solph.Flow()}, outputs={bel: solph.Flow()}, investment=solph.Investment( ep_costs=145, minimum=100, maximum=200)) self.compare_lp_files('storage_invest_minimum.lp')
def test_storage_invest_unbalanced(self): """Testing a unbalanced storage (e.g. battery).""" bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage1', inputs={bel: solph.Flow()}, outputs={bel: solph.Flow()}, nominal_storage_capacity=None, initial_storage_level=0.5, balanced=False, invest_relation_input_capacity=1, invest_relation_output_capacity=1, investment=solph.Investment(ep_costs=145)) self.compare_lp_files('storage_invest_unbalanced.lp')
def test_nonconvex_invest_sink_without_offset(self): """ Non convex invest flow without offset, with minimum. """ bel = solph.Bus(label='electricityBus') solph.Sink(label='sink_nonconvex_invest', inputs={ bel: solph.Flow(summed_max=2.3, variable_costs=25, max=0.8, investment=solph.Investment(ep_costs=500, minimum=15, nonconvex=True, maximum=172)) }) self.compare_lp_files('flow_invest_without_offset.lp')
def test_nonconvex_invest_source_with_offset_no_minimum(self): """ Non convex invest flow with offset, without minimum. """ bel = solph.Bus(label='electricityBus') solph.Source(label='source_nonconvex_invest', inputs={ bel: solph.Flow(summed_max=2.3, variable_costs=25, max=0.8, investment=solph.Investment( ep_costs=500, maximum=1234, offset=34, nonconvex=True)) }) self.compare_lp_files('flow_invest_with_offset_no_minimum.lp')
def add_storage(it, labels, gd, nodes, busd): for i, s in it.iterrows(): if s['active']: label_storage = oh.Label(labels['l_1'], s['bus'], s['label'], labels['l_4']) label_bus = busd[(labels['l_1'], s['bus'], 'bus', labels['l_4'])] if s['invest']: epc_s = economics.annuity(capex=s['capex'], n=s['n'], wacc=gd['rate']) * gd['f_invest'] nodes.append( solph.components.GenericStorage( label=label_storage, inputs={label_bus: solph.Flow()}, outputs={label_bus: solph.Flow()}, loss_rate=s['capacity_loss'], invest_relation_input_capacity=s[ 'invest_relation_input_capacity'], invest_relation_output_capacity=s[ 'invest_relation_output_capacity'], inflow_conversion_factor=s['inflow_conversion_factor'], outflow_conversion_factor=s[ 'outflow_conversion_factor'], investment=solph.Investment(ep_costs=epc_s))) else: nodes.append( solph.components.GenericStorage( label=label_storage, inputs={label_bus: solph.Flow()}, outputs={label_bus: solph.Flow()}, loss_rate=s['capacity_loss'], nominal_capacity=s['capacity'], inflow_conversion_factor=s['inflow_conversion_factor'], outflow_conversion_factor=s[ 'outflow_conversion_factor'])) return nodes, busd
def test_storage_invest(self): """ """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage', inputs={bel: solph.Flow(variable_costs=56)}, outputs={bel: solph.Flow(variable_costs=24)}, nominal_capacity=None, capacity_loss=0.13, capacity_max=0.9, capacity_min=0.1, nominal_input_capacity_ratio=1 / 6, nominal_output_capacity_ratio=1 / 6, inflow_conversion_factor=0.97, outflow_conversion_factor=0.86, investment=solph.Investment(ep_costs=145, maximum=234)) self.compare_lp_files('storage_invest.lp')
def test_storage_invest_1(self): """All invest variables are coupled. The invest variables of the Flows will be created during the initialisation of the storage e.g. battery """ bel = solph.Bus(label='electricityBus') solph.components.GenericStorage( label='storage1', inputs={bel: solph.Flow(variable_costs=56)}, outputs={bel: solph.Flow(variable_costs=24)}, nominal_capacity=None, capacity_loss=0.13, capacity_max=0.9, capacity_min=0.1, invest_relation_input_capacity=1 / 6, invest_relation_output_capacity=1 / 6, inflow_conversion_factor=0.97, outflow_conversion_factor=0.86, investment=solph.Investment(ep_costs=145, maximum=234)) self.compare_lp_files('storage_invest_1.lp')
inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=10e10, variable_costs=0)}, conversion_factors={bel: 0.58}) # create storage object representing a battery storage = solph.components.GenericStorage( label='storage', inputs={bel: solph.Flow(variable_costs=0.0001)}, outputs={bel: solph.Flow()}, loss_rate=0.00, initial_storage_level=0, invest_relation_input_capacity=1 / 6, invest_relation_output_capacity=1 / 6, inflow_conversion_factor=1, outflow_conversion_factor=0.8, investment=solph.Investment(ep_costs=epc_storage), ) energysystem.add(excess, gas_resource, wind, pv, demand, pp_gas, storage) ########################################################################## # Optimise the energy system ########################################################################## logging.info('Optimise the energy system') # initialise the operational model om = solph.Model(energysystem) # if tee_switch is true solver messages will be displayed logging.info('Solve the optimization problem')