def test_output_by_type_view(self): results = processing.results(self.om) transformer_output = views.node_output_by_type(results, node_type=Transformer) compare = views.node(results, 'diesel', multiindex=True)['sequences'][('diesel', 'b_el1', 'flow')] eq_(int(transformer_output.sum()), int(compare.sum()))
def test_net_storage_flow(self): results = processing.results(self.om) storage_flow = views.net_storage_flow(results, node_type=GenericStorage) compare = views.node(results, 'storage', multiindex=True)['sequences'] eq_(((compare[('storage', 'b_el2', 'flow')] - compare[('b_el1', 'storage', 'flow')]).to_frame() == storage_flow.values).all()[0], True)
def simulating(dict_values, model, local_energy_system): """ Initiates the oemof-solph simulation, accesses results and writes main results into dict Parameters ---------- dict_values: dict All simulation inputs model: object oemof-solph object for energy system model local_energy_system: object pyomo object storing all constraints of the energy system model Returns ------- Updated model with results, main results (flows, assets) and meta results (simulation) """ logging.info("Starting simulation.") local_energy_system.solve( solver="cbc", solve_kwargs={ "tee": False }, # if tee_switch is true solver messages will be displayed cmdline_options={"ratioGap": str(0.03)}, ) # ratioGap allowedGap mipgap logging.info("Problem solved.") # add results to the energy system to make it possible to store them. results_main = processing.results(local_energy_system) results_meta = processing.meta_results(local_energy_system) model.results["main"] = results_main model.results["meta"] = results_meta dict_values.update({ SIMULATION_RESULTS: { LABEL: SIMULATION_RESULTS, "objective_value": results_meta["objective"], "simulation_time": round(results_meta["solver"]["Time"], 2), } }) logging.info( "Simulation time: %s minutes.", round(dict_values[SIMULATION_RESULTS]["simulation_time"] / 60, 2), ) return model, results_main, results_main
def simulate(experiment, micro_grid_system, model, file_name): """ Simulates the optimization problem using the given model and experiment's settings Parameters ---------- experiment: dict Contains general settings for the experiment micro_grid_system: oemof.solph.network.EnergySystem Energy system for oemof optimization model: oemof.solph.models.Model Model used for the oemof optimization file_name: str Name used for saving the simulation's result Returns ------- micro_grid_system: oemof.solph.network.EnergySystem Model for the optimization with integrated results """ logging.info("Simulating...") model.solve( solver=experiment[SOLVER], solve_kwargs={ "tee": experiment[SOLVER_VERBOSE] }, # if tee_switch is true solver messages will be displayed cmdline_options={ experiment[CMDLINE_OPTION]: str(experiment[CMDLINE_OPTION_VALUE]) }, ) # ratioGap allowedGap mipgap logging.debug("Problem solved") if experiment["save_lp_file"] is True: logging.debug("Saving lp-file to folder.") model.write( experiment[OUTPUT_FOLDER] + "/lp_files/model_" + file_name + ".lp", io_options={SYMBOLIC_SOLVER_LABELS: True}, ) # add results to the energy system to make it possible to store them. micro_grid_system.results[MAIN] = processing.results(model) micro_grid_system.results[META] = processing.meta_results(model) return micro_grid_system
inputs={ bel: solph.Flow(my_keyword=True, fix=[0, 1, 1, 0], nominal_value=130) }) model = solph.Model(energy_system) # only one of the two flows may be active at a time solph.constraints.limit_active_flow_count_by_keyword(model, "my_keyword", lower_limit=0, upper_limit=1) model.solve() results = processing.results(model) if plt is not None: data = views.node(results, 'bel')['sequences'] ax = data.plot(kind='line', grid=True) ax.set_xlabel('Time (h)') ax.set_ylabel('P (MW)') plt.figure() ax = plt.gca() plt.plot(results[('my_keyword', 'my_keyword')]['sequences'], label="my_keyword_count") ax.set_xlabel('Time (h)') ax.set_ylabel('Count (1)') plt.grid() plt.legend()
efficiency=1, marginal_cost=0.0001) energysystem.add(bus_heat, heat_source, shortage, excess, heat_demand, thermal_storage) # Create and solve the optimization model optimization_model = Model(energysystem) optimization_model.solve(solver=solver, solve_kwargs={ 'tee': False, 'keepfiles': False }) # Get results results = processing.results(optimization_model) string_results = processing.convert_keys_to_strings(results) sequences = {k: v['sequences'] for k, v in string_results.items()} df = pd.concat(sequences, axis=1) # Print storage sizing built_storage_capacity = results[thermal_storage, None]['scalars']['invest'] initial_storage_capacity = results[thermal_storage, None]['scalars']['init_content'] maximum_heat_flow_charging = results[bus_heat, thermal_storage]['scalars']['invest'] dash = '-' * 50 print(dash) print('{:>32s}{:>15.3f}'.format('Invested capacity [MW]', maximum_heat_flow_charging))
def run_model_electric(config_path, var_number): with open(config_path, 'r') as ymlfile: cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) if cfg['debug']: number_of_time_steps = 3 else: number_of_time_steps = cfg['number_timesteps'] solver = cfg['solver'] debug = cfg['debug'] solver_verbose = cfg['solver_verbose'] # show/hide solver output # ## Read data and parameters ## # # Define the used directories abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) results_path = abs_path + '/results' data_ts_path = abs_path + '/data/data_confidential/' data_param_path = abs_path + '/data/data_public/' # Read parameter values from parameter file if type(cfg['parameters_variation']) == list: file_path_param_01 = data_param_path + cfg['parameters_system'] file_path_param_02 = data_param_path + cfg['parameters_variation'][ var_number] elif type(cfg['parameters_system']) == list: file_path_param_01 = data_param_path + cfg['parameters_system'][ var_number] file_path_param_02 = data_param_path + cfg['parameters_variation'] else: file_path_param_01 = data_param_path + cfg['parameters_system'] file_path_param_02 = data_param_path + cfg['parameters_variation'] param_df_01 = pd.read_csv(file_path_param_01, index_col=1) param_df_02 = pd.read_csv(file_path_param_02, index_col=1) param_df = pd.concat([param_df_01, param_df_02], sort=True) param_value = param_df['value'] # Import PV and demand data data = pd.read_csv((data_ts_path + cfg['time_series_file_name'])) # Redefine ep_costs_function: def ep_costs_f(capex, n, opex): return ep_costs_func(capex, n, opex, param_value['wacc']) # Initiate the logger logger.define_logging(logfile='electric_model_{0}_{1}.log'.format( cfg['exp_number'], var_number), logpath=results_path + '/logs', screen_level=logging.INFO, file_level=logging.DEBUG) date_time_index = pd.date_range('1/1/2017', periods=number_of_time_steps, freq='H') # Initialise the energysystem logging.info('Initialize the energy system') energysystem = solph.EnergySystem(timeindex=date_time_index) ####################### # Build up the system # ####################### # Busses bco = solph.Bus(label="cool") bwh = solph.Bus(label="waste") bel = solph.Bus(label="electricity") bam = solph.Bus(label="ambient") energysystem.add(bco, bwh, bel, bam) # Sinks and sources ambience = solph.Sink(label='ambience', inputs={bam: solph.Flow()}) grid_el = solph.Source( label='grid_el', outputs={ bel: solph.Flow( variable_costs=(param_value['price_electr'] * float(param_value['price_electr_variation']))) }) pv = solph.Source( label='pv', outputs={ bel: solph.Flow( fix=data['pv_normiert'], investment=solph.Investment(ep_costs=ep_costs_f( param_value['invest_costs_pv_output_el_09708'], param_value['lifetime_pv'], param_value['opex_pv']))) }) # Einheit: 0,9708 kWpeak demand = solph.Sink( label='demand', inputs={bco: solph.Flow(fix=data['Cooling load kW'], nominal_value=1)}) excess_el = solph.Sink(label='excess_el', inputs={bel: solph.Flow()}) energysystem.add(ambience, grid_el, pv, demand, excess_el) # Transformers chil = solph.Transformer( label='compression_chiller', inputs={bel: solph.Flow()}, outputs={ bco: solph.Flow(investment=solph.Investment(ep_costs=ep_costs_f( param_value['invest_costs_compression_output_cool'], param_value['lifetime_compression'], param_value['opex_compression']))), bwh: solph.Flow() }, conversion_factors={ bco: param_value['conv_factor_compression_output_cool'], bwh: param_value['conv_factor_compression_output_waste'] }) towe = solph.Transformer( label='cooling_tower', inputs={ bwh: solph.Flow(investment=solph.Investment(ep_costs=ep_costs_f( param_value['invest_costs_tower_input_th'], param_value['lifetime_tower'], param_value['opex_tower']))), bel: solph.Flow() }, outputs={bam: solph.Flow()}, conversion_factors={ bwh: param_value['conv_factor_tower_input_waste'], bel: param_value['conv_factor_tower_input_el'] }) energysystem.add(chil, towe) # Storages if param_value['nominal_capacitiy_stor_cool'] == 0: stor_co = solph.components.GenericStorage( label='storage_cool', inputs={bco: solph.Flow()}, outputs={bco: solph.Flow()}, loss_rate=param_value['capac_loss_stor_cool'], # invest_relation_input_capacity=1 / 6, # invest_relation_output_capacity=1 / 6, inflow_conversion_factor=param_value[ 'conv_factor_stor_cool_input'], outflow_conversion_factor=param_value[ 'conv_factor_stor_cool_output'], investment=solph.Investment(ep_costs=ep_costs_f( param_value['invest_costs_stor_cool_capacity'], param_value['lifetime_stor_cool'], param_value['opex_stor_cool']))) else: stor_co = solph.components.GenericStorage( label='storage_cool', inputs={bco: solph.Flow()}, outputs={bco: solph.Flow()}, loss_rate=param_value['capac_loss_stor_cool'], inflow_conversion_factor=param_value[ 'conv_factor_stor_cool_input'], outflow_conversion_factor=param_value[ 'conv_factor_stor_cool_output'], nominal_capacity=param_value['nominal_capacitiy_stor_cool']) if param_value['nominal_capacitiy_stor_el'] == 0: stor_el = solph.components.GenericStorage( label='storage_electricity', inputs={bel: solph.Flow()}, outputs={bel: solph.Flow()}, loss_rate=param_value['capac_loss_stor_el'], inflow_conversion_factor=param_value['conv_factor_stor_el_input'], outflow_conversion_factor=param_value[ 'conv_factor_stor_el_output'], investment=solph.Investment(ep_costs=ep_costs_f(( param_value['invest_costs_stor_el_capacity'] * float(param_value['capex_stor_el_variation']) ), param_value['lifetime_stor_el'], param_value['opex_stor_el']))) else: stor_el = solph.components.GenericStorage( label='storage_electricity', inputs={bel: solph.Flow()}, outputs={bel: solph.Flow()}, loss_rate=param_value['capac_loss_stor_el'], inflow_conversion_factor=param_value['conv_factor_stor_el_input'], outflow_conversion_factor=param_value[ 'conv_factor_stor_el_output'], nominal_capacity=param_value['nominal_capacitiy_stor_el']) energysystem.add(stor_co, stor_el) ######################################## # Create a model and solve the problem # ######################################## # Initialise the operational model (create the problem) with constrains model = solph.Model(energysystem) # ## Add own constrains ## # # Create a block and add it to the system myconstrains = po.Block() model.add_component('MyBlock', myconstrains) demand_sum = sum(data['Cooling load kW']) myconstrains.solar_constr = po.Constraint( expr=((sum(model.flow[grid_el, bel, t] for t in model.TIMESTEPS)) <= ( demand_sum / param_value['conv_factor_compression_output_cool'] * param_value['sol_fraction_el'] * float(param_value['sol_fraction_el_variation'])))) logging.info('Solve the optimization problem') model.solve(solver=solver, solve_kwargs={'tee': solver_verbose}) if debug: filename = ( results_path + '/lp_files/' + 'electric_model_{0}_{1}.lp'.format(cfg['exp_number'], var_number)) logging.info('Store lp-file in {0}.'.format(filename)) model.write(filename, io_options={'symbolic_solver_labels': True}) logging.info('Store the energy system with the results.') energysystem.results['main'] = processing.results(model) energysystem.results['meta'] = processing.meta_results(model) energysystem.results['param'] = (processing.parameter_as_dict(model)) energysystem.dump(dpath=(results_path + '/dumps'), filename='electric_model_{0}_{1}.oemof'.format( cfg['exp_number'], var_number))
def simulating(dict_values, model, local_energy_system): """ Initiates the oemof-solph simulation, accesses results and writes main results into dict If an error is encountered in the oemof solver, mvs should not be allowed to continue, otherwise other errors related to the uncomplete simulation result might occur and it will be more obscure to the endusers what went wrong. A MVS error is raised if the omoef solver warning states explicitely that "termination condition infeasible", otherwise the oemof solver warning is re-raised as an error. Parameters ---------- dict_values: dict All simulation inputs model: object oemof-solph object for energy system model local_energy_system: object pyomo object storing all constraints of the energy system model Returns ------- Updated model with results, main results (flows, assets) and meta results (simulation) """ logging.info("Starting simulation.") # turn warnings into errors warnings.filterwarnings("error") try: local_energy_system.solve( solver="cbc", solve_kwargs={ "tee": False }, # if tee_switch is true solver messages will be displayed cmdline_options={"ratioGap": str(0.03)}, ) # ratioGap allowedGap mipgap except UserWarning as e: error_message = str(e) compare_message = "termination condition infeasible" if compare_message in error_message: error_message = ( f"The following error occurred during the mvs solver: {error_message}\n\n " f"There are several reasons why this could have happened." "\n\t- the energy system is not properly connected. " "\n\t- the capacity of some assets might not have been optimized. " "\n\t- the demands might not be supplied with the installed capacities in " "current energy system. Check your maximum power demand and if your energy " "production assets and/or energy conversion assets have enough capacity to " "meet the total demand") logging.error(error_message) raise MVSOemofError(error_message) from None else: raise e # stop turning warnings into errors warnings.resetwarnings() # add results to the energy system to make it possible to store them. results_main = processing.results(local_energy_system) results_meta = processing.meta_results(local_energy_system) model.results["main"] = results_main model.results["meta"] = results_meta dict_values.update({ SIMULATION_RESULTS: { LABEL: SIMULATION_RESULTS, OBJECTIVE_VALUE: results_meta["objective"], SIMULTATION_TIME: round(results_meta["solver"]["Time"], 2), } }) logging.info( "Simulation time: %s minutes.", round(dict_values[SIMULATION_RESULTS][SIMULTATION_TIME] / 60, 2), ) return model, results_main, results_main
def test_lopf(solver="cbc"): logging.info("Initialize the energy system") # create time index for 192 hours in May. date_time_index = pd.date_range("5/5/2012", periods=1, freq="H") es = EnergySystem(timeindex=date_time_index) ########################################################################## # Create oemof.solph objects ########################################################################## logging.info("Create oemof.solph objects") b_el0 = custom.ElectricalBus(label="b_0", v_min=-1, v_max=1) b_el1 = custom.ElectricalBus(label="b_1", v_min=-1, v_max=1) b_el2 = custom.ElectricalBus(label="b_2", v_min=-1, v_max=1) es.add(b_el0, b_el1, b_el2) es.add( custom.ElectricalLine( input=b_el0, output=b_el1, reactance=0.0001, investment=Investment(ep_costs=10), min=-1, max=1, )) es.add( custom.ElectricalLine( input=b_el1, output=b_el2, reactance=0.0001, nominal_value=60, min=-1, max=1, )) es.add( custom.ElectricalLine( input=b_el2, output=b_el0, reactance=0.0001, nominal_value=60, min=-1, max=1, )) es.add( Source( label="gen_0", outputs={b_el0: Flow(nominal_value=100, variable_costs=50)}, )) es.add( Source( label="gen_1", outputs={b_el1: Flow(nominal_value=100, variable_costs=25)}, )) es.add(Sink( label="load", inputs={b_el2: Flow(nominal_value=100, fix=1)}, )) ########################################################################## # Optimise the energy system and plot the results ########################################################################## logging.info("Creating optimisation model") om = Model(es) logging.info("Running lopf on 3-Node exmaple system") om.solve(solver=solver) results = processing.results(om) generators = views.node_output_by_type(results, Source) generators_test_results = { (es.groups["gen_0"], es.groups["b_0"], "flow"): 20, (es.groups["gen_1"], es.groups["b_1"], "flow"): 80, } for key in generators_test_results.keys(): logging.debug("Test genertor production of {0}".format(key)) eq_( int(round(generators[key])), int(round(generators_test_results[key])), ) eq_( results[es.groups["b_2"], es.groups["b_0"]]["sequences"]["flow"][0], -40, ) eq_(results[es.groups["b_1"], es.groups["b_2"]]["sequences"]["flow"][0], 60) eq_( results[es.groups["b_0"], es.groups["b_1"]]["sequences"]["flow"][0], -20, ) # objective function eq_(round(processing.meta_results(om)["objective"]), 3200)
def setup(self): self.results = processing.results(optimization_model) self.param_results = processing.parameter_as_dict(optimization_model)
def test_dispatch_fix_example(solver='cbc', periods=10): """Invest in a flow with a `fix` sequence containing values > 1.""" Node.registry = None filename = os.path.join(os.path.dirname(__file__), 'input_data.csv') data = pd.read_csv(filename, sep=",") # ######################### create energysystem components ################ # electricity and heat bel = Bus(label='b_el') # an excess and a shortage variable can help to avoid infeasible problems excess_el = Sink(label='excess_el', inputs={bel: Flow()}) # shortage_el = Source(label='shortage_el', # outputs={bel: Flow(variable_costs=200)}) # sources ep_pv = economics.annuity(capex=1500, n=20, wacc=0.05) pv = Source(label='pv', outputs={ bel: Flow(fix=data['pv'], investment=Investment(ep_costs=ep_pv)) }) # demands (electricity/heat) demand_el = Sink( label='demand_elec', inputs={bel: Flow(nominal_value=85, fix=data['demand_el'])}) datetimeindex = pd.date_range('1/1/2012', periods=periods, freq='H') energysystem = EnergySystem(timeindex=datetimeindex) energysystem.add(bel, excess_el, pv, demand_el) # ################################ optimization ########################### # create optimization model based on energy_system optimization_model = Model(energysystem=energysystem) # solve problem optimization_model.solve(solver=solver) # ################################ results ################################ # generic result object results = processing.results(om=optimization_model) # subset of results that includes all flows into and from electrical bus # sequences are stored within a pandas.DataFrames and scalars e.g. # investment values within a pandas.Series object. # in this case the entry data['scalars'] does not exist since no investment # variables are used data = views.node(results, 'b_el') # generate results to be evaluated in tests comp_results = data['sequences'].sum(axis=0).to_dict() comp_results['pv_capacity'] = results[(pv, bel)]['scalars'].invest assert comp_results[(('pv', 'b_el'), 'flow')] > 0
def test_connect_invest(): date_time_index = pd.date_range('1/1/2012', periods=24 * 7, freq='H') energysystem = EnergySystem(timeindex=date_time_index) network.Node.registry = energysystem # Read data file full_filename = os.path.join(os.path.dirname(__file__), 'connect_invest.csv') data = pd.read_csv(full_filename, sep=",") logging.info('Create oemof objects') # create electricity bus bel1 = Bus(label="electricity1") bel2 = Bus(label="electricity2") # create excess component for the electricity bus to allow overproduction Sink(label='excess_bel', inputs={bel2: Flow()}) Source(label='shortage', outputs={bel2: Flow(variable_costs=50000)}) # create fixed source object representing wind power plants Source(label='wind', outputs={bel1: Flow(fix=data['wind'], nominal_value=1000000)}) # create simple sink object representing the electrical demand Sink(label='demand', inputs={bel1: Flow(fix=data['demand_el'], nominal_value=1)}) storage = components.GenericStorage( label='storage', inputs={bel1: Flow(variable_costs=10e10)}, outputs={bel1: 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=Investment(ep_costs=0.2), ) line12 = Transformer( label="line12", inputs={bel1: Flow()}, outputs={bel2: Flow(investment=Investment(ep_costs=20))}) line21 = Transformer( label="line21", inputs={bel2: Flow()}, outputs={bel1: Flow(investment=Investment(ep_costs=20))}) om = Model(energysystem) constraints.equate_variables(om, om.InvestmentFlow.invest[line12, bel2], om.InvestmentFlow.invest[line21, bel1], 2) constraints.equate_variables( om, om.InvestmentFlow.invest[line12, bel2], om.GenericInvestmentStorageBlock.invest[storage]) # if tee_switch is true solver messages will be displayed logging.info('Solve the optimization problem') om.solve(solver='cbc') # check if the new result object is working for custom components results = processing.results(om) my_results = dict() my_results['line12'] = float(views.node(results, 'line12')['scalars']) my_results['line21'] = float(views.node(results, 'line21')['scalars']) stor_res = views.node(results, 'storage')['scalars'] my_results['storage_in'] = stor_res[(('electricity1', 'storage'), 'invest')] my_results['storage'] = stor_res[(('storage', 'None'), 'invest')] my_results['storage_out'] = stor_res[(('storage', 'electricity1'), 'invest')] connect_invest_dict = { 'line12': 814705, 'line21': 1629410, 'storage': 814705, 'storage_in': 135784, 'storage_out': 135784 } for key in connect_invest_dict.keys(): eq_(int(round(my_results[key])), int(round(connect_invest_dict[key])))
def test_optimise_storage_size(filename="storage_investment.csv", solver='cbc'): global PP_GAS logging.info('Initialize the energy system') date_time_index = pd.date_range('1/1/2012', periods=400, freq='H') energysystem = solph.EnergySystem(timeindex=date_time_index) Node.registry = energysystem full_filename = os.path.join(os.path.dirname(__file__), filename) data = pd.read_csv(full_filename, sep=",") # Buses bgas = solph.Bus(label="natural_gas") bel = solph.Bus(label="electricity") # Sinks solph.Sink(label='excess_bel', inputs={bel: solph.Flow()}) solph.Sink( label='demand', inputs={bel: solph.Flow(fix=data['demand_el'], nominal_value=1)}) # Sources solph.Source(label='rgas', outputs={ bgas: solph.Flow(nominal_value=194397000 * 400 / 8760, summed_max=1) }) solph.Source( label='wind', outputs={bel: solph.Flow(fix=data['wind'], nominal_value=1000000)}) solph.Source( label='pv', outputs={bel: solph.Flow(fix=data['pv'], nominal_value=582000)}) # Transformer PP_GAS = solph.Transformer( label='pp_gas', inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=10e10, variable_costs=50)}, conversion_factors={bel: 0.58}) # Investment storage epc = economics.annuity(capex=1000, n=20, wacc=0.05) solph.components.GenericStorage( label='storage', 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=epc, existing=6851), ) # Solve model om = solph.Model(energysystem) om.receive_duals() om.solve(solver=solver) energysystem.results['main'] = processing.results(om) energysystem.results['meta'] = processing.meta_results(om) # Check dump and restore energysystem.dump()
def test_gen_caes(): # read sequence data full_filename = os.path.join(os.path.dirname(__file__), 'generic_caes.csv') data = pd.read_csv(full_filename) # select periods periods = len(data)-1 # create an energy system idx = pd.date_range('1/1/2017', periods=periods, freq='H') es = EnergySystem(timeindex=idx) Node.registry = es # resources bgas = Bus(label='bgas') Source(label='rgas', outputs={ bgas: Flow(variable_costs=20)}) # power bel_source = Bus(label='bel_source') Source(label='source_el', outputs={ bel_source: Flow(variable_costs=data['price_el_source'])}) bel_sink = Bus(label='bel_sink') Sink(label='sink_el', inputs={ bel_sink: Flow(variable_costs=data['price_el_sink'])}) # dictionary with parameters for a specific CAES plant # based on thermal modelling and linearization techniques concept = { 'cav_e_in_b': 0, 'cav_e_in_m': 0.6457267578, 'cav_e_out_b': 0, 'cav_e_out_m': 0.3739636077, 'cav_eta_temp': 1.0, 'cav_level_max': 211.11, 'cmp_p_max_b': 86.0918959849, 'cmp_p_max_m': 0.0679999932, 'cmp_p_min': 1, 'cmp_q_out_b': -19.3996965679, 'cmp_q_out_m': 1.1066036114, 'cmp_q_tes_share': 0, 'exp_p_max_b': 46.1294016678, 'exp_p_max_m': 0.2528340303, 'exp_p_min': 1, 'exp_q_in_b': -2.2073411014, 'exp_q_in_m': 1.129249765, 'exp_q_tes_share': 0, 'tes_eta_temp': 1.0, 'tes_level_max': 0.0 } # generic compressed air energy storage (caes) plant custom.GenericCAES( label='caes', electrical_input={bel_source: Flow()}, fuel_input={bgas: Flow()}, electrical_output={bel_sink: Flow()}, params=concept, fixed_costs=0) # create an optimization problem and solve it om = Model(es) # solve model om.solve(solver='cbc') # create result object results = processing.results(om) data = views.node( results, 'caes', keep_none_type=True )['sequences'].sum(axis=0).to_dict() test_dict = { (('caes', None), 'cav_level'): 25658.82964382, (('caes', None), 'exp_p'): 5020.801997000007, (('caes', None), 'exp_q_fuel_in'): 5170.880360999999, (('caes', None), 'tes_e_out'): 0.0, (('caes', None), 'exp_st'): 226.0, (('bgas', 'caes'), 'flow'): 5170.880360999999, (('caes', None), 'cav_e_out'): 1877.5972265299995, (('caes', None), 'exp_p_max'): 17512.352336, (('caes', None), 'cmp_q_waste'): 2499.9125993000007, (('caes', None), 'cmp_p'): 2907.7271520000004, (('caes', None), 'exp_q_add_in'): 0.0, (('caes', None), 'cmp_st'): 37.0, (('caes', None), 'cmp_q_out_sum'): 2499.9125993000007, (('caes', None), 'tes_level'): 0.0, (('caes', None), 'tes_e_in'): 0.0, (('caes', None), 'exp_q_in_sum'): 5170.880360999999, (('caes', None), 'cmp_p_max'): 22320.76334300001, (('caes', 'bel_sink'), 'flow'): 5020.801997000007, (('bel_source', 'caes'), 'flow'): 2907.7271520000004, (('caes', None), 'cav_e_in'): 1877.597226} for key in test_dict.keys(): eq_(int(round(data[key])), int(round(test_dict[key])))
def test_net_storage_flow_empty(self): results = processing.results(self.om) view = views.net_storage_flow(results, node_type=Sink) ok_(view is None) view2 = views.net_storage_flow(results, node_type=Flow) ok_(view2 is None)
def test_node_weight_by_type_empty(self): results = processing.results(self.om) view = views.node_weight_by_type(results, node_type=Flow) ok_(view is None)
def test_multiindex_sequences(self): results = processing.results(self.om) bel1 = views.node(results, 'b_el1', multiindex=True) eq_(int(bel1['sequences'][('diesel', 'b_el1', 'flow')].sum()), 2875)
def test_dispatch_one_time_step(solver='cbc'): """Create an energy system and optimize the dispatch at least costs.""" # ######################### create energysystem components ################ Node.registry = None # resource buses bgas = Bus(label='gas', balanced=False) # electricity and heat bel = Bus(label='b_el') bth = Bus(label='b_th') # an excess and a shortage variable can help to avoid infeasible problems excess_el = Sink(label='excess_el', inputs={bel: Flow()}) # sources wind = Source(label='wind', outputs={bel: Flow(fix=0.5, nominal_value=66.3)}) # demands (electricity/heat) demand_el = Sink(label='demand_elec', inputs={bel: Flow(nominal_value=85, fix=0.3)}) demand_th = Sink(label='demand_therm', inputs={bth: Flow(nominal_value=40, fix=0.2)}) # combined heat and power plant (chp) pp_chp = Transformer(label='pp_chp', inputs={bgas: Flow()}, outputs={ bel: Flow(nominal_value=30, variable_costs=42), bth: Flow(nominal_value=40) }, conversion_factors={ bel: 0.3, bth: 0.4 }) # heatpump with a coefficient of performance (COP) of 3 b_heat_source = Bus(label='b_heat_source') heat_source = Source(label='heat_source', outputs={b_heat_source: Flow()}) cop = 3 heat_pump = Transformer(label='heat_pump', inputs={ bel: Flow(), b_heat_source: Flow() }, outputs={bth: Flow(nominal_value=10)}, conversion_factors={ bel: 1 / 3, b_heat_source: (cop - 1) / cop }) energysystem = EnergySystem(timeindex=[1]) energysystem.add(bgas, bel, bth, excess_el, wind, demand_el, demand_th, pp_chp, b_heat_source, heat_source, heat_pump) # ################################ optimization ########################### # create optimization model based on energy_system optimization_model = Model(energysystem=energysystem, timeincrement=1) # solve problem optimization_model.solve(solver=solver) # write back results from optimization object to energysystem optimization_model.results() # ################################ results ################################ data = views.node(processing.results(om=optimization_model), 'b_el') # generate results to be evaluated in tests results = data['sequences'].sum(axis=0).to_dict() test_results = { (('wind', 'b_el'), 'flow'): 33, (('b_el', 'demand_elec'), 'flow'): 26, (('b_el', 'excess_el'), 'flow'): 5, (('b_el', 'heat_pump'), 'flow'): 3, } for key in test_results.keys(): eq_(int(round(results[key])), int(round(test_results[key])))
def test_error_from_nan_values(self): trsf = self.es.groups['diesel'] bus = self.es.groups['b_el1'] self.mod.flow[trsf, bus, 5] = float('nan') with assert_raises(ValueError): processing.results(self.mod)
def test_gen_chp(): # read sequence data full_filename = os.path.join(os.path.dirname(__file__), 'ccet.csv') data = pd.read_csv(full_filename) # select periods periods = len(data) - 1 # create an energy system idx = pd.date_range('1/1/2017', periods=periods, freq='H') es = solph.EnergySystem(timeindex=idx) Node.registry = es # resources bgas = solph.Bus(label='bgas') solph.Source(label='rgas', outputs={bgas: solph.Flow()}) # heat bth = solph.Bus(label='bth') solph.Source(label='source_th', outputs={bth: solph.Flow(variable_costs=1000)}) solph.Sink( label='demand_th', inputs={bth: solph.Flow(fix=data['demand_th'], nominal_value=200)}) # power bel = solph.Bus(label='bel') solph.Sink(label='demand_el', inputs={bel: solph.Flow(variable_costs=data['price_el'])}) # generic chp # (for back pressure characteristics Q_CW_min=0 and back_pressure=True) solph.components.GenericCHP( label='combined_cycle_extraction_turbine', fuel_input={ bgas: solph.Flow(H_L_FG_share_max=data['H_L_FG_share_max']) }, electrical_output={ bel: solph.Flow(P_max_woDH=data['P_max_woDH'], P_min_woDH=data['P_min_woDH'], Eta_el_max_woDH=data['Eta_el_max_woDH'], Eta_el_min_woDH=data['Eta_el_min_woDH']) }, heat_output={bth: solph.Flow(Q_CW_min=data['Q_CW_min'])}, Beta=data['Beta'], back_pressure=False) # create an optimization problem and solve it om = solph.Model(es) # solve model om.solve(solver='cbc') # create result object results = processing.results(om) data = views.node(results, 'bth')['sequences'].sum(axis=0).to_dict() test_dict = { (('bth', 'demand_th'), 'flow'): 20000.0, (('combined_cycle_extraction_turbine', 'bth'), 'flow'): 14070.15215799, (('source_th', 'bth'), 'flow'): 5929.8478649200015 } for key in test_dict.keys(): eq_(int(round(data[key])), int(round(test_dict[key])))
def test_duals(self): results = processing.results(self.om) bel = views.node(results, 'b_el1', multiindex=True) eq_(int(bel['sequences']['b_el1', 'None', 'duals'].sum()), 48)
def results(self): """ Returns a nested dictionary of the results of this optimization """ return processing.results(self)
def test_node_weight_by_type(self): results = processing.results(self.om) storage_content = views.node_weight_by_type(results, node_type=GenericStorage) eq_(round(float(storage_content.sum()), 6), 1437.500003)
) ) es.add(Sink(label="load", inputs={b_el2: Flow(nominal_value=100, fix=[1, 1])})) m = Model(energysystem=es) # m.write('lopf.lp', io_options={'symbolic_solver_labels': True}) m.solve(solver="cbc", solve_kwargs={"tee": True, "keepfiles": False}) m.results() graph = create_nx_graph(es) draw_graph( graph, plot=True, layout="neato", node_size=3000, node_color={"b_0": "#cd3333", "b_1": "#7EC0EE", "b_2": "#eeac7e"}, ) results = processing.results(m) print(views.node(results, "gen_0")) print(views.node(results, "gen_1")) print(views.node(results, "line_1"))
def test_input_by_type_view(self): results = processing.results(self.om) sink_input = views.node_input_by_type(results, node_type=Sink) compare = views.node(results, 'demand_el', multiindex=True) eq_(int(sink_input.sum()), int(compare['sequences'][('b_el2', 'demand_el', 'flow')].sum()))
def test_dispatch_example(solver='cbc', periods=24*5): """Create an energy system and optimize the dispatch at least costs.""" Node.registry = None filename = os.path.join(os.path.dirname(__file__), 'input_data.csv') data = pd.read_csv(filename, sep=",") # ######################### create energysystem components ################ # resource buses bcoal = Bus(label='coal', balanced=False) bgas = Bus(label='gas', balanced=False) boil = Bus(label='oil', balanced=False) blig = Bus(label='lignite', balanced=False) # electricity and heat bel = Bus(label='b_el') bth = Bus(label='b_th') # an excess and a shortage variable can help to avoid infeasible problems excess_el = Sink(label='excess_el', inputs={bel: Flow()}) # shortage_el = Source(label='shortage_el', # outputs={bel: Flow(variable_costs=200)}) # sources ep_wind = economics.annuity(capex=1000, n=20, wacc=0.05) wind = Source(label='wind', outputs={bel: Flow( fix=data['wind'], investment=Investment(ep_costs=ep_wind, existing=100))}) ep_pv = economics.annuity(capex=1500, n=20, wacc=0.05) pv = Source(label='pv', outputs={bel: Flow( fix=data['pv'], investment=Investment(ep_costs=ep_pv, existing=80))}) # demands (electricity/heat) demand_el = Sink(label='demand_elec', inputs={bel: Flow(nominal_value=85, fix=data['demand_el'])}) demand_th = Sink(label='demand_therm', inputs={bth: Flow(nominal_value=40, fix=data['demand_th'])}) # power plants pp_coal = Transformer(label='pp_coal', inputs={bcoal: Flow()}, outputs={bel: Flow(nominal_value=20.2, variable_costs=25)}, conversion_factors={bel: 0.39}) pp_lig = Transformer(label='pp_lig', inputs={blig: Flow()}, outputs={bel: Flow(nominal_value=11.8, variable_costs=19)}, conversion_factors={bel: 0.41}) pp_gas = Transformer(label='pp_gas', inputs={bgas: Flow()}, outputs={bel: Flow(nominal_value=41, variable_costs=40)}, conversion_factors={bel: 0.50}) pp_oil = Transformer(label='pp_oil', inputs={boil: Flow()}, outputs={bel: Flow(nominal_value=5, variable_costs=50)}, conversion_factors={bel: 0.28}) # combined heat and power plant (chp) pp_chp = Transformer(label='pp_chp', inputs={bgas: Flow()}, outputs={bel: Flow(nominal_value=30, variable_costs=42), bth: Flow(nominal_value=40)}, conversion_factors={bel: 0.3, bth: 0.4}) # heatpump with a coefficient of performance (COP) of 3 b_heat_source = Bus(label='b_heat_source') heat_source = Source(label='heat_source', outputs={b_heat_source: Flow()}) cop = 3 heat_pump = Transformer(label='el_heat_pump', inputs={bel: Flow(), b_heat_source: Flow()}, outputs={bth: Flow(nominal_value=10)}, conversion_factors={ bel: 1/3, b_heat_source: (cop-1)/cop}) datetimeindex = pd.date_range('1/1/2012', periods=periods, freq='H') energysystem = EnergySystem(timeindex=datetimeindex) energysystem.add(bcoal, bgas, boil, bel, bth, blig, excess_el, wind, pv, demand_el, demand_th, pp_coal, pp_lig, pp_oil, pp_gas, pp_chp, b_heat_source, heat_source, heat_pump) # ################################ optimization ########################### # create optimization model based on energy_system optimization_model = Model(energysystem=energysystem) # solve problem optimization_model.solve(solver=solver) # write back results from optimization object to energysystem optimization_model.results() # ################################ results ################################ # generic result object results = processing.results(om=optimization_model) # subset of results that includes all flows into and from electrical bus # sequences are stored within a pandas.DataFrames and scalars e.g. # investment values within a pandas.Series object. # in this case the entry data['scalars'] does not exist since no investment # variables are used data = views.node(results, 'b_el') # generate results to be evaluated in tests comp_results = data['sequences'].sum(axis=0).to_dict() comp_results['pv_capacity'] = results[(pv, bel)]['scalars'].invest comp_results['wind_capacity'] = results[(wind, bel)]['scalars'].invest test_results = { (('wind', 'b_el'), 'flow'): 9239, (('pv', 'b_el'), 'flow'): 1147, (('b_el', 'demand_elec'), 'flow'): 7440, (('b_el', 'excess_el'), 'flow'): 6261, (('pp_chp', 'b_el'), 'flow'): 477, (('pp_lig', 'b_el'), 'flow'): 850, (('pp_gas', 'b_el'), 'flow'): 934, (('pp_coal', 'b_el'), 'flow'): 1256, (('pp_oil', 'b_el'), 'flow'): 0, (('b_el', 'el_heat_pump'), 'flow'): 202, 'pv_capacity': 44, 'wind_capacity': 246, } for key in test_results.keys(): eq_(int(round(comp_results[key])), int(round(test_results[key])))
def test_tuples_as_labels_example(filename="storage_investment.csv", solver='cbc'): logging.info('Initialize the energy system') date_time_index = pd.date_range('1/1/2012', periods=40, freq='H') energysystem = solph.EnergySystem(timeindex=date_time_index) Node.registry = energysystem full_filename = os.path.join(os.path.dirname(__file__), filename) data = pd.read_csv(full_filename, sep=",") # Buses bgas = solph.Bus(label=Label('bus', 'natural_gas', None)) bel = solph.Bus(label=Label('bus', 'electricity', '')) # Sinks solph.Sink(label=Label('sink', 'electricity', 'excess'), inputs={bel: solph.Flow()}) solph.Sink( label=Label('sink', 'electricity', 'demand'), inputs={bel: solph.Flow(fix=data['demand_el'], nominal_value=1)}) # Sources solph.Source(label=Label('source', 'natural_gas', 'commodity'), outputs={ bgas: solph.Flow(nominal_value=194397000 * 400 / 8760, summed_max=1) }) solph.Source( label=Label('renewable', 'electricity', 'wind'), outputs={bel: solph.Flow(fix=data['wind'], nominal_value=1000000)}) solph.Source( label=Label('renewable', 'electricity', 'pv'), outputs={bel: solph.Flow( fix=data['pv'], nominal_value=582000, )}) # Transformer solph.Transformer( label=Label('pp', 'electricity', 'natural_gas'), inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=10e10, variable_costs=50)}, conversion_factors={bel: 0.58}) # Investment storage solph.components.GenericStorage( label=Label('storage', 'electricity', 'battery'), nominal_storage_capacity=204685, 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, ) # Solve model om = solph.Model(energysystem) om.solve(solver=solver) energysystem.results['main'] = processing.results(om) energysystem.results['meta'] = processing.meta_results(om) # Check dump and restore energysystem.dump() es = solph.EnergySystem() es.restore() # Results results = es.results['main'] meta = es.results['meta'] electricity_bus = views.node(results, 'bus_electricity_') my_results = electricity_bus['sequences'].sum(axis=0).to_dict() storage = es.groups['storage_electricity_battery'] storage_node = views.node(results, storage) my_results['max_load'] = storage_node['sequences'].max()[(( storage, None), 'storage_content')] commodity_bus = views.node(results, 'bus_natural_gas_None') gas_usage = commodity_bus['sequences'][(('source_natural_gas_commodity', 'bus_natural_gas_None'), 'flow')] my_results['gas_usage'] = gas_usage.sum() stor_invest_dict = { 'gas_usage': 1304112, 'max_load': 0, (('bus_electricity_', 'sink_electricity_demand'), 'flow'): 8239764, (('bus_electricity_', 'sink_electricity_excess'), 'flow'): 22036732, (('bus_electricity_', 'storage_electricity_battery'), 'flow'): 0, (('pp_electricity_natural_gas', 'bus_electricity_'), 'flow'): 756385, (('renewable_electricity_pv', 'bus_electricity_'), 'flow'): 744132, (('renewable_electricity_wind', 'bus_electricity_'), 'flow'): 28775978, (( 'storage_electricity_battery', 'bus_electricity_', ), 'flow'): 0 } for key in stor_invest_dict.keys(): eq_(int(round(my_results[key])), int(round(stor_invest_dict[key]))) # Solver results eq_(str(meta['solver']['Termination condition']), 'optimal') eq_(meta['solver']['Error rc'], 0) eq_(str(meta['solver']['Status']), 'ok') # Problem results eq_(int(meta['problem']['Lower bound']), 37819254) eq_(int(meta['problem']['Upper bound']), 37819254) eq_(meta['problem']['Number of variables'], 281) eq_(meta['problem']['Number of constraints'], 163) eq_(meta['problem']['Number of nonzeros'], 116) eq_(meta['problem']['Number of objectives'], 1) eq_(str(meta['problem']['Sense']), 'minimize') # Objective function eq_(round(meta['objective']), 37819254)