Source code for pycalphad.property_framework.units
import pint
import numpy as np
import numpy.typing as npt
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pycalphad.property_framework import ComputableProperty
ureg = pint.UnitRegistry(preprocessors=[lambda s: s.replace('%', ' percent ')])
ureg.define('atom = 1/avogadro_number * mol')
ureg.define('fraction = []')
ureg.define('percent = 1e-2 fraction = %')
ureg.define('ppm = 1e-6 fraction')
pint.set_application_registry(ureg)
Q_ = ureg.Quantity
DimensionalityError = pint.DimensionalityError
[docs]
def as_quantity(prop: "ComputableProperty", qt: npt.ArrayLike):
if not isinstance(qt, Q_):
return Q_(qt, prop.display_units)
else:
return qt
energy_implementation_units = GM_implementation_units = 'J / mol'
energy_display_units = GM_display_units = 'J / mol'
energy_display_name = GM_display_name = 'Gibbs Energy'
G_implementation_units = 'J'
G_display_units = 'J'
G_display_name = 'Gibbs Energy'
enthalpy_implementation_units = HM_implementation_units = GM_implementation_units
enthalpy_display_units = HM_display_units = GM_display_units
enthalpy_display_name = HM_display_name = 'Enthalpy'
H_implementation_units = 'J'
H_display_units = 'J'
H_display_name = 'Enthalpy'
entropy_implementation_units = SM_implementation_units = 'J / mol / K'
entropy_display_units = SM_display_units = 'J / mol / K'
entropy_display_name = SM_display_name = 'Entropy'
cpm_implementation_units = CPM_implementation_units = 'J / mol / K'
cpm_display_units = CPM_display_units = 'J / mol / K'
cpm_display_name = CPM_display_name = 'Heat Capacity'
def _conversions_per_formula_unit(compset):
components = compset.phase_record.nonvacant_elements
num_components = len(components)
moles_per_fu = np.zeros((num_components,1))
for comp_idx in range(num_components):
compset.phase_record.formulamole_obj(moles_per_fu[comp_idx, :], compset.dof, comp_idx)
# now we have 'moles per formula unit'
# need to convert by adding molecular weight of each element
grams_per_mol = np.array(compset.phase_record.molar_masses, dtype='float')
grams_per_fu = np.dot(grams_per_mol, moles_per_fu)
return moles_per_fu.sum(), grams_per_fu
[docs]
def unit_conversion_context(compsets, prop):
context = pint.Context()
# these will be something/mol by convention
# XXX: This is a very rough check
if not ('/ mol' in str(prop.implementation_units)):
return context
implementation_units = (ureg.Unit(prop.implementation_units) * ureg.Unit('mol'))
molar_weight = 0.0 # g/mol-atom
for compset in compsets:
if compset.NP > 0:
moles_per_fu, grams_per_fu = _conversions_per_formula_unit(compset)
grams_per_mol_atoms = (compset.NP / moles_per_fu) * grams_per_fu
molar_weight += grams_per_mol_atoms
molar_weight = Q_(molar_weight, 'g/mol')
per_moles = ureg.get_dimensionality(ureg.Unit('{} / mol'.format(implementation_units)))
per_mass = ureg.get_dimensionality(ureg.Unit('{} / g'.format(implementation_units)))
context.add_transformation(
per_moles,
per_mass,
lambda ureg, x: np.true_divide(x, molar_weight).to_reduced_units(),
)
context.add_transformation(
per_mass,
per_moles,
lambda ureg, x: (x * molar_weight).to_reduced_units()
)
return context