You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.6 KiB
Python

import pint
class DimensionConverter(object):
def __init__(self):
# Initialise unit definitions
self.ureg = pint.UnitRegistry()
def _convert(self, x, length_scale_factor, input_unit, target_unit):
# Calculate unit conversion factor
input_unit = self.ureg(input_unit)
target_unit = self.ureg(target_unit)
unit_conversion_factor = input_unit.to(target_unit).magnitude
# Calculate Froude scaling factor
froude_scale_factor = length_scale_factor**(
input_unit.dimensionality['[length]'] * self.LENGTH_EXPONENT +
input_unit.dimensionality['[time]'] * self.TIME_EXPONENT +
input_unit.dimensionality['[mass]'] * self.MASS_EXPONENT)
# Scale values
x_scaled = x * froude_scale_factor
# Convert to output units
x_scaled *= unit_conversion_factor
return x_scaled
def proto_to_model(self,
x_proto,
length_scale,
input_unit,
target_unit,
index_input_unit=None,
index_target_unit=None):
"""Convert prototype value(s) to model value(s) in specified units.
Args:
x_proto: prototype values (array_like, or pandas dataframe)
length_scale: ratio between proto and model dimensions (float)
input_unit: unit of input (string)
target_unit: unit of output (string)
index_input_unit: unit of input index (dataframe only)
index_target_unit: unit of output index (dataframe only)
Returns:
input values in model scale
"""
length_scale_factor = 1 / length_scale
# Convert values
x_model = self._convert(x_proto, length_scale_factor, input_unit,
target_unit)
# Convert index (dataframe or series only)
if (index_input_unit is not None) and (index_target_unit is not None):
if type(x_model).__name__ in ['DataFrame', 'Series']:
x_model.index = self._convert(
x_model.index, length_scale_factor, index_input_unit,
index_target_unit)
else:
raise ValueError("'index_input_unit' and 'index_target_unit' "
"can only be used when input is dataframe")
return x_model
def model_to_proto(self,
x_model,
length_scale,
input_unit,
target_unit,
index_input_unit=None,
index_target_unit=None):
"""Convert model value(s) to prototype value(s) in specified units.
Args:
x_model: model values (array_like, or pandas dataframe)
length_scale: ratio between proto and model dimensions (float)
input_unit: unit of input (string)
target_unit: unit of output (string)
index_input_unit: unit of input index (dataframe only)
index_target_unit: unit of output index (dataframe only)
Returns:
input values in prototype scale
"""
length_scale_factor = length_scale
# Convert values
x_proto = self._convert(x_model, length_scale_factor, input_unit,
target_unit)
# Convert index (dataframe or series only)
if (index_input_unit is not None) and (index_target_unit is not None):
if type(x_proto).__name__ in ['DataFrame', 'Series']:
x_proto.index = self._convert(
x_proto.index, length_scale_factor, index_input_unit,
index_target_unit)
else:
raise ValueError("'index_input_unit' and 'index_target_unit' "
"can only be used when input is dataframe")
return x_proto
def dimensions(self, unit):
"""Get unit dimensions.
Args:
unit: unit name or symbol (string)
Returns:
string containing unit dimensions
"""
# Get dimensions of unit
dims = self.ureg(unit).dimensionality
dim_data = {'L': '[length]', 'M': '[mass]', 'T': '[time]'}
s = ''
for symbol, key in dim_data.items():
exponent = dims[key]
if exponent != 0:
s += '{}^{:g} '.format(symbol, exponent)
return s.strip()
def scaling_exponent(self, unit):
"""Convert prototype value(s) to model value(s) in specified units.
Args:
unit: unit of quantity to be scaled (string)
Returns:
scaling factor
"""
# Calculate Froude scaling factor
scaling_exponent = (
self.ureg(unit).dimensionality['[length]'] * self.LENGTH_EXPONENT +
self.ureg(unit).dimensionality['[time]'] * self.TIME_EXPONENT +
self.ureg(unit).dimensionality['[mass]'] * self.MASS_EXPONENT)
return scaling_exponent
class FroudeConverter(DimensionConverter):
def __init__(self):
super(FroudeConverter, self).__init__()
# Define Froude scaling relationships
self.LENGTH_EXPONENT = 1
self.TIME_EXPONENT = 1 / 2
self.MASS_EXPONENT = 3
class ReynoldsConverter(DimensionConverter):
def __init__(self):
super(ReynoldsConverter, self).__init__()
# Define Reynolds scaling relationships
self.LENGTH_EXPONENT = 1
self.TIME_EXPONENT = 2
self.MASS_EXPONENT = 3