Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d015dd3
Rename PERIODS to CAPACITY_PERIODS
p-snft Apr 2, 2025
9e9a9bb
Adhere to maximum line length
p-snft Apr 2, 2025
661e774
Merge branch 'dev' into revision/steamline_investment_periods
p-snft May 8, 2025
94daad4
Remove lifetime tracking functionality
p-snft May 9, 2025
09a16e9
Remove unused imports
p-snft May 10, 2025
ddf36cf
Remove fixed costs from GenericStorage
p-snft May 12, 2025
ed5107e
Remove fixed_costs from Flow
p-snft May 12, 2025
8ca2d6d
Haronise capacity investment in Flow
p-snft May 12, 2025
af8302f
Remove remains of lifetime tracking and discounting
p-snft May 12, 2025
c21e606
Remove unused imports
p-snft May 12, 2025
dd36255
Remove left-over parameter use_remaining_value
p-snft May 13, 2025
9b908df
Rename EnergySystem.periods to investment_times
p-snft May 13, 2025
30c7813
Adhere to Black
p-snft May 14, 2025
035d9dc
Move from investement periods to investment times
p-snft May 20, 2025
f52ab74
Adhere to Black
p-snft May 20, 2025
752e1f0
Remove obsolete check for periods in InvestStorage
p-snft May 23, 2025
627da53
Make parameters to create_time_index more precise
p-snft May 23, 2025
0c7a413
Remove disused age tracking variables in GenericStorage
p-snft May 23, 2025
104c5fa
Use Result class in some tests
p-snft May 23, 2025
4f992b0
Fix GenericStorage
p-snft May 23, 2025
d04009e
Fix handling of EnergySystem.timeincrement
p-snft May 23, 2025
4b2e1d0
Use Result class for constrain tests
p-snft May 23, 2025
5554cb0
Disuse processing module in non-equidistant time step test
p-snft May 26, 2025
cc59b02
Merge branch 'dev' into revision/steamline_investment_periods
p-snft Jun 16, 2025
5f83d10
Merge branch 'dev' into revision/steamline_investment_periods
p-snft Aug 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/generic_invest_limit/example_generic_invest.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def main(optimize=True):
data = [0, 15, 30, 35, 20, 25, 27, 10, 5, 2, 15, 40, 20, 0, 0]

# create an energy system
idx = solph.create_time_index(2020, number=len(data))
idx = solph.create_time_index(2020, number_of_intervals=len(data))
es = solph.EnergySystem(timeindex=idx, infer_last_interval=False)

# Parameter: costs for the sources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def main(optimize=True):

# Create the energy system.
date_time_index = solph.create_time_index(
number=n_days * 24, start=start_date
number_of_intervals=n_days * 24, start=start_date
)
energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
2 changes: 1 addition & 1 deletion examples/investment_with_minimal_invest/minimal_invest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def main(optimize=True):
data = [0, 15, 30, 35, 20, 25, 27, 10, 5, 2, 15, 40, 20, 0, 0]

# create an energy system
idx = solph.create_time_index(2017, number=len(data))
idx = solph.create_time_index(2017, number_of_intervals=len(data))
es = solph.EnergySystem(timeindex=idx, infer_last_interval=False)

bus_0 = solph.Bus(label="bus_0")
Expand Down
2 changes: 1 addition & 1 deletion examples/min_max_runtimes/min_max_runtimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def main(optimize=True):
demand_el[n] = 1

# create an energy system
idx = solph.create_time_index(2017, number=24)
idx = solph.create_time_index(2017, number_of_intervals=24)
es = solph.EnergySystem(timeindex=idx, infer_last_interval=False)

# power bus and components
Expand Down
4 changes: 3 additions & 1 deletion examples/result_object/result_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ def main(optimize=True):
)

logging.info("Initialize the energy system")
date_time_index = create_time_index(2012, number=number_of_time_steps)
date_time_index = create_time_index(
2012, number_of_intervals=number_of_time_steps
)

# create the energysystem and assign the time index
energysystem = EnergySystem(
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_dispatch/simple_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def main(optimize=True):

# Create an energy system and optimize the dispatch at least costs.
# ####################### initialize and provide data #####################
datetimeindex = create_time_index(2016, number=len(data))
datetimeindex = create_time_index(2016, number_of_intervals=len(data))
energysystem = EnergySystem(
timeindex=datetimeindex, infer_last_interval=False
)
Expand Down
2 changes: 1 addition & 1 deletion examples/start_and_shutdown_costs/startup_shutdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def main(optimize=True):
0,
]
# create an energy system
idx = solph.create_time_index(2017, number=len(demand_el))
idx = solph.create_time_index(2017, number_of_intervals=len(demand_el))
es = solph.EnergySystem(timeindex=idx, infer_last_interval=False)

# power bus and components
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def main(optimize=True):

logger.define_logging()
logging.info("Initialize the energy system")
date_time_index = solph.create_time_index(2012, number=number_timesteps)
date_time_index = solph.create_time_index(
2012, number_of_intervals=number_timesteps
)
energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ def main(optimize=True):

logger.define_logging()
logging.info("Initialize the energy system")
date_time_index = solph.create_time_index(2012, number=number_timesteps)
date_time_index = solph.create_time_index(
2012, number_of_intervals=number_timesteps
)

energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ def main(optimize=True):

logger.define_logging()
logging.info("Initialize the energy system")
date_time_index = solph.create_time_index(2012, number=number_timesteps)
date_time_index = solph.create_time_index(
2012, number_of_intervals=number_timesteps
)

energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def main(optimize=True):

logger.define_logging()
logging.info("Initialize the energy system")
date_time_index = solph.create_time_index(2012, number=number_timesteps)
date_time_index = solph.create_time_index(
2012, number_of_intervals=number_timesteps
)

energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
4 changes: 3 additions & 1 deletion examples/time_index_example/simple_time_step_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ def main(optimize=True):
solver = "cbc" # 'glpk', 'gurobi',...
solver_verbose = False # show/hide solver output

date_time_index = solph.create_time_index(2000, interval=0.25, number=8)
date_time_index = solph.create_time_index(
2000, interval_length=0.25, number_of_intervals=8
)

energy_system = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,7 @@ def main():
outputs={
bel: solph.Flow(
fix=wind_profile,
nominal_capacity=solph.Investment(
ep_costs=epc_wind, lifetime=10
),
nominal_capacity=solph.Investment(ep_costs=epc_wind),
)
},
)
Expand All @@ -254,9 +252,7 @@ def main():
],
ignore_index=True,
),
nominal_capacity=solph.Investment(
ep_costs=epc_pv, lifetime=10
),
nominal_capacity=solph.Investment(ep_costs=epc_pv),
)
},
)
Expand Down Expand Up @@ -298,7 +294,7 @@ def main():
invest_relation_output_capacity=1 / 6,
inflow_conversion_factor=1,
outflow_conversion_factor=0.8,
nominal_capacity=solph.Investment(ep_costs=epc_storage, lifetime=10),
nominal_capacity=solph.Investment(ep_costs=epc_storage),
)

energysystem.add(excess, gas_resource, wind, pv, demand, pp_gas, storage)
Expand Down
4 changes: 3 additions & 1 deletion examples/tuple_as_labels/tuple_as_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ def main(optimize=True):

logging.info("Initialize the energy system")
energysystem = EnergySystem(
timeindex=create_time_index(2012, number=number_of_time_steps),
timeindex=create_time_index(
2012, number_of_intervals=number_of_time_steps
),
infer_last_interval=False,
)

Expand Down
4 changes: 3 additions & 1 deletion examples/variable_chp/variable_chp.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ def main(optimize=True):
logging.info("Initialize the energy system")

# create time index for 192 hours in May.
date_time_index = solph.create_time_index(2012, number=len(data))
date_time_index = solph.create_time_index(
2012, number_of_intervals=len(data)
)

energysystem = solph.EnergySystem(
timeindex=date_time_index, infer_last_interval=False
Expand Down
137 changes: 27 additions & 110 deletions src/oemof/solph/_energy_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,10 @@
a 'freq' attribute that is not None. The parameter has no effect on the
timeincrement parameter.
periods : list or None
The periods of a multi-period model.
If this is explicitly specified, it leads to creating a multi-period
model, providing a respective user warning as a feedback.
list of pd.date_range objects carrying the timeindex for the
respective period;
For a standard model, periods are not (to be) declared, i.e. None.
A list with one entry is derived, i.e. [0].
investment_times : list or None
The points in time investments can be made. Defaults to timeindex[0].
If multiple times are specified, it leads to creating a multi-period
model.
tsa_parameters : list of dicts, dict or None
Parameter can be set in order to use aggregated timeseries from TSAM.
Expand All @@ -76,10 +70,6 @@
will be adapted. Note that timeseries for components have to
be set up as already aggregated timeseries.
use_remaining_value : bool
If True, compare the remaining value of an investment to the
original value (only applicable for multi-period models)
kwargs
"""

Expand All @@ -88,9 +78,8 @@
timeindex=None,
timeincrement=None,
infer_last_interval=False,
periods=None,
investment_times=None,
tsa_parameters=None,
use_remaining_value=False,
groupings=None,
):
# Doing imports at runtime is generally frowned upon, but should work
Expand Down Expand Up @@ -130,20 +119,18 @@
)
warnings.warn(msg, FutureWarning)
else:
if periods is None:
msg = (
"Specifying the timeincrement and the timeindex"
" parameter at the same time is not allowed since"
" these might be conflicting to each other."
)
raise AttributeError(msg)
else:
msg = (
"Ensure that your timeindex and timeincrement are "
"consistent."
)
warnings.warn(msg, debugging.ExperimentalFeatureWarning)
msg = (
"The timeincrement is infered from the given timeindex."
" As both parameters might be conflicting to each other,"
" you cannot define both at the same time."
" Please give only a timeindex."
)
raise AttributeError(msg)

elif timeindex is None and timeincrement is not None:
timeindex = pd.Index(
np.append(np.array([0]), np.cumsum(timeincrement))
)
Comment on lines +131 to +133

Check warning

Code scanning / CodeQL

Unreachable code Warning

This statement is unreachable.
elif timeindex is not None and timeincrement is None:
if tsa_parameters is not None:
pass
Expand Down Expand Up @@ -188,8 +175,8 @@
tsa_parameters = [tsa_parameters]

# Construct occurrences of typical periods
if periods is not None:
for p in range(len(periods)):
if investment_times is not None:
for p in range(len(investment_times)):
tsa_parameters[p]["occurrences"] = collections.Counter(
tsa_parameters[p]["order"]
)
Expand All @@ -211,92 +198,22 @@
self.tsa_parameters = tsa_parameters

timeincrement = self._init_timeincrement(
timeincrement, timeindex, periods, tsa_parameters
timeincrement, timeindex, investment_times, tsa_parameters
)
super().__init__(
groupings=groupings,
timeindex=timeindex,
timeincrement=timeincrement,
)

self.periods = periods
if self.periods is not None:
msg = (
"CAUTION! You specified the 'periods' attribute for your "
"energy system.\n This will lead to creating "
"a multi-period optimization modeling which can be "
"used e.g. for long-term investment modeling.\n"
"Please be aware that the feature is experimental as of "
"now. If you find anything suspicious or any bugs, "
"please report them."
)
warnings.warn(msg, debugging.ExperimentalFeatureWarning)
self._extract_periods_years()
self._extract_periods_matrix()
self._extract_end_year_of_optimization()
self.use_remaining_value = use_remaining_value
else:
self.end_year_of_optimization = 1

def _extract_periods_years(self):
"""Map years in optimization to respective period based on time indices
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]
start_year = self.periods[0].min().year
for k, v in enumerate(self.periods):
if k >= 1:
periods_years.append(v.min().year - start_year)

self.periods_years = periods_years

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.
"""
periods_matrix = []
period_years = np.array(self.periods_years)
for v in period_years:
row = period_years - v
row = np.where(row < 0, 0, row)
periods_matrix.append(row)
self.periods_matrix = np.array(periods_matrix)

def _extract_end_year_of_optimization(self):
"""Extract the end of the optimization in years
Attribute `end_year_of_optimization` of int is set.
"""
duration_last_period = self.get_period_duration(-1)
self.end_year_of_optimization = (
self.periods_years[-1] + duration_last_period
)

def get_period_duration(self, period):
"""Get duration of a period in full years
Parameters
----------
period : int
Period for which the duration in years shall be obtained
Returns
-------
int
Duration of the period
"""
return (
self.periods[period].max().year
- self.periods[period].min().year
+ 1
)
# bare system to load pickled data
if self.timeindex is not None:
if investment_times is None:
self.investment_times = [self.timeindex[0]]
else:
self.investment_times = sorted(
set([self.timeindex[0]] + investment_times)
)

@staticmethod
def _init_timeincrement(timeincrement, timeindex, periods, tsa_parameters):
Expand Down
Loading
Loading