pownet.reservoir package

Submodules

pownet.reservoir.manager module

manager.py: ReservoirManager class for managing reservoir operations and simulations.

class pownet.reservoir.manager.ReservoirManager[source]

Bases: object

get_hydropower_ts(unit_node_mapping=None)[source]

Get the hydropower time series for all reservoirs.

Return type:

DataFrame

load_reservoirs_from_csv(input_folder)[source]

Load Basin information from a CSV file.

Return type:

None

reoperate(daily_dispatch, days_in_step)[source]

Reoperate the reservoirs based on the daily dispatch of the power system model. Note that we don’t reoperate on the first day of the simulation period.

Return type:

dict[str, float]

simulate()[source]

Simulate the reservoir operations to get hydropower time series.

Return type:

None

write_hydropower_to_csv(output_filepath, unit_node_mapping=None)[source]

Write the hydropower time series to CSV files.

Return type:

None

pownet.reservoir.manager.find_upstream_flow(reservoir, reservoirs)[source]
Return type:

Series

pownet.reservoir.reservoir module

reservoir.py: Reservoir class

class pownet.reservoir.reservoir.Reservoir(params)[source]

Bases: object

Simulates the operation of a single reservoir, initialized using ReservoirParams. The simulation horizon is set to 365 days with a daily time step.

get_daily_hydropower()[source]

Return the daily hydropower values.

Return type:

Series

get_hourly_hydropower()[source]
Return type:

Series

get_operation_timeseries()[source]

Return the timeseries of the reservoir.

Return type:

DataFrame

get_reop_daily_hydropower()[source]

Return the reoperated daily hydropower values.

Return type:

Series

plot_state(year=None, output_folder=None)[source]
Return type:

None

reoperate(day, daily_dispatch, upstream_flow_t, hydropeak_factor=0.15)[source]

Reoperate the reservoir based on the daily dispatch of the power system model. There are seven cases which are outlined in the code. Note t-1 is denoted as t0; t is denoted as t; t+1 is denoted as t1.

Parameters:
  • day (int) – The current day for which the reoperation is being calculated.

  • daily_dispatch (float) – The daily dispatch value from the power system model.

  • upstream_flow (float) – The flow of water from upstream.

  • hydropeak_factor (float) – The hydropeak factor for the reservoir.

Returns:

New daily hydropower value after reoperation.

Return type:

float

set_upstream_flow(upstream_flow)[source]

Set the upstream flow for the reservoir.

Parameters:

upstream_flow (pd.Series) – The upstream flow for the reservoir.

Raises:

ValueError – If the upstream flow is negative or if the index is not in the expected range.

Return type:

None

simulate(initial_storage=None)[source]

Simulate the operation of the reservoir. This method calculates the release, spill, storage, level, and daily hydropower.

Return type:

None

pownet.reservoir.reservoir_functions module

reservoir_functions.py: Functions for operating reservoirs.

pownet.reservoir.reservoir_functions.adjust_hydropeaking(release, release_t0, max_release, min_release, hydropeak_factor=0.15)[source]

Adjust water release by considering hydropeaking and minimum environmental flow. The change in release is limited to hydropeak_factor times the maximum release. Also, the release cannot be lower than the minimum release or higher than the maximum release.

Parameters:
  • release (float) – The release for the current day.

  • release_t0 (float) – The release for the previous day.

  • max_release (float) – The maximum release as a positive value

  • min_release (float) – The minimum release as a positive value

  • hydropeak_factor (float) – The factor to limit the change in release. Default is 0.15.

Returns:

The adjusted release.

Return type:

float

pownet.reservoir.reservoir_functions.calc_daily_hydropower(release, mid_level, max_generation, turbine_factor, max_head, max_level)[source]

Calculate daily hydropower generation from release and mid-level.

Parameters:
  • release (Series) – Water release (m3/daily)

  • mid_level (Series) – Average water level between current and previous timestep (m)

  • max_generation (float) – Maximum power generation capacity of the turbine (MW)

  • turbine_factor (float) – Turbine efficiency

  • max_head (float) – Maximum head (m)

  • max_level (float) – Maximum water level (m)

Returns:

Daily hydropower generation (MW-day)

Return type:

pd.Series

pownet.reservoir.reservoir_functions.calc_hourly_hydropower(release, mid_level, max_generation, turbine_factor, max_head, max_level)[source]

Calculate hourly hydropower generation from release and mid-level.

The hourly hydropower (MW) is calculated using the following formula:

hourly_hydropower = min(turbine_factor * rho * g * head * flow_rate, max_generation)

where: * rho: Density of water (kg/m3) * g: Acceleration due to gravity (m/s2) * head: Water head above the turbine (m) * flow_rate: Water flow rate (m3/hour) * max_generation: Maximum power generation capacity of the turbine (MW) * turbine_factor: Turbine efficiency

Parameters:
  • release (Series) – Water release (m3/hour)

  • mid_level (Series) – Average water level between current and previous timestep (m)

  • max_generation (float) – Maximum power generation capacity of the turbine (MW)

  • turbine_factor (float) – Turbine efficiency

  • max_head (float) – Maximum head (m)

  • max_level (float) – Maximum water level (m)

Returns:

Hourly hydropower generation (MW)

Return type:

pd.Series

pownet.reservoir.reservoir_functions.calc_level_from_storage(storage, min_level, max_level, max_storage)[source]

Calculate the level for each day based on linear interpolation.

Parameters:
  • storage (pd.Series) – The storage for each day

  • min_level (float) – The minimum level

  • max_level (float) – The maximum level

  • max_storage (float) – The maximum storage

Returns:

The level for each day

Return type:

pd.Series

pownet.reservoir.reservoir_functions.calc_max_release(total_inflow_t, release_t0, storage_t0, minflow_t, max_release, hydropeak_factor)[source]

Calculate the maximum allowable release of the current timestep.

Return type:

float

pownet.reservoir.reservoir_functions.calc_min_release(total_inflow_t, release_t0, storage_t0, minflow_t, max_release, hydropeak_factor)[source]

Calculate the minimum allowable release of the current timestep.

Return type:

float

pownet.reservoir.reservoir_functions.calc_release_impact(release_t, storage_t0, total_inflow_t, min_level, max_level, max_storage, level_t0, max_generation, turbine_factor, max_head)[source]

Calculate the impact of a given release on storage, level, mid-level, and hydropower.

Return type:

tuple[float, float, float, float]

pownet.reservoir.reservoir_functions.calc_target_level(min_day, max_day, min_level, max_level)[source]

Calculate the target level for each day based on linear interpolation.

Parameters:
  • min_day (int) – The day when the target level is at its minimum

  • max_day (int) – The day when the target level is at its maximum

  • min_level (float) – The minimum target level

  • max_level (float) – The maximum target level

Returns:

The target level for each day of the year

Return type:

pd.Series

pownet.reservoir.reservoir_functions.calc_target_storage(target_level, min_level, max_level, max_storage)[source]

Calculate the target storage for each day based on linear interpolation.

Parameters:
  • target_level (pd.Series) – The target level for each day

  • min_level (float) – The minimum level

  • max_level (float) – The maximum level

  • max_storage (float) – The maximum storage

Returns:

The target storage for each day

Return type:

pd.Series

pownet.reservoir.reservoir_functions.convert_to_hourly_hydropower(daily_hydropower)[source]

Return the hourly hydropower values.

Return type:

Series

pownet.reservoir.reservoir_functions.find_downstream_flow_fractions(flow_paths, unit_name)[source]

Find downstream units for a given unit.

Parameters:
  • flow_paths (pd.DataFrame) – DataFrame containing flow paths between units.

  • unit_name (str) – The name of the unit to find downstream units for.

Returns:

Dict of downstream unit names and their flow fractions.

Return type:

dict[str, float]

pownet.reservoir.reservoir_functions.find_simulation_order(reservoir_names, flow_paths)[source]

Determine the order in which reservoirs are simulated based on their upstream/downstream relationships.

Parameters:
  • reservoir_names (list[str]) – List of reservoir names.

  • flow_paths (pd.DataFrame) – DataFrame containing flow paths represented by the source and sink columns.

Returns:

A list of reservoir names in the order they should be simulated.

Return type:

list[str]

pownet.reservoir.reservoir_functions.find_upstream_units(flow_paths, unit_name)[source]

Find upstream units for a given unit.

Parameters:
  • flow_paths (pd.DataFrame) – DataFrame containing flow paths between units.

  • unit_name (str) – The name of the unit to find upstream units for.

Returns:

List of upstream unit names.

Return type:

list[str]

pownet.reservoir.solve_release module

solve_release.py: Functions to solve the release given other values from a reservoir.

pownet.reservoir.solve_release.solve_release_from_dispatch(reservoir_name, daily_dispatch, turbine_factor, max_head, max_level, min_level, level_t0, storage_max, storage_t0, inflow, min_release, max_release, max_generation)[source]

For each day, solve for release_t from daily dispatch_t as an optimization problem.

min abs(DISPATCH_t - daily_hydropower_t) s.t. :rtype: tuple[float, float, float, float, float, float, float]

  1. Calculate hourly_hydropower_t

    hourly_hydropower_t = TURBINE_FACTOR * DENSITY * g * head_t * release_t

    where

    DENSITY = 998 # kg/m3 g = 9.81 # m/s2

2. Hydrautic head is a function of water levvel head_t = MAX_HEAD - (MAX_LEVEL - mid_level_t)

where mid_level_t = (level_t0 + level_t) / 2

3. level_t is a function of storage level_t = storage_t / STORAGE_MAX * (MAX_LEVEL - MIN_LEVEL) + MIN_LEVEL

4. Definition of storage storage_t = STORAGE_t0 + INFLOW_t - release_t - spill_t

5. Definition of spill spill_t = max(0, INFLOW_t + storage_t - STORAGE_MAX - release_t) Rearrange to spill_t = max(0, spill_bar)

6. Definition of spill_bar spill_bar = INFLOW_t + storage_t-1 - STORAGE_MAX - release_t

Note that the objective function is not linear because of the absolute value. To make it linear, we introduce a new variable mismatch_t and rewrite the objective function as:

min mismatch

s.t.

-mismatch <= DISPATCH_t - daily_hydropower_t <= mismatch

pownet.reservoir.solve_release.solve_release_from_target_storage(reservoir_name, start_day, end_day, max_release, max_storage, initial_storage, target_storage, minflow, total_inflow)[source]

Build an optimization problem to find the optimal release from the reservoir. The objective is to minimize the storage deviation from the target storage with L1 norm.

OBJECTIVE FUNCTION: min | target_storage - storage | + spill

Rewrite this as:

min sum_{day} sbar[day] s.t. - sbar[day] <= target_storage[day] - storage[day] <= sbar[day]

CONSTRAINTS:

Return type:

tuple[Series, Series, Series, float]

Module contents

This is the reservoir module.