Source code for pml.units
import numpy as np
from scipy.interpolate import PchipInterpolator
from pml.exceptions import UniqueSolutionException
[docs]def unit_function(value):
return value
[docs]class UnitConv(object):
def __init__(self, f1=unit_function, f2=unit_function):
self.f1 = f1
self.f2 = f2
def _raw_eng_to_phys(self, value):
raise NotImplementedError()
[docs] def eng_to_phys(self, value):
x = self._raw_eng_to_phys(value)
y = self.f1(x)
return y
def _raw_phys_to_eng(self, value):
raise NotImplementedError()
[docs] def phys_to_eng(self, value):
x = self._raw_phys_to_eng(value)
y = self.f2(x)
return y
[docs]class PolyUnitConv(UnitConv):
def __init__(self, coef, f1=unit_function, f2=unit_function):
"""Linear interpolation for converting between physics and engineering units.
Args:
coef(array_like): The polynomial's coefficients, in decreasing powers.
"""
super(self.__class__, self).__init__(f1, f2)
self.p = np.poly1d(coef)
def _raw_eng_to_phys(self, eng_value):
"""Convert between engineering and physics units.
Args:
eng_value(float): The engineering value to be converted to the engineering unit.
Returns:
float: The physics value determined using the engineering value.
"""
return self.p(eng_value)
def _raw_phys_to_eng(self, physics_value):
"""Convert between physics and engineering units.
Args:
physics_value(float): The physics value to be converted to the
engineering value.
Returns:
float: The converted engineering value from the given physics value.
Raises:
ValueError: An error occured when there exist no or more than one roots.
"""
roots = (self.p - physics_value).roots
if len(roots) == 1:
x = roots[0]
return x
else:
raise ValueError("There doesn't exist a corresponding engineering value or "
"they are not unique:", roots)
[docs]class PchipUnitConv(UnitConv):
def __init__(self, x, y, f1=unit_function, f2=unit_function):
""" PChip interpolation for converting between physics and engineering units.
Args:
x(list): A list of points on the x axis. These must be in increasing order
for the interpolation to work. Otherwise, a ValueError is raised.
y(list): A list of points on the y axis. These must be in increasing or
decreasing order. Otherwise, a ValueError is raised.
Raises:
ValueError: An error occured when the given y coefficients are neither in
increasing or decreasing order.
"""
super(self.__class__, self).__init__(f1, f2)
self.x = x
self.y = y
self.pp = PchipInterpolator(x, y)
diff = np.diff(y)
if not ((np.all(diff > 0)) or (np.all((diff < 0)))):
raise ValueError("Given coefficients must be monotonically"
"decreasing.")
def _raw_eng_to_phys(self, eng_value):
"""Convert between engineering and physics units.
Args:
eng_value(float): The engineering value to be converted to the engineering unit.
Returns:
float: The converted engineering value from the given engineering value.
"""
return self.pp(eng_value)
def _raw_phys_to_eng(self, physics_value):
"""Convert between physics and engineering units.
Args:
physics_value(float): The engineering value to be converted to the
engineering value.
Returns:
float: The converted engineering value from the given physics value.
Raises:
ValueError: An error occured when there exist no or more than one roots.
"""
y = [val - physics_value for val in self.y]
new_pp = PchipInterpolator(self.x, y)
roots = new_pp.roots()
if len(roots) == 1:
x = roots[0]
return x
else:
raise UniqueSolutionException("The function does not have any solution.")