Source code for wombat.utilities.utilities
"""Provides various utility functions that don't fit within a common theme."""
from __future__ import annotations
from string import digits, punctuation
from typing import Callable
from functools import cache
import numpy as np
import pandas as pd
# Don't repeat the most common inputs that occur when there are no state changes, but
# the result is needed again for logging
[docs]
@cache
def _mean(*args) -> float:
"""Multiplies two numbers. Used for a reduce operation.
Parameters
----------
args : int | float
The values to compute the mean over
Returns
-------
float
The average of the values provided
"""
return np.mean(args)
[docs]
def create_variable_from_string(string: str) -> str:
"""Creates a valid Python variable style string from a passed string.
Parameters
----------
string : str
The string to convert into a Python-friendly variable name.
Returns
-------
str
A Python-valid variable name.
Examples
--------
>>> example_string = "*Electrical!*_ _System$*_"
>>> print(create_variable_from_string(example_string))
'electrical_system'
"""
new_string = (
string.lstrip(punctuation + digits)
.translate(str.maketrans("", "", punctuation.replace("_", " ")))
.lower()
)
return new_string
[docs]
def IEC_power_curve(
windspeed_column: np.ndarray | pd.Series,
power_column: np.ndarray | pd.Series,
bin_width: float = 0.5,
windspeed_start: float = 0.0,
windspeed_end: float = 30.0,
) -> Callable:
"""Direct copyfrom OpenOA:
https://github.com/NREL/OpenOA/blob/main/operational_analysis/toolkits/power_curve/functions.py#L16-L57
Use IEC 61400-12-1-2 method for creating wind-speed binned power curve.
Parameters
----------
windspeed_column : np.ndarray | pandas.Series
The power curve's windspeed values, in m/s.
power_column : np.ndarray | pandas.Series
The power curve's output power values, in kW.
bin_width : float
Width of windspeed bin, default is 0.5 m/s according to standard, by default
0.5.
windspeed_start : float
Left edge of first windspeed bin, where all proceeding values will be 0.0,
by default 0.0.
windspeed_end : float
Right edge of last windspeed bin, where all following values will be 0.0, by
default 30.0.
Returns
-------
Callable
Python function of the power curve, of type (Array[float] -> Array[float]),
that maps input windspeed value(s) to ouptut power value(s).
"""
if not isinstance(windspeed_column, pd.Series):
windspeed_column = pd.Series(windspeed_column)
if not isinstance(power_column, pd.Series):
power_column = pd.Series(power_column)
# Set up evenly spaced bins of fixed width, with np.inf for any value over the max
n_bins = int(np.ceil((windspeed_end - windspeed_start) / bin_width)) + 1
bins = np.append(np.linspace(windspeed_start, windspeed_end, n_bins), [np.inf])
# Initialize an array which will hold the mean values of each bin
P_bin = np.ones(len(bins) - 1) * np.nan
# Compute the mean of each bin and set corresponding P_bin
for ibin in range(0, len(bins) - 1):
indices = (windspeed_column >= bins[ibin]) & (windspeed_column < bins[ibin + 1])
P_bin[ibin] = power_column.loc[indices].mean()
# Linearly interpolate any missing bins
P_bin = pd.Series(data=P_bin).interpolate(method="linear").bfill().values
# Create a closure over the computed bins which computes the power curve value for
# arbitrary array-like input
def pc_iec(x):
P = np.zeros(np.shape(x))
for i in range(0, len(bins) - 1):
idx = np.where((x >= bins[i]) & (x < bins[i + 1]))
P[idx] = P_bin[i]
cutoff_idx = (x < windspeed_start) | (x > windspeed_end)
P[cutoff_idx] = 0.0
return P
return pc_iec