Декоратор не возвращает значение в ожидаемых единицах - PullRequest
1 голос
/ 17 февраля 2020

В следующем коде используется пинта для преобразования массового расхода в объемный c поток. Чтобы преобразовать массу в объем, необходимо рассчитать плотность газа. Вычисления возвращают правильные значения в желаемых единицах.

import pint
ureg = pint.UnitRegistry()
Q_ = ureg.Quantity


def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return (P / R / T.to(ureg.kelvin)).to(ureg('kg/m^3'))


@ureg.wraps(ret='m^3/sec', args=['kg/sec', 'kg/m^3'])
def volumetric_flow_rate(mass_flow_rate, rho):
    return mass_flow_rate / rho


mfr = 1 * ureg('kg/s')
temperature = Q_(25, ureg.degC)

rho = density(temperature)
print(rho)
# 1.1841314120000166 kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 meter ** 3 / second

Однако, когда я подаю заявку на использование декоратора @ureg.wraps в функции density так же, как для volumetric_flow_rate, значение верное, но единицы не являются желаемыми единицами.

@ureg.wraps(ret='kg/m^3', args=['K'])
def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return P / R / T

rho = density(temperature)
print(rho)
# 1.1841314120000166 kelvin * kilogram * pascal / joule kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 joule / kelvin / kilogram / pascal meter ** 3 / second

Все следующие версии декоратора дают одинаковые результаты (неправильные единицы возврата) для функции density:

@ureg.wraps(ret='kg/m^3', args='K')
@ureg.wraps(ret='kg/m^3', args=['K'])
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin)
@ureg.wraps(ret='kg/m^3', args='K', strict=True)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=True)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=True)
@ureg.wraps(ret='kg/m^3', args='K', strict=False)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=False)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=False)

Следующая версия декоратора вызывает ошибку

@ureg.wraps(ret=ureg('kg/m^3'), args=ureg.kelvin)

TypeError: аргумент ret 'обертывания должен иметь тип str или Unit, а не (1,0 кг / метр ** 3)

С этим сообщением об ошибке я определил пользовательскую единицу mass_flow

ureg.define('mass_flow = 1 * kg / m^3')
print(ureg.mass_flow)
# mass_flow
print(type(ureg.mass_flow))
# <class 'pint.unit.build_unit_class.<locals>.Unit'>
print(1 * ureg.mass_flow)
# 1 mass_flow

Следующие декораторы надевают не выдают ошибку, однако они все равно выдали неправильные единицы (хотя теперь с mass_flow "единицами".

@ureg.wraps(ret=ureg.mass_flow, args='K')
@ureg.wraps(ret='mass_flow', args='K')
# 1.1841314120000166 kelvin * kilogram * pascal / joule mass_flow

Одна из последних попыток рва, которую я пытался, была определить R и P за пределами функции. Не ожидал, что это изменит ответ, и ожидания были правильными.

R = 287 * ureg('J/kg/K')
P = 101325 * ureg('Pa')
@ureg.wraps(ret='kg/m^3', args='K')
def density(T):
    return P / R / T

Вопрос:

Как определить декоратор для функции density в аналогично функции volumetric_flow_rate, так что тело функции чище и не требует от меня выполнения внутренних преобразований единиц?

Кроме того, если функция volumetric_flow_rate имеет сложную единицу возврата m^3/sec почему kg/m^3 не работает для функции density?

Python 3.7.0, пинта 0.10.1

1 Ответ

1 голос
/ 18 февраля 2020

Пинта выводит все единицы перед входом в функцию, а затем применяет единицы после завершения функции. Таким образом, работает любое из следующих действий:

@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'])
def density(T, P=101325 * ureg.Pa, R=287 * ureg('J/kg/K')):
    return P / R / T

@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'], strict=False)
def density(T, P=101325, R=287):
    return P / R / T

Ключ должен гарантировать, что все в функции безразмерно. Если вы вызываете другую функцию в оформленной функции @ureg.wraps, и эта функция возвращает размерную величину, преобразуйте ее в необходимые единицы, а затем обрезайте единицы с помощью атрибута .magnitude.

...