def optimize(input_data_dir, results_data_dir, solver='cbc', debug=False): r""" Takes the specified datapackage, creates an energysystem and solves the optimization problem. """ # create energy system object logging.info("Creating EnergySystem from datapackage") es = EnergySystem.from_datapackage( os.path.join(input_data_dir, "datapackage.json"), attributemap={}, typemap=TYPEMAP, ) # create model from energy system (this is just oemof.solph) logging.info("Creating the optimization model") m = Model(es) # if you want dual variables / shadow prices uncomment line below # m.receive_duals() # save lp file together with optimization results if debug: lp_file_dir = os.path.join(results_data_dir, 'model.lp') logging.info(f"Saving the lp-file to {lp_file_dir}") m.write(lp_file_dir, io_options={'symbolic_solver_labels': True}) # select solver 'gurobi', 'cplex', 'glpk' etc logging.info(f'Solving the problem using {solver}') m.solve(solver=solver) # get the results from the the solved model(still oemof.solph) es.results = m.results() es.params = outputlib.processing.parameter_as_dict(es) # now we use the write results method to write the results in oemof-tabular # format logging.info(f'Writing the results to {results_data_dir}') es.dump(results_data_dir)
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_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])))
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, 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"))
import oemof.tabular.tools.postprocessing as pp # create path for results (we use the datapackage_dir to store results) results_path = 'results' if not os.path.exists(results_path): os.makedirs(results_path) # create energy system object es = EnergySystem.from_datapackage( os.path.join("./datapackage", "datapackage.json"), attributemap={}, typemap=TYPEMAP, ) # create model from energy system (this is just oemof.solph) m = Model(es) # if you want dual variables / shadow prices uncomment line below # m.receive_duals() # select solver 'gurobi', 'cplex', 'glpk' etc m.solve("glpk") # get the results from the the solved model(still oemof.solph) m.results = m.results() # now we use the write results method to write the results in oemof-tabular # format pp.write_results(m, results_path) print("process completed")
})) # ################################ optimization ########################### # create optimization model based on energy_system optimization_model = Model(energysystem=energysystem) # solve problem optimization_model.solve(solver=solver, solve_kwargs={ 'tee': True, 'keepfiles': False }) # write back results from optimization object to energysystem optimization_model.results() # ################################ results ################################ # 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(optimization_model.results(), 'bel') data['sequences'].info() print('Optimization successful. Showing some results:') # see: https://pandas.pydata.org/pandas-docs/stable/visualization.html node_results_bel = views.node(optimization_model.results(), 'bel') node_results_flows = node_results_bel['sequences']
)) # ################################ optimization ########################### # create optimization model based on energy_system optimization_model = Model(energysystem=energysystem) # solve problem optimization_model.solve(solver=solver, solve_kwargs={ "tee": True, "keepfiles": False }) # write back results from optimization object to energysystem optimization_model.results() # ################################ results ################################ # 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(optimization_model.results(), "bel") data["sequences"].info() print("Optimization successful. Showing some results:") # see: https://pandas.pydata.org/pandas-docs/stable/visualization.html node_results_bel = views.node(optimization_model.results(), "bel") node_results_flows = node_results_bel["sequences"]
"oemof.tabular", "examples/datapackages/{}/datapackage.json".format(example), ), attributemap={}, typemap=TYPEMAP, ) es.timeindex = es.timeindex[0:5] m = Model(es) m.solve(solver="cbc") # skip foreignkeys example as not all buses are present if example != "foreignkeys": br = pp.bus_results(es, m.results(), select="scalars") if example == "investment": br["bus0"].xs([es.groups["bus0"], "invest"], level=[1, 2]) pp.supply_results(results=m.results(), es=es, bus=["heat-bus"]) pp.supply_results(results=m.results(), es=es, bus=["bus0", "bus1"]) pp.demand_results(results=m.results(), es=es, bus=["bus0", "bus1"]) pp.component_results(results=m.results(), es=es, select="sequences") pp.component_results(results=m.results(), es=es, select="scalars") views.node_input_by_type(
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])))
here = os.path.abspath(os.path.dirname(__file__)) name = 'simple_model' preprocessed = sys.argv[1] optimized = sys.argv[2] if not os.path.exists(optimized): os.mkdir(optimized) es = EnergySystem.from_datapackage( os.path.join(preprocessed, "datapackage.json"), attributemap={}, typemap=TYPEMAP, ) # create model from energy system (this is just oemof.solph) m = Model(es) # select solver 'gurobi', 'cplex', 'glpk' etc m.solve(solver='cbc') # get the results from the the solved model(still oemof.solph) es.results = m.results() # now we use the write results method to write the results in oemoftabular # format es.dump(optimized)
"oemof.tabular", "examples/datapackages/{}/datapackage.json".format(example), ), attributemap={}, typemap=TYPEMAP, ) es.timeindex = es.timeindex[0:5] m = Model(es) m.solve(solver="cbc") # skip foreignkeys example as not all buses are present if example != "foreignkeys": br = pp.bus_results(es, m.results(), select="scalars") if example == "investment": br["bus0"].xs([es.groups["bus0"], "invest"], level=[1, 2]) pp.supply_results(results=m.results(), es=es, bus=["heat-bus"]) pp.supply_results(results=m.results(), es=es, bus=["bus0", "bus1"]) pp.demand_results(results=m.results(), es=es, bus=["bus0", "bus1"]) pp.component_results(results=m.results(), es=es, select="sequences") pp.component_results(results=m.results(), es=es, select="scalars") views.node_input_by_type(m.results(),
demand_el = Sink(label='electricity_demand', inputs={bus_el: Flow(nominal_value=2, fixed=True, actual_value=demand_ts)}) curtailment = Sink(label='curtailment', inputs={bus_el: Flow(nominal_value=5, max=pv_ts)}) es.add(bus_el, bus_gas, source_gas, gas_pp, pv, demand_el, curtailment) optimodel = Model(es) optimodel.solve() results = optimodel.results() string_results = outputlib.processing.convert_keys_to_strings(results) # collect all timeseries in a DataFrame sequences = {k: v['sequences'] for k, v in string_results.items()} sequences = pd.concat(sequences, axis=1) print(sequences) # plot idx = pd.IndexSlice fig, ax = plt.subplots() sequences.loc[:,idx[:,'electricity_bus',:]].plot.area(ax=ax, stacked=True) sequences.loc[:,idx[:,'electricity_demand',:]].plot(ax=ax, c='r')
variable_costs=10 ) } ) es.add(el_bus, demand, pp1, pp2) om = Model(es) lp_file_dir = 'dispatch.lp' om.write(lp_file_dir, io_options={'symbolic_solver_labels': True}) om.solve() results = om.results() string_results = outputlib.processing.convert_keys_to_strings(results) string_results = outputlib.processing.convert_keys_to_strings(results) # collect all timeseries in a DataFrame sequences = {k: v['sequences'] for k, v in string_results.items()} sequences = pd.concat(sequences, axis=1) print(sequences) # plot idx = pd.IndexSlice fig, ax = plt.subplots() sequences.loc[:,idx[:,'el_bus',:]].plot.area(ax=ax, stacked=True)
def compute(datapackage, solver="gurobi"): """ """ config = Scenario.from_path( os.path.join("scenarios", datapackage + ".toml") ) emission_limit = config["scenario"].get("co2_limit") temporal_resolution = config.get("model", {}).get("temporal_resolution", 1) datapackage_dir = os.path.join("datapackages", datapackage) # create results path scenario_path = os.path.join("results", datapackage) if not os.path.exists(scenario_path): os.makedirs(scenario_path) output_path = os.path.join(scenario_path, "output") if not os.path.exists(output_path): os.makedirs(output_path) # copy package either aggregated or the original one (only data!) if temporal_resolution > 1: logging.info("Aggregating for temporal aggregation ... ") path = aggregation.temporal_skip( os.path.join(datapackage_dir, "datapackage.json"), temporal_resolution, path=scenario_path, name="input", ) else: path = processing.copy_datapackage( os.path.join(datapackage_dir, "datapackage.json"), os.path.abspath(os.path.join(scenario_path, "input")), subset="data", ) es = EnergySystem.from_datapackage( os.path.join(path, "datapackage.json"), attributemap={}, typemap=facades.TYPEMAP, ) m = Model(es) if emission_limit is not None: constraints.emission_limit(m, limit=emission_limit) flows = {} for (i, o) in m.flows: if hasattr(m.flows[i, o], "emission_factor"): flows[(i, o)] = m.flows[i, o] # add emission as expression to model BUSES = [b for b in es.nodes if isinstance(b, Bus)] def emission_rule(m, b, t): expr = sum( m.flow[inflow, outflow, t] * m.timeincrement[t] * getattr(flows[inflow, outflow], "emission_factor", 0) for (inflow, outflow) in flows if outflow is b ) return expr m.emissions = Expression(BUSES, m.TIMESTEPS, rule=emission_rule) m.receive_duals() m.solve(solver) m.results = m.results() pp.write_results(m, output_path) modelstats = outputlib.processing.meta_results(m) modelstats.pop("solver") modelstats["problem"].pop("Sense") # TODO: This is not model stats -> move somewhere else! modelstats["temporal_resolution"] = temporal_resolution modelstats["emission_limit"] = emission_limit with open(os.path.join(scenario_path, "modelstats.json"), "w") as outfile: json.dump(modelstats, outfile, indent=4) supply_sum = ( pp.supply_results( results=m.results, es=m.es, bus=[b.label for b in es.nodes if isinstance(b, Bus)], types=[ "dispatchable", "volatile", "conversion", "backpressure", "extraction", # "storage", "reservoir", ], ) # .clip(0) .sum().reset_index() ) supply_sum["from"] = supply_sum.apply( lambda x: "-".join(x["from"].label.split("-")[1::]), axis=1 ) supply_sum.drop("type", axis=1, inplace=True) supply_sum = ( supply_sum.set_index(["from", "to"]).unstack("from") / 1e6 * temporal_resolution ) supply_sum.columns = supply_sum.columns.droplevel(0) summary = supply_sum # pd.concat([supply_sum, excess_share], axis=1) ## grid imports = pd.DataFrame() link_results = pp.component_results(m.es, m.results).get("link") link_results.to_csv( os.path.join(scenario_path, "output", "transmission.csv") ) for b in [b.label for b in es.nodes if isinstance(b, Bus)]: if link_results is not None and m.es.groups[b] in list( link_results.columns.levels[0] ): ex = link_results.loc[ :, (m.es.groups[b], slice(None), "flow") ].sum(axis=1) im = link_results.loc[ :, (slice(None), m.es.groups[b], "flow") ].sum(axis=1) net_import = im - ex net_import.name = m.es.groups[b] imports = pd.concat([imports, net_import], axis=1) summary["total_supply"] = summary.sum(axis=1) summary["RE-supply"] = ( summary["wind-onshore"] + summary["wind-offshore"] + summary["biomass-st"] + summary["hydro-ror"] + summary["hydro-reservoir"] + summary["solar-pv"] ) if "other-res" in summary: summary["RE-supply"] += summary["other-res"] summary["RE-share"] = summary["RE-supply"] / summary["total_supply"] summary["import"] = imports[imports > 0].sum() / 1e6 * temporal_resolution summary["export"] = imports[imports < 0].sum() / 1e6 * temporal_resolution summary.to_csv(os.path.join(scenario_path, "summary.csv")) emissions = ( pd.Series({key: value() for key, value in m.emissions.items()}) .unstack() .T ) emissions.to_csv(os.path.join(scenario_path, "emissions.csv"))