diff --git a/HydroGenerate/flow_preprocessing.py b/HydroGenerate/flow_preprocessing.py
index a48a190..75e78f6 100644
--- a/HydroGenerate/flow_preprocessing.py
+++ b/HydroGenerate/flow_preprocessing.py
@@ -1,42 +1,3 @@
-'''
-Copyright 2023, Battelle Energy Alliance, LLC
-'''
-
-"""
-07-2024
-@author: Soumyadeep Nag, Camilo J. Bastidas Pacheco, J. Gallego-Calderon
-
-This module applies the flow limit constraints and incorporates the impact
-of annual and major maintenance activities on turbine flow.
-
-It provides utilities to:
-1) Cap turbine flow at design limits.
-2) Enforce minimum turbine flow thresholds (absolute or % of design flow).
-3) Set turbine flow to zero during annual and major maintenance windows.
-
-Expected `flow_obj` interface (used by functions here)
------------------------------------------------------
-Attributes
-----------
-flow : numpy.ndarray
- Raw inflow time series (m³/s), same length as `datetime_index`.
-design_flow : float or numpy.ndarray
- Turbine design flow (m³/s). If array, must align with `flow`.
-turbine_flow : numpy.ndarray
- Turbine flow (m³/s); created/updated by the functions in this module.
-datetime_index : pandas.DatetimeIndex
- Timestamps for `flow`. Weekly grouping assumes this index (or a level)
- is named "dateTime" when using pandas.Grouper(level="dateTime", ...).
-
-Notes
------
-- Annual maintenance zeros 7 consecutive days once per year, selecting the week
- with the lowest weekly mean flow.
-- Major maintenance zeros 14 consecutive days every 5 years (skipping the first),
- selecting the two-week period with the lowest bi-weekly mean flow.
-"""
-
-
import numpy as np
import pandas as pd
from datetime import datetime
@@ -45,37 +6,35 @@
# Hydraulic design parameters
class FlowPreProcessingParameters:
- """
- Container for flow pre-processing options used by flow limit and
- maintenance logic.
+ """Configuration container for flow preprocessing.
- Parameters
- ----------
- minimum_turbineflow : float or None
- Absolute minimum turbine flow (m^3/s). If None, a percentage of
- `design_flow` is used (see `minimum_turbineflow_percent`).
- minimum_turbineflow_percent : float or None
- Minimum turbine flow as a percentage of `design_flow` (1–100). Used
- only when `minimum_turbineflow` is None. If both are None, a default
- of 10% is applied.
- annual_maintenance_flag : bool
- If True, enforce a 7-day annual maintenance outage (flow set to 0).
- major_maintenance_flag : bool
- If True, enforce a 14-day major maintenance outage every 5 years
- (flow set to 0).
+ This class holds user-configurable parameters that control minimum turbine
+ flow enforcement and maintenance scheduling. It does not perform any
+ computations by itself; the values are consumed by
+ :class:`~FlowPreProcessing`.
- Attributes
+ Parameters
----------
minimum_turbineflow : float or None
- minimum_turbineflow_percent : float or None
+ Absolute minimum turbine flow (m³/s). If provided, this overrides the
+ percentage-based minimum flow. If ``None``, the minimum is computed from
+ ``minimum_turbineflow_percent`` (or a default of 10%).
+ minimum_turbineflow_percent : float or int or None
+ Minimum turbine flow as a percentage of ``design_flow`` (1–100). Used
+ only when ``minimum_turbineflow`` is ``None``.
annual_maintenance_flag : bool
+ If ``True``, apply annual maintenance by setting turbine flow to zero
+ for the lowest-flow calendar week each year (based on mean weekly flow).
major_maintenance_flag : bool
+ If ``True``, apply major maintenance by setting turbine flow to zero
+ for the lowest-flow two-week period every five years.
Notes
-----
- This class only stores configuration; calculations are performed by
- methods in `FlowPreProcessing`.
- """
+ These parameters are typically attached to a higher-level *flow object*
+ (e.g., a project-specific container) and then read by methods in
+ :class:`~FlowPreProcessing`.
+ """
def __init__(self, minimum_turbineflow, minimum_turbineflow_percent, # Flow parameters
annual_maintenance_flag, major_maintenance_flag):
@@ -89,22 +48,21 @@ def __init__(self, minimum_turbineflow, minimum_turbineflow_percent, # Flo
class FlowPreProcessing():
+ """Flow preprocessing routines operating on a provided flow object.
- """
- Apply design flow limits and scheduled maintenance to a flow object.
-
- The methods in this class expect a `flow_obj` with, at minimum, the
- attributes described in the module docstring. Methods update
- `flow_obj.turbine_flow` in place and do not return values.
-
- See Also
- --------
- max_turbineflow_checker : Cap turbine flow at design flow.
- min_turbineflow_checker : Enforce minimum turbine flow threshold.
- annual_maintenance_implementer : Zero 7 days/year at lowest-flow week.
- major_maintenance_implementer : Zero 14 days/5 years at lowest bi-weekly mean.
- """
+ Methods in this class update values on ``flow_obj`` in-place (most
+ importantly ``flow_obj.turbine_flow``).
+ Notes
+ -----
+ The caller is responsible for ensuring that:
+
+ - ``flow_obj.turbine_flow`` is a 1D numpy array aligned with
+ ``flow_obj.datetime_index``.
+ - ``flow_obj.datetime_index`` is a pandas.DatetimeIndex whose name (or level
+ name) is ``"dateTime"`` so that ``pd.Grouper(level="dateTime", ...)``
+ works as written in the implementation.
+ """
# Function that sets max turbine flow to the design flow
def max_turbineflow_checker(self, flow_obj):
"""
@@ -113,21 +71,17 @@ def max_turbineflow_checker(self, flow_obj):
Parameters
----------
flow_obj : object
- Object with attributes:
- - flow : numpy.ndarray
- Raw inflow time series (m^3/s).
- - design_flow : float or numpy.ndarray
- Turbine design flow (m^3/s). If array, must align with `flow`.
+ A flow object with attributes:
- Side Effects
+ - ``turbine_flow`` (numpy.ndarray)
+ - ``design_flow`` (float)
+ - ``minimum_turbineflow`` (float or None)
+ - ``minimum_turbineflow_percent`` (float or None)
+
+ Notes
------------
Updates `flow_obj.turbine_flow` (numpy.ndarray), where each element is
`min(flow, design_flow)`.
-
- Examples
- --------
- >>> # flow_obj.flow = [12, 8], design_flow = 10
- >>> # turbine_flow becomes [10, 8]
"""
flow = flow_obj.flow # this is a numpy array
@@ -136,42 +90,26 @@ def max_turbineflow_checker(self, flow_obj):
# Function that sets min turbine flow to the design flow
def min_turbineflow_checker(self, flow_obj):
- """
- Enforce a minimum turbine flow threshold; set values below it to zero.
+ """Enforce a minimum turbine flow threshold.
- Logic
- -----
- - If `flow_obj.minimum_turbineflow` is provided, use it (m^3/s).
- - Else, compute min flow as
- (`minimum_turbineflow_percent` or 10 by default) × `design_flow` / 100.
- The computed value is stored back into `flow_obj.minimum_turbineflow`.
+ Any values in ``flow_obj.turbine_flow`` that fall below the computed
+ minimum are replaced with zero.
Parameters
----------
flow_obj : object
- Object with attributes:
- - turbine_flow : numpy.ndarray
- Turbine flow series (m^3/s), typically after max-capping.
- - design_flow : float or numpy.ndarray
- Turbine design flow (m^3/s).
- - minimum_turbineflow : float or None
- - minimum_turbineflow_percent : float or None
-
- Side Effects
- ------------
- Updates `flow_obj.turbine_flow`, replacing values `< min_flow` with 0.
Notes
-----
- - If `design_flow` is an array, elementwise percentages are applied.
- - Default minimum percent is 10 if neither absolute nor percentage is given.
+ This method modifies ``flow_obj.turbine_flow`` in place.
+
+ If ``flow_obj.minimum_turbineflow`` is ``None``, the minimum flow is
+ computed as::
- Examples
- --------
- >>> # design_flow = 20 m^3/s, minimum_turbineflow_percent = 10
- >>> # min_flow = 2.0; turbine_flow < 2.0 becomes 0
+ min_flow = (minimum_turbineflow_percent / 100) * design_flow
+
+ where ``minimum_turbineflow_percent`` defaults to 10 if not provided.
"""
-
flow = flow_obj.turbine_flow # this is a numpy array
design_flow = flow_obj.design_flow
@@ -190,40 +128,23 @@ def min_turbineflow_checker(self, flow_obj):
flow_obj.turbine_flow = np.where(flow < min_flow, 0, flow) # replace flows less than min flow with 0
def annual_maintenance_implementer(self, flow_obj):
- """
- Zero turbine flow for 7 consecutive days once per calendar year.
+ """Apply annual maintenance by zeroing the lowest-flow week each year.
- Procedure
- ---------
- 1) Compute weekly mean flow and identify the week with the lowest mean
- (excluding first/last partial weeks).
- 2) For each year in the time span, zero out the 7-day window starting on
- the Monday of that lowest-flow week.
+ The method identifies the calendar week with the lowest mean weekly
+ flow (aggregated across all years) and sets turbine flow to zero for
+ that week in every year of the dataset.
Parameters
----------
flow_obj : object
- Object with attributes:
- - turbine_flow : numpy.ndarray
- Turbine flow series (m^3/s).
- - datetime_index : pandas.DatetimeIndex
- Timestamps aligned with `turbine_flow`.
- Side Effects
- ------------
- Updates `flow_obj.turbine_flow`, setting the 7 chosen days per year to 0.
-
- Assumptions
- -----------
- - `datetime_index` covers multiple years or at least one full year.
- - Weekly grouping uses `pd.Grouper(level="dateTime", freq='W')`. Ensure your
- index (or a MultiIndex level) is named "dateTime" or adjust the grouper
- accordingly.
-
- Examples
- --------
- >>> # After applying, each year has a 7-day zero-flow outage at the
- >>> # statistically lowest weekly mean period.
+ Notes
+ -----
+ This method modifies ``flow_obj.turbine_flow`` in place.
+
+ Weekly means are computed using ``freq='W'`` and grouped by calendar
+ week number (``%W``). The maintenance window spans 7 days starting on
+ the Monday of the selected week.
"""
# Function to set annual maintennace - i.e., make the flow 0 for a week a year
@@ -262,44 +183,24 @@ def annual_maintenance_implementer(self, flow_obj):
# Function that schedules the major maintennace
def major_maintenance_implementer(self, flow_obj):
+ """Apply major maintenance by zeroing a low-flow two-week period every 5 years.
- """
- Zero turbine flow for 14 consecutive days every 5 years (skip first year).
-
- Procedure
- ---------
- 1) Compute bi-weekly (2W) mean flow and identify the bi-weekly window with
- the lowest mean (excluding first/last partial windows).
- 2) For maintenance years spaced every 5 years (starting after the first),
- zero out the 14-day window starting on the Monday of the selected week.
+ The method identifies the calendar week associated with the lowest
+ mean two-week flow and applies a 14-day zero-flow window starting
+ from that week in each major-maintenance year.
Parameters
----------
flow_obj : object
- Object with attributes:
- - turbine_flow : numpy.ndarray
- Turbine flow series (m^3/s).
- - datetime_index : pandas.DatetimeIndex
- Timestamps aligned with `turbine_flow`.
- Side Effects
- ------------
- Updates `flow_obj.turbine_flow`, setting the selected 14 days to 0 in each
- maintenance year (every 5 years; first year excluded).
-
- Assumptions
- -----------
- - Sufficient span to include one or more 5-year intervals.
- - Bi-weekly grouping uses `pd.Grouper(level="dateTime", freq='2W')`. Ensure
- your index (or a MultiIndex level) is named "dateTime" or adjust the
- grouper accordingly.
-
- Examples
- --------
- >>> # In a 10-year record, days 1–14 of the lowest 2-week flow window
- >>> # are zeroed in years 5 and 10 (year 0 excluded).
+ Notes
+ -----
+ This method modifies ``flow_obj.turbine_flow`` in place.
+
+ Major maintenance years occur every five years starting after the
+ first year of the dataset. Two-week means are computed using
+ ``freq='2W'``.
"""
-
# Major maintenance will happend on the month with lowest flow a year - during the first 15 days of this month.
turbine_flow = flow_obj.turbine_flow # turbine flow series with max and min (if on) limits implemented
@@ -334,5 +235,3 @@ def major_maintenance_implementer(self, flow_obj):
flow.loc[flow.date.isin(dates_maint), 'flow_cms'] = 0 # replace flow in minimum weeks with 0
flow_obj.turbine_flow = flow['flow_cms'].to_numpy() # update
-
-
diff --git a/HydroGenerate/hydraulic_processing.py b/HydroGenerate/hydraulic_processing.py
index ac575bd..8102e53 100755
--- a/HydroGenerate/hydraulic_processing.py
+++ b/HydroGenerate/hydraulic_processing.py
@@ -10,7 +10,6 @@
- Size penstocks to respect a maximum allowable head loss.
"""
-
import numpy as np
from abc import ABC, abstractmethod
@@ -19,61 +18,65 @@
# Hydraulic design parameters
class HydraulicDesignParameters:
- """
- Container for hydraulic inputs/derived values used in head-loss and sizing.
+
+ """Hydraulic design parameter container.
+
+ This class stores input values needed for penstock head-loss calculations
+ and provides helper methods for computing Reynolds number and a starting
+ design diameter for iterative sizing.
Parameters
----------
- flow : float or numpy.ndarray
- Flow values (m^3/s) for general context or time-series use.
+ flow : float or array-like
+ Flow values (m³/s). This may represent a single value or a time series,
+ depending on the calling context.
design_flow : float
- Design discharge (m^3/s) used for diameter/head-loss sizing.
- head : float or None
- Available gross head (m).
+ Design flow (m³/s).
+ head : float
+ Available (gross) head (m).
head_loss : float or numpy.ndarray or None
- Head loss (m). Can be precomputed or filled by calculators.
+ Head loss for the provided ``flow`` values (m). This may be provided by
+ the user or computed by head-loss calculators in this module.
max_headloss_allowed : float or None
- Maximum head loss as a percent of `head` (1–100). If None, 10% default
- is applied in Darcy–Weisbach sizing.
+ Maximum head loss allowed as a percentage of head (%, 1–100). If
+ ``None``, method-specific defaults may be applied.
penstock_headloss_method : str or None
- Text identifier for method: e.g., "Darcy-Weisbach" or "Hazen-Williams".
+ Name of the head-loss method. Current options in this module include
+ ``"Darcy-Weisbach"`` and ``"Hazen-Williams"``. (Manning is referenced
+ but not implemented in this file.)
penstock_headloss_calculation : bool
- If True, compute penstock head loss; set False when net head is given.
+ Whether to calculate head loss in the penstock. If net head is already
+ available externally, set to ``False``.
penstock_length : float or None
- Penstock length (m).
+ Penstock length (m). Required for head-loss calculations that depend on
+ length.
penstock_diameter : float or None
- Known penstock diameter (m). If None, methods will size it.
+ Penstock diameter (m). If ``None``, some methods may size diameter to
+ meet the allowed head-loss constraint.
penstock_material : str or None
- Material key in roughness tables (e.g., "Steel", "Concrete", etc.).
+ Penstock material key used for roughness selection. Expected options include: ``CastIron``, ``Concrete``, ``GalvanizedIron``, ``Plastic``, ``Steel``.
penstock_frictionfactor : float or None
- For Darcy–Weisbach: friction factor `f`. For Hazen–Williams: C-factor.
- If None, it is computed/selected.
+ Friction parameter for the chosen method:
+ - Darcy–Weisbach: friction factor ``f`` (if provided), or roughness
+ ``epsilon`` used to compute ``f``.
+ - Hazen–Williams: coefficient ``C``.
+ - Manning: ``n`` (not used in this file).
channel_average_velocity : float or None
- Average channel velocity (m/s), if used elsewhere.
-
- Attributes
- ----------
- Re : list or float
- Reynolds number (dimensionless), computed for design flow.
- penstock_design_diameter : float or None
- Working/selected design diameter (m).
- penstock_design_headloss : float or None
- Head loss (m) at design conditions for current diameter.
- channel_design_headloss : float or None
- channel_headloss : float or None
+ Average cross-sectional water velocity in the channel (Q/A), if
+ applicable.
+
+ Notes
+ -----
+ Many algorithms in this module mutate attributes on a shared
+ :class:`HydraulicDesignParameters` instance (e.g., updating
+ ``penstock_design_diameter`` during iterations).
"""
-
-
def __init__(self, flow, design_flow, # Flow parameters
head, head_loss,
max_headloss_allowed, penstock_headloss_method, penstock_headloss_calculation, # head / head loss
penstock_length, penstock_diameter, penstock_material, penstock_frictionfactor, # penstock parameters
channel_average_velocity):
- '''
- This class initializes hydraulic parameters needed for multiple calculations
- Parameter descriptions are provided below:
- '''
# Inputs
self.flow = flow # flow values (m3/s)
self.design_flow = design_flow # design flow (m3/s)
@@ -97,36 +100,35 @@ def __init__(self, flow, design_flow, # Flow parameters
# Reynolds number calculation
def reynoldsnumber_calculator(self):
- """
- Compute Reynolds number at design conditions.
+ """Compute and store the Reynolds number for the design condition.
Notes
-----
- Uses :math:`Re = 4Q / (\\pi D \\nu)` with kinematic viscosity `nu`
- defined at module level.
-
- Side Effects
- ------------
- - Ensures `penstock_design_diameter` is initialized via
- `designdiameter_calculator`.
- - Updates `self.Re`.
- """
+ This method updates ``self.penstock_design_diameter`` (if needed) and
+ writes the resulting Reynolds number to ``self.Re``.
+
+ The Reynolds number is computed as::
+ Re = 4 * Q / (pi * D * nu)
+
+ where ``Q`` is ``self.design_flow``, ``D`` is the (design) diameter, and
+ ``nu`` is the kinematic viscosity constant defined in this module.
+ """
self.designdiameter_calculator() # calculate diameter
self.Re = 4 * self.design_flow / (np.pi * self.penstock_design_diameter * nu) # Reynolds number, update
# Design diameter calculator - initial assumed diameter
def designdiameter_calculator(self):
- """
- Initialize the working design diameter if needed.
+ """Initialize ``penstock_design_diameter`` for calculations.
- Logic
+ Notes
-----
- - If `penstock_diameter` is provided, use it as the design diameter.
- - Else, if `penstock_design_diameter` is None, initialize to 0.01 m
- (seed for iterative sizing).
+ - If ``self.penstock_diameter`` is provided, it becomes the design
+ diameter.
+ - Otherwise, the method initializes ``self.penstock_design_diameter`` to
+ a small starting value (0.01 m) the first time it is needed.
"""
-
+
if self.penstock_diameter is not None: # penstock diameter is known
self.penstock_design_diameter = self.penstock_diameter # update
@@ -136,19 +138,18 @@ def designdiameter_calculator(self):
# Roughness coefficients
class RoughnessCoefficients:
- """
- Roughness tables for multiple formulas.
+ """Roughness coefficient record for a penstock material.
Parameters
----------
material : str
- Material name key.
+ Material identifier key (e.g., ``"Steel"``).
darcyweisbach_epsilon : float
- Absolute roughness (m) for Darcy–Weisbach.
+ Absolute roughness ``epsilon`` for Darcy–Weisbach calculations (m).
hazenwiliams_c : float
- C-factor for Hazen–Williams.
+ Hazen–Williams coefficient ``C`` (dimensionless).
mannings_n : float
- Manning's n for open-channel/pipe use.
+ Manning roughness coefficient ``n`` (s/m^(1/3)).
"""
def __init__(self, material, darcyweisbach_epsilon, hazenwiliams_c, mannings_n): # Epsilon, C, n
self.material = material
@@ -157,13 +158,11 @@ def __init__(self, material, darcyweisbach_epsilon, hazenwiliams_c, mannings_n):
self.mannings_n = mannings_n
class Values: # roughness values from Epanet documentation
- """
- Built-in roughness dictionary seeded from EPANET documentation.
+ """Catalog of default roughness values.
- Attributes
- ----------
- roughnesscoefficients : dict[str, RoughnessCoefficients]
- Mapping from material name to roughness parameters.
+ This nested class provides a dictionary mapping material keys to
+ :class:`RoughnessCoefficients` instances. Values are sourced from EPANET
+ documentation as indicated in the original code comments.
"""
def __init__(self):
self.roughnesscoefficients = { }
@@ -174,59 +173,63 @@ def __init__(self):
self.add_roughnesscoefficient_values("Steel", 0.00004572, 145, 0.016) # Steel. Epsilon, C, n
def add_roughnesscoefficient_values(self, material, darcyweisbach_epsilon, hazenwiliams_c, mannings_n): # method for adding roughness values
- """
- Add/override a material entry in the roughness table.
+ """Add a roughness coefficient record for a material key.
Parameters
----------
material : str
- Material key (e.g., "Steel").
+ Material identifier key.
darcyweisbach_epsilon : float
- Absolute roughness epsilon (m).
+ Darcy–Weisbach roughness (m).
hazenwiliams_c : float
- Hazen–Williams C-factor.
+ Hazen–Williams coefficient.
mannings_n : float
- Manning's n.
+ Manning ``n``.
+
+ Notes
+ -----
+ This method mutates ``self.roughnesscoefficients`` in place.
"""
self.roughnesscoefficients[material] = RoughnessCoefficients(material, darcyweisbach_epsilon, hazenwiliams_c, mannings_n)
# Roughness selection
class Roughness(ABC):
- """
- Abstract base for roughness selectors used by different head-loss methods.
- """
+ """Abstract base class for roughness selection."""
@abstractmethod
def roughness_selector(self, material):
- """
- Return the appropriate roughness parameter for the given material.
+ """Select a roughness parameter for the given material.
Parameters
----------
material : str or None
- Material name. If None, a method-specific default is used.
+ Material identifier key. If ``None``, implementations should apply
+ a method-specific default.
Returns
-------
float
- Roughness parameter (epsilon, C, or n) depending on implementation.
+ The selected roughness parameter (e.g., ``epsilon``, ``C``, or
+ ``n`` depending on the implementation).
"""
pass
class DW_RoughnessSelector(Roughness): # Darcy-Weisbach roughness selector
-
+ """Darcy–Weisbach roughness selector.
+
+ Selects absolute roughness ``epsilon`` (m) based on material.
+ """
def roughness_selector(self, material):
- """
- Select absolute roughness epsilon (m) for Darcy–Weisbach.
+ """Select Darcy–Weisbach absolute roughness ``epsilon``.
Parameters
----------
material : str or None
- Material key. If None, defaults to 'Steel'.
+ Material identifier key. Defaults to ``"Steel"`` when ``None``.
Returns
-------
float
- Absolute roughness epsilon (m).
+ Absolute roughness ``epsilon`` (m).
"""
roughness_coefficients = RoughnessCoefficients.Values() # read existing roughness coefficient values
if material is not None: # user provided material
@@ -236,22 +239,23 @@ def roughness_selector(self, material):
return epsilon
class HW_RoughnessSelector(Roughness): # Hazen-Williams roughness selector
-
+ """Hazen–Williams roughness selector.
+
+ Selects Hazen–Williams coefficient ``C`` based on material.
+ """
def roughness_selector(self, material):
- """
- Select Hazen–Williams C-factor.
+ """Select Hazen–Williams coefficient ``C``.
Parameters
----------
material : str or None
- Material key. If None, defaults to 'Steel'.
+ Material identifier key. Defaults to ``"Steel"`` when ``None``.
Returns
-------
float
- Hazen–Williams C-factor.
+ Hazen–Williams coefficient ``C``.
"""
-
roughness_coefficients = RoughnessCoefficients.Values() # read existing roughness coefficient values
if material is not None: # user provided material
C = roughness_coefficients.roughnesscoefficients[material].hazenwiliams_c
@@ -260,22 +264,23 @@ def roughness_selector(self, material):
return C
class Manning_RoughnessSelector(Roughness):
+ """Manning roughness selector.
+ Selects Manning coefficient ``n`` based on material.
+ """
def roughness_selector(self, material):
- """
- Select Manning's n.
+ """Select Manning roughness coefficient ``n``.
Parameters
----------
material : str or None
- Material key. If None, defaults to 'Concrete'.
+ Material identifier key. Defaults to ``"Concrete"`` when ``None``.
Returns
-------
float
- Manning's n.
+ Manning roughness coefficient ``n``.
"""
-
roughness_coefficients = RoughnessCoefficients.Values() # read existing roughness coefficient values
if material is not None: # user provided material
n = roughness_coefficients.roughnesscoefficients[material].mannings_n
@@ -284,27 +289,34 @@ def roughness_selector(self, material):
return n
class DW_FrictionFactor(): # Darcy-Weisbach friction factor calculator
-
+ """Darcy–Weisbach friction factor calculator.
+
+ Computes a Darcy friction factor using regime-dependent formulas:
+ Swamee–Jain approximation (turbulent),
+ Cubic interpolation (transitional),
+ Laminar expression (laminar),
+
+ References are preserved from the original inline comments.
+ """
def frictionfactor_calculator(self, hydraulic_parameters):
- """
- Compute Darcy–Weisbach friction factor `f`.
+ """Compute Darcy–Weisbach friction factor ``f``.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Must provide `Re`, `penstock_design_diameter`, and `penstock_material`.
+ Hydraulic parameters containing:
+ ``penstock_material`` (str or None),
+ ``Re`` (float),
+ ``penstock_design_diameter`` (float)
Returns
-------
float
- Friction factor `f` (dimensionless).
+ Darcy friction factor ``f`` (dimensionless).
Notes
-----
- - Uses Swamee–Jain (turbulent), Dunlop cubic interpolation (transition),
- and `64/Re` (laminar), with epsilon from `DW_RoughnessSelector`.
- - Assumes `hydraulic_parameters.Re` has been computed (call
- `reynoldsnumber_calculator` first if needed).
+ This method does not mutate ``hydraulic_parameters``; it reads from it.
"""
epsilon = DW_RoughnessSelector().roughness_selector(material = hydraulic_parameters.penstock_material) # DW roughness factor
@@ -335,47 +347,44 @@ def frictionfactor_calculator(self, hydraulic_parameters):
# Head loss calculation
class HeadLoss(ABC):
- """
- Abstract base for head-loss calculators.
- """
-
+ """Abstract base class for penstock head-loss calculators."""
@abstractmethod
def penstock_headloss_calculator(self, hydraulic_parameters):
- """
- Compute (or size for) head loss at design conditions.
+ """Compute (or size) penstock head loss for the design condition.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Inputs/outputs container. Implementations may update:
- - `penstock_design_diameter`
- - `penstock_design_headloss`
- - `penstock_frictionfactor`
+ The parameter container to read inputs from and update outputs on.
+
+ Notes
+ -----
+ Implementations typically update ``hydraulic_parameters`` in place.
"""
pass
class DarcyWeisbach(HeadLoss): # Head loss calculator using Darcy-Weisbach
-
+ """Penstock head-loss calculator using Darcy–Weisbach."""
def penstock_headloss_calculator(self, hydraulic_parameters):
- """
- Compute Darcy–Weisbach head loss at design conditions and (optionally) size D.
+ """Compute Darcy–Weisbach head loss at design flow and update parameters.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Requires `design_flow`, `penstock_length`, `penstock_material`,
- and either a known `penstock_diameter` or permission to size it.
- Uses/updates `penstock_frictionfactor`, `penstock_design_headloss`,
- and `penstock_design_diameter`.
+ Parameter container. This method reads (at minimum) ``design_flow``,
+ ``head``, ``penstock_length``, ``penstock_diameter`` and updates
+ working values such as ``penstock_design_diameter``,
+ ``penstock_design_headloss``, and ``penstock_frictionfactor``.
Notes
-----
- - If `penstock_frictionfactor` is None, it is computed via
- `DW_FrictionFactor`.
- - If `penstock_diameter` is None, `diameter_check` iteratively increases D
- until head loss ≤ (`max_headloss_allowed` × `head`).
- """
+ This method mutates ``hydraulic_parameters`` in place.
+ If ``hydraulic_parameters.penstock_diameter`` is ``None``, the method
+ will iteratively increase diameter until the computed head loss is less
+ than or equal to the allowed fraction of head (see
+ :meth:`diameter_check`).
+ """
hydraulic_parameters.reynoldsnumber_calculator() # calculate Reynolds number
D = hydraulic_parameters.penstock_design_diameter # Design diameter
L = hydraulic_parameters.penstock_length # Penstock lenght
@@ -394,22 +403,28 @@ def penstock_headloss_calculator(self, hydraulic_parameters):
if hydraulic_parameters.penstock_diameter is None:
DarcyWeisbach().diameter_check(hydraulic_parameters) # Check: head loss does not exceed the max allowed head loss - increase D until reached
- def diameter_check(self, hydraulic_parameters): #
- """
- Enforce maximum allowable head-loss by increasing diameter iteratively.
+ def diameter_check(self, hydraulic_parameters):
+ """Iteratively increase diameter until head-loss constraint is met.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Must define `head`. If `max_headloss_allowed` is None, 10% is used.
+ Parameter container updated in place. The method reads
+ ``max_headloss_allowed``, ``head``, ``penstock_length`` and updates
+ ``penstock_design_diameter``, ``penstock_design_headloss``, and
+ finally ``penstock_diameter``.
- Side Effects
- ------------
- - Increases `penstock_design_diameter` in 0.1 m steps and recomputes head loss
- until `penstock_design_headloss` ≤ (`max_headloss_allowed` × `head`).
- - Updates `penstock_diameter` with the final selected diameter.
+ Notes
+ -----
+ This method mutates ``hydraulic_parameters`` in place.
+
+ - If ``max_headloss_allowed`` is ``None``, a default of 10% is used.
+ - If ``penstock_length`` is ``None``, the method sets design head loss
+ to ``head * max_headloss_allowed`` and skips diameter iteration.
+ - Otherwise, the method uses recursion via
+ :meth:`penstock_headloss_calculator` while incrementing diameter by
+ 0.1 m until the constraint is satisfied.
"""
-
# max head loss allowes
max_headloss_allowed = hydraulic_parameters.max_headloss_allowed
@@ -435,57 +450,64 @@ def diameter_check(self, hydraulic_parameters): #
hydraulic_parameters.penstock_diameter = hydraulic_parameters.penstock_design_diameter # update
def penstock_headloss_calculator_ts(self, hydraulic_parameters):
- """
- Compute Darcy–Weisbach head loss (time-series) for `turbine_flow`.
+ """Compute Darcy–Weisbach head loss for a flow time series.
- Parameters
- ----------
- hydraulic_parameters : HydraulicDesignParameters
- Requires `penstock_length`, `penstock_design_diameter`,
- `penstock_frictionfactor`, and `turbine_flow` (array).
-
- Raises
- ------
- ValueError
- If `penstock_length` is not provided.
-
- Side Effects
- ------------
- Updates `hydraulic_parameters.head_loss` (array, m) using
- :math:`h_f = f L V^2 / (2 g D)` with :math:`V = Q / A`.
- """
-
- if hydraulic_parameters.penstock_length is None: # penstock lenght not provided
- raise ValueError("The penstock lenght is required for head loss calculations")
-
- else:
- D = hydraulic_parameters.penstock_design_diameter
- V = hydraulic_parameters.turbine_flow / (np.pi * (D/2)**2) # V = Q/A
- ff = hydraulic_parameters.penstock_frictionfactor # DW friction factor
- L = hydraulic_parameters.penstock_length #
- hydraulic_parameters.head_loss = ff * L * V**2 / (D * 2*g) # D-W head loss for flow != design_flow - update
+ Parameters
+ ----------
+ hydraulic_parameters : HydraulicDesignParameters
+ Parameter container with:
+ ``turbine_flow`` (array-like): flow values (m³/s),
+ ``penstock_length`` (float): required,
+ ``penstock_design_diameter`` (float),
+ ``penstock_frictionfactor`` (float): Darcy friction factor
+
+ Raises
+ ------
+ ValueError
+ If ``hydraulic_parameters.penstock_length`` is ``None``.
+
+ Notes
+ -----
+ This method mutates ``hydraulic_parameters.head_loss`` in place by
+ computing head loss for each time-series flow value.
+ """
+ if hydraulic_parameters.penstock_length is None: # penstock lenght not provided
+ raise ValueError("The penstock lenght is required for head loss calculations")
+
+ else:
+ D = hydraulic_parameters.penstock_design_diameter
+ V = hydraulic_parameters.turbine_flow / (np.pi * (D/2)**2) # V = Q/A
+ ff = hydraulic_parameters.penstock_frictionfactor # DW friction factor
+ L = hydraulic_parameters.penstock_length #
+ hydraulic_parameters.head_loss = ff * L * V**2 / (D * 2*g) # D-W head loss for flow != design_flow - update
class HazenWilliamns(HeadLoss): # Head loss calculator using Hazen-Williams
+ """Penstock head-loss calculator using Hazen–Williams.
+ Notes
+ -----
+ The class name is kept as in the source (``HazenWilliamns``), though the
+ standard spelling is "HazenWilliams".
+ """
def penstock_headloss_calculator(self, hydraulic_parameters):
- """
- Compute Hazen–Williams head loss at design flow and (optionally) size D.
+ """Compute Hazen–Williams head loss and update parameters.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Requires `design_flow` and either known `penstock_diameter` or
- `max_headloss_allowed`/`head` to size D. Uses/updates:
- - `penstock_frictionfactor` (C),
- - `penstock_design_headloss`,
- - `penstock_diameter`,
- - `Re` via `reynoldsnumber_calculator`.
+ Parameter container. This method reads (at minimum) ``design_flow``,
+ ``head``, ``penstock_length``, ``penstock_diameter`` and updates
+ ``penstock_frictionfactor`` (as Hazen–Williams ``C``),
+ ``penstock_design_headloss``, and potentially ``penstock_diameter``.
Notes
-----
- Uses :math:`h_f = 10.67\\, L\\, Q^{1.852} / (C^{1.852} D^{4.87})`.
- """
+ This method mutates ``hydraulic_parameters`` in place.
+ - If ``penstock_diameter`` is provided, head loss is computed directly.
+ - If ``penstock_diameter`` is ``None``, diameter is computed to satisfy
+ a head-loss allowance (default 10% of head if not provided).
+ """
if hydraulic_parameters.penstock_frictionfactor is None: # if a value of C is not given
C = HW_RoughnessSelector().roughness_selector(material = hydraulic_parameters.penstock_material) # HW roughness factor (C)
@@ -516,21 +538,24 @@ def penstock_headloss_calculator(self, hydraulic_parameters):
return None
def penstock_headloss_calculator_ts(self, hydraulic_parameters):
- """
- Compute Hazen–Williams head loss (time-series) for `turbine_flow`.
+ """Compute Hazen–Williams head loss for a flow time series.
Parameters
----------
hydraulic_parameters : HydraulicDesignParameters
- Requires `penstock_design_diameter`, `penstock_frictionfactor` (C),
- `penstock_length`, and `turbine_flow` (array).
+ Parameter container with:
+ ``turbine_flow`` (array-like): flow values (m³/s),
+ ``penstock_length`` (float or None),
+ ``penstock_design_diameter`` (float),
+ ``penstock_frictionfactor`` (float): Hazen–Williams ``C``
- Side Effects
- ------------
- Updates `hydraulic_parameters.head_loss` (array, m) via the
- Hazen–Williams formula.
- """
+ Notes
+ -----
+ This method mutates ``hydraulic_parameters.head_loss`` in place.
+ If ``penstock_length`` is ``None``, the method returns immediately
+ without modification.
+ """
if hydraulic_parameters.penstock_length is None:
return
diff --git a/HydroGenerate/hydropower_potential.py b/HydroGenerate/hydropower_potential.py
index deed35e..e572b13 100755
--- a/HydroGenerate/hydropower_potential.py
+++ b/HydroGenerate/hydropower_potential.py
@@ -51,40 +51,28 @@
# Economic Parameters
class EconomicParameters:
- """
- Container for simple economic inputs.
+ """Economic input parameter container.
Parameters
----------
resource_category : str or None
- Category for cost model (e.g., 'Non-PoweredDam', 'NewStream-reachDevelopment').
+ Resource category identifier used by the cost model. Examples include
+ ``'Non-PoweredDam'`` and ``'NewStream-reachDevelopment'`` (exact accepted
+ values depend on the downstream model).
capacity_factor : float or None
- Capacity factor as a fraction (0–1) or percent (0–100) depending on use;
- see revenue calculators for interpretation.
+ Capacity factor as a proportion (0–1) for constant-price energy
+ estimation. When using ``n_operation_days``, this may be inferred.
electricity_sell_price : float or None
- Electricity price ($/kWh). If None, a 2023 wholesale default is used.
- n_operation_days : int or None
- Days per year the plant operates (<= 365) when capacity factor is not supplied.
+ Electricity sell price ($/kWh). If ``None``, a default wholesale price
+ is used in revenue calculations.
+ n_operation_days : int or float or None
+ Number of operation days per year (0–365). Used when capacity factor is
+ not provided.
- Attributes
- ----------
- resource_category : str or None
- electricity_sell_price : float or None
- capacity_factor : float or None
- n_operation_days : int or None
"""
-
def __init__(self, resource_category,
capacity_factor, electricity_sell_price, n_operation_days):
- '''
- This class initializes the calculation of hydropower potential for a specific turbine type
- Input variables:
- - sell_price: Selects the particular turbine based on available head
-
- Returns: None
- '''
-
self.resource_category = resource_category # Options: 'Non-PoweredDam', 'NewStream-reachDevelopment',
self.electricity_sell_price = electricity_sell_price # selling price of electricity, $/kWh
self.capacity_factor = capacity_factor # capcity factor, %
@@ -92,77 +80,85 @@ def __init__(self, resource_category,
# Function to combine multiple instances
def merge_instances(ob1, *args):
- """
- Merge attributes from multiple objects into the first object.
+ """Merge the attributes of multiple objects into a single instance.
Parameters
----------
ob1 : object
- Target object to be updated in-place.
+ Base object whose ``__dict__`` will be updated.
*args : object
- One or more objects whose `__dict__` will be merged into `ob1`.
+ Additional objects whose attributes are merged into ``ob1``. For each
+ object ``d``, the merge behavior is equivalent to::
+
+ ob1.__dict__.update(d.__dict__)
Returns
-------
object
- The updated `ob1` reference.
+ The updated ``ob1`` instance.
Notes
-----
- Later objects in `*args` may overwrite attributes from earlier ones.
+ - If multiple objects share the same attribute name, later objects in
+ ``*args`` override earlier values.
+ - This function performs a shallow merge of ``__dict__`` only.
"""
-
for d in args:
ob1.__dict__.update(d.__dict__)
return ob1
# function to calculated head
def calculate_head(rated_flow, rated_power):
- """
- Compute net head (m) from rated flow and power.
+ """Compute net head from rated flow and rated power.
Parameters
----------
rated_flow : float
- Flow at rated conditions (m³/s).
+ Rated flow (m³/s).
rated_power : float
- Electrical power (W).
+ Rated power (kW).
Returns
-------
float
- Net head in meters computed as `P / (rho * g * Q)`.
- """
+ Head (m), computed as::
+
+ head = rated_power / (rho * g * rated_flow)
+ Notes
+ -----
+ - ``rated_power`` is expected in kW, consistent with the rest of this module.
+ - ``rho`` and ``g`` are module-level constants.
+ """
return rated_power/(rho*g*rated_flow)
# Function to check if a pandas dataframe is used and extract flow values
def pd_checker(flow, flow_column):
- """
- Normalize flow input and detect pandas DataFrame usage.
+ """Check for pandas DataFrame input and extract flow values.
Parameters
----------
- flow : float or array-like or pandas.DataFrame
- Flow input. If DataFrame, must include the column named by `flow_column`.
+ flow : array-like or pandas.DataFrame
+ Flow input. If a DataFrame is provided, ``flow_column`` must specify the
+ column containing flow values.
flow_column : str or None
- Column name containing flow values when `flow` is a DataFrame.
+ Name of the DataFrame column that contains flow values.
Returns
-------
tuple
- (flow_data, pandas_dataframe) where:
- - flow_data : float or numpy.ndarray
- Scalar/array extracted from the DataFrame or the original value.
- - pandas_dataframe : bool
- True if DataFrame input was used.
+ ``(flow_data, pandas_dataframe)`` where:
+
+ - ``flow_data`` : array-like
+ Extracted flow values (NumPy array when DataFrame input is used).
+ - ``pandas_dataframe`` : bool
+ True if the original input was a DataFrame, otherwise False.
Raises
------
ValueError
- If `flow` is a DataFrame but `flow_column` is not provided.
+ If ``flow`` is a DataFrame and ``flow_column`` is not provided.
"""
-
pandas_dataframe = False # flag to track if a pandas dataframe is used outside of this function
if isinstance(flow, pd.DataFrame): # check if a pandas dataframe is used
@@ -181,31 +177,30 @@ def pd_checker(flow, flow_column):
# Unit transformation
class Units:
- """
- Convert selected attributes on `self` from US to SI units.
-
- Side Effects
- ------------
- Converts in place (when present):
- - flow, design_flow, minimum_turbineflow : cfs → m³/s
- - head, head_loss, penstock_length, hk_blade_diameter, hk_blade_heigth : ft → m
- - channel_average_velocity : ft/s → m/s
- - penstock_diameter : ft → m
- """
+ """Unit conversion helper for HydroGenerate parameter objects.
+ Notes
+ -----
+ These methods assume ``self`` is an object with the relevant attributes
+ (e.g., the merged ``all_params`` object created by :func:`calculate_hp_potential`).
+
+ - ``us_to_si_conversion`` converts from US customary units to SI.
+ - ``si_to_us_conversion`` converts from SI back to US customary units.
+
+ The conversion is performed in place by mutating the corresponding attributes.
+ """
def us_to_si_conversion(self):
- """
- Convert selected attributes on `self` from US to SI units.
-
- Side Effects
- ------------
- Converts in place (when present):
- - flow, design_flow, minimum_turbineflow : cfs → m³/s
- - head, head_loss, penstock_length, hk_blade_diameter, hk_blade_heigth : ft → m
- - channel_average_velocity : ft/s → m/s
- - penstock_diameter : ft → m
- """
+ """Convert supported attributes from US customary units to SI.
+ Notes
+ -----
+ This method mutates attributes on ``self`` in place when they are present.
+
+ Expected unit assumptions (US -> SI):
+ - Flow (cfs) -> m³/s
+ - Head/length (ft) -> m
+ - Velocity (ft/s) -> m/s (implemented via ``ft_to_m`` multiplier)
+ """
if self.flow is not None:
self.flow = self.flow * cfs_to_cms # cfs to m3/s
@@ -237,24 +232,17 @@ def us_to_si_conversion(self):
self.hk_blade_heigth = self.hk_blade_heigth * ft_to_m # ft to m
def si_to_us_conversion(self):
- """
- Convert selected attributes on `self` from SI to US units.
-
- Side Effects
- ------------
- Converts in place (when present):
- - flow, turbine_flow, design_flow, minimum_turbineflow : m³/s → cfs
- - dataframe_output['turbine_flow_cfs'] : m³/s → cfs
- - head, head_loss, penstock_design_headloss, net_head, max_headloss_allowed,
- penstock_length, penstock_diameter, hk_blade_diameter, hk_blade_heigth,
- runner_diameter : m (or m-derived) → ft
- - channel_average_velocity : m/s → ft/s
+ """Convert supported attributes from SI to US customary units.
Notes
-----
- Net head is only converted for non-hydrokinetic modes.
- """
+ This method mutates attributes on ``self`` in place when they are present.
+ Expected unit conversions (SI -> US):
+ - Flow (m³/s) -> cfs
+ - Head/length (m) -> ft
+ - Velocity (m/s) -> ft/s
+ """
if self.flow is not None:
self.flow = self.flow / cfs_to_cms # m3/s tp cfs
@@ -306,51 +294,56 @@ def si_to_us_conversion(self):
# Hydropower calculation
class Hydropower(ABC):
- """
- Abstract base class for hydropower calculators.
- """
-
+ """Abstract base class for hydropower calculation workflows."""
@abstractmethod
def hydropower_calculation(self, hp_params):
- """
- Compute hydropower for the given parameter container.
+ """Run a hydropower calculation for a parameter container.
Parameters
----------
hp_params : object
- Parameter object updated in place with results.
- """
+ Parameter container holding hydropower inputs and outputs.
+ Notes
+ -----
+ Implementations typically mutate ``hp_params`` in place by setting fields
+ such as ``rated_power``, ``power``, ``turbine_efficiency``, and
+ ``net_head``.
+ """
pass
# Basic calculation
class Basic(Hydropower):
+ """Basic hydropower calculation using the standard power equation."""
+
def hydropower_calculation(self, hp_params):
- """
- Solve for the missing variable among {flow, head, rated_power} and compute power.
+ """Compute hydropower (or back-calculate missing variable) for basic projects.
Parameters
----------
hp_params : object
- Must supply at least two of {flow (m³/s), head (m), rated_power (kW)}.
- May include `head_loss` (m) and `system_efficiency` (0–1).
+ Parameter container with attributes including:
+ ``flow`` (float),
+ ``head`` (float),
+ ``rated_power`` (float),
+ ``system_efficiency`` (float or None),
+ ``head_loss`` (float or None)
Raises
------
ValueError
- If fewer than two of {flow, head, rated_power} are provided.
-
- Side Effects
- ------------
- Updates `hp_params.flow`, `hp_params.head`, `hp_params.rated_power`,
- `hp_params.net_head`, `hp_params.penstock_design_headloss` as needed.
+ If insufficient inputs are provided (at least two of flow, head,
+ rated power must be known).
Notes
-----
- Default overall efficiency is 0.85 if not provided.
- Power formula: `P[kW] = n * rho * g * Q * H / 1000`.
+ This method mutates ``hp_params`` in place. It may update:
+ ``hp_params.head`` (if head is computed),
+ ``hp_params.flow`` (if flow is computed),
+ ``hp_params.rated_power`` (if rated power is computed),
+ ``hp_params.net_head`` and ``hp_params.head`` (net head accounting for head loss),
+ ``hp_params.penstock_design_headloss`` (set to None for unit conversion reuse).
"""
-
flow = hp_params.flow # flow, m3/s
head = hp_params.head # head, m
rated_power = hp_params.rated_power # rated power, KW
@@ -393,38 +386,35 @@ def hydropower_calculation(self, hp_params):
# Diversion - Run-of-river
class Diversion(Hydropower):
- def hydropower_calculation(self, hp_params):
- """
- Run full run-of-river (diversion) workflow from design flow to power.
+ """Diversion (run-of-river) hydropower workflow including turbine and head-loss modeling."""
+ def hydropower_calculation(self, hp_params):
+ """Compute diversion hydropower potential for single values or time series flows.
+
Parameters
----------
hp_params : object
- Requires:
- - flow/design_flow and head (SI inside the routine)
- - penstock settings if head-loss calculation is enabled
- - turbine selection inputs (e.g., Rm, pelton_n_jets)
- - flags for annual/major maintenance when time series present
+ Parameter container expected to include:
+ Flow inputs: ``flow`` / ``design_flow``, and possibly time series metadata,
+ Turbine settings: ``turbine_type``, ``generator_efficiency``,
+ Head-loss settings: ``penstock_headloss_calculation``, ``penstock_length``, ``penstock_headloss_method``, etc.,
+ Flow preprocessing settings: minimum flow, maintenance flags
Raises
------
ValueError
- If unsupported turbine or head-loss method is requested, or when
- required values for head-loss calculations are missing.
-
- Side Effects
- ------------
- - Selects turbine type and computes efficiency curve.
- - Applies flow min/max limits, maintenance outages (if flagged).
- - Computes head loss (design and time series) for DW/HW as configured.
- - Updates rated power, per-step power, net head, and related fields.
+ If turbine type is not supported, head-loss method is not supported,
+ or required inputs (e.g., penstock length when head-loss calculation is enabled)
+ are missing.
Notes
-----
- Turbine types supported: Kaplan, Francis, Pelton, Turgo, Crossflow, Propeller.
- Head-loss methods supported: Darcy–Weisbach, Hazen–Williams.
+ This method mutates ``hp_params`` in place. It updates (as available):
+ Flow range / turbine flow series,
+ Turbine efficiencies and power time series,
+ Rated power and net head,
+ Head loss arrays (when penstock head-loss calculations are enabled)
"""
-
# Calculate design flow
if hp_params.design_flow is None:
PercentExceedance().designflow_calculator(hp_params)
@@ -538,23 +528,26 @@ def hydropower_calculation(self, hp_params):
hp_params.head = h # update
class Hydrokinetic(Hydropower):
+ """Hydrokinetic (in-stream) hydropower workflow."""
def hydropower_calculation(self, hp_params):
- """
- Compute hydrokinetic power from swept area and channel velocity.
+ """Compute hydrokinetic power based on velocity and swept area.
Parameters
----------
hp_params : object
- Uses/updates:
- - system_efficiency : percent if not None, otherwise defaults to 59 (Betz limit)
- - hk_swept_area or geometry fields to compute it
- - channel_average_velocity : m/s
-
- Side Effects
- ------------
- Updates `hp_params.rated_power` (kW).
- """
+ Parameter container expected to include:
+ ``system_efficiency`` (percent, optional; defaults to Betz limit),
+ ``hk_swept_area`` (m², optional),
+ ``channel_average_velocity`` (m/s),
+ Blade geometry if swept area needs to be computed
+ Notes
+ -----
+ This method mutates ``hp_params`` in place by updating:
+ ``system_efficiency`` (defaulted to 59% if not provided),
+ ``hk_swept_area`` (computed if not provided),
+ ``rated_power`` (kW)
+ """
# System efficiency
if hp_params.system_efficiency: # if the user provides an efficiency value
n = hp_params.system_efficiency
@@ -576,50 +569,58 @@ def hydropower_calculation(self, hp_params):
# Hydropower economic analysis: Cost
class Cost(ABC):
- """
- Abstract base for cost models.
- """
-
+ """Abstract base class for cost models."""
@abstractmethod
def cost_calculation(self, hp_params):
- """
- Compute and update capital and O&M cost fields on `hp_params`.
- """
+ """Compute (or estimate) cost quantities and update ``hp_params``.
+ Parameters
+ ----------
+ hp_params : object
+ Parameter container holding project descriptors and hydropower outputs.
+
+ Notes
+ -----
+ Implementations typically mutate ``hp_params`` in place by adding fields
+ such as ``icc`` and ``annual_om``.
+ """
pass
# ORNL_HBCM methods obtained from: https://info.ornl.gov/sites/publications/files/Pub58666.pdf
class ONRL_BaselineCostModeling_V2(Cost):
+ """ORNL baseline cost model (HBCM v2) implementation.
+
+ Notes
+ -----
+ The cost method is annotated in the source as derived from the ORNL report:
+ https://info.ornl.gov/sites/publications/files/Pub58666.pdf
+
+ The original source code contains some non-ASCII variable symbols in a few
+ expressions (e.g., ``𝑃`` / ``𝐻``). They are preserved here as-is to avoid
+ altering runtime behavior.
+ """
def cost_calculation(self, hp_params):
- """
- Estimate initial capital cost (ICC) and annual O&M via ORNL HBCM (2014).
+ """Estimate initial capital cost (ICC) and annual O&M and update parameters.
Parameters
----------
hp_params : object
- Requires:
- - rated_power : float (kW)
- - net_head : float (m)
- - resource_category : str (mapped to model cases)
-
- Returns
- -------
- None
-
- Side Effects
- ------------
- Sets:
- - `hp_params.icc` : float
- ICC in million 2014 USD.
- - `hp_params.annual_om` : float
- Annual O&M in million 2014 USD (min of model curve and 2.5% of ICC
- for categories other than GENERATORREWIND).
+ Parameter container expected to include:
+ ``rated_power`` (kW),
+ ``net_head`` (m),
+ ``resource_category`` (str or None)
+
+ Raises
+ ------
+ ValueError
+ If ``resource_category`` is not in the accepted list.
Notes
-----
- Internally converts head to ft and power to MW per model definitions.
+ This method mutates ``hp_params`` in place by setting:
+ ``hp_params.icc`` (million $2014),
+ ``hp_params.annual_om`` (million $2014)
"""
-
P = hp_params.rated_power / 1000 # rated power, mW
H = hp_params.net_head / ft_to_m # net head, ft
@@ -674,46 +675,50 @@ def cost_calculation(self, hp_params):
# Hydropower economic analysis: evenue
class Revenue(ABC):
- """
- Abstract base for revenue models.
- """
-
+ """Abstract base class for revenue models."""
@abstractmethod
def revenue_calculation(self, hp_params):
- """
- Compute and update energy and revenue fields on `hp_params`.
- """
+ """Compute revenue quantities and update ``hp_params``.
+ Parameters
+ ----------
+ hp_params : object
+ Parameter container holding power outputs and economic settings.
+
+ Notes
+ -----
+ Implementations typically mutate ``hp_params`` in place by adding fields
+ such as ``annual_energy_generated`` and ``annual_revenue``.
+ """
pass
# Constant electricty price for single / multiple values of flow - not a time series
class ConstantEletrictyPrice(Revenue):
- def revenue_calculation(self, hp_params):
- """
- Annual energy/revenue from mean power and capacity factor or days/year.
+ """Revenue model using a constant electricity price (non-time-indexed flows)."""
+ def revenue_calculation(self, hp_params):
+ """Compute annual energy and revenue using constant price assumptions.
Parameters
----------
hp_params : object
- Uses:
- - power : array-like of kW (time series)
- - capacity_factor : float or None
- - n_operation_days : int or None
- - electricity_sell_price : float ($/kWh) or None
-
- Side Effects
- ------------
- Sets:
- - `hp_params.annual_energy_generated` : float (kWh)
- - `hp_params.annual_revenue` : float (million $)
- - Harmonizes `capacity_factor` and `n_operation_days` when one is given.
+ Parameter container expected to include:
+ ``power`` (array-like): kW time series or flow-range power,
+ ``capacity_factor`` (float or None): proportion (0–1),
+ ``n_operation_days`` (int/float or None): 0–365,
+ ``electricity_sell_price`` (float or None): $/kWh
Raises
------
ValueError
- If `n_operation_days` > 365 when capacity factor is not provided.
- """
+ If ``n_operation_days`` exceeds 365.
+ Notes
+ -----
+ This method mutates ``hp_params`` in place by setting:
+ ``annual_energy_generated`` (kWh),
+ ``annual_revenue`` (million $),
+ and may update ``capacity_factor`` / ``n_operation_days`` defaults.
+ """
mean_power = np.mean(hp_params.power) # mean of the power provided for a time series of flow
if hp_params.n_operation_days is None:
@@ -738,29 +743,29 @@ def revenue_calculation(self, hp_params):
# Constant electricty price for a pandas dataframe with a dateTime index.
class ConstantEletrictyPrice_pd(Revenue):
+ """Revenue model for a time-indexed pandas DataFrame flow input."""
+
def revenue_calculation(self, hp_params, flow):
- """
- Annual energy/revenue from a time-indexed pandas DataFrame.
+ """Compute annual energy, revenue, and summary statistics for time series flows.
Parameters
----------
hp_params : object
- Uses/updates: power (kW), turbine_flow (m³/s or cfs depending on mode),
- turbine_efficiency (0–1), rated_power (kW), electricity_sell_price ($/kWh).
+ Parameter container expected to include:
+ ``power`` (array-like): kW time series aligned with ``flow.index``,
+ ``turbine_flow`` (array-like): turbine flow aligned with ``flow.index``,
+ ``rated_power`` (float): kW,
+ ``electricity_sell_price`` (float or None),
+ ``turbine_efficiency`` (array-like): turbine efficiency series
flow : pandas.DataFrame
- Time-indexed DataFrame; index frequency determines hourly energy step.
-
- Side Effects
- ------------
- - Populates `hp_params.dataframe_output` with power/flow/efficiency/energy.
- - Populates `hp_params.annual_dataframe_output` with annual KPIs
- (energy, revenue, capacity factor).
+ Original user-provided flow DataFrame with a DatetimeIndex.
Notes
-----
- Capacity factor is clipped to ≤ 1. Hours are computed from index diffs.
+ This method mutates ``hp_params`` in place by setting:
+ ``dataframe_output`` : per-timestep outputs (power, energy, efficiency),
+ ``annual_dataframe_output`` : annual aggregates including capacity factor and revenue
"""
-
if hp_params.electricity_sell_price is None:
hp_params.electricity_sell_price = wholesale_elecprice_2023 # electricity sell price, defined above
@@ -834,100 +839,124 @@ def calculate_hp_potential(flow= None,
minimum_turbineflow_percent = None,
annual_maintenance_flag = False,
major_maintenance_flag = False):
- """
- End-to-end hydropower potential calculation and (optionally) revenue/costs.
+ """Calculate hydropower potential and related outputs.
+
+ This is the primary user-facing entry point for HydroGenerate. It constructs
+ parameter containers, merges them into a single object, performs unit
+ conversions, runs the requested hydropower calculation workflow, and (optionally)
+ runs cost and annual revenue calculations.
Parameters
----------
- flow : float or array-like or pandas.DataFrame, optional
- Input flow. If DataFrame, provide `flow_column` with the column name.
- head : float, optional
- Gross head (ft or m depending on `units`).
- rated_power : float, optional
- Rated power (kW). Used with `flow`/`head` to solve missing variables in BASIC.
- hydropower_type : {'BASIC','DIVERSION','HYDROKINETIC'} or None, default 'BASIC'
- Calculation mode. If None, skips hydro calc but enables cost if requested.
- units : {'US','SI'}, default 'US'
- Input/output unit system. Internally converted to SI for calculations.
- penstock_headloss_method : {'Darcy-Weisbach','Hazen-Williams'}, default 'Darcy-Weisbach'
- Method for head-loss estimation when `penstock_headloss_calculation` is True.
- design_flow : float, optional
- Design flow (same units as `flow`). If None, estimated from percent exceedance when available.
- system_efficiency : float, optional
- Overall efficiency (0–1 or 0–100% depending on context).
- generator_efficiency : float, optional
- Generator efficiency (0–1 or 0–100%). Defaults to 0.98 if None.
- turbine_type : str, optional
- Fixed turbine type; if None, selected automatically in DIVERSION mode.
- head_loss : float, optional
- Known head loss (same units as `head`).
- penstock_headloss_calculation : bool, default False
- Whether to compute penstock head-loss (design and time series).
- penstock_length, penstock_diameter : float, optional
- Penstock geometry (length, diameter).
- penstock_material : str, optional
- Material key for roughness tables (e.g., 'Steel').
- penstock_frictionfactor : float, optional
- DW friction factor or HW C value; if None, computed/selected.
- pctime_runfull : float, optional
- Target percent exceedance used to derive `design_flow` from FDC.
- max_headloss_allowed : float, optional
- Max allowed head loss as percent of head.
- turbine_Rm : float, optional
- Manufacturer/design coefficient for reaction turbines.
- pelton_n_jets : int, optional
- Pelton jet count.
- flow_column : str, optional
- Column name when `flow` is a pandas.DataFrame.
- channel_average_velocity : float, optional
- Cross-sectional mean velocity (m/s) for hydrokinetic mode.
- hk_blade_diameter, hk_blade_heigth : float, optional
- Hydrokinetic rotor geometry (m).
- hk_blade_type : {'ConventionalRotor','H-DarrieusRotor','DarrieusRotor'}, optional
- hk_swept_area : float, optional
- Hydrokinetic swept area (m²); computed if not provided.
- annual_caclulation : bool, default False
- If True, compute annual energy and revenue (DataFrame-based if available).
- resource_category : str, optional
- Cost model category used by ORNL HBCM.
- electricity_sell_price : float, optional
- Price of electricity ($/kWh) for revenue.
- cost_calculation_method : {'ORNL_HBCM'}, default 'ORNL_HBCM'
- Cost model selector.
- capacity_factor : float, optional
- Capacity factor (0–1 or 0–100%) for revenue if not using DataFrame timing.
- n_operation_days : int, optional
- Days/year the plant operates when `capacity_factor` not supplied.
- minimum_turbineflow : float, optional
- Absolute minimum turbine flow (same units as `flow`).
- minimum_turbineflow_percent : float, optional
- Minimum turbine flow as percent of design flow when absolute min not given.
- annual_maintenance_flag, major_maintenance_flag : bool, default False
- Zero-flow outages (7 days/year, 14 days/5 years) applied in DIVERSION
- when a DataFrame with a datetime index is provided.
+ flow : array-like or pandas.DataFrame or None
+ Flow values. If a DataFrame is provided, a DatetimeIndex is expected for
+ annual calculations and ``flow_column`` must indicate which column
+ contains flow values.
+ head : float or None
+ Gross head. In US units this is in ft; in SI units this is in m.
+ rated_power : float or None
+ Rated power (kW).
+ hydropower_type : str or None
+ Hydropower calculation type. Supported values:
+ ``'BASIC'``: uses the basic power equation,
+ ``'DIVERSION'``: run-of-river workflow (turbines + head losses),
+ ``'HYDROKINETIC'``: in-stream kinetic workflow,
+ If ``None``, hydropower computation is skipped and only cost calculation
+ (when configured) may run.
+ units : {'US', 'SI'}
+ Units of the input values.
+
+ penstock_headloss_method : str
+ Penstock head-loss method (e.g., ``'Darcy-Weisbach'`` or ``'Hazen-Williams'``).
+ design_flow : float or None
+ Design flow. If not provided for diversion projects, it may be computed
+ from exceedance logic.
+ system_efficiency : float or None
+ System efficiency. For BASIC workflow, used directly; for hydrokinetic,
+ treated as a percent.
+ generator_efficiency : float or None
+ Generator efficiency (%) for diversion workflow.
+ turbine_type : str or None
+ Turbine type identifier.
+ head_loss : float or None
+ External head loss (if already computed), in same unit system as head.
+
+ penstock_headloss_calculation : bool
+ If True, penstock head loss is calculated and applied to compute net head.
+ penstock_length : float or None
+ Penstock length.
+ penstock_diameter : float or None
+ Penstock diameter.
+ penstock_material : str or None
+ Penstock material used for roughness defaults.
+ penstock_frictionfactor : float or None
+ Friction parameter value (method-dependent).
+
+ pctime_runfull : float or None
+ Turbine parameter: percent time running full (method-specific).
+ max_headloss_allowed : float or None
+ Maximum allowable head loss (percent of head) used for sizing.
+ turbine_Rm : float or None
+ Turbine parameter used in turbine selection/parameter calculation.
+ pelton_n_jets : int or None
+ Pelton turbine number of jets.
+ flow_column : str or None
+ Flow column name when ``flow`` is a pandas DataFrame.
+
+ channel_average_velocity : float or None
+ Channel average velocity (m/s).
+ hk_blade_diameter : float or None
+ Hydrokinetic blade diameter.
+ hk_blade_heigth : float or None
+ Hydrokinetic blade height.
+ hk_blade_type : str or None
+ Hydrokinetic blade type identifier.
+ hk_swept_area : float or None
+ Hydrokinetic swept area (m²). If None, may be computed.
+
+ annual_caclulation : bool
+ If True, annual energy and revenue are computed.
+ resource_category : str or None
+ Cost model resource category.
+ electricity_sell_price : float or None
+ Electricity sell price ($/kWh).
+ cost_calculation_method : str
+ Cost calculation method identifier (currently supports ``'ORNL_HBCM'``).
+ capacity_factor : float or None
+ Capacity factor (0–1) for annual revenue model when not using a time series.
+ n_operation_days : int or float or None
+ Operation days per year (0–365) for annual revenue model.
+
+ minimum_turbineflow : float or None
+ Minimum turbine flow threshold (method-dependent units; converted if needed).
+ minimum_turbineflow_percent : float or None
+ Minimum turbine flow as a percent of design flow.
+ annual_maintenance_flag : bool
+ Whether to apply annual maintenance downtime (DataFrame/time-series only).
+ major_maintenance_flag : bool
+ Whether to apply major maintenance downtime (DataFrame/time-series only).
Returns
-------
object
- A merged parameter/result object containing inputs and computed fields,
- including (as available) `rated_power`, `power`, `net_head`, `head_loss`,
- `turbine_efficiency`, `dataframe_output`, `annual_dataframe_output`,
- and cost/revenue summaries.
+ A merged parameter object containing inputs and computed outputs. This
+ includes (as available) attributes such as:
+ ``rated_power`` (kW),
+ ``power`` (kW series),
+ ``head_loss`` (m/ft series),
+ ``net_head`` (m/ft),
+ cost outputs (``icc``, ``annual_om``),
+ revenue outputs (``annual_energy_generated``, ``annual_revenue``),
+ DataFrame summaries when applicable
Raises
------
ValueError
- For invalid unit choices, unsupported hydro types, bad inputs for
- DataFrame flow, or missing values required by selected sub-methods.
-
- Notes
- -----
- - US inputs are converted to SI internally; results are converted back to US
- when `units == 'US'`.
- - In DIVERSION mode, turbine selection and performance are computed before
- penstock head-loss if enabled.
+ If:
+ ``units`` is not ``'US'`` or ``'SI'``,
+ ``hydropower_type`` is invalid,
+ required inputs are missing for the chosen workflow
"""
-
# Check if a pandas dataframe
flow_data, pandas_dataframe = pd_checker(flow, flow_column) # check if a dataframe is used and extract flow values
diff --git a/HydroGenerate/summary_results.py b/HydroGenerate/summary_results.py
index d980b20..993674a 100644
--- a/HydroGenerate/summary_results.py
+++ b/HydroGenerate/summary_results.py
@@ -36,7 +36,6 @@
required attributes are missing.
"""
-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
@@ -49,30 +48,29 @@
ft_to_m = 0.3048 # 1 feet to meters
# function to plot turbine efficiency and power generation as a function of flow
-def flow_efficiency_power_plot(x):
- """
- Plot turbine efficiency and power (kW) as functions of discrete turbine flow.
+def flow_efficiency_power_plot(x):
+ """Plot turbine efficiency and power as a function of turbine flow.
+
+ This function expects time-series outputs stored on ``x.dataframe_output``.
+ It deduplicates by turbine flow, sorts, and then creates a dual-axis plot:
+ efficiency on the left axis and power on the right axis.
Parameters
----------
- x : object
- HydroGenerate results container with:
- - pandas_dataframe : bool
- - dataframe_output : pandas.DataFrame
- Must include columns: 'turbine_flow_cfs', 'efficiency', 'power_kW'.
+ x : object
+ HydroGenerate results object. Expected attributes include ``pandas_dataframe`` (bool)
+ ``dataframe_output`` (pandas.DataFrame) with columns: ``'turbine_flow_cfs'``, ``'efficiency'``, ``'power_kW'``
Returns
-------
- matplotlib.figure.Figure or None
- Figure with efficiency (left y-axis) and power (right y-axis) vs flow (cfs).
- Returns None and prints a message if `x.pandas_dataframe` is False.
+ matplotlib.figure.Figure
+ Matplotlib figure containing the dual-axis plot.
Notes
-----
- - Points are deduplicated by 'turbine_flow_cfs' and sorted before plotting.
- - The function closes the figure (`plt.close()`) and returns the handle.
- """
-
+ If ``x.pandas_dataframe`` is False, the function prints an informational
+ message and returns ``None``.
+ """
# extract dataframe output, order and subset wanted values
if x.pandas_dataframe:
df = x.dataframe_output
@@ -104,28 +102,24 @@ def flow_efficiency_power_plot(x):
'provided as pandas dataframe')
def flow_efficiency_plot(x):
- """
- Plot turbine efficiency as a function of discrete turbine flow.
+ """Plot turbine efficiency as a function of turbine flow.
Parameters
----------
x : object
- HydroGenerate results container with:
- - pandas_dataframe : bool
- - dataframe_output : pandas.DataFrame
- Must include columns: 'turbine_flow_cfs', 'efficiency', 'power_kW'.
+ HydroGenerate results object. Expected attributes include ``pandas_dataframe`` (bool),
+ ``dataframe_output`` (pandas.DataFrame) with columns: ``'turbine_flow_cfs'``, ``'efficiency'``, ``'power_kW'``
Returns
-------
- matplotlib.figure.Figure or None
- Figure with efficiency vs flow (cfs).
- Returns None and prints a message if `x.pandas_dataframe` is False.
+ matplotlib.figure.Figure
+ Matplotlib figure containing the efficiency plot.
Notes
-----
- Points are deduplicated by 'turbine_flow_cfs' and sorted before plotting.
+ If ``x.pandas_dataframe`` is False, the function prints an informational
+ message and returns ``None``.
"""
-
# extract dataframe output, order and subset wanted values
if x.pandas_dataframe:
df = x.dataframe_output
@@ -152,30 +146,31 @@ def flow_efficiency_plot(x):
# function to plot the flow duration curve
def flow_duration_curve_plot(x):
- """
- Plot the flow duration curve with design-flow and percent-run-full markers.
+ """Plot the flow duration curve (FDC).
+
+ The function reads ``x.flowduration_curve`` and plots flow versus percent
+ exceedance. It also overlays the design-flow marker using ``x.design_flow``
+ and ``x.pctime_runfull`` when available.
Parameters
----------
x : object
- HydroGenerate results container with:
- - flowduration_curve : pandas.DataFrame with columns 'Percent_Exceedance', 'Flow'
- - units : {'US', 'SI'}
- - design_flow : float
- - pctime_runfull : float
+ HydroGenerate results object expected to include ``flowduration_curve`` (pandas.DataFrame) with columns
+ ``'Percent_Exceedance'`` and ``'Flow'`` (in m³/s),
+ ``units`` ('US' or 'SI'),
+ ``design_flow`` (float),
+ ``pctime_runfull`` (float)
+
Returns
-------
- matplotlib.figure.Figure or None
- Flow-duration figure. Returns None and prints a message if required
- attributes are missing.
+ matplotlib.figure.Figure
+ Matplotlib figure containing the flow duration curve.
Notes
-----
- - If `x.units == 'US'`, the y-axis is ft^3/s (cfs); otherwise m^3/s.
- - Draws horizontal/vertical dashed lines and a marker at
- (percent run-full, design flow).
+ If the required ``flowduration_curve`` attribute is missing, the function
+ prints an informational message and returns ``None``.
"""
-
# if x.flowduration_curve:
try:
df = x.flowduration_curve.copy()
@@ -213,29 +208,31 @@ def flow_duration_curve_plot(x):
# function to plot turbine selection figure
def turbine_type_plot(x):
- """
- Plot turbine selection regions and overlay site head/flow on log–log axes.
+ """Plot turbine selection regions and mark site characteristics.
+
+ The plot uses polygon "regions of influence" in head-flow space for common
+ turbine types (Pelton, Turgo, Francis, Crossflow, Kaplan) and marks the
+ site's (flow, head) point.
Parameters
----------
x : object
- HydroGenerate results container with:
- - net_head : float
- - design_flow : float or None (falls back to `flow` if None)
- - flow : float (used if `design_flow` is None)
- - units : {'US', 'SI'}
+ HydroGenerate results object expected to include:
+ ``net_head`` (float): head (m in SI; ft in US, then converted),
+ ``design_flow`` (float or None): m³/s in SI; cfs in US, then converted,
+ ``flow`` (float): used if ``design_flow`` is not available,
+ ``units`` ('US' or 'SI')
Returns
-------
matplotlib.figure.Figure
- Log–log plot with Pelton, Turgo, Francis, Crossflow, and Kaplan regions,
- plus a point marking the site's (flow, head).
+ Matplotlib figure containing the turbine selection plot.
Notes
-----
- Converts ft→m and cfs→m^3/s when `x.units == 'US'`.
+ The turbine region polygons are defined in SI units. If ``x.units == 'US'``,
+ head and flow are converted to SI before plotting.
"""
-
# inputs
head = x.net_head # head, m
@@ -284,27 +281,31 @@ def turbine_type_plot(x):
# function that generates a monhtly figure given a dataframe and a column name
def monthly_figure_plot(df, var_fig):
- """
- Create a monthly summary figure with mean/median and IQR shading.
+ """Generate a monthly summary figure for a specified variable.
+
+ The function computes monthly mean and median, and plots the interquartile
+ range (IQR) as a shaded band.
Parameters
----------
df : pandas.DataFrame
- Time-indexed DataFrame (DatetimeIndex) containing `var_fig` as a column.
- var_fig : {"turbine_flow_cfs", "energy_kWh", "capacity_factor"}
- Column to summarize by calendar month.
+ Time-indexed DataFrame (DatetimeIndex) containing the target column.
+ var_fig : str
+ Column name to plot. Common values in HydroGenerate outputs include:
+ ``'turbine_flow_cfs'``,
+ ``'energy_kWh'``,
+ ``'capacity_factor'``
Returns
-------
matplotlib.figure.Figure
- Figure with monthly mean, median, and interquartile range.
+ Matplotlib figure containing the monthly plot.
Notes
-----
- - The y-axis label is set based on `var_fig`.
- - The function closes the figure (`plt.close()`) and returns the handle.
+ Axis labels are set based on ``var_fig`` to match the original plotting
+ behavior.
"""
-
y_mean = df[var_fig].groupby(df[var_fig].index.month).mean()
y_med = df[var_fig].groupby(df[var_fig].index.month).median()
x = y_mean.index
@@ -344,7 +345,26 @@ def monthly_figure_plot(df, var_fig):
# 1) Capacity factor
def plant_capfactor_plot(x):
-
+ """Plot monthly capacity factor statistics.
+
+ Parameters
+ ----------
+ x : object
+ HydroGenerate results object expected to include:
+ ``pandas_dataframe`` (bool),
+ ``dataframe_output`` (pandas.DataFrame) with column ``'power_kW'``,
+ ``rated_power`` (float): kW
+
+ Returns
+ -------
+ matplotlib.figure.Figure
+ Matplotlib figure of monthly capacity factor summary.
+
+ Notes
+ -----
+ If ``x.pandas_dataframe`` is False, the function prints an informational
+ message and returns ``None``.
+ """
if x.pandas_dataframe:
df = x.dataframe_output
df['rated_power_kw'] = x.rated_power
@@ -358,7 +378,25 @@ def plant_capfactor_plot(x):
# 2) turbine flow
def plant_turbineflow_plot(x):
-
+ """Plot monthly turbine flow statistics.
+
+ Parameters
+ ----------
+ x : object
+ HydroGenerate results object expected to include:
+ ``pandas_dataframe`` (bool),
+ ``dataframe_output`` (pandas.DataFrame) with column ``'turbine_flow_cfs'``
+
+ Returns
+ -------
+ matplotlib.figure.Figure
+ Matplotlib figure of monthly turbine flow summary.
+
+ Notes
+ -----
+ If ``x.pandas_dataframe`` is False, the function prints an informational
+ message and returns ``None``.
+ """
if x.pandas_dataframe:
df = x.dataframe_output
tf = monthly_figure_plot(df, 'turbine_flow_cfs')
@@ -370,7 +408,25 @@ def plant_turbineflow_plot(x):
# 3) Electricty generation
def plant_elecgeneration_plot(x):
-
+ """Plot monthly electricity generation statistics.
+
+ Parameters
+ ----------
+ x : object
+ HydroGenerate results object expected to include:
+ ``pandas_dataframe`` (bool),
+ ``dataframe_output`` (pandas.DataFrame) with column ``'energy_kWh'``
+
+ Returns
+ -------
+ matplotlib.figure.Figure
+ Matplotlib figure of monthly electricity generation summary.
+
+ Notes
+ -----
+ If ``x.pandas_dataframe`` is False, the function prints an informational
+ message and returns ``None``.
+ """
if x.pandas_dataframe:
df = x.dataframe_output
eg = monthly_figure_plot(df, 'energy_kWh')
diff --git a/HydroGenerate/turbine_calculation.py b/HydroGenerate/turbine_calculation.py
index 8afed93..a3ebb4b 100755
--- a/HydroGenerate/turbine_calculation.py
+++ b/HydroGenerate/turbine_calculation.py
@@ -42,58 +42,60 @@
max_flow_turbine = 1 # multiplier for the maximum flow that can be passed through a turbine
# Turbine Parameters
-class TurbineParameters:
- """
- Container for turbine inputs and computed attributes.
+class TurbineParameters:
+ """Turbine parameter container used by HydroGenerate workflows.
+
+ This class stores the turbine-related inputs (head, flow, efficiencies,
+ turbine selection controls) and computed outputs (efficiency curve, runner
+ diameter, turbine-flow array, and optional DataFrame outputs).
Parameters
----------
turbine_type : str or None
- One of {"Hydrokinetic","Francis","Propellor","Pelton","Turgo","CrossFlow"}.
- flow : float or pandas.Series or numpy.ndarray
- Flow (cfs or m³/s). Use a scalar for single-point design calculations.
- design_flow : float
- Design flow (cfs or m³/s).
+ Turbine type name. Typical options include: ``'Kaplan'``, ``'Francis'``,
+ ``'Pelton'``, ``'Turgo'``, ``'Crossflow'``, ``'Propeller'``,
+ ``'Hydrokinetic'``. If ``None``, a turbine type may be selected using
+ :func:`turbine_type_selector`.
+ flow : float, array-like, or pandas.Series
+ Flow input (m³/s or cfs depending on upstream unit handling). May be a
+ single value or a time series / array.
+ design_flow : float or None
+ Design flow for the hydropower system. If ``None`` and flow is a series,
+ it can be computed using :class:`PercentExceedance`.
flow_column : str or None
- If `flow` is a DataFrame, column name containing the flow series.
- head : float
- Hydraulic head (ft or m).
+ If ``flow`` was originally provided as a pandas DataFrame elsewhere in
+ the workflow, this is the name of the column containing flow values.
+ head : float or None
+ Hydraulic head (m or ft depending on upstream unit handling).
rated_power : float or None
Rated power (kW).
system_efficiency : float or None
- Overall system efficiency in [0, 1].
+ Overall system efficiency (proportion, 0–1) used in some workflows.
generator_efficiency : float or None
- Generator efficiency in [0, 1] (default 0.98 if set upstream).
+ Generator efficiency (percent or proportion depending on upstream usage).
+ HydroGenerate commonly defaults this to ~98% in the main workflow.
Rm : float or None
- Manufacturer/design coefficient; if None defaults to 4.5.
+ Turbine manufacture/design coefficient used in peak efficiency formulas.
+ If ``None``, this class sets a default of 4.5.
pctime_runfull : float or None
- Percent of time the turbine runs at full flow (0–100).
+ Percent of time the turbine will run full (used for design-flow selection
+ via exceedance logic). If ``None``, a default is used by
+ :class:`PercentExceedance`.
pelton_n_jets : int or None
- Number of jets for Pelton turbines (default 3 if None).
+ Number of jets for a Pelton turbine. If ``None``, defaults to 3 in
+ :class:`PeltonTurbine`.
hk_blade_diameter : float or None
- Hydrokinetic rotor/blade diameter (m).
+ Hydrokinetic blade diameter (m).
hk_blade_heigth : float or None
- Hydrokinetic blade height (m) for Darrieus types.
+ Hydrokinetic blade height (m).
hk_blade_type : str or None
- {'ConventionalRotor','H-DarrieusRotor','DarrieusRotor'}.
+ Hydrokinetic blade type identifier. Typical values:
+ ``'ConventionalRotor'``, ``'H-DarrieusRotor'``, ``'DarrieusRotor'``.
hk_swept_area : float or None
- Hydrokinetic swept area (m²), computed if not provided.
-
- Attributes
- ----------
- Rm : float
- Manufacturer/design coefficient (defaults to 4.5 when None).
- design_efficiency : float or None
- Efficiency at design flow (set by calculators when applicable).
- turbine_flow : numpy.ndarray or None
- Flow array used in efficiency curves (may be filled by helpers).
- dataframe_output : pandas.DataFrame or None
- Optional results table.
- runner_diameter : float or None
- Runner diameter (m) for reaction turbines.
-
- """
+ Hydrokinetic swept area (m²). If ``None``, may be computed by
+ :class:`Hydrokinetic_Turbine`.
+ """
def __init__(self, turbine_type, flow, design_flow, flow_column, head,
rated_power,
system_efficiency,
@@ -134,30 +136,31 @@ def __init__(self, turbine_type, flow, design_flow, flow_column, head,
self.runner_diameter = None # placeholder for the runner diameter
def turbine_type_selector(hp_params):
- """
- Select a feasible turbine type from head/flow using polygon regions.
+ """Select an appropriate turbine type based on head and design flow.
+
+ The selection is based on which turbine “region of influence” polygons
+ contain the point (design_flow, head). If multiple regions contain the point,
+ the turbine whose polygon centroid is closest to the point is selected.
Parameters
----------
- hp_params : TurbineParameters
- Must provide `head` (m) and `design_flow` (m³/s).
+ hp_params : object
+ Parameter container is expected to provide, ``head`` (float), hydraulic head (m),
+ ``design_flow`` (float): design flow (m³/s).
Raises
------
ValueError
- If the (flow, head) point falls outside all supported turbine regions.
-
- Side Effects
- ------------
- Updates
- - `hp_params.turbine_type` with the closest (centroid distance) match.
- - `hp_params.turbine_type_dict` with {turbine: distance} for all hits.
+ If the (head, design_flow) point does not fall within any supported
+ turbine regions.
Notes
-----
- The polygon limits are specified in SI units (m, m³/s).
+ This function mutates ``hp_params`` in place.
+
+ The function updates ``hp_params.turbine_type`` (str), ``hp_params.turbine_type_dict`` (dict[str, float]) mapping candidates
+ to centroid distances.
"""
-
# inputs
head = hp_params.head # head, m
design_flow = hp_params.design_flow # flow, m3/s
@@ -223,26 +226,29 @@ def turbine_type_selector(hp_params):
# Flow range calculation
class FlowRange():
+ """Flow range generation helper.
+
+ Notes
+ -----
+ This helper is used to expand a single flow value into a flow range for
+ evaluating turbine efficiency curves across operating conditions.
"""
- Utility to expand a scalar flow into a range for efficiency curves.
- """
+ def flowrange_calculator(self, turbine):
+ """Expand a single flow value into a range for turbine evaluation.
- def flowrange_calculator(self, turbine):
- """
- If `turbine.flow` is scalar, create a flow vector from 50% to
- `max_flow_turbine` (default 100%) of that scalar.
+ If ``turbine.flow`` is a scalar number, it is expanded to a range from
+ 50% to ``max_flow_turbine`` of the provided value (18 evenly spaced points).
Parameters
----------
- turbine : TurbineParameters
- Must have scalar `flow`.
+ turbine : object
+ Parameter container expected to include ``flow``.
- Side Effects
- ------------
- Overwrites `turbine.flow` with an array of 18 values.
-
- """
-
+ Notes
+ -----
+ This method mutates ``turbine.flow`` in place. The turbine calculators in
+ this file often expect a flow array to compute efficiency curves.
+ """
if isinstance(turbine.flow, Number):
range = np.linspace(0.5, max_flow_turbine, 18) # the values are %
turbine.flow = turbine.flow * range
@@ -251,30 +257,25 @@ def flowrange_calculator(self, turbine):
# Runner diameter for reaction turbines
class ReactionTurbines():
- """
- Runner sizing utilities for reaction turbines.
- """
-
+ """Sizing utilities for reaction turbines (e.g., Francis, Kaplan, Propeller)."""
def runnersize_calculator(self, design_flow):
- """
- Estimate runner throat diameter for reaction turbines.
+ """Compute an estimated runner throat diameter for reaction turbines.
Parameters
----------
design_flow : float
- Design discharge (m³/s).
+ Design flow (m³/s).
Returns
-------
float
- Runner throat diameter (m).
+ Runner throat diameter (m), computed using a piecewise coefficient.
Notes
-----
- Uses piecewise k coefficient (0.41 for Qd>23 m³/s, else 0.46) and
- d = k * Qd**0.473.
+ The coefficient ``k`` changes for higher flows to avoid a region in the
+ source correlation described as "undefined" in the original comments.
"""
-
if design_flow > 23: # d > 1.8 - The formula in the document has an 'undefined' area
k = 0.41
else:
@@ -284,50 +285,49 @@ def runnersize_calculator(self, design_flow):
# Functions to calculate turbine efficiency by turbine type (CANMET Energy Technology Center, 2004)
class Turbine(ABC):
- """
- Abstract base class for turbine efficiency calculators.
- """
-
+ """Abstract base class for turbine calculators."""
@abstractmethod
def turbine_calculator(self, turbine):
- """
- Compute efficiency curve and update turbine attributes.
+ """Compute turbine performance characteristics and update the container.
Parameters
----------
- turbine : TurbineParameters
- Input/output container with at least `head`, `design_flow`,
- `flow` or `turbine_flow`, and optional coefficients.
- """
+ turbine : object
+ Parameter container (e.g., :class:`TurbineParameters`) holding inputs
+ like ``design_flow``, ``head``, and optional coefficients.
+ Notes
+ -----
+ Implementations typically mutate ``turbine`` in place by setting:
+ - ``turbine.turbine_efficiency`` (array-like)
+ - ``turbine.runner_diameter`` (float, when applicable)
+ - and may generate/expect a flow range.
+ """
pass
class FrancisTurbine(Turbine):
- """
- Francis turbine efficiency calculation (CANMET, 2004).
- """
-
- def turbine_calculator(self, turbine):
- """
- Populate `turbine.turbine_efficiency` across a flow range around Qd.
+ """Francis turbine efficiency curve calculator."""
+ def turbine_calculator(self, turbine):
+ """Compute Francis turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `head`, `design_flow`, `Rm`. Creates/uses a flow range.
-
- Side Effects
- ------------
- Updates:
- - `turbine.turbine_efficiency` (numpy.ndarray in [0,1]).
- - `turbine.runner_diameter` (m).
+ turbine : object
+ Container expected to include:
+ ``design_flow`` (float),
+ ``head`` (float),
+ ``Rm`` (float),
+ ``flow`` (float or array-like)
Notes
-----
- Uses specific speed and runner-size adjustments to peak efficiency, and
- piecewise relations above/below peak-flow `Qp`.
- """
+ This method mutates ``turbine`` in place. It computes:
+ ``turbine.turbine_efficiency`` (numpy.ndarray),
+ ``turbine.runner_diameter`` (float)
+ The efficiency formulation follows correlations cited in the original
+ comments (CANMET Energy Technology Center, 2004).
+ """
Qd = turbine.design_flow # design flow
d = ReactionTurbines().runnersize_calculator(Qd)
nq = 600 * turbine.head**(-0.5) # Specific speed
@@ -356,24 +356,26 @@ def turbine_calculator(self, turbine):
turbine.runner_diameter = d # update
class KaplanTurbine(Turbine):
- """
- Kaplan turbine efficiency calculation (CANMET, 2004).
- """
-
+ """Kaplan turbine efficiency curve calculator."""
def turbine_calculator(self, turbine):
- """
- Compute efficiency across flow range; clip negatives to zero.
+ """Compute Kaplan turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `head`, `design_flow`, `Rm`.
+ turbine : object
+ Container expected to include:
+ ``design_flow`` (float),
+ ``head`` (float),
+ ``Rm`` (float),
+ ``flow`` (float or array-like)
- Side Effects
- ------------
- Updates `turbine.turbine_efficiency` and `turbine.runner_diameter`.
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``turbine.turbine_flow`` (array-like),
+ ``turbine.turbine_efficiency`` (numpy.ndarray),
+ ``turbine.runner_diameter`` (float)
"""
-
Qd = turbine.design_flow # design flow
d = ReactionTurbines().runnersize_calculator(Qd)
nq = 800 * turbine.head**(-0.5) # Specific speed
@@ -388,24 +390,26 @@ def turbine_calculator(self, turbine):
turbine.runner_diameter = d # update
class PropellerTurbine(Turbine):
- """
- Propeller turbine efficiency calculation (CANMET, 2004).
- """
-
+ """Propeller turbine efficiency curve calculator."""
def turbine_calculator(self, turbine):
- """
- Compute efficiency across flow range; clip negatives to zero.
+ """Compute Propeller turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `head`, `design_flow`, `Rm`.
+ turbine : object
+ Container expected to include:
+ ``design_flow`` (float),
+ ``head`` (float),
+ ``Rm`` (float),
+ ``flow`` (float or array-like)
- Side Effects
- ------------
- Updates `turbine.turbine_efficiency` and `turbine.runner_diameter`.
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``turbine.turbine_flow`` (array-like),
+ ``turbine.turbine_efficiency`` (numpy.ndarray),
+ ``turbine.runner_diameter`` (float)
"""
-
Qd = turbine.design_flow # design flow
d = ReactionTurbines().runnersize_calculator(Qd)
nq = 800 * turbine.head**(-0.5) # Specific speed
@@ -420,24 +424,28 @@ def turbine_calculator(self, turbine):
turbine.runner_diameter = d # update
class PeltonTurbine(Turbine):
- """
- Pelton turbine efficiency calculation (CANMET, 2004).
- """
-
- def turbine_calculator(self, turbine):
- """
- Compute Pelton efficiency across the flow range.
+ """Pelton turbine efficiency curve calculator."""
+ def turbine_calculator(self, turbine):
+ """Compute Pelton turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `head`, `design_flow`; uses `pelton_n_jets` (default 3).
+ turbine : object
+ Container expected to include:
+ ``head`` (float),
+ ``design_flow`` (float),
+ ``pelton_n_jets`` (int or None),
+ ``flow`` (float or array-like)
- Side Effects
- ------------
- Updates `turbine.turbine_efficiency` and `turbine.runner_diameter`.
- """
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``turbine.turbine_flow`` (array-like),
+ ``turbine.turbine_efficiency`` (numpy.ndarray),
+ ``turbine.runner_diameter`` (float)
+ If ``turbine.pelton_n_jets`` is None, a default of 3 is used.
+ """
if turbine.pelton_n_jets is None:
turbine.pelton_n_jets = 3
@@ -454,76 +462,73 @@ def turbine_calculator(self, turbine):
turbine.runner_diameter = d # update
class TurgoTurbine(Turbine):
- """
- Turgo turbine efficiency approximated from Pelton minus 0.03.
- """
-
+ """Turgo turbine efficiency curve calculator (derived from Pelton)."""
def turbine_calculator(self, turbine):
- """
- Compute Turgo efficiency by offsetting Pelton efficiency.
+ """Compute Turgo turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `head`, `design_flow`.
+ turbine : object
+ Container compatible with :class:`PeltonTurbine`.
- Side Effects
- ------------
- Updates `turbine.turbine_efficiency` (values clipped at 0).
+ Notes
+ -----
+ This method mutates ``turbine`` in place. It first computes Pelton
+ efficiency and then subtracts 0.03, clipping negative values to zero.
"""
-
PeltonTurbine().turbine_calculator(turbine) # Calculate Pelton efficiency
turbine.turbine_efficiency = turbine.turbine_efficiency - 0.03 # Pelton efficiency - 0.03
turbine.turbine_efficiency = np.where(turbine.turbine_efficiency <= 0 , 0, turbine.turbine_efficiency) # Correct negative efficiencies
class CrossFlowTurbine(Turbine):
- """
- Crossflow turbine efficiency calculation (empirical relation).
- """
-
+ """Crossflow turbine efficiency curve calculator."""
def turbine_calculator(self, turbine):
- """
- Compute crossflow efficiency across the flow range.
+ """Compute Crossflow turbine efficiency across a flow range.
Parameters
----------
- turbine : TurbineParameters
- Requires `design_flow`; uses empirical relation vs Qd and Q.
+ turbine : object
+ Container expected to include:
+ ``design_flow`` (float),
+ ``flow`` (float or array-like)
- Side Effects
- ------------
- Updates `turbine.turbine_efficiency` (values clipped at 0).
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``turbine.turbine_flow`` (array-like),
+ ``turbine.turbine_efficiency`` (numpy.ndarray)
"""
-
Qd = turbine.design_flow
FlowRange().flowrange_calculator(turbine= turbine) # generate a flow range from 60% to 120% of the flow given
Q = turbine.turbine_flow
turbine.turbine_efficiency = 0.79 - 0.15 *((Qd - Q) / Qd) - 1.37 * ((Qd - Q) / Q)**14 # Efficiency (e_q)
turbine.turbine_efficiency = np.where(turbine.turbine_efficiency <= 0 , 0, turbine.turbine_efficiency) # Correct negative efficiencies
-class Hydrokinetic_Turbine(Turbine):
- """
- Hydrokinetic turbine swept-area setup and related parameters.
- """
+class Hydrokinetic_Turbine(Turbine):
+ """Hydrokinetic turbine swept-area calculator.
+ This calculator derives the swept area for hydrokinetic turbines based on
+ rotor diameter and (for Darrieus-type rotors) blade height.
+ """
def turbine_calculator(self, turbine):
- """
- Ensure hydrokinetic blade geometry and swept area are populated.
+ """Compute hydrokinetic swept area and update the container.
Parameters
----------
- turbine : TurbineParameters
- Uses/updates:
- - hk_blade_type : {'ConventionalRotor','H-DarrieusRotor','DarrieusRotor'}
- - hk_blade_diameter : float (m)
- - hk_blade_heigth : float (m) when required
- - hk_swept_area : float (m²)
-
- Side Effects
- ------------
- Sets defaults when missing and updates `hk_swept_area`.
- """
+ turbine : object
+ Container expected to include hydrokinetic attributes:
+ ``hk_blade_type`` (str or None),
+ ``hk_blade_diameter`` (float or None),
+ ``hk_blade_heigth`` (float or None)
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``hk_blade_type``,
+ ``hk_blade_diameter`` (default 1 m if missing),
+ ``hk_blade_heigth`` (default 1 m if missing for Darrieus-type),
+ ``hk_swept_area`` (m²)
+ """
if turbine.hk_blade_type is None: # if a turbine type is not given
turbine.hk_blade_type = 'ConventionalRotor' # default - update
@@ -557,47 +562,46 @@ def turbine_calculator(self, turbine):
# Functions to calculate design flow.
class DesignFlow(ABC):
- """
- Abstract base for design-flow selection strategies.
- """
-
@abstractmethod
def designflow_calculator(self, turbine):
- """
- Compute and update `turbine.design_flow`.
- """
-
pass
# Desing flow selected from the flow duration curve for a percentage of exceedance
class PercentExceedance(DesignFlow):
- """
- Design flow based on a target percent exceedance from a flow duration curve.
- """
+ """Design-flow selection using a specified percent exceedance.
+ This method computes a flow duration curve (FDC) from a flow series and
+ selects the design flow as the flow value exceeded ``pctime_runfull`` percent
+ of the time.
+ """
def designflow_calculator(self, turbine):
- """
- Select design flow from the flow duration curve at target exceedance.
+ """Compute and set design flow based on percent exceedance.
Parameters
----------
- turbine : TurbineParameters
- Uses:
- - pctime_runfull : float or None
- Target % exceedance (rounded to nearest integer). If None,
- defaults to 30%.
- - flow : array-like or scalar
- If array-like, computes the flow duration curve; if scalar,
- uses it directly as `design_flow`.
-
- Side Effects
- ------------
- Updates:
- - `turbine.design_flow`
- - `turbine.pctime_runfull` (rounded int)
- - `turbine.flowduration_curve` (pandas.DataFrame) when series provided.
- """
+ turbine : object
+ Container expected to include:
+ ``flow`` (float or array-like),
+ ``pctime_runfull`` (float or None)
+
+ Raises
+ ------
+ ValueError
+ If a flow series is provided and no percentile value exists for the
+ computed exceedance percentage.
+ Notes
+ -----
+ This method mutates ``turbine`` in place by setting:
+ ``turbine.design_flow`` (float),
+ ``turbine.pctime_runfull`` (rounded percent exceedance),
+ ``turbine.flowduration_curve`` (pandas.DataFrame) when using series input
+
+ Defaults
+ --------
+ If ``turbine.pctime_runfull`` is None, a default of 30 is used.
+ If ``turbine.flow`` is a scalar, the scalar is treated as the design flow.
+ """
pe = turbine.pctime_runfull # percentage of time a turbine is running full
flow = turbine.flow # user-entered flow
diff --git a/README.md b/README.md
index 9709865..0e44cec 100755
--- a/README.md
+++ b/README.md
@@ -80,8 +80,8 @@ _Bibtex_
```
@misc{osti_1829986,
-title = {Hydrogenerate: Open Source Python Tool To Estimate Hydropower Generation Time-series, Version 3.6 or newer},
-author = {Mitra, Bhaskar and Gallego-Calderon, Juan F. and Elliott, Shiloh N and Mosier, Thomas M and Bastidas Pacheco, Camilo Jose and USDOE Office of Energy Efficiency and Renewable Energy},
+title = {Hydrogenerate: Open Source Python Tool To Estimate Hydropower Generation Time-series},
+author = {Mitra, Bhaskar and Gallego-Calderon, Juan F. and Elliott, Shiloh N and Mosier, Thomas M and Bastidas Pacheco, Camilo Jose, Nag, Soumyadeep and USDOE Office of Energy Efficiency and Renewable Energy},
abstractNote = {Hydropower is one of the most mature forms of renewable energy generation. The United States (US) has almost 103 GW of installed, with 80 GW of conventional generation and 23 GW of pumped hydropower [1]. Moreover, the potential for future development on Non-Powered Dams is up to 10 GW. With the US setting its goals to become carbon neutral [2], more renewable energy in the form of hydropower needs to be integrated with the grid. Currently, there are no publicly available tool that can estimate the hydropower potential for existing hydropower dams or other non-powered dams. The HydroGenerate is an open-source python library that has the capability of estimating hydropower generation based on flow rate either provided by the user or received from United States Geological Survey (USGS) water data services. The tool calculates the efficiency as a function of flow based on the turbine type either selected by the user or estimated based on the “head” provided by the user.},
url = {https://www.osti.gov//servlets/purl/1829986},
doi = {10.11578/dc.20211112.1},
diff --git a/docs/.Rhistory b/docs/.Rhistory
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/GeneralWorkflow.SVG b/docs/GeneralWorkflow.SVG
deleted file mode 100644
index dc6cec9..0000000
--- a/docs/GeneralWorkflow.SVG
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/GettingStarted_1_Installation.md b/docs/GettingStarted_1_Installation.md
index 4392be1..ef62e29 100644
--- a/docs/GettingStarted_1_Installation.md
+++ b/docs/GettingStarted_1_Installation.md
@@ -14,17 +14,6 @@ pip install HydroGenerate
For a quick start guide, follow the steps in the **Quick start** page.
-
-## Optional - Verify your installation (run tests)
-
-After installing HydroGenerate locally, you can validate the setup and (optionally) see test coverage:
-
-``` bash
-# From the repository root
-pip install pytest pytest-cov
-pytest -q --cov=HydroGenerate --cov-report=term-missing:skip-covered
-```
-
## For developers
1. Clone the repo:
@@ -64,4 +53,12 @@ conda install -c conda-forge jupyterlab
```
pip install dataretrieval
+```
+
+6. Optional - Verify your installation (run tests): After installing HydroGenerate locally, you can validate the setup and see test coverage:
+
+``` bash
+# From the repository root
+pip install pytest pytest-cov
+pytest -q --cov=HydroGenerate --cov-report=term-missing:skip-covered
```
\ No newline at end of file
diff --git a/docs/HG_horizontal.png b/docs/HG_horizontal.png
old mode 100755
new mode 100644
diff --git a/docs/HG_workflow.jpg b/docs/HG_workflow.jpg
new file mode 100644
index 0000000..fec3ee0
Binary files /dev/null and b/docs/HG_workflow.jpg differ
diff --git a/docs/UserGuide_3_FlowOptions.ipynb b/docs/UserGuide_3_FlowOptions.ipynb
index 5bb7238..3afe10d 100644
--- a/docs/UserGuide_3_FlowOptions.ipynb
+++ b/docs/UserGuide_3_FlowOptions.ipynb
@@ -107,6 +107,13 @@
"#### Flow as Pandas dataframe with a datetime index - Additional functionality."
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Flow input as a dataframe can also be handled by HydroGenerate. The should have the datetime format and maintain that 'flow_column= 'discharge_cfs' '."
+ ]
+ },
{
"cell_type": "code",
"execution_count": 3,
diff --git a/docs/UserGuide_5_Cost&Revenue.ipynb b/docs/UserGuide_5_Cost&Revenue.ipynb
index 26ae50b..9f03d49 100644
--- a/docs/UserGuide_5_Cost&Revenue.ipynb
+++ b/docs/UserGuide_5_Cost&Revenue.ipynb
@@ -54,7 +54,7 @@
"power = None\n",
"hydropower_type = 'Diversion'\n",
"penstock_length = 1200\n",
- "resource_category = 'NewStream-reach'\n",
+ "resource_category = 'NEWSTREAM-REACH'\n",
"capacity_factor = 0.6\n",
"\n",
"hp = calculate_hp_potential(flow= flow, rated_power= power, head= head,\n",
@@ -276,7 +276,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.13"
+ "version": "3.11.14"
}
},
"nbformat": 4,
diff --git a/docs/UserGuide_7_HydroGenerateWorkflow.md b/docs/UserGuide_7_HydroGenerateWorkflow.md
index 202eec2..e0b4ba8 100644
--- a/docs/UserGuide_7_HydroGenerateWorkflow.md
+++ b/docs/UserGuide_7_HydroGenerateWorkflow.md
@@ -5,7 +5,7 @@ This section describes all avaliable inputs and outputs and presents a graphic w
{numref}`GWorkflow` shows the general workflow computations followed in **_HydroGenerate_**.
-```{figure} GeneralWorkflow.SVG
+```{figure} HG_workflow.jpg
---
name: GWorkflow
---
diff --git a/docs/_build/.doctrees/CMF.doctree b/docs/_build/.doctrees/CMF.doctree
deleted file mode 100644
index aa5ad95..0000000
Binary files a/docs/_build/.doctrees/CMF.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/DeveloperGuide_1_Architecture.doctree b/docs/_build/.doctrees/DeveloperGuide_1_Architecture.doctree
index af8934b..065c355 100644
Binary files a/docs/_build/.doctrees/DeveloperGuide_1_Architecture.doctree and b/docs/_build/.doctrees/DeveloperGuide_1_Architecture.doctree differ
diff --git a/docs/_build/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree b/docs/_build/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree
index 36b1b6e..4332902 100644
Binary files a/docs/_build/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree and b/docs/_build/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree differ
diff --git a/docs/_build/.doctrees/DeveloperGuide_3_Contributing.doctree b/docs/_build/.doctrees/DeveloperGuide_3_Contributing.doctree
index a5f31f5..7a7ae4b 100644
Binary files a/docs/_build/.doctrees/DeveloperGuide_3_Contributing.doctree and b/docs/_build/.doctrees/DeveloperGuide_3_Contributing.doctree differ
diff --git a/docs/_build/.doctrees/DeveloperGuide_4_Testing.doctree b/docs/_build/.doctrees/DeveloperGuide_4_Testing.doctree
index 791baad..2ba4036 100644
Binary files a/docs/_build/.doctrees/DeveloperGuide_4_Testing.doctree and b/docs/_build/.doctrees/DeveloperGuide_4_Testing.doctree differ
diff --git a/docs/_build/.doctrees/GettingStarted_1_Installation.doctree b/docs/_build/.doctrees/GettingStarted_1_Installation.doctree
index 9689c9a..c4bcb08 100644
Binary files a/docs/_build/.doctrees/GettingStarted_1_Installation.doctree and b/docs/_build/.doctrees/GettingStarted_1_Installation.doctree differ
diff --git a/docs/_build/.doctrees/GettingStarted_2_QuickStart.doctree b/docs/_build/.doctrees/GettingStarted_2_QuickStart.doctree
index 90463be..2acd6f8 100644
Binary files a/docs/_build/.doctrees/GettingStarted_2_QuickStart.doctree and b/docs/_build/.doctrees/GettingStarted_2_QuickStart.doctree differ
diff --git a/docs/_build/.doctrees/HydroGenerate_Introduction.doctree b/docs/_build/.doctrees/HydroGenerate_Introduction.doctree
index b17df4f..ce1dfd4 100644
Binary files a/docs/_build/.doctrees/HydroGenerate_Introduction.doctree and b/docs/_build/.doctrees/HydroGenerate_Introduction.doctree differ
diff --git a/docs/_build/.doctrees/Inputs.doctree b/docs/_build/.doctrees/Inputs.doctree
deleted file mode 100644
index 13830e3..0000000
Binary files a/docs/_build/.doctrees/Inputs.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/Outputs.doctree b/docs/_build/.doctrees/Outputs.doctree
deleted file mode 100644
index 359ddf9..0000000
Binary files a/docs/_build/.doctrees/Outputs.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/Theory_1_Hydropower.doctree b/docs/_build/.doctrees/Theory_1_Hydropower.doctree
index 4d151c4..6688994 100644
Binary files a/docs/_build/.doctrees/Theory_1_Hydropower.doctree and b/docs/_build/.doctrees/Theory_1_Hydropower.doctree differ
diff --git a/docs/_build/.doctrees/Theory_2_Design_Flow.doctree b/docs/_build/.doctrees/Theory_2_Design_Flow.doctree
index 9e0b9fb..4fd9da7 100644
Binary files a/docs/_build/.doctrees/Theory_2_Design_Flow.doctree and b/docs/_build/.doctrees/Theory_2_Design_Flow.doctree differ
diff --git a/docs/_build/.doctrees/Theory_3_Efficiency.doctree b/docs/_build/.doctrees/Theory_3_Efficiency.doctree
index 830457d..0a87598 100644
Binary files a/docs/_build/.doctrees/Theory_3_Efficiency.doctree and b/docs/_build/.doctrees/Theory_3_Efficiency.doctree differ
diff --git a/docs/_build/.doctrees/Theory_4_HeadLoss.doctree b/docs/_build/.doctrees/Theory_4_HeadLoss.doctree
index 99f87a6..3259207 100644
Binary files a/docs/_build/.doctrees/Theory_4_HeadLoss.doctree and b/docs/_build/.doctrees/Theory_4_HeadLoss.doctree differ
diff --git a/docs/_build/.doctrees/Theory_4_Head_loss.doctree b/docs/_build/.doctrees/Theory_4_Head_loss.doctree
deleted file mode 100644
index 91693cc..0000000
Binary files a/docs/_build/.doctrees/Theory_4_Head_loss.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/Theory_5_CostOM.doctree b/docs/_build/.doctrees/Theory_5_CostOM.doctree
index 1f46217..c3f911a 100644
Binary files a/docs/_build/.doctrees/Theory_5_CostOM.doctree and b/docs/_build/.doctrees/Theory_5_CostOM.doctree differ
diff --git a/docs/_build/.doctrees/Theory_6_FlowConstraints.doctree b/docs/_build/.doctrees/Theory_6_FlowConstraints.doctree
index 6a0097b..220eb67 100644
Binary files a/docs/_build/.doctrees/Theory_6_FlowConstraints.doctree and b/docs/_build/.doctrees/Theory_6_FlowConstraints.doctree differ
diff --git a/docs/_build/.doctrees/Turbine selsction.doctree b/docs/_build/.doctrees/Turbine selsction.doctree
deleted file mode 100644
index af3cdb3..0000000
Binary files a/docs/_build/.doctrees/Turbine selsction.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/UserGuide_1_Introduction-Tutorial.doctree b/docs/_build/.doctrees/UserGuide_1_Introduction-Tutorial.doctree
deleted file mode 100644
index 8b24759..0000000
Binary files a/docs/_build/.doctrees/UserGuide_1_Introduction-Tutorial.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/UserGuide_1_IntroductionTutorial.doctree b/docs/_build/.doctrees/UserGuide_1_IntroductionTutorial.doctree
index 609f6bc..b1c6a2e 100644
Binary files a/docs/_build/.doctrees/UserGuide_1_IntroductionTutorial.doctree and b/docs/_build/.doctrees/UserGuide_1_IntroductionTutorial.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_2_Diversion.doctree b/docs/_build/.doctrees/UserGuide_2_Diversion.doctree
index 3b7a7ac..b4d10ec 100644
Binary files a/docs/_build/.doctrees/UserGuide_2_Diversion.doctree and b/docs/_build/.doctrees/UserGuide_2_Diversion.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_3_FlowOptions.doctree b/docs/_build/.doctrees/UserGuide_3_FlowOptions.doctree
index 063190d..4bf5193 100644
Binary files a/docs/_build/.doctrees/UserGuide_3_FlowOptions.doctree and b/docs/_build/.doctrees/UserGuide_3_FlowOptions.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGS-NWIS.doctree b/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGS-NWIS.doctree
deleted file mode 100644
index bcaab69..0000000
Binary files a/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGS-NWIS.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGSNWIS.doctree b/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGSNWIS.doctree
index 449ce12..5057ef2 100644
Binary files a/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGSNWIS.doctree and b/docs/_build/.doctrees/UserGuide_4_QueryingDataUSGSNWIS.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_5_Cost&Revenue.doctree b/docs/_build/.doctrees/UserGuide_5_Cost&Revenue.doctree
index 22b7e39..0bce8eb 100644
Binary files a/docs/_build/.doctrees/UserGuide_5_Cost&Revenue.doctree and b/docs/_build/.doctrees/UserGuide_5_Cost&Revenue.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_6_Hydrokinetics.doctree b/docs/_build/.doctrees/UserGuide_6_Hydrokinetics.doctree
index 9b88b3d..ce0805b 100644
Binary files a/docs/_build/.doctrees/UserGuide_6_Hydrokinetics.doctree and b/docs/_build/.doctrees/UserGuide_6_Hydrokinetics.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree b/docs/_build/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree
index af4a394..fba2df5 100644
Binary files a/docs/_build/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree and b/docs/_build/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree differ
diff --git a/docs/_build/.doctrees/UserGuide_8_Issues_Support.doctree b/docs/_build/.doctrees/UserGuide_8_Issues_Support.doctree
index f3f1a5c..298d8c3 100644
Binary files a/docs/_build/.doctrees/UserGuide_8_Issues_Support.doctree and b/docs/_build/.doctrees/UserGuide_8_Issues_Support.doctree differ
diff --git a/docs/_build/.doctrees/api/FPP.doctree b/docs/_build/.doctrees/api/FPP.doctree
new file mode 100644
index 0000000..e18e6b7
Binary files /dev/null and b/docs/_build/.doctrees/api/FPP.doctree differ
diff --git a/docs/_build/.doctrees/api/HYDPP.doctree b/docs/_build/.doctrees/api/HYDPP.doctree
new file mode 100644
index 0000000..d6898d1
Binary files /dev/null and b/docs/_build/.doctrees/api/HYDPP.doctree differ
diff --git a/docs/_build/.doctrees/api/HYDPR.doctree b/docs/_build/.doctrees/api/HYDPR.doctree
new file mode 100644
index 0000000..4633b9b
Binary files /dev/null and b/docs/_build/.doctrees/api/HYDPR.doctree differ
diff --git a/docs/_build/.doctrees/api/SR.doctree b/docs/_build/.doctrees/api/SR.doctree
new file mode 100644
index 0000000..60efadc
Binary files /dev/null and b/docs/_build/.doctrees/api/SR.doctree differ
diff --git a/docs/_build/.doctrees/api/TC.doctree b/docs/_build/.doctrees/api/TC.doctree
new file mode 100644
index 0000000..613d216
Binary files /dev/null and b/docs/_build/.doctrees/api/TC.doctree differ
diff --git a/docs/_build/.doctrees/api/hydropower_potential.doctree b/docs/_build/.doctrees/api/hydropower_potential.doctree
deleted file mode 100644
index 2b646e9..0000000
Binary files a/docs/_build/.doctrees/api/hydropower_potential.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/api/index.doctree b/docs/_build/.doctrees/api/index.doctree
deleted file mode 100644
index 1b6ef0c..0000000
Binary files a/docs/_build/.doctrees/api/index.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/api/turbine_calculation.doctree b/docs/_build/.doctrees/api/turbine_calculation.doctree
deleted file mode 100644
index 1f7ff9c..0000000
Binary files a/docs/_build/.doctrees/api/turbine_calculation.doctree and /dev/null differ
diff --git a/docs/_build/.doctrees/environment.pickle b/docs/_build/.doctrees/environment.pickle
index f76afa0..9bad9a0 100644
Binary files a/docs/_build/.doctrees/environment.pickle and b/docs/_build/.doctrees/environment.pickle differ
diff --git a/docs/_build/.doctrees/glue_cache.json b/docs/_build/.doctrees/glue_cache.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/docs/_build/.doctrees/glue_cache.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo
index 17d40f8..8235c21 100644
--- a/docs/_build/html/.buildinfo
+++ b/docs/_build/html/.buildinfo
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 0bc7aca0c38a31d463514b54b1c8304c
+config: e4fdb0233cc83056a8de08a4bd48f7f2
tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/_build/html/.doctrees/DeveloperGuide_1_Architecture.doctree b/docs/_build/html/.doctrees/DeveloperGuide_1_Architecture.doctree
new file mode 100644
index 0000000..0d83998
Binary files /dev/null and b/docs/_build/html/.doctrees/DeveloperGuide_1_Architecture.doctree differ
diff --git a/docs/_build/html/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree b/docs/_build/html/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree
new file mode 100644
index 0000000..2d55b7f
Binary files /dev/null and b/docs/_build/html/.doctrees/DeveloperGuide_2_MethodsFunctions.doctree differ
diff --git a/docs/_build/html/.doctrees/DeveloperGuide_3_Contributing.doctree b/docs/_build/html/.doctrees/DeveloperGuide_3_Contributing.doctree
new file mode 100644
index 0000000..617d1da
Binary files /dev/null and b/docs/_build/html/.doctrees/DeveloperGuide_3_Contributing.doctree differ
diff --git a/docs/_build/html/.doctrees/DeveloperGuide_4_Testing.doctree b/docs/_build/html/.doctrees/DeveloperGuide_4_Testing.doctree
new file mode 100644
index 0000000..969736d
Binary files /dev/null and b/docs/_build/html/.doctrees/DeveloperGuide_4_Testing.doctree differ
diff --git a/docs/_build/html/.doctrees/GettingStarted_1_Installation.doctree b/docs/_build/html/.doctrees/GettingStarted_1_Installation.doctree
new file mode 100644
index 0000000..cf00243
Binary files /dev/null and b/docs/_build/html/.doctrees/GettingStarted_1_Installation.doctree differ
diff --git a/docs/_build/html/.doctrees/GettingStarted_2_QuickStart.doctree b/docs/_build/html/.doctrees/GettingStarted_2_QuickStart.doctree
new file mode 100644
index 0000000..200e72a
Binary files /dev/null and b/docs/_build/html/.doctrees/GettingStarted_2_QuickStart.doctree differ
diff --git a/docs/_build/html/.doctrees/HydroGenerate_Introduction.doctree b/docs/_build/html/.doctrees/HydroGenerate_Introduction.doctree
new file mode 100644
index 0000000..1748f66
Binary files /dev/null and b/docs/_build/html/.doctrees/HydroGenerate_Introduction.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_1_Hydropower.doctree b/docs/_build/html/.doctrees/Theory_1_Hydropower.doctree
new file mode 100644
index 0000000..184e41f
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_1_Hydropower.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_2_Design_Flow.doctree b/docs/_build/html/.doctrees/Theory_2_Design_Flow.doctree
new file mode 100644
index 0000000..1af2da9
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_2_Design_Flow.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_3_Efficiency.doctree b/docs/_build/html/.doctrees/Theory_3_Efficiency.doctree
new file mode 100644
index 0000000..8baff00
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_3_Efficiency.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_4_HeadLoss.doctree b/docs/_build/html/.doctrees/Theory_4_HeadLoss.doctree
new file mode 100644
index 0000000..3630707
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_4_HeadLoss.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_5_CostOM.doctree b/docs/_build/html/.doctrees/Theory_5_CostOM.doctree
new file mode 100644
index 0000000..4c684e5
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_5_CostOM.doctree differ
diff --git a/docs/_build/html/.doctrees/Theory_6_FlowConstraints.doctree b/docs/_build/html/.doctrees/Theory_6_FlowConstraints.doctree
new file mode 100644
index 0000000..220eb67
Binary files /dev/null and b/docs/_build/html/.doctrees/Theory_6_FlowConstraints.doctree differ
diff --git a/docs/_build/html/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree b/docs/_build/html/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree
new file mode 100644
index 0000000..f39ca1d
Binary files /dev/null and b/docs/_build/html/.doctrees/UserGuide_7_HydroGenerateWorkflow.doctree differ
diff --git a/docs/_build/html/.doctrees/UserGuide_8_Issues_Support.doctree b/docs/_build/html/.doctrees/UserGuide_8_Issues_Support.doctree
new file mode 100644
index 0000000..01fb130
Binary files /dev/null and b/docs/_build/html/.doctrees/UserGuide_8_Issues_Support.doctree differ
diff --git a/docs/_build/html/.doctrees/api/FPP.doctree b/docs/_build/html/.doctrees/api/FPP.doctree
new file mode 100644
index 0000000..f5bf37a
Binary files /dev/null and b/docs/_build/html/.doctrees/api/FPP.doctree differ
diff --git a/docs/_build/html/CMF.html b/docs/_build/html/CMF.html
deleted file mode 100644
index c9118d5..0000000
--- a/docs/_build/html/CMF.html
+++ /dev/null
@@ -1,651 +0,0 @@
-
-
-
-
-
-
-
-
Table 4: Description of classes, methods, and functions implemented in HydroGenerate.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Table 4: Description of classes, methods, and functions implemented in HydroGenerate.#
-
-
-
Name
-
Type
-
Functionality
-
-
-
-
TurbineParameters
-
Class
-
Initializes parameters needed for turbine calculation
-
-
turbine_type_selector
-
Function
-
Selects a turbine type based on head.
-
-
FlowRange:
-
Class
-
-
-
flowrange_calculator
-
Method in FlowRange
-
Creates a flow range from half the value of flow to the flow provided. This flow range is used to evaluate the efficiency of a turbine for flows below the design flow when a time series is not available
-
-
ReactionTurbines
-
Class
-
-
-
Runnersize_calculator
-
Method in reaction turbines
-
Computes the runner diameter for reaction turbines