Source code for torx.basic_functions_m
"""Simple functions which are commonly used."""
import numpy as np
import xarray as xr
from torx.autodoc_decorators_m import autodoc_function
[docs]
@autodoc_function
def smoothstep(test_point: float, step_center: float, step_width: float, order=3):
"""
Return a hermite smoothstep of a specific order.
The step will be exactly 0 for test_point values less than step_center - step_width / 2
The step will be exactly 1 for test_point values greater than step_center + step_width / 2
For a step of order A, the derivative of order (A-1) will also be zero
at the endpoints.
"""
xn = (np.atleast_1d(test_point) - step_center) / step_width + 0.5
# Ignore the runtime warning that comes from comparing NaN
# NaN will return False in any comparison
with np.errstate(invalid="ignore"):
xn[xn <= 0] = 0
xn[xn >= 1] = 1
if order == 1:
step_values = xn
elif order == 2:
step_values = -2.0 * xn**3 + 3.0 * xn**2
elif order == 3:
step_values = 6.0 * xn**5 - 15.0 * xn**4 + 10.0 * xn**3
elif order == 4:
step_values = -20.0 * xn**7 + 70.0 * xn**6 - 84.0 * xn**5 + 35.0 * xn**4
elif order == 5:
step_values = (
70.0 * xn**9
- 315.0 * xn**8
+ 540.0 * xn**7
- 420.0 * xn**6
+ 126.0 * xn**5
)
elif order == 6:
step_values = (
-252.0 * xn**11
+ 1386.0 * xn**10
- 3080.0 * xn**9
+ 3465.0 * xn**8
- 1980.0 * xn**7
+ 462.0 * xn**6
)
elif order == 7:
step_values = (
924.0 * xn**13
- 6006.0 * xn**12
+ 16380.0 * xn**11
- 24024.0 * xn**10
+ 20020.0 * xn**9
- 9009.0 * xn**8
+ 1716.0 * xn**7
)
else:
return NotImplemented
if isinstance(test_point, xr.DataArray):
return xr.DataArray(
step_values,
coords=test_point.coords,
dims=test_point.dims,
attrs=test_point.attrs,
)
else:
return step_values
[docs]
@autodoc_function
def find_nearest_index(array, value):
"""Return the index in the array that is nearest to the value."""
array = np.asarray(array)
idx = (np.abs(array - value)).argmin()
return idx
[docs]
@autodoc_function
def second_smallest(array):
"""Find the second smallest, unique entry in an array."""
m1 = m2 = float("inf")
for x in array.flat:
if x < m1:
m1, m2 = x, m1
elif x < m2 and x != m1:
m2 = x
return m2