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
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 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_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)