Source code for tessif.examples.data.omf.py_hard

# tessif/examples/data/omf/py_hard.py
"""
:mod:`~tessif.examples.data.omf.py_hard` is a :mod:`tessif` module for giving
examples on how to create an :class:`oemof energy system
<oemof.core.energy_system.EnergySystem>`.

It collects minimum working examples, meaningful working
examples and full fledged use case wrappers for common scenarios.
"""

# 1.) Handle imports:
# standard library
import pathlib
import os

# third party
from oemof import solph
import pandas as pd
import numpy as np

# local imports
import tessif.frused.namedtuples as nts
from tessif.frused.paths import write_dir
from tessif.frused.paths import example_dir
import tessif.simulate as optimize


[docs]def create_mwe(directory=None, filename=None): r""" Create a minimum working example using :any:`oemof`. Creates a simple energy system simulation to potentially store it on disc in :paramref:`~create_mwe.directory` as :paramref:`~create_mwe.filename` Parameters ---------- directory : str, default=None String representing of the path the created energy system is dumped to. Passed to :meth:`~oemof.core.energy_system.EnergySystem.dump`. Will be :func:`joined <os.path.join>` with :paramref:`~create_mwe.filename`. If set to ``None`` (default) :attr:`tessif.frused.paths.write_dir`/omf will be the chosen directory. filename : str, default=None :func:`~pickle.dump` the energy system using this name. If set to ``None`` (default) filename will be ``mwe.oemof``. Return ------ optimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system carrying the optimization results. Examples -------- Using :func:`create_mwe` to quickly access an optimized oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> optimized_es = omf_py.create_mwe() """ # 2.) Create a simulation time frame of 2 timesteps of hourly resolution simulation_time = pd.date_range('7/13/1990', periods=2, freq='H') # 3.) Create an energy system object: es = solph.EnergySystem(timeindex=simulation_time) # 4.) Create nodes for a simple energy system # feeding a demand with conventional source and a renewable source # (Using namedtuples to store location (latt/long) region, carrier and # sector categorization as all oemof simulations do in this framework) # 4.1) Power Line power_line = solph.Bus( label=nts.Uid('Power Line', 53, 10, 'Germany', 'Power', 'Electricity', 'bus')) # 4.2) Demand needing 10 energy units demand = solph.Sink( label=nts.Uid('Demand', 53, 10, 'Germany', 'Power', 'Electricity', 'sink'), inputs={power_line: solph.Flow(nominal_value=10, fix=[1, 1])}) # 4.3) Renewable source producing 8 and 2 energy units with a cost of 9 renewable = solph.Source( label=nts.Uid('Renewable', 53, 10, 'Germany', 'Power', 'Electricity', 'source'), outputs={power_line: solph.Flow( nominal_value=10, fix=[0.8, 0.2], variable_costs=9)}) # 4.4) Chemically Bound Energy Transport cbet = solph.Bus( label=nts.Uid('CBET', 53, 10, 'Germany', 'Power', 'Electricity', 'bus')) # 4.5) Chemically Bound Energy Source cbe = solph.Source( label=nts.Uid('CBE', 53, 10, 'Germany', 'Power', 'Electricity', 'source'), outputs={cbet: solph.Flow()}) # 4.6) Conventional Engergy Transformer # producing up to 10 energy units for a cost of 10 conventional = solph.Transformer( label=nts.Uid('Transformer', 53, 10, 'Germany', 'Power', 'Electricity', 'transformer'), inputs={cbet: solph.Flow()}, outputs={power_line: solph.Flow(nominal_value=10, variable_costs=10)}, conversion_factors={power_line: 0.6}) # 5.) Adding nodes to energy system es.add(power_line, demand, renewable, cbet, cbe, conventional) # 6.) Create an energy system model esm = solph.Model(es) # 7.) Optimize model: esm.solve(solver='glpk') # 8.) Pump results into the energy system object to utilize its dump # functionality for saving the data es.results['main'] = solph.processing.results(esm) es.results['meta'] = solph.processing.meta_results(esm) # 9.) Store result pumped energy system: # Set default diretory if necessary if not directory: d = os.path.join(write_dir, 'omf') else: d = directory # create output directory if necessary pathlib.Path(os.path.abspath(d)).mkdir( parents=True, exist_ok=True) # Set default filename if necessary, using the isoformat if not filename: f = 'mwe.oemof' else: f = filename es.dump(dpath=d, filename=f) # 10.) Return the mwe oemof energy system return es
[docs]def create_star(directory=None, filename=None): r""" Create a star like energy system using the :any:`oemof` library. Creates a simple energy system simulation to potentially store it on disc in :paramref:`~create_mwe.directory` as :paramref:`~create_mwe.filename`. Usefull for testing behaviour of nodes with more than 1 inflow **and** outflow. Parameters ---------- directory : str, default=None String representing of the path the created energy system is dumped to. Passed to :meth:`~oemof.core.energy_system.EnergySystem.dump`. Will be :func:`joined <os.path.join>` with :paramref:`~create_mwe.filename`. If set to ``None`` (default) :attr:`tessif.frused.paths.write_dir`/omf will be the chosen directory. filename : str, default=None :func:`~pickle.dump` the energy system using this name. If set to ``None`` (default) filename will be ``star.oemof``. Return ------ optimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system carrying the optimization results. Examples -------- Using :func:`create_star` to quickly access an optimized oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> optimized_es = omf_py.create_star() """ # 2.) Create a simulation time frame of 2 timesteps of hourly resolution simulation_time = pd.date_range('7/13/1990', periods=2, freq='H') # 3.) Create an energy system object: es = solph.EnergySystem(timeindex=simulation_time) # 4.) Create nodes for a simple energy system # feeding a demand with conventional source and a renewable source # (Using namedtuples to store location (latt/long) region, carrier and # sector categorization as all oemof simulations do in this framework) # 4.1) Power Line power_line = solph.Bus( label=nts.Uid('Power Line', 53, 10, 'Germany', 'Power', 'Electricity', 'bus')) # 4.2) Demand needing 13 energy units demand13 = solph.Sink( label=nts.Uid('Demand13', 53, 10, 'Germany', 'Power', 'Electricity', 'sink'), inputs={power_line: solph.Flow( nominal_value=10, fix=[1, 1], emissions=2)}) # 4.3) Demand needing 7 energy units demand7 = solph.Sink( label=nts.Uid('Demand7', 53, 10, 'Germany', 'Power', 'Electricity', 'sink'), inputs={power_line: solph.Flow( nominal_value=7, fix=[1, 1], emissions=1)}) # 4.2) Demand needing 90 energy units demand90 = solph.Sink( label=nts.Uid('Demand90', 53, 10, 'Germany', 'Power', 'Electricity', 'sink'), inputs={power_line: solph.Flow( nominal_value=90, fix=[1, 1], emissions=3)}) # 3.4) Endless energy source ulp = solph.Source( label=nts.Uid('Unlimited Power', 53, 10, 'Germany', 'Power', 'Electricity', 'source'), outputs={power_line: solph.Flow(variable_costs=2, emissions=1)}) # 3.4) Depletive energy source lp = solph.Source( label=nts.Uid('Limited Power', 53, 10, 'Germany', 'Power', 'Electricity', 'source'), outputs={power_line: solph.Flow( nominal_value=20, fix=[1, 0.5], variable_costs=1, emissions=0.5)}) # 5.) Adding nodes to energy system es.add(power_line, demand13, demand7, demand90, ulp, lp) # # 6.) Create an energy system model # esm = solph.Model(es) # # 7.) Optimize model: # esm.solve(solver='glpk') # # 8.) Pump results into the energy system object to utilize its dump # # functionality for saving the data # es.results['main'] = solph.processing.results(esm) # es.results['meta'] = solph.processing.meta_results(esm) es = optimize.omf_from_es(es) # 9.) Store result pumped energy system: # Set default diretory if necessary if not directory: d = os.path.join(write_dir, 'omf') else: d = directory # create output directory if necessary pathlib.Path(os.path.abspath(d)).mkdir( parents=True, exist_ok=True) # Set default filename if necessary, using the isoformat if not filename: f = 'star.oemof' else: f = filename es.dump(dpath=d, filename=f) # 10.) Return the mwe oemof energy system return es
[docs]def emission_objective(directory=None, filename=None): r""" Create a small working example using :any:`oemof`. Optimizing it for costs and keeping the total emissions below an emission objective. Creates a simple energy system simulation to potentially store it on disc in :paramref:`~emission_objective.directory` as :paramref:`~emission_objective.filename` Parameters ---------- directory : str, default=None String representing of the path the created energy system is dumped to. Passed to :meth:`~oemof.core.energy_system.EnergySystem.dump`. Will be :func:`joined <os.path.join>` with :paramref:`~emission_objective.filename`. If set to ``None`` (default) :attr:`tessif.frused.paths.write_dir`/omf will be the chosen directory. filename : str, default=None :func:`~pickle.dump` the energy system using this name. If set to ``None`` (default) filename will be ``mwe.oemof``. Return ------ optimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system carrying the optimization results. Examples -------- Using :func:`emission_objective` to quickly access an optimized oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation on how to create an oemof minimum working example see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> optimized_es = omf_py.emission_objective() Conduct the post processing: >>> import tessif.transform.es2mapping.omf as post_process_oemof >>> global_resultier = post_process_oemof.IntegratedGlobalResultier( ... optimized_es) >>> load_resultier = post_process_oemof.LoadResultier(optimized_es) And access some post processed results: >>> import pprint >>> pprint.pprint(global_resultier.global_results) {'capex (ppcd)': 0.0, 'costs (sim)': 110.0, 'emissions (sim)': 30.0, 'opex (ppcd)': 110.0} >>> for load_results in load_resultier.node_load.values(): ... print(load_results) Power Line Renewable Transformer Demand 1990-07-13 00:00:00 -0.0 -10.0 10.0 1990-07-13 01:00:00 -0.0 -10.0 10.0 1990-07-13 02:00:00 -0.0 -10.0 10.0 1990-07-13 03:00:00 -10.0 -0.0 10.0 Demand Power Line 1990-07-13 00:00:00 -10.0 1990-07-13 01:00:00 -10.0 1990-07-13 02:00:00 -10.0 1990-07-13 03:00:00 -10.0 Renewable Power Line 1990-07-13 00:00:00 0.0 1990-07-13 01:00:00 0.0 1990-07-13 02:00:00 0.0 1990-07-13 03:00:00 10.0 CBET CBE Transformer 1990-07-13 00:00:00 -23.809524 23.809524 1990-07-13 01:00:00 -23.809524 23.809524 1990-07-13 02:00:00 -23.809524 23.809524 1990-07-13 03:00:00 -0.000000 0.000000 CBE CBET 1990-07-13 00:00:00 23.809524 1990-07-13 01:00:00 23.809524 1990-07-13 02:00:00 23.809524 1990-07-13 03:00:00 0.000000 Transformer CBET Power Line 1990-07-13 00:00:00 -23.809524 10.0 1990-07-13 01:00:00 -23.809524 10.0 1990-07-13 02:00:00 -23.809524 10.0 1990-07-13 03:00:00 -0.000000 0.0 See user's guide on :ref:`Secondary_Objectives` for more on this example. """ # 2.) Create a simulation time frame of four timesteps of hourly resolution timeframe = pd.date_range('7/13/1990', periods=4, freq='H') # 3.) Create an energy system object: es = solph.EnergySystem(timeindex=timeframe) # 4.) Create nodes for a simple energy system # feeding a demand with conventional source and a renewable source # (Using namedtuples to store location (latt/long) region, carrier and # sector categorization as all oemof simulations do in this framework) # 4.1) Power Line power_line = solph.Bus( label=nts.Uid('Power Line', 53, 10, 'Germany', 'Power', 'Electricity', 'Bus', 'Powerline')) # 4.2) Demand needing 10 energy units per time step demand = solph.Sink( label=nts.Uid('Demand', 53, 10, 'Germany', 'Power', 'Electricity', 'Sink', 'Demand'), inputs={power_line: solph.Flow(nominal_value=10, fix=[1, 1, 1, 1])}) # 4.3) Renewable power is more expensive but has no emissions allocated renewable = solph.Source( label=nts.Uid('Renewable', 53, 10, 'Germany', 'Power', 'Electricity', 'source', 'Renewable'), outputs={power_line: solph.Flow( variable_costs=5)}) # 4.4) Chemically Bound Energy Transport cbet = solph.Bus( label=nts.Uid('CBET', 53, 10, 'Germany', 'Power', 'Electricity', 'Bus', 'Pipeline')) # 3.4) Chemically Bound Energy Source cbe = solph.Source( label=nts.Uid('CBE', 53, 10, 'Germany', 'Power', 'Electricity', 'Source', 'Gas'), outputs={cbet: solph.Flow()}) # 4.5) Conventional power supply is cheaper but has emissions allocated conventional = solph.Transformer( label=nts.Uid('Transformer', 53, 10, 'Germany', 'Power', 'Electricity', 'Transformer', 'Gas Power Plant'), inputs={cbet: solph.Flow()}, outputs={power_line: solph.Flow(variable_costs=2, emissions=1)}, conversion_factors={power_line: 0.42}) # 5.) Adding nodes to energy system es.add(power_line, demand, renewable, cbet, cbe, conventional) # 6.) Create an energy system model esm = solph.Model(es) # 7.) Add an emisions limit of 30 units in total esm = solph.constraints.generic_integral_limit( om=esm, keyword='emissions', limit=30) # 8.) Optimize model: esm.solve(solver='glpk') # 9.) Pump results into the energy system object to utilize its dump # functionality for saving the data es.results['main'] = solph.processing.results(esm) es.results['meta'] = solph.processing.meta_results(esm) es.results['global'] = { 'emissions': esm.integral_limit_emissions(), 'costs': es.results['meta']['objective'], } # 10.) Store result pumped energy system: # Set default diretory if necessary if not directory: d = os.path.join(write_dir, 'omf') else: d = directory # create output directory if necessary pathlib.Path(os.path.abspath(d)).mkdir( parents=True, exist_ok=True) # Set default filename if necessary, using the isoformat if not filename: f = 'emission_objective.oemof' else: f = filename es.dump(dpath=d, filename=f) # 10.) Return the mwe oemof energy system return es
[docs]def undeclared_emission_objective(): r""" Create a minimum working example using :any:`oemof`. Optimizing it for costs and keeping the total emissions below an emission objective. This energy system however however does not store the emission results back into the actual energy system (compared to :meth:`emission_objective`). Designed to test out the automated post processing of global constraints using :func:`tessif.simualte.omf_from_es`. Return ------ unoptimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system on which no simulation/optimization has been performed Examples -------- Using :func:`emission_objective` to quickly access an **unoptimized** oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation on how to create an oemof minimum working example see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> unoptimized_es = omf_py.undeclared_emission_objective() >>> print(hasattr(unoptimized_es, 'global_constraints')) False Conduct the simulation: >>> import tessif.simulate as simulate >>> optimized_es = simulate.omf_from_es(unoptimized_es) And the post processing: >>> import tessif.transform.es2mapping.omf as post_process_oemof >>> global_resultier = post_process_oemof.IntegratedGlobalResultier( ... optimized_es) >>> import pprint >>> pprint.pprint(global_resultier.global_results) {'capex (ppcd)': 0.0, 'costs (sim)': 80.0, 'emissions (sim)': 40.0, 'opex (ppcd)': 80.0} Note how their are no emisison results, since the emission objective was not declared for tessif to understand it. """ # 2.) Create a simulation time frame of four timesteps of hourly resolution timeframe = pd.date_range('7/13/1990', periods=4, freq='H') # 3.) Create an energy system object: es = solph.EnergySystem(timeindex=timeframe) # 4.) Create nodes for a simple energy system # feeding a demand with conventional source and a renewable source # (Using namedtuples to store location (latt/long) region, carrier and # sector categorization as all oemof simulations do in this framework) # 4.1) Power Line power_line = solph.Bus( label=nts.Uid('Power Line', 53, 10, 'Germany', 'Power', 'Electricity', 'Bus', 'Powerline')) # 4.2) Demand needing 10 energy units per time step demand = solph.Sink( label=nts.Uid('Demand', 53, 10, 'Germany', 'Power', 'Electricity', 'Sink', 'Demand'), inputs={power_line: solph.Flow(nominal_value=10, fix=[1, 1, 1, 1])}) # 4.3) Renewable power is more expensive but has no emissions allocated renewable = solph.Source( label=nts.Uid('Renewable', 53, 10, 'Germany', 'Power', 'Electricity', 'source', 'Renewable'), outputs={power_line: solph.Flow( variable_costs=5)}) # 4.4) Chemically Bound Energy Transport cbet = solph.Bus( label=nts.Uid('CBET', 53, 10, 'Germany', 'Power', 'Electricity', 'Bus', 'Pipeline')) # 3.4) Chemically Bound Energy Source cbe = solph.Source( label=nts.Uid('CBE', 53, 10, 'Germany', 'Power', 'Electricity', 'Source', 'Gas'), outputs={cbet: solph.Flow()}) # 4.5) Conventional power supply is cheaper but has emissions allocated conventional = solph.Transformer( label=nts.Uid('Transformer', 53, 10, 'Germany', 'Power', 'Electricity', 'Transformer', 'Gas Power Plant'), inputs={cbet: solph.Flow()}, outputs={power_line: solph.Flow(variable_costs=2, emissions=1)}, conversion_factors={power_line: 0.42}) # 5.) Adding nodes to energy system es.add(power_line, demand, renewable, cbet, cbe, conventional) # 10.) Return the unoptimized oemof energy system return es
[docs]def create_commitment_scenario(periods=3, directory=None, filename=None): """ Create a model of a generic component based energy system using :any:`oemof`. Parameters ---------- periods : int, default=3 Number of time steps of the evaluated timeframe (one time step is one hour) directory : str, default=None String representing of the path the created energy system is dumped to. Passed to :meth:`~oemof.core.energy_system.EnergySystem.dump`. Will be :func:`joined <os.path.join>` with :paramref:`~create_commitment_scenario.filename`. If set to ``None`` (default) :attr:`tessif.frused.paths.write_dir`/omf will be the chosen directory. filename : str, default=None :func:`~pickle.dump` the energy system using this name. If set to ``None`` (default) filename will be ``commitment_scenario.oemof``. Return ------ optimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system carrying the optimization results. Examples -------- Using :func:`create_commitment_scenario` to quickly access an optimized oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> optimized_es = omf_py.create_commitment_scenario() """ # Create a simulation time frame timeframe = pd.date_range( '1/1/2019', periods=periods, freq='H') # month/day/year # Create an energy system object my_energysystem = solph.EnergySystem(timeindex=timeframe) # create busses and add them to the energy system lignite_bus = solph.Bus('lignite') hard_coal_bus = solph.Bus(label='hard_coal') biogas_bus = solph.Bus(label='biogas') gas_bus = solph.Bus(label='gas') electricity_bus = solph.Bus(label='electricity') heat_bus = solph.Bus(label='hot_water') my_energysystem.add(lignite_bus, hard_coal_bus, biogas_bus, gas_bus, electricity_bus, heat_bus) # add prerequisites for sinks csv_data = pd.read_csv(os.path.join(example_dir, 'data', 'tsf', 'load_profiles', 'component_scenario_profiles.csv'), index_col=0, sep=';') # electricity demand: el_demand = csv_data['el_demand'].values.flatten()[0:periods] max_el = np.max(el_demand) for i in range(0, periods): el_demand[i] = el_demand[i]/max_el # heat demand: th_demand = csv_data['th_demand'].values.flatten()[0:periods] max_th = np.max(th_demand) for i in range(0, periods): th_demand[i] = th_demand[i]/max_th # create sinks and add them to the energy system electricity_demand = solph.Sink(label='electricity_demand', inputs={electricity_bus: solph.Flow( fix=el_demand, nominal_value=max_el)}) heat_demand = solph.Sink(label='thermal_demand', inputs={heat_bus: solph.Flow( fix=th_demand, nominal_value=max_th)}) my_energysystem.add(electricity_demand, heat_demand) # create fossil sources gas_source = solph.Source( label='gas_supply', outputs={gas_bus: solph.Flow()}) lignite_source = solph.Source( label='lignite_supply', outputs={lignite_bus: solph.Flow()}) hard_coal_source = solph.Source( label='hard_coal_supply', outputs={hard_coal_bus: solph.Flow()}) biogas_source = solph.Source( label='biogas_supply', outputs={biogas_bus: solph.Flow()}) # add prerequisite for fluctuating sources # solar: series_pv = csv_data['pv'].values.flatten()[0:periods] # wind onshore: series_wind_onshore = csv_data['wind_on'].values.flatten()[0:periods] # wind offshore: series_wind_offshore = csv_data['wind_off'].values.flatten()[0:periods] # create fluctuating sources and add all sources to energy system wind_off_source = solph.Source(label='wind_off', outputs={electricity_bus: solph.Flow( max=series_wind_offshore, nominal_value=150, variable_costs=105, emission_factor=0.02)}) wind_on_source = solph.Source(label='wind_on', outputs={electricity_bus: solph.Flow( max=series_wind_onshore, nominal_value=1100, variable_costs=60, emission_factor=0.02)}) pv_source = solph.Source(label='pv', outputs={electricity_bus: solph.Flow( max=series_pv, nominal_value=1100, variable_costs=80, emission_factor=0.05)}) my_energysystem.add(gas_source, lignite_source, biogas_source, hard_coal_source, wind_on_source, wind_off_source, pv_source) # create transformers gas_pp = solph.Transformer( label="pp_gas", inputs={gas_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow( nominal_value=600, variable_costs=90, emission_factor=0.35)}, conversion_factors={electricity_bus: 0.6}) lignite_pp = solph.Transformer( label="pp_lignite", inputs={lignite_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow( nominal_value=500, variable_costs=65, emission_factor=1)}, conversion_factors={electricity_bus: 0.4}) hard_coal_pp = solph.Transformer( label="pp_hard_coal", inputs={hard_coal_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow( nominal_value=500, variable_costs=80, emission_factor=0.8)}, conversion_factors={electricity_bus: 0.43}) hard_coal_chp = solph.Transformer( label='chp_hard_coal', inputs={hard_coal_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(nominal_value=300, variable_costs=80, emission_factor=0.8), heat_bus: solph.Flow(nominal_value=300, variable_costs=6, emission_factor=0.06)}, conversion_factors={electricity_bus: 0.4, heat_bus: 0.4}) biogas_chp = solph.Transformer( label='chp_biogas', inputs={biogas_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(nominal_value=200, variable_costs=150, emission_factor=0.25), heat_bus: solph.Flow(nominal_value=250, variable_costs=11.25, emission_factor=0.01875)}, conversion_factors={electricity_bus: 0.4, heat_bus: 0.5}) heat_plant = solph.Transformer( label="heat_plant", inputs={gas_bus: solph.Flow()}, outputs={heat_bus: solph.Flow( nominal_value=450, variable_costs=35, emission_factor=0.23)}, conversion_factors={heat_bus: 0.9}) p2h = solph.Transformer( label="p2h", inputs={electricity_bus: solph.Flow()}, outputs={heat_bus: solph.Flow( nominal_value=100, variable_costs=20, emission_factor=0.0007)}, conversion_factors={heat_bus: 0.99}) # create storages battery = solph.GenericStorage( label='battery', inputs={electricity_bus: solph.Flow( nominal_value=33, variable_costs=0)}, outputs={electricity_bus: solph.Flow( nominal_value=33, variable_costs=400, emission_factor=0.06)}, loss_rate=0.005, nominal_storage_capacity=100, initial_storage_level=0, balanced=False, inflow_conversion_factor=0.95, outflow_conversion_factor=0.95) heat_storage = solph.GenericStorage( label='heat_storage', inputs={heat_bus: solph.Flow(nominal_value=10, variable_costs=0)}, outputs={heat_bus: solph.Flow(nominal_value=10, variable_costs=20)}, loss_rate=0.005, nominal_storage_capacity=50, initial_storage_level=0, balanced=False, inflow_conversion_factor=0.95, outflow_conversion_factor=0.95) # add transformers and storages to energy system my_energysystem.add(lignite_pp, hard_coal_pp, gas_pp, heat_plant, p2h, hard_coal_chp, biogas_chp, battery, heat_storage) # Create an energy system model esm = solph.Model(my_energysystem) # create emission constraint so oemof aknowledges the emissions and returns them esm = solph.constraints.generic_integral_limit( om=esm, keyword='emission_factor', limit=float('+inf')) # Optimize model: esm.solve(solver='cbc') # Pump results into the energy system object to utilize its dump # functionality for saving the data my_energysystem.results['main'] = solph.processing.results(esm) my_energysystem.results['meta'] = solph.processing.meta_results(esm) my_energysystem.results['global'] = { 'emissions': esm.integral_limit_emission_factor(), 'costs': my_energysystem.results['meta']['objective'], } # Store result pumped energy system: if not filename: filename = 'commitment_es.oemof' my_energysystem.dump(dpath=directory, filename=filename) return my_energysystem
[docs]def create_expansion_scenario(periods=3, directory=None, filename=None): """ Create a model of a generic component based energy system using :any:`oemof`. Basically the same energy system as :func:`create_commitment_scenario` but with expansions and emission constraint. Parameters ---------- periods : int, default=3 Number of time steps of the evaluated timeframe (one time step is one hour) directory : str, default=None String representing of the path the created energy system is dumped to. Passed to :meth:`~oemof.core.energy_system.EnergySystem.dump`. Will be :func:`joined <os.path.join>` with :paramref:`~create_expansion_scenario.filename`. If set to ``None`` (default) :attr:`tessif.frused.paths.write_dir`/omf will be the chosen directory. filename : str, default=None :func:`~pickle.dump` the energy system using this name. If set to ``None`` (default) filename will be ``expansion_scenario.oemof``. Return ------ optimized_es : :class:`~oemof.core.energy_system.EnergySystem` Energy system carrying the optimization results. Examples -------- Using :func:`create_expansion_scenario` to quickly access an optimized oemof energy system to use for doctesting, or trying out this frameworks utilities. (For a step by step explanation see :ref:`Models_Oemof_Examples_Mwe`): >>> import tessif.examples.data.omf.py_hard as omf_py >>> optimized_es = omf_py.create_expansion_scenario() """ # Create a simulation time frame timeframe = pd.date_range( '1/1/2019', periods=periods, freq='H') # month/day/year # Create an energy system object my_energysystem = solph.EnergySystem(timeindex=timeframe) # create busses and add them to the energy system lignite_bus = solph.Bus(label='lignite') hard_coal_bus = solph.Bus(label='hard_coal') biogas_bus = solph.Bus(label='biogas') gas_bus = solph.Bus(label='gas') electricity_bus = solph.Bus(label='electricity') heat_bus = solph.Bus(label='hot_water') my_energysystem.add(lignite_bus, hard_coal_bus, biogas_bus, gas_bus, electricity_bus, heat_bus) # add prerequisites for sinks csv_data = pd.read_csv(os.path.join(example_dir, 'data', 'tsf', 'load_profiles', 'component_scenario_profiles.csv'), index_col=0, sep=';') # electricity demand: el_demand = csv_data['el_demand'].values.flatten()[0:periods] max_el = np.max(el_demand) for i in range(0, periods): el_demand[i] = el_demand[i]/max_el # heat demand: th_demand = csv_data['th_demand'].values.flatten()[0:periods] max_th = np.max(th_demand) for i in range(0, periods): th_demand[i] = th_demand[i]/max_th # create sinks and add them to the energy system electricity_demand = solph.Sink(label='electricity_demand', inputs={electricity_bus: solph.Flow( fix=el_demand, nominal_value=max_el)}) heat_demand = solph.Sink(label='thermal_demand', inputs={heat_bus: solph.Flow( fix=th_demand, nominal_value=max_th)}) my_energysystem.add(electricity_demand, heat_demand) # create fossil sources gas_source = solph.Source( label='gas_supply', outputs={gas_bus: solph.Flow()}) lignite_source = solph.Source( label='lignite_supply', outputs={lignite_bus: solph.Flow()}) hard_coal_source = solph.Source( label='hard_coal_supply', outputs={hard_coal_bus: solph.Flow()}) biogas_source = solph.Source( label='biogas_supply', outputs={biogas_bus: solph.Flow()}) # create fluctuating sources and add all sources to energy system # solar: series_pv = csv_data['pv'].values.flatten()[0:periods] pv_source = solph.Source(label='pv', outputs={electricity_bus: solph.Flow( max=series_pv, variable_costs=80, emission_factor=0.05, investment=solph.Investment(maximum=None, minimum=0, ep_costs=1000000, existing=1100))}) # wind onshore: series_wind_onshore = csv_data['wind_on'].values.flatten()[0:periods] wind_on_source = solph.Source(label='wind_on', outputs={electricity_bus: solph.Flow( max=series_wind_onshore, variable_costs=60, emission_factor=0.02, investment=solph.Investment(maximum=None, minimum=0, ep_costs=1750000, existing=1100))}) # wind offshore: series_wind_offshore = csv_data['wind_off'].values.flatten()[0:periods] wind_off_source = solph.Source(label='wind_off', outputs={electricity_bus: solph.Flow( max=series_wind_offshore, variable_costs=105, emission_factor=0.02, investment=solph.Investment(maximum=None, minimum=0, ep_costs=3900000, existing=150))}) # add all sources to energy system my_energysystem.add(gas_source, lignite_source, biogas_source, hard_coal_source, wind_on_source, wind_off_source, pv_source) # create transformers gas_pp = solph.Transformer( label="pp_gas", inputs={gas_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(variable_costs=90, emission_factor=0.35, investment=solph.Investment( maximum=None, minimum=0, ep_costs=950000, existing=600))}, conversion_factors={electricity_bus: 0.6}) lignite_pp = solph.Transformer( label="pp_lignite", inputs={lignite_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(variable_costs=65, emission_factor=1, investment=solph.Investment( maximum=None, minimum=0, ep_costs=1900000, existing=500))}, conversion_factors={electricity_bus: 0.4}) hard_coal_pp = solph.Transformer( label="pp_hard_coal", inputs={hard_coal_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(variable_costs=80, emission_factor=0.8, investment=solph.Investment( maximum=None, minimum=0, ep_costs=1650000, existing=500))}, conversion_factors={electricity_bus: 0.43}) hard_coal_chp = solph.Transformer( label='chp_hard_coal', inputs={hard_coal_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(variable_costs=80, emission_factor=0.8, investment=solph.Investment( maximum=None, minimum=0, ep_costs=1750000, existing=300)), heat_bus: solph.Flow(variable_costs=6, emission_factor=0.06, investment=solph.Investment( maximum=None, minimum=0, ep_costs=131250, existing=300) )}, conversion_factors={electricity_bus: 0.4, heat_bus: 0.4}) biogas_chp = solph.Transformer( label='chp_biogas', inputs={biogas_bus: solph.Flow()}, outputs={electricity_bus: solph.Flow(variable_costs=150, emission_factor=0.25, investment=solph.Investment( maximum=None, minimum=0, ep_costs=3500000, existing=200) ), heat_bus: solph.Flow(variable_costs=11.25, emission_factor=0.01875, investment=solph.Investment( maximum=None, minimum=0, ep_costs=262500, existing=250) )}, conversion_factors={electricity_bus: 0.4, heat_bus: 0.5}) heat_plant = solph.Transformer( label="heat_plant", inputs={gas_bus: solph.Flow()}, outputs={heat_bus: solph.Flow(variable_costs=35, emission_factor=0.23, investment=solph.Investment( maximum=None, minimum=0, ep_costs=390000, existing=450))}, conversion_factors={heat_bus: 0.9}) p2h = solph.Transformer( label="p2h", inputs={electricity_bus: solph.Flow()}, outputs={heat_bus: solph.Flow(variable_costs=20, emission_factor=0.0007, investment=solph.Investment( maximum=None, minimum=0, ep_costs=100000, existing=100))}, conversion_factors={heat_bus: 0.99}) # create storages battery = solph.GenericStorage( label='battery', inputs={electricity_bus: solph.Flow(variable_costs=0)}, outputs={electricity_bus: solph.Flow( variable_costs=400, emission_factor=0.06)}, loss_rate=0.005, inflow_conversion_factor=0.95, outflow_conversion_factor=0.95, initial_storage_level=0, balanced=False, invest_relation_input_capacity=1/3, invest_relation_output_capacity=1/3, investment=solph.Investment( maximum=None, minimum=0, ep_costs=1630000, existing=100) ) heat_storage = solph.GenericStorage( label='heat_storage', inputs={heat_bus: solph.Flow(variable_costs=0)}, outputs={heat_bus: solph.Flow(variable_costs=20, emission_factor=0)}, loss_rate=0.005, inflow_conversion_factor=0.95, outflow_conversion_factor=0.95, initial_storage_level=0, balanced=False, invest_relation_input_capacity=1/5, invest_relation_output_capacity=1/5, investment=solph.Investment( maximum=None, minimum=0, ep_costs=4500, existing=50) ) # add transformers and storages to energy system my_energysystem.add(lignite_pp, hard_coal_pp, gas_pp, heat_plant, p2h, hard_coal_chp, biogas_chp, battery, heat_storage) # Create an energy system model esm = solph.Model(my_energysystem) # Add constraints esm = solph.constraints.generic_integral_limit( om=esm, keyword='emission_factor', limit=250000) # 22000 bei 720 steps, 250000 bei 8760 esm = solph.constraints.additional_investment_flow_limit( model=esm, keyword='investment', limit=float('+inf')) # Optimize model: esm.solve(solver='cbc') # Pump results into the energy system object to utilize its dump # functionality for saving the data my_energysystem.results['main'] = solph.processing.results(esm) my_energysystem.results['meta'] = solph.processing.meta_results(esm) my_energysystem.results['global'] = { 'emissions': esm.integral_limit_emission_factor(), 'costs': my_energysystem.results['meta']['objective'], 'capex': esm.InvestmentFlow.investment_costs.expr() + esm.GenericInvestmentStorageBlock.investment_costs.expr() } # Store result pumped energy system: if not filename: filename = 'expansion_es.oemof' else: filename = filename my_energysystem.dump(dpath=directory, filename=filename) return my_energysystem