def simulate(es=None, **arguments): """Creates the optimization model, solves it and writes back results to energy system object Parameters ---------- es : :class:`oemof.solph.network.EnergySystem` object Energy system holding nodes, grouping functions and other important information. **arguments : key word arguments Arguments passed from command line """ logging.info("Creating optimization model...") om = OperationalModel(es=es, constraint_groups=ADD_SOLPH_BLOCKS) if arguments['--loglevel'] == 'DEBUG': lppath = os.path.join(arguments['--output-directory'], 'lp-file') if not os.path.exists(lppath): os.mkdir(lppath) lpfilepath = os.path.join(lppath, ''.join([om.name, '_', es.timestamp, '.lp'])) logging.info("Writing lp-file to '{}'".format(lpfilepath)) om.write(lpfilepath, io_options={'symbolic_solver_labels': True}) logging.info('Solving optimization model...') om.solve(arguments['--solver'], solve_kwargs={'tee': arguments['--solver-output']}, cmdline_options={"mipgap": arguments.get('--mipgap', 0)}) om.results() return om
def test_bus_to_sink_outputs_in_results_dataframe(self): bus = Bus(uid="bus") source = FS(label="source", outputs={bus: Flow(nominal_value=1, actual_value=0.5, fixed=True)}) sink = Sink(label="sink", inputs={bus: Flow(nominal_value=1)}) es = self.es om = OM(es) es.results = om.results() es.results[bus][sink] = [0.7] rdf = RDF(energy_system=es) try: eq_( rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0], 0.7, "Output from bus to sink does not have the correct value.", ) except KeyError: self.failed = True if self.failed: ok_(False, "Output from bus to sink does not appear in results dataframe.") es.results[bus][bus] = [-1] rdf = RDF(energy_system=es) try: eq_( rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0], 0.7, "Output from bus to sink does not have the correct value.", ) except KeyError: self.failed = True if self.failed: ok_(False, "Output from bus (with duals) to sink " + "does not appear in results dataframe.")
def test_issue_74(self): Storage.optimization_options.update({"investment": True}) bus = Bus(uid="bus") store = Storage(uid="store", inputs=[bus], outputs=[bus], c_rate_out=0.1, c_rate_in=0.1) sink = Sink(uid="sink", inputs=[bus], val=[1]) es = self.es om = OM(es) om.objective.set_value(-1) es.results = om.results() try: es.dump() except AttributeError as ae: self.failed = ae if self.failed: ok_( False, "EnergySystem#dump should not raise `AttributeError`: \n" + " Error message: " + str(self.failed) )
def test_bus_to_sink_outputs_in_results_dataframe(self): bus = Bus(uid="bus") source = FS( label="source", outputs={bus: Flow(nominal_value=1, actual_value=0.5, fixed=True)}) sink = Sink(label="sink", inputs={bus: Flow(nominal_value=1)}) es = self.es om = OM(es) es.results = om.results() es.results[bus][sink] = [0.7] rdf = RDF(energy_system=es) try: eq_( rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0], 0.7, "Output from bus to sink does not have the correct value.") except KeyError: self.failed = True if self.failed: ok_( False, "Output from bus to sink does not appear in results dataframe." ) es.results[bus][bus] = [-1] rdf = RDF(energy_system=es) try: eq_( rdf.loc[(slice(None), slice(None), slice(None), "sink"), :].val[0], 0.7, "Output from bus to sink does not have the correct value.") except KeyError: self.failed = True if self.failed: ok_( False, "Output from bus (with duals) to sink " + "does not appear in results dataframe.")
def test_issue_74(self): Storage.optimization_options.update({'investment': True}) bus = Bus(uid="bus") store = Storage(uid="store", inputs=[bus], outputs=[bus], c_rate_out=0.1, c_rate_in=0.1) sink = Sink(uid="sink", inputs=[bus], val=[1]) es = self.es om = OM(es) om.objective.set_value(-1) es.results = om.results() try: es.dump() except AttributeError as ae: self.failed = ae if self.failed: ok_( False, "EnergySystem#dump should not raise `AttributeError`: \n" + " Error message: " + str(self.failed))
def simulate(energysystem, filename=None, solver='cbc', tee_switch=True, keep=True): """ """ if filename is None: filename = os.path.join(os.path.dirname(__file__), 'input_data.csv') logging.info("Creating objects") data = pd.read_csv(filename, sep=",") # 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 b_el = Bus(label="b_el") b_th = Bus(label="b_th") # adding an excess variable can help to avoid infeasible problems Sink(label="excess", inputs={b_el: Flow()}) # adding an excess variable can help to avoid infeasible problems # Source(label="shortage", outputs={b_el: Flow(variable_costs=200)}) # Sources Source(label="wind", outputs={ b_el: Flow(actual_value=data['wind'], nominal_value=66.3, fixed=True) }) Source(label="pv", outputs={ b_el: Flow(actual_value=data['pv'], nominal_value=65.3, fixed=True) }) # Demands (electricity/heat) Sink(label="demand_el", inputs={ b_el: Flow(nominal_value=85, actual_value=data['demand_el'], fixed=True) }) Sink(label="demand_th", inputs={ b_th: Flow(nominal_value=40, actual_value=data['demand_th'], fixed=True) }) # Power plants LinearTransformer( label='pp_coal', inputs={bcoal: Flow()}, outputs={b_el: Flow(nominal_value=20.2, variable_costs=25)}, conversion_factors={b_el: 0.39}) LinearTransformer( label='pp_lig', inputs={blig: Flow()}, outputs={b_el: Flow(nominal_value=11.8, variable_costs=19)}, conversion_factors={b_el: 0.41}) LinearTransformer( label='pp_gas', inputs={bgas: Flow()}, outputs={b_el: Flow(nominal_value=41, variable_costs=40)}, conversion_factors={b_el: 0.50}) LinearTransformer(label='pp_oil', inputs={boil: Flow()}, outputs={b_el: Flow(nominal_value=5, variable_costs=50)}, conversion_factors={b_el: 0.28}) # CHP LinearTransformer(label='pp_chp', inputs={bgas: Flow()}, outputs={ b_el: Flow(nominal_value=30, variable_costs=42), b_th: Flow(nominal_value=40) }, conversion_factors={ b_el: 0.3, b_th: 0.4 }) # Heatpump with a coefficient of performance (COP) of 3 b_heat_source = Bus(label="b_heat_source") Source(label="heat_source", outputs={b_heat_source: Flow()}) cop = 3 LinearN1Transformer(label='heat_pump', inputs={ b_el: Flow(), b_heat_source: Flow() }, outputs={b_th: Flow(nominal_value=10)}, conversion_factors={ b_el: cop, b_heat_source: cop / (cop - 1) }) # ################################ optimization ############################### # create Optimization model based on energy_system logging.info("Create optimization problem") om = OperationalModel(es=energysystem) # solve with specific optimization options (passed to pyomo) logging.info("Solve optimization problem") om.solve(solver=solver, solve_kwargs={ 'tee': tee_switch, 'keepfiles': keep }) # write back results from optimization object to energysystem om.results() return om
def simulate(folder, **kwargs): # This is how you get a scenario object from the database. # Since the iD editor prefixes element ids with their type ('r' for # relation, 'w' for way and 'n' for node), we have to strip a leading # character from the scenario id string before converting it to int. # This is what the [1:] is for. engine = db.engine(osm.configsection) Session = sessionmaker(bind=engine) session = Session() scenario = session.query( osm.Relation).filter_by(id=int(kwargs['scenario'][1:])).first() #id = 1).first() # Delete the scenario id from `kwargs` so that is doesn't show up in the # response later. del kwargs['scenario'] # Now you can access the nodes, ways and relations this scenario contains # and build oemof objects from them. I'll only show you how to access the # contents here. # These are lists with Node, Way and Relation objects. # See the .schemas.osm module for the API. elements = scenario.elements nodes = [n for n in elements if isinstance(n, osm.Node)] ways = [w for w in elements if isinstance(w, osm.Way)] relations = [r for r in elements if isinstance(r, osm.Relation)] # emission factor (hardcoded for now....) t/MWh emission_factors = { 'gas': 0.2, 'coal': 0.34, 'oil': 0.27, 'lignite': 0.4, 'waste': 0.3, 'biomass': 0, 'wind': 0, 'solar': 0 } ######################################################################### # OEMOF SOLPH ######################################################################### # We need a datetimeindex for the optimization problem / energysystem first = pd.to_datetime(scenario.tags.get('scenario_year' + '0101', '2016')) start = first + pd.DateOffset( hours=int(scenario.tags.get('start_timestep', 1)) - 1) end = first + pd.DateOffset( hours=int(scenario.tags.get('end_timestep', 8760)) - 1) datetimeindex = pd.date_range(start=start, end=end, freq='H') energy_system = EnergySystem(groupings=GROUPINGS, timeindex=datetimeindex) ## CREATE BUSES FROM RELATIONS OF TYPE "HUB RELATION" buses = {} for r in relations: if r.tags.get('type') is not None: if r.tags['type'] == 'hub_relation': name = r.tags.get('name') buses[name] = Bus(label=str(name)) buses[name].energy_sector = r.tags['energy_sector'] else: raise ValueError('Missing tag type of component with ' + 'name {0}.'.format(r.tags['name'])) ## GLOBAL FUEL BUSES FOR TRANSFORMER INPUTS (THAT ARE NOT IN RELATIONS) global_buses = {} for n in nodes: if n.tags.get('oemof_class') == 'linear_transformer': # Only create global bus if not already exist if global_buses.get(n.tags['fuel_type']) is None: global_buses[n.tags['fuel_type']] = Bus( label=n.tags['fuel_type'], balanced=False) ## Create Nodes (added automatically to energysystem) for n in nodes: # GET RELATIONS 'HUB ASSIGNMENT' FOR NODE node_bus = [ r.tags['name'] for r in n.referencing_relations if r.tags['name'] in list(buses.keys()) ] # create the variable cost timeseries if specified, otherwise use # variable costs key from tags if n.tags.get('variable_costs', 0) == 'timeseries': variable_costs = n.timeseries.get('variable_costs') if variable_costs is None: raise ValueError('No timeseries `variable cost` found for ' + 'node {0}.'.format(n.tags.get('name'))) else: variable_costs = _float(n, 'variable_costs') # CREATE SINK OBJECTS if n.tags.get('oemof_class') == 'sink': if n.tags.get('energy_amount') is None: nominal_value = None if n.timeseries.get('load_profile') is not None: raise ValueError('No enery amount has been specified' + ' but the load_profile has been set!') else: nominal_value = _float(n, 'energy_amount') # calculate actual value if n.timeseries.get('load_profile') is None: actual_value = None else: try: actual_value = [ i / sum(n.timeseries.get('load_profile')) for i in n.timeseries.get('load_profile') ] except Exception: actual_value = None s = Sink(label=n.tags['name'], inputs={ buses[node_bus[0]]: Flow(nominal_value=nominal_value, actual_value=actual_value, variable_costs=variable_costs, fixed=True) }) s.type = n.tags['type'] # CREATE SOURCE OBJECTS if n.tags.get('oemof_class') == 'source': s = Source(label=n.tags['name'], outputs={ buses[node_bus[0]]: Flow(nominal_value=_float(n, 'installed_power'), actual_value=n.timeseries['load_profile'], variable_costs=variable_costs, fixed=True) }) s.fuel_type = n.tags['fuel_type'] s.type = n.tags['type'] # CREATE TRANSFORMER OBJECTS if n.tags.get('oemof_class') == 'linear_transformer': # CREATE LINEAR TRANSFORMER if n.tags.get('type') == 'flexible_generator': ins = global_buses[n.tags['fuel_type']] outs = buses[node_bus[0]] t = LinearTransformer( label=n.tags['name'], inputs={ins: Flow(variable_costs=variable_costs)}, outputs={ outs: Flow(nominal_value=_float(n, 'installed_power')) }, conversion_factors={outs: _float(n, 'efficiency')}) # store fuel_type as attribute for identification t.fuel_type = n.tags['fuel_type'] t.type = n.tags['type'] # CREATE COMBINED HEAT AND POWER AS LINEAR TRANSFORMER if n.tags.get('type') == 'combined_flexible_generator': ins = global_buses[n.tags['fuel_type']] heat_out = [ buses[k] for k in node_bus if buses[k].energy_sector == 'heat' ][0] power_out = [ buses[k] for k in node_bus if buses[k].energy_sector == 'electricity' ][0] t = LinearTransformer( label=n.tags['name'], inputs={ins: Flow(variable_costs=variable_costs)}, outputs={ power_out: Flow(nominal_value=_float(n, 'installed_power')), heat_out: Flow() }, conversion_factors={ heat_out: _float(n, 'thermal_efficiency'), power_out: _float(n, 'electrical_efficiency') }) t.fuel_type = n.tags['fuel_type'] t.type = n.tags['type'] # CRAETE STORAGE OBJECTS if n.tags.get('oemof_class') == 'storage': # Oemof solph does not provide direct way to set power in/out of # storage hence, we need to caculate the needed ratios upfront nicr = (_float(n, 'installed_power') / _float(n, 'installed_energy')) nocr = (_float(n, 'installed_power') / _float(n, 'installed_energy')) s = Storage(label=n.tags['name'], inputs={ buses[node_bus[0]]: Flow(variable_costs=variable_costs) }, outputs={ buses[node_bus[0]]: Flow(variable_costs=variable_costs) }, nominal_capacity=_float(n, 'installed_energy'), nominal_input_capacity_ratio=nicr, nominal_output_capacity_ration=nocr) s.energy_sector = n.tags['energy_sector'] s.type = n.tags['type'] # loop over all ways to create transmission objects for w in ways: way_bus = [ r.tags['name'] for r in w.referencing_relations if r.tags['name'] in list(buses.keys()) ] if w.tags.get('oemof_class') == 'linear_transformer': # CREATE TWO TRANSFORMER OBJECTS WITH DIFFERENT DIRECTIONS IN/OUTS if w.tags.get('type') == 'transmission': # transmission lines are modelled as two transformers with # the same technical parameters ins = buses[way_bus[0]] outs = buses[way_bus[1]] # 1st transformer t1 = LinearTransformer( label=w.tags['name'] + '_1', inputs={outs: Flow()}, outputs={ ins: Flow(nominal_value=_float(w, 'installed_power')) }, conversion_factors={ins: _float(w, 'efficiency')}) t1.type = w.tags.get('type') # 2nd transformer t2 = LinearTransformer( label=w.tags['name'] + '_2', inputs={ins: Flow()}, outputs={ outs: Flow(nominal_value=_float(w, 'installed_power')) }, conversion_factors={outs: _float(w, 'efficiency')}) t2.type = w.tags.get('type') # Create optimization model, solve it, wrtie back results om = OperationalModel(es=energy_system) solver = scenario.tags.get('solver') if solver is None: solver = 'glpk' om.solve(solver=solver, solve_kwargs={'tee': True, 'keepfiles': False}) om.results() # create results dataframe based on oemof's outputlib (multiindex) esplot = output.DataFramePlot(energy_system=energy_system) # select subsets of data frame (full hub balances) and write to temp-csv csv_links = {} for b in buses.values(): subset = esplot.slice_by(bus_label=b.label, type='to_bus').unstack([0, 1, 2]) fd, temp_path = mkstemp(dir=folder, suffix='.csv') file = open(temp_path, 'w') file.write(subset.to_csv()) file.close() os.close(fd) head, tail = os.path.split(temp_path) link = "/static/" + tail # storage csv-file links in dictionary for html result page csv_links[b.label] = link ####################### CALCULATIONS FOR OUTPUT ########################### # get electical hubs production el_buses = [ b.label for b in buses.values() if b.energy_sector == 'electricity' ] components = [n for n in energy_system.nodes if not isinstance(n, Bus)] #plot_nodes = [c.label for c in components if c.type != 'transmission'] renewables = [c for c in components if isinstance(c, Source)] wind = [c.label for c in renewables if c.fuel_type == 'wind'] solar = [c.label for c in renewables if c.fuel_type == 'solar'] wind_production = esplot.slice_by(bus_label=el_buses, obj_label=wind, type='to_bus').unstack(2).sum(axis=1) wind_production.index = wind_production.index.droplevel(1) wind_production = wind_production.unstack(0) #pdb.set_trace() if not wind_production.empty: wind_production.columns = ['wind'] solar_production = esplot.slice_by(bus_label=el_buses, obj_label=solar, type='to_bus').unstack(2).sum(axis=1) solar_production.index = solar_production.index.droplevel(1) solar_production = solar_production.unstack(0) if not solar_production.empty: solar_production.columns = ['solar'] # slice fuel types, unstack components and sum components by fuel type fossil_production = esplot.slice_by(bus_label=global_buses.keys(), type='from_bus').unstack(2).sum(axis=1) # drop level 'from_bus' that all rows have anyway fossil_production.index = fossil_production.index.droplevel(1) # turn index with fuel type to columns fossil_production = fossil_production.unstack(0) all_production = pd.concat( [fossil_production, wind_production, solar_production], axis=1) all_production = all_production.resample('1D', how='sum') fossil_emissions = fossil_production.copy() #pdb.set_trace() for col in fossil_production: fossil_emissions[col] = fossil_production[col] * emission_factors[col] # sum total emissions emission = fossil_emissions.sum(axis=1) emission = emission.resample('1D', how='sum') # helpers for generating python-html ouput help_fill = ['tozeroy'] + ['tonexty'] * (len(all_production.columns) - 1) fill_dict = dict(zip(all_production.columns, help_fill)) colors = { 'gas': '#9bc8c8', 'coal': '#9b9499', 'oil': '#2e1629', 'lignite': '#c89b9b', 'waste': '#8b862a', 'biomass': '#187c66', 'wind': '#2b99ff', 'solar': '#ffc125' } p = Bar(all_production.sum() / 1e3, legend=False, title="Summend energy production", xlabel="Type", ylabel="Energy Production in GWh", width=400, height=300, palette=[colors[col] for col in all_production]) output_file(os.path.join(folder, 'all_production.html')) #show(p) e = Bar(fossil_emissions.sum(), legend=False, title="Summend CO2-emissions of production", xlabel="Type", ylabel="Energy Production in tons", width=400, height=300, palette=[colors[col] for col in all_production]) output_file(os.path.join(folder, 'emissions.html')) #show(e) plots = {'production': p, 'emissions': e} script, div = bokeh_components(plots) ########## RENDER PLOTS ################ # Define our html template for out plots template = Template('''<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>openmod.sh Scenario Results</title> {{ js_resources }} {{ css_resources }} <script src='https://cdn.plot.ly/plotly-latest.min.js'></script> </head> <body> <table> <tr> <td> <h3> Total CO2 - Emission </h3> {{ plot_div.emissions }} </td> <td> </td> <td> <h3> Total energy production </h3> {{ plot_div.production }} </td> </tr> </table> {{ plot_script }} <h3> Daily production and emissions </h3> {{ timeplot }} <h3> Download your results </h3> {{ download }} </body> </html> ''') timeplot = ( "<div id='myDiv' style='width: 800px; height: 500px;'></div>" + "<script>" + "var traces = [" + ", ".join([ "{{x: {0}, y: {1}, fill: '{fillarg}', name: '{name}'}}".format( list(range(len(all_production.index.values))), list(all_production[col].values), name=col, fillarg=fill_dict[col]) for col in all_production ]) + "];" + "function stackedArea(traces) {" + "for(var i=1; i<traces.length; i++) {" + "for(var j=0; j<(Math.min(traces[i]['y'].length, traces[i-1]['y'].length)); j++) {" + "traces[i]['y'][j] += traces[i-1]['y'][j];}}" + "return traces;}" + "var layout = {title: 'Total electricity production on all hubs'," + "xaxis: {title: 'Day of the year'}," + "yaxis : {title: 'Energy in MWh'}," + "yaxis2: {title: 'CO2-emissions in tons', " + "range: [0, {0}],".format(emission.max() * 1.1) + #"titlefont: {color: 'rgb(148, 103, 189)'}, " + #"tickfont: {color: 'rgb(148, 103, 189)'}," + "overlaying: 'y', side: 'right'}," + "legend: {x: 0, y: 1,}};" + #"var data = " + "["+",".join(["{0}".format(col) for col in subset]) + "];" "var emission = {{x: {0}, y: {1}, type: 'scatter', yaxis: 'y2', name: 'CO2-Emissions'}};" .format(list(range(len(emission.index.values))), list(emission.values)) + "data = stackedArea(traces);" + "data.push(emission);" + "Plotly.newPlot('myDiv', data, layout);" + "</script>") download = ( "<br />You can download your results below:<br /> Hub: " + "<br /> Hub: ".join( ["<a href='{1}'>{0}</a>".format(*x) for x in csv_links.items()])) resources = INLINE js_resources = resources.render_js() css_resources = resources.render_css() html = template.render(js_resources=js_resources, css_resources=css_resources, plot_script=script, plot_div=div, download=download, timeplot=timeplot) #filename = 'embed_multiple_responsive.html' #with open(filename, 'w') as f: # f.write(html) #pdb.set_trace() response = (html) return response
def simulate(energysystem, filename=None, solver='cbc', tee_switch=True, keep=True): """ """ if filename is None: filename = os.path.join(os.path.dirname(__file__), 'input_data.csv') logging.info("Creating objects") data = pd.read_csv(filename, sep=",") # 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 b_el = Bus(label="b_el") b_th = Bus(label="b_th") # adding an excess variable can help to avoid infeasible problems Sink(label="excess", inputs={b_el: Flow()}) # adding an excess variable can help to avoid infeasible problems # Source(label="shortage", outputs={b_el: Flow(variable_costs=200)}) # Sources Source(label="wind", outputs={b_el: Flow(actual_value=data['wind'], nominal_value=66.3, fixed=True)}) Source(label="pv", outputs={b_el: Flow(actual_value=data['pv'], nominal_value=65.3, fixed=True)}) # Demands (electricity/heat) Sink(label="demand_el", inputs={b_el: Flow(nominal_value=85, actual_value=data['demand_el'], fixed=True)}) Sink(label="demand_th", inputs={b_th: Flow(nominal_value=40, actual_value=data['demand_th'], fixed=True)}) # Power plants LinearTransformer(label='pp_coal', inputs={bcoal: Flow()}, outputs={b_el: Flow(nominal_value=20.2, variable_costs=25)}, conversion_factors={b_el: 0.39}) LinearTransformer(label='pp_lig', inputs={blig: Flow()}, outputs={b_el: Flow(nominal_value=11.8, variable_costs=19)}, conversion_factors={b_el: 0.41}) LinearTransformer(label='pp_gas', inputs={bgas: Flow()}, outputs={b_el: Flow(nominal_value=41, variable_costs=40)}, conversion_factors={b_el: 0.50}) LinearTransformer(label='pp_oil', inputs={boil: Flow()}, outputs={b_el: Flow(nominal_value=5, variable_costs=50)}, conversion_factors={b_el: 0.28}) # CHP LinearTransformer(label='pp_chp', inputs={bgas: Flow()}, outputs={b_el: Flow(nominal_value=30, variable_costs=42), b_th: Flow(nominal_value=40)}, conversion_factors={b_el: 0.3, b_th: 0.4}) # Heatpump with a coefficient of performance (COP) of 3 b_heat_source = Bus(label="b_heat_source") Source(label="heat_source", outputs={b_heat_source: Flow()}) cop = 3 LinearN1Transformer(label='heat_pump', inputs={b_el: Flow(), b_heat_source: Flow()}, outputs={b_th: Flow(nominal_value=10)}, conversion_factors={b_el: cop, b_heat_source: cop/(cop-1)}) # ################################ optimization ############################### # create Optimization model based on energy_system logging.info("Create optimization problem") om = OperationalModel(es=energysystem) # solve with specific optimization options (passed to pyomo) logging.info("Solve optimization problem") om.solve(solver=solver, solve_kwargs={'tee': tee_switch, 'keepfiles': keep}) # write back results from optimization object to energysystem om.results() return om