def solve_and_create_results(m, lp_write=True, gap=0.01): """ The function solves the optimization problem represented by the operational model m and returns a results table. It can also be chosen to write an lp file. :param m: operational model om.solph.model :param lp_write: write LP-file 'True' don't write LP-file 'False' boolean :param gap: allowable gap of optimization takes float values [0,1] :return: res results table pd.DataFrame """ if lp_write == True: m.write( os.path.join( 'results', 'Lifuka.lp' ), io_options={'symbolic_solver_labels': True} ) # solve with specific optimization options (passed to pyomo) logging.info( "Solve optimization problem" ) m.solve( solver='gurobi', solve_kwargs={'tee': False}, cmdline_options={'MIPGap': gap} ) # cmdline_options = {'MIPGap': 0.01} # write back results from optimization object to energysystem logging.info( 'Print results back to energysystem' ) res = processing.results( m ) return res
def solve(self, with_duals=False, tee=True, logfile=None, solver=None): logging.info("Optimising using {0}.".format(solver)) if with_duals: self.model.receive_duals() if self.debug: filename = os.path.join(helpers.extend_basic_path("lp_files"), "reegis.lp") logging.info("Store lp-file in {0}.".format(filename)) self.model.write(filename, io_options={"symbolic_solver_labels": True}) self.model.solve(solver=solver, solve_kwargs={ "tee": tee, "logfile": logfile }) self.es.results["main"] = processing.results(self.model) self.es.results["meta"] = processing.meta_results(self.model) self.es.results["param"] = processing.parameter_as_dict(self.es) self.es.results["meta"]["scenario"] = self.scenario_info(solver) self.es.results["meta"]["in_location"] = self.location self.es.results["meta"]["file_date"] = datetime.datetime.fromtimestamp( os.path.getmtime(self.location)) self.es.results["meta"]["oemof_version"] = logger.get_version() self.results = self.es.results["main"]
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 run_oemof(es, output_filename='my_dump.oemof'): print('run oemof simulation') om = solph.Model(es) om.solve(solver='cbc') print('optimization done, processing results') es.results['main'] = processing.results(om) es.results['meta'] = processing.meta_results(om) es.dump(str(Path.cwd() / 'oemof_runs' / 'results'), output_filename) print('oemof done')
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 run_oemof_sliced(es, index): print('run oemof simulation') om = solph.Model(es) om.solve(solver='cbc') es.results['main'] = processing.results(om) es.results['meta'] = processing.meta_results(om) es.dump(str(Path.cwd() / 'oemof_runs' / 'results_sliced'), f"dump_{index}.oemof") print('oemof done')
def write_results(es, m, p, **arguments): """Write results to CSV-files Parameters ---------- es : :class:`oemof.solph.network.EnergySystem` object Energy system holding nodes, grouping functions and other important information. m : A solved :class:'oemof.solph.models.Model' object for dispatch or investment optimization p: datapackage.Package instance of the input datapackage **arguments : key word arguments Arguments passed from command line """ # get the model name for processing and storing results from input dpkg modelname = p.descriptor['name'].replace(' ', '_') output_base_directory = os.path.join(arguments['--output-directory'], modelname) if not os.path.isdir(output_base_directory): os.makedirs(output_base_directory) meta_results = processing.meta_results(m) meta_results_path = os.path.join(output_base_directory, 'problem.csv') logging.info('Exporting solver information to {}'.format( os.path.abspath(meta_results_path))) pd.DataFrame({ 'objective': { modelname: meta_results['objective']}, 'solver_time': { modelname: meta_results['solver']['Time']}, 'constraints': { modelname: meta_results['problem']['Number of constraints']}, 'variables': { modelname: meta_results['problem']['Number of variables']}})\ .to_csv(meta_results_path) results = processing.results(m) _write_results = { 'default': default_results, 'component': component_results, 'bus': bus_results} \ [arguments['--output-orient']] logging.info('Exporting results to {}'.format( os.path.abspath(output_base_directory))) _write_results(es, results, path=output_base_directory, model=m) return True
def solve_and_create_results(m, lp_write=False, gap=0.01): if lp_write == True: m.write(os.path.join('results', 'Lifuka.lp'), io_options={'symbolic_solver_labels': True}) # solve with specific optimization options (passed to pyomo) logging.info("Solve optimization problem") m.solve(solver='gurobi', solve_kwargs={'tee': False}, cmdline_options={'MIPGap': gap}) # cmdline_options = {'MIPGap': 0.01} # write back results from optimization object to energysystem logging.info('Print results back to energysystem') res = processing.results(m) return res
def run_model(params, wind_invest=False, pv_invest=False, storage_invest=False): logging.info('Initialize the energy system') energysystem = solph.EnergySystem(timeindex=date_time_index) Node.registry = energysystem logging.info('Create oemof objects') bgas = solph.Bus(label="natural_gas") bel = solph.Bus(label="electricity") solph.Sink(label='excess_bel', inputs={bel: solph.Flow()}) solph.Source(label='rgas', outputs={bgas: solph.Flow(nominal_value=params['rgas_nom_val'], summed_max=1)}) solph.Source(label='wind', outputs={bel: solph.Flow( actual_value=data['wind'], nominal_value=params['wind_nom_val'], fixed=True)}) solph.Source(label='pv', outputs={bel: solph.Flow( actual_value=data['pv'], nominal_value=params['pv_nom_val'], fixed=True)}) solph.Sink(label='demand', inputs={bel: solph.Flow( actual_value=data['demand_el'], fixed=True, nominal_value=1)}) solph.Transformer( label="pp_gas", inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=10e10, variable_costs=50)}, conversion_factors={bel: 0.58}) logging.info('Optimise the energy system') om = solph.Model(energysystem) logging.info('Solve the optimization problem') om.solve(solver='cbc') energysystem.results['main'] = processing.convert_keys_to_strings(processing.results(om)) energysystem.results['param'] = processing.convert_keys_to_strings(processing.param_results(energysystem)) return energysystem, om
def test_regression_investment_storage(solver='cbc'): """The problem was infeasible if the existing capacity and the maximum was defined in the Flow. """ logging.info('Initialize the energy system') date_time_index = pd.date_range('1/1/2012', periods=4, freq='H') energysystem = solph.EnergySystem(timeindex=date_time_index) Node.registry = energysystem # Buses bgas = solph.Bus(label=('natural', 'gas')) bel = solph.Bus(label='electricity') solph.Sink(label='demand', inputs={ bel: solph.Flow(actual_value=[209643, 207497, 200108, 191892], fixed=True, nominal_value=1) }) # Sources solph.Source(label='rgas', outputs={bgas: solph.Flow()}) # Transformer solph.Transformer(label='pp_gas', inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=300000)}, conversion_factors={bel: 0.58}) # Investment storage solph.components.GenericStorage( label='storage', inputs={ bel: solph.Flow( investment=solph.Investment(existing=625046 / 6, maximum=0)) }, outputs={ bel: solph.Flow( investment=solph.Investment(existing=104174.33, maximum=1)) }, 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=50, existing=625046), ) # Solve model om = solph.Model(energysystem) om.solve(solver=solver) # Results results = processing.results(om) electricity_bus = views.node(results, 'electricity') my_results = electricity_bus['sequences'].sum(axis=0).to_dict() storage = energysystem.groups['storage'] my_results['storage_invest'] = results[(storage, None)]['scalars']['invest']
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(actual_value=data['demand_el'], fixed=True, 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(actual_value=data['wind'], nominal_value=1000000, fixed=True) }) solph.Source(label='pv', outputs={ bel: solph.Flow(actual_value=data['pv'], nominal_value=582000, fixed=True) }) # 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 setup(self): self.results = processing.results(optimization_model) self.param_results = processing.parameter_as_dict(optimization_model)
def results(self): """ Returns a nested dictionary of the results of this optimization """ result = processing.results(self) return result
def storage_example(): # read time series timeseries = pd.read_csv( os.path.join(os.path.dirname(__file__), 'storage_data.csv')) # create an energy system idx = pd.date_range('1/1/2017', periods=len(timeseries), freq='H') es = solph.EnergySystem(timeindex=idx) for data_set in DATA: name = data_set['name'] # power bus bel = solph.Bus(label='bel_{0}'.format(name)) es.add(bel) es.add( solph.Source(label='source_el_{0}'.format(name), outputs={ bel: solph.Flow(variable_costs=PARAMETER['el_price']) })) es.add( solph.Source(label='pv_el_{0}'.format(name), outputs={ bel: solph.Flow(actual_value=timeseries['pv_el'], nominal_value=1, fixed=True) })) es.add( solph.Sink(label='demand_el_{0}'.format(name), inputs={ bel: solph.Flow(actual_value=timeseries['demand_el'], nominal_value=1, fixed=True) })) es.add( solph.Sink( label='shunt_el_{0}'.format(name), inputs={bel: solph.Flow(variable_costs=PARAMETER['sh_price'])})) # Electric Storage es.add( solph.components.GenericStorage( label='storage_elec_{0}'.format(name), nominal_storage_capacity=PARAMETER['nominal_storage_capacity'], inputs={bel: solph.Flow()}, outputs={bel: solph.Flow()}, initial_storage_level=data_set['initial_storage_level'], balanced=data_set['balanced'])) # create an optimization problem and solve it om = solph.Model(es) # solve model om.solve(solver='cbc') # create result object results = processing.results(om) flows = [x for x in results if x[1] is not None] components = [x for x in results if x[1] is None] storage_cap = pd.DataFrame() costs = pd.Series() balance = pd.Series() for flow in [x for x in flows if 'source_el' in x[0].label]: name = '_'.join(flow[0].label.split('_')[2:]) print(name, float(results[flow]['sequences'].sum())) costs[name] = float(results[flow]['sequences'].sum() * PARAMETER['el_price']) for flow in [x for x in flows if 'shunt_el' in x[1].label]: name = '_'.join(flow[1].label.split('_')[2:]) costs[name] += float(results[flow]['sequences'].sum() * PARAMETER['sh_price']) storages = [x[0] for x in components if 'storage' in x[0].label] idx = results[storages[0], None]['sequences']['capacity'].index last = idx[-1] prev = idx[0] - 1 for s in storages: name = s.label storage_cap[name] = results[s, None]['sequences']['capacity'] storage_cap.loc[prev, name] = results[s, None]['scalars']['init_cap'] balance[name] = (storage_cap.loc[last][name] - storage_cap.loc[prev][name]) if plt is not None: storage_cap.plot(drawstyle="steps-mid", subplots=False, sharey=True) storage_cap.plot(drawstyle="steps-mid", subplots=True, sharey=True) costs.plot(kind='bar', ax=plt.subplots()[1]) balance.plot(kind='bar', linewidth=1, edgecolor='#000000', ax=plt.subplots()[1]) plt.show() print(storage_cap) print(costs) print(balance)
def run_smooth(model): # Run the smooth simulation framework. # Parameters: # model: smooth model object containing parameters for components, simulation and busses. """ INITIALIZATION """ # CHECK IF COMPONENT NAMES ARE UNIQUE # Check if all component names are unique, otherwise throw an error. Therefor first get all component names. comp_names = [] for this_comp in model['components']: comp_names.append(this_comp['name']) # Then check if all component names are unique. for this_comp_name in comp_names: if comp_names.count(this_comp_name) is not 1: raise ValueError( 'Component name "{}" is not unique, please name components unique.' .format(this_comp_name)) # GET SIMULATION PARAMETERS # Create an object with the simulation parameters. sim_params = sp(model['sim_params']) # CREATE COMPONENT OBJECTS components = [] for this_comp in model['components']: # Add simulation parameters to the components so they can be used this_comp['sim_params'] = sim_params # Loop through all components of the model and load the component classes. this_comp_name = this_comp['component'] # Import the module of the component. this_comp_module = importlib.import_module( 'smooth.components.component_' + this_comp_name) # While class name is camel case, underscores has to be removed and letters after underscores have to be capital class_name = '' if this_comp_name.isupper(): class_name = this_comp_name else: this_comp_name_split = this_comp_name.split('_') for this_comp_name_part in this_comp_name_split: class_name += this_comp_name_part.capitalize() # Load the class (which by convention has a name with a capital first letter and camel case). this_comp_class = getattr(this_comp_module, class_name) # Initialize the component. this_comp_obj = this_comp_class(this_comp) # Check if this component is valid. this_comp_obj.check_validity() # Add this component to the list containing all components. components.append(this_comp_obj) """ SIMULATION """ for i_interval in range(sim_params.n_intervals): # Save the interval index of this run to the sim_params to make it usable later on. sim_params.i_interval = i_interval if sim_params.print_progress: print('Simulating interval {}/{}'.format(i_interval, sim_params.n_intervals)) # Initialize the oemof energy system for this time step. this_time_index = sim_params.date_time_index[i_interval:(i_interval + 1)] oemof_model = solph.EnergySystem(timeindex=this_time_index, freq='{}min'.format( sim_params.interval_time)) """ CREATE THE OEMOF MODEL FOR THIS INTERVAL """ # Create all busses and save them to a dict for later use in the components. busses = {} for i_bus in model['busses']: # Create this bus and append it to the "busses" dict. busses[i_bus] = solph.Bus(label=i_bus) # Add the bus to the simulation model. oemof_model.add(busses[i_bus]) # Prepare the simulation. for this_comp in components: # Execute the prepare simulation step (if this component has one). this_comp.prepare_simulation(components) # Get the oemof representation of this component. this_oemof_model = this_comp.create_oemof_model( busses, oemof_model) if this_oemof_model is not None: # Add the component to the oemof model. oemof_model.add(this_oemof_model) else: # If None is given back, no model is supposed to be added. pass """ RUN THE SIMULATION """ # Do the simulation for this time step. model_to_solve = solph.Model(oemof_model) for this_comp in components: this_comp.update_constraints(busses, model_to_solve) if i_interval == 0: # Save the set of linear equations for the first interval. model_to_solve.write('./oemof_model.lp', io_options={'symbolic_solver_labels': True}) model_to_solve.solve(solver='cbc', solve_kwargs={'tee': False}) """ CHECK IF SOLVING WAS SUCCESSFUL """ # Get the meta results. # meta_results = processing.meta_results(model_to_solve) """ HANDLE RESULTS """ # Get the results of this oemof run. results = processing.results(model_to_solve) # Loop through every component and call the result handling functions for this_comp in components: # Update the flows this_comp.update_flows(results, sim_params) # Update the states. this_comp.update_states(results, sim_params) # Update the costs and artificial costs. this_comp.update_costs(results, sim_params) # Calculate the annuity for each component. for this_comp in components: this_comp.generate_results() return components
def setup(self): self.results = processing.results(optimization_model)
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(actual_value=data['demand_el'], fixed=True, 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(actual_value=data['wind'], nominal_value=1000000, fixed=True) }) solph.Source(label=Label('renewable', 'electricity', 'pv'), outputs={ bel: solph.Flow(actual_value=data['pv'], nominal_value=582000, fixed=True) }) # 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_capacity=204685, inputs={bel: solph.Flow(variable_costs=10e10)}, outputs={bel: solph.Flow(variable_costs=10e10)}, capacity_loss=0.00, initial_capacity=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), 'capacity')] 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'], 280) eq_(meta['problem']['Number of constraints'], 162) eq_(meta['problem']['Number of nonzeros'], 519) eq_(meta['problem']['Number of objectives'], 1) eq_(str(meta['problem']['Sense']), 'minimize') # Objective function eq_(round(meta['objective']), 37819254)
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') om.solve(solver='cbc', solve_kwargs={'tee': True}) ########################################################################## # Check and plot the results ########################################################################## # check if the new result object is working for custom components results = processing.results(om) custom_storage = views.node(results, 'storage') electricity_bus = views.node(results, 'electricity') meta_results = processing.meta_results(om) pp.pprint(meta_results) my_results = electricity_bus['scalars'] # installed capacity of storage in GWh my_results['storage_invest_GWh'] = ( results[(storage, None)]['scalars']['invest'] / 1e6) # resulting renewable energy share my_results['res_share'] = (1 - results[(pp_gas, bel)]['sequences'].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(actual_value=data['wind'], fixed=True, 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(actual_value=data['pv'], fixed=True, investment=Investment(ep_costs=ep_pv, existing=80)) }) # demands (electricity/heat) demand_el = Sink(label='demand_elec', inputs={ bel: Flow(nominal_value=85, actual_value=data['demand_el'], fixed=True) }) demand_th = Sink(label='demand_therm', inputs={ bth: Flow(nominal_value=40, actual_value=data['demand_th'], fixed=True) }) # 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_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)
energysystem.add( solph.Transformer(label="pp_gas", inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=200)}, conversion_factors={bel: 0.58})) # initialise the operational model model = solph.Model(energysystem) # add the emission constraint constraints.emission_limit(model, limit=100) # print out the emission constraint model.integral_limit_emission_factor_constraint.pprint() model.integral_limit_emission_factor.pprint() # solve the model model.solve() # print out the amount of emissions from the emission constraint print(model.integral_limit_emission_factor()) results = processing.results(model) if plt is not None: data = views.node(results, 'electricity')['sequences'] ax = data.plot(kind='line', grid=True) ax.set_xlabel('Time (h)') ax.set_ylabel('P (MW)') plt.show()
def run_model_dessau(config_path, results_dir): r""" Create the energy system and run the optimisation model. Parameters ---------- config_path : Path to experiment config results_dir : Directory for results Returns ------- energysystem.results : Dict containing results """ abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) with open(config_path, 'r') as ymlfile: cfg = yaml.load(ymlfile) # load input parameter in_param = pd.read_csv(os.path.join(abs_path, cfg['input_parameter']), index_col=[1, 2])['var_value'] wacc = in_param['general', 'wacc'] # load timeseries demand_heat_timeseries = pd.read_csv(os.path.join(results_dir, cfg['timeseries']['timeseries_demand_heat']), index_col=0, names=['demand_heat'], sep=',')['demand_heat'] print(demand_heat_timeseries.head()) # create timeindex if cfg['debug']: number_timesteps = 200 else: number_timesteps = 8760 date_time_index = pd.date_range('1/1/2017', periods=number_timesteps, freq='H') logging.info('Initialize the energy system') energysystem = solph.EnergySystem(timeindex=date_time_index) ##################################################################### logging.info('Create oemof objects') ##################################################################### bgas = solph.Bus(label="natural_gas", balanced=False) bel = solph.Bus(label="electricity", balanced=False) bth_prim = solph.Bus(label="heat_prim") bth_sec = solph.Bus(label="heat_sec") bth_end = solph.Bus(label="heat_end") energysystem.add(bgas, bth_prim, bth_sec, bth_end, bel) # energysystem.add(solph.Sink(label='excess_heat', # inputs={bth: solph.Flow()})) energysystem.add(solph.Source(label='shortage_heat', outputs={bth_prim: solph.Flow(variable_costs=in_param['shortage_heat','var_costs'])})) # energysystem.add(solph.Source(label='rgas', # outputs={bgas: solph.Flow( # variable_costs=0)})) if cfg['investment']['invest_chp']: energysystem.add(solph.Transformer( label='ccgt', inputs={bgas: solph.Flow(variable_costs=in_param['bgas','price_gas'])}, outputs={bth_prim: solph.Flow( investment=solph.Investment( ep_costs=economics.annuity( capex=in_param['ccgt','capex'], n=in_param['ccgt','inv_period'], wacc=wacc)), variable_costs=0)}, conversion_factors={bth_prim: 0.5})) else: energysystem.add(solph.Transformer( label='ccgt', inputs={bgas: solph.Flow(variable_costs=in_param['bgas','price_gas'])}, outputs={bth_prim: solph.Flow( nominal_value=in_param['ccgt','nominal_value'], variable_costs=0)}, conversion_factors={bth_prim: 0.5})) if cfg['investment']['invest_pth']: energysystem.add(solph.Transformer( label='power_to_heat', inputs={bel: solph.Flow(variable_costs=in_param['bel','price_el'])}, outputs={bth_prim: solph.Flow( investment=solph.Investment( ep_costs=economics.annuity( capex=in_param['power_to_heat','capex'], n=in_param['power_to_heat','inv_period'], wacc=wacc)), variable_costs=0)}, conversion_factors={bth_prim: 1})) else: energysystem.add(solph.Transformer(label='power_to_heat', inputs={bel: solph.Flow(variable_costs=in_param['bel','price_el'])}, outputs={bth_prim: solph.Flow( nominal_value=in_param['power_to_heat','nominal_value'], variable_costs=0)}, conversion_factors={bth_prim: 1})) energysystem.add(solph.Transformer( label='dhn_prim', inputs={bth_prim: solph.Flow()}, outputs={bth_sec: solph.Flow()}, conversion_factors={bth_sec: 1.})) energysystem.add(solph.Transformer( label='dhn_sec', inputs={bth_sec: solph.Flow()}, outputs={bth_end: solph.Flow()}, conversion_factors={bth_end: 1.})) energysystem.add(solph.Sink( label='demand_heat', inputs={bth_end: solph.Flow( actual_value=demand_heat_timeseries, fixed=True, nominal_value=1., summed_min=1)})) energysystem.add(solph.components.GenericStorage( label='storage_heat', nominal_capacity=in_param['storage_heat','nominal_capacity'], inputs={bth_prim: solph.Flow( variable_costs=0, nominal_value=in_param['storage_heat','input_nominal_value'])}, outputs={bth_prim: solph.Flow( nominal_value=in_param['storage_heat','output_nominal_value'])}, capacity_loss=in_param['storage_heat','capacity_loss'], initial_capacity=in_param['storage_heat','initial_capacity'], capacity_max=in_param['storage_heat','nominal_capacity'], inflow_conversion_factor=1, outflow_conversion_factor=1)) energysystem_graph = graph.create_nx_graph(energysystem) graph_file_name = os.path.join(results_dir, 'energysystem_graph.pkl') nx.readwrite.write_gpickle(G=energysystem_graph, path=graph_file_name) ##################################################################### logging.info('Solve the optimization problem') om = solph.Model(energysystem) om.solve(solver=cfg['solver'], solve_kwargs={'tee': True}) if cfg['debug']: filename = os.path.join( oemof.tools.helpers.extend_basic_path('lp_files'), 'app_district_heating.lp') logging.info('Store lp-file in {0}.'.format(filename)) om.write(filename, io_options={'symbolic_solver_labels': True}) ##################################################################### logging.info('Check the results') ##################################################################### energysystem.results['main'] = processing.results(om) energysystem.results['meta'] = processing.meta_results(om) energysystem.results['param'] = processing.parameter_as_dict(om) energysystem.dump(dpath=results_dir + '/optimisation_results', filename='es.dump') return energysystem.results
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 = solph.EnergySystem(timeindex=idx) Node.registry = es # resources bgas = solph.Bus(label='bgas') solph.Source(label='rgas', outputs={bgas: solph.Flow(variable_costs=20)}) # power bel_source = solph.Bus(label='bel_source') solph.Source(label='source_el', outputs={ bel_source: solph.Flow(variable_costs=data['price_el_source']) }) bel_sink = solph.Bus(label='bel_sink') solph.Sink( label='sink_el', inputs={bel_sink: solph.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 solph.custom.GenericCAES(label='caes', electrical_input={bel_source: solph.Flow()}, fuel_input={bgas: solph.Flow()}, electrical_output={bel_sink: solph.Flow()}, params=concept, fixed_costs=0) # 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, '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_dispatch_one_time_step(solver='cbc', periods=1): """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(actual_value=0.5, nominal_value=66.3, fixed=True)}) # demands (electricity/heat) demand_el = Sink( label='demand_elec', inputs={bel: Flow(nominal_value=85, actual_value=0.3, fixed=True)}) demand_th = Sink( label='demand_therm', inputs={bth: Flow(nominal_value=40, actual_value=0.2, fixed=True)}) # 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_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_connect_invest(): date_time_index = pd.date_range('1/1/2012', periods=24 * 7, freq='H') energysystem = solph.EnergySystem(timeindex=date_time_index) 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 = solph.Bus(label="electricity1") bel2 = solph.Bus(label="electricity2") # create excess component for the electricity bus to allow overproduction solph.Sink(label='excess_bel', inputs={bel2: solph.Flow()}) solph.Source(label='shortage', outputs={bel2: solph.Flow(variable_costs=50000)}) # create fixed source object representing wind power plants solph.Source(label='wind', outputs={ bel1: solph.Flow(actual_value=data['wind'], nominal_value=1000000, fixed=True) }) # create simple sink object representing the electrical demand solph.Sink(label='demand', inputs={ bel1: solph.Flow(actual_value=data['demand_el'], fixed=True, nominal_value=1) }) storage = solph.components.GenericStorage( label='storage', inputs={bel1: solph.Flow(variable_costs=10e10)}, outputs={bel1: solph.Flow(variable_costs=10e10)}, capacity_loss=0.00, initial_capacity=0, nominal_input_capacity_ratio=1 / 6, nominal_output_capacity_ratio=1 / 6, inflow_conversion_factor=1, outflow_conversion_factor=0.8, investment=solph.Investment(ep_costs=0.2), ) line12 = solph.Transformer( label="line12", inputs={bel1: solph.Flow()}, outputs={bel2: solph.Flow(investment=solph.Investment(ep_costs=20))}) line21 = solph.Transformer( label="line21", inputs={bel2: solph.Flow()}, outputs={bel1: solph.Flow(investment=solph.Investment(ep_costs=20))}) om = solph.Model(energysystem) solph.constraints.equate_variables(om, om.InvestmentFlow.invest[line12, bel2], om.InvestmentFlow.invest[line21, bel1], 2) solph.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.iloc[0] # ('electricity1', 'storage') my_results['storage'] = stor_res.iloc[1] # ('storage', 'None') my_results['storage_out'] = stor_res.iloc[2] # ('storage', 'electricity1') 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_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 run_model(params, wind_invest=False, pv_invest=False, storage_invest=False): logging.info('Initialize the energy system') energysystem = solph.EnergySystem(timeindex=date_time_index) Node.registry = energysystem logging.info('Create oemof objects') bgas = solph.Bus(label="natural_gas") bel = solph.Bus(label="electricity") solph.Sink(label='excess_bel', inputs={bel: solph.Flow()}) solph.Source(label='rgas', outputs={bgas: solph.Flow(nominal_value=params['rgas_nom_val'], summed_max=1)}) if wind_invest == True: solph.Source(label='wind', outputs={bel: solph.Flow( actual_value=data['wind'], fixed=True, investment=solph.Investment(ep_costs=params['epc_wind']))}) else: solph.Source(label='wind', outputs={bel: solph.Flow( actual_value=data['wind'], nominal_value=params['wind_nom_val'], fixed=True)}) if pv_invest == True: pv = solph.Source(label='pv', outputs={bel: solph.Flow( actual_value=data['pv'], fixed=True, investment=solph.Investment(ep_costs=params['epc_pv']))}) else: solph.Source(label='pv', outputs={bel: solph.Flow( actual_value=data['pv'], nominal_value=params['pv_nom_val'], fixed=True)}) solph.Sink(label='demand', inputs={bel: solph.Flow( actual_value=data['demand_el'], fixed=True, nominal_value=1)}) solph.Transformer( label="pp_gas", inputs={bgas: solph.Flow()}, outputs={bel: solph.Flow(nominal_value=10e10, variable_costs=50)}, conversion_factors={bel: 0.58}) storage = solph.components.GenericStorage( label='storage', inputs={bel: solph.Flow(variable_costs=10e10)}, outputs={bel: solph.Flow(variable_costs=10e10)}, capacity_loss=0.00, initial_capacity=0, nominal_input_capacity_ratio=1/6, nominal_output_capacity_ratio=1/6, inflow_conversion_factor=1, outflow_conversion_factor=0.8, investment=solph.Investment(ep_costs=params['epc_storage']), ) logging.info('Optimise the energy system') om = solph.Model(energysystem) test_var = 2 print(test_var) logging.info('Solve the optimization problem') om.solve(solver='cbc') string_results = processing.convert_keys_to_strings(processing.results(om)) electricity_results = views.node(string_results, 'electricity') param_dict = processing.convert_keys_to_strings(processing.parameter_as_dict(energysystem)) param_dict_scalars = {key: value['scalars'] for (key,value) in param_dict.items()} print(string_results.keys()) print(string_results[('wind','electricity')]['scalars']['invest']) print(string_results[('pv','electricity')]['scalars']['invest'])
p_max = 3000 eta = 0.95 storage = solph.components.GenericStorage( nominal_storage_capacity=4000, initial_storage_level=0.5, inflow_conversion_factor=eta, outflow_conversion_factor=eta, label='storage', inputs={b1: solph.Flow(nominal_value=p_max)}, outputs={b1: solph.Flow(nominal_value=p_max)}) es.add(storage) # solving om = solph.Model(es) logging.info('Build model') om.solve(solver='cbc') logging.info('Solved model') # debug equations should be used with 3 timesteps to have a readable file # om.write('./equations.lp', io_options={'symbolic_solver_labels': True}) es.results['main'] = processing.results(om) es.results['meta'] = processing.meta_results(om) es.dump('results', 'my_dump.oemof') plot_oemof_results(Path.cwd() / 'results', 'my_dump.oemof') plt.show()
# Adding all the components to the energy system es.add(excess_el, demand_el, el_storage, th_storage, pv, shortage_el, elbus, thbus) # Create the model for optimization and run the optimization opt_model = Model(es) opt_model.solve(solver='cbc') logging.info('Optimization successful') # Collect and plot the results results = processing.results(opt_model) results_el = views.node(results, 'electricity') meta_results = processing.meta_results(opt_model) pp.pprint(meta_results) el_sequences = results_el['sequences'] to_el = { key[0][0]: key for key in el_sequences.keys() if key[0][1] == 'electricity' and key[1] == 'flow' } to_el = [to_el.pop('pv')] + list(to_el.values()) el_prod = el_sequences[to_el]