diff --git a/docs/usage.rst b/docs/usage.rst index 32b8e3741..c8f0c5f0f 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1004,8 +1004,8 @@ mathematical background, like variables and constraints, which are used. .. _multi_period_mode_label: -Using the multi-period (investment) mode (experimental) -------------------------------------------------------- +Multi-period (investment) mode (experimental) +--------------------------------------------- Sometimes you might be interested in how energy systems could evolve in the longer-term, e.g. until 2045 or 2050 to meet some carbon neutrality and climate protection or RES and energy efficiency targets. @@ -1020,7 +1020,7 @@ only unfolds if you look at long-term investments. Let's see how. First, you start by defining your energy system as you might have done before, but you * choose a longer-term time horizon (spanning multiple years, i.e. multiple periods) and -* explicitly define the `periods` attribute of your energy system which maps time steps to the simulated period. +* explicitly define the `periods` attribute of your energy system which lists the time steps for each period. .. code-block:: python @@ -1028,10 +1028,10 @@ First, you start by defining your energy system as you might have done before, b import oemof.solph as solph my_index = pd.date_range('1/1/2013', periods=17520, freq='H') - periods = { - 0: pd.date_range('1/1/2013', periods=8760, freq='H'), - 1: pd.date_range('1/1/2014', periods=8760, freq='H'), - } + periods = [ + pd.date_range('1/1/2013', periods=8760, freq='H'), + pd.date_range('1/1/2014', periods=8760, freq='H'), + ] my_energysystem = solph.EnergySystem(timeindex=my_index, periods=periods) If you want to use a multi-period model you have define periods of your energy system explicitly. This way, @@ -1057,17 +1057,16 @@ and adjust to your needs: Returns ------- - periods : dict - pd.date_ranges defining the time stamps for the respective period, - starting with period 0 + periods : list + periods for the optimization run """ years = sorted(list(set(getattr(datetimeindex, "year")))) - periods = {} + periods = [] filter_series = datetimeindex.to_series() for number, year in enumerate(years): start = filter_series.loc[filter_series.index.year == year].min() end = filter_series.loc[filter_series.index.year == year].max() - periods[number] = pd.date_range(start, end, freq=datetimeindex.freq) + periods.append(pd.date_range(start, end, freq=datetimeindex.freq)) return periods @@ -1269,6 +1268,8 @@ Besides the `invest` variable, new variables are introduced as well. These are: * You can specify periods of different lengths, but the frequency of your timeindex needs to be consistent. Also, you could use the `timeincrement` attribute of the energy system to model different weightings. Be aware that this has not yet been tested. + * For now, both, the `timeindex` as well as the `timeincrement` of an energy system have to be defined since they + have to be of the same length for a multi-period model. * Also please be aware, that periods correspond to years by default. You could also choose monthly periods, but you would need to be very careful in parameterizing your energy system and your model and also, this would mean monthly discounting (if applicable) as well as specifying your plants lifetimes in months. diff --git a/docs/whatsnew/v0-5-1.rst b/docs/whatsnew/v0-5-1.rst index 1922d23ab..06c327774 100644 --- a/docs/whatsnew/v0-5-1.rst +++ b/docs/whatsnew/v0-5-1.rst @@ -23,8 +23,8 @@ New features * Add option to run multi-period (dynamic) investment models with oemof.solph as an experimental feature: * You can change from standard model to multi-period model by defining the newly introduced `periods` - attribute of your energy system. Be aware that it is experimental as of now. `periods` is a dictionary - mapping the periods you want to model (usually years) to pandas.date_range objects. + attribute of your energy system. Be aware that it is experimental as of now. `periods` is a list + of the periods you want to model (usually years) given as pandas.date_range objects. * Add attributes `periods` to :class:`oemof.solph._energy_system.EnergySystem`. * Introduce new Pyomo Sets `PERIODS` and `TIMEINDEX` in :class:`oemof.solph.models.Model`. * Index all investment-related variables with `PERIODS` and flow variable with `TIMEINDEX`, which diff --git a/src/oemof/solph/_energy_system.py b/src/oemof/solph/_energy_system.py index a2a166fb5..29177edfa 100644 --- a/src/oemof/solph/_energy_system.py +++ b/src/oemof/solph/_energy_system.py @@ -176,13 +176,11 @@ def __init__( self._extract_periods_matrix() def _extract_periods_years(self): - """Map simulation years to the respective period based on time indices + """Map years in optimization to respective period based on time indices - Returns - ------- - periods_years: dict - the simulation year of the start of each a period, - relative to the start of the optimization run and starting with 0 + Attribute `periods_years` of type list is set. It contains + the year of the start of each period, relative to the + start of the optimization run and starting with 0. """ periods_years = [0] if self.periods is not None: @@ -195,14 +193,11 @@ def _extract_periods_years(self): def _extract_periods_matrix(self): """Determines a matrix describing the temporal distance to each period. + + Attribute `periods_matrix` of type list np.array is set. Rows represent investment/commissioning periods, columns represent decommissioning periods. The values describe the temporal distance between each investment period to each decommissioning period. - - Returns - ------- - period_distance_matrix: np.array - """ periods_matrix = [] if self.periods is not None: diff --git a/src/oemof/solph/_options.py b/src/oemof/solph/_options.py index 051eb8479..42bf15885 100644 --- a/src/oemof/solph/_options.py +++ b/src/oemof/solph/_options.py @@ -62,7 +62,7 @@ class Investment: Units lifetime, given in years; only applicable for multi-period models age : int, :math:`a` - Units start age, given in years at the beginning of the simulation; + Units start age, given in years at the beginning of the optimization; only applicable for multi-period models interest_rate : float, :math:`ir` Interest rate for calculating annuities when investing in a particular diff --git a/src/oemof/solph/flows/_investment_flow_block.py b/src/oemof/solph/flows/_investment_flow_block.py index 9ee4122e3..f763d2c7e 100644 --- a/src/oemof/solph/flows/_investment_flow_block.py +++ b/src/oemof/solph/flows/_investment_flow_block.py @@ -316,7 +316,7 @@ def _create_constraints(self): & else:\\ & - P_{old,end}(p)\\ + P_{old,end}(p) = 0\\ &\\ & if \quad p=0:\\ @@ -529,7 +529,7 @@ def _old_capacity_rule_end(block): # multiple invests can be decommissioned in the same period # but only sequential ones, thus a bookkeeping is - # introduced andconstraints are added to equation one + # introduced and constraints are added to equation one # iteration later. last_decomm_p = np.nan # loop over invest periods (values are decomm_periods)