Ejemplo n.º 1
0
    def setup():
        """
        initalize beat, samplerate, and percent units
        """

        # define beats
        for i in Units._get_beat_frac_tables():
            if i[2] == "beat":
                Units._reg.define("beat = [beat_time] = b")
            else:
                Units._reg.define("{0} = {1} beat = {2}".format(i[2], i[1], i[0]))

        # define samples
        Units._reg.define("sample = [sample_time] = samp")

        # percent
        Units._reg.define(pint.unit.UnitDefinition('percent', 'pct', ('pct', 'pcnt'), 
            pint.converters.ScaleConverter(1 / 100.0)))

        # samplerate
        cont = pint.Context('samplerate')
        cont.add_transformation("[sample_time]", "[time]", 
            lambda reg, x: x / _proj_rate_wrapper())
        cont.add_transformation("[time]", "[sample_time]",
            lambda reg, x: x * _proj_rate_wrapper())
        Units._reg.add_context(cont)
        Units._reg.enable_contexts('samplerate')

        # bpm
        cont = pint.Context("bpm")
        cont.add_transformation("[beat_time]", "[time]", 
            lambda reg, x, bpm_context: _time_beat_convert(x, bpm_context, to="time"))
        cont.add_transformation("[time]", "[beat_time]", 
            lambda reg, x, bpm_context: _time_beat_convert(x, bpm_context, to="beats"))
        Units._reg.add_context(cont)
Ejemplo n.º 2
0
    def _load_contexts(self) -> None:
        """
        Load contexts.
        """
        _ch4_context = pint.Context("CH4_conversions")
        _ch4_context.add_transformation(
            "[carbon]",
            "[methane]",
            lambda registry, x: 16 / 12 * registry.CH4 * x / registry.C,
        )
        _ch4_context.add_transformation(
            "[methane]",
            "[carbon]",
            lambda registry, x: x * registry.C / registry.CH4 / (16 / 12),
        )
        self.add_context(_ch4_context)

        _n2o_context = pint.Context("NOx_conversions")
        _n2o_context.add_transformation(
            "[nitrogen]",
            "[NOx]",
            lambda registry, x:
            (14 + 2 * 16) / 14 * registry.NOx * x / registry.nitrogen,
        )
        _n2o_context.add_transformation(
            "[NOx]",
            "[nitrogen]",
            lambda registry, x: x * registry.nitrogen / registry.NOx /
            ((14 + 2 * 16) / 14),
        )
        self.add_context(_n2o_context)

        self._load_metric_conversions()
Ejemplo n.º 3
0
    def _load_contexts(self):
        """
        Load contexts.
        """
        _ch4_context = pint.Context("CH4_conversions")
        _ch4_context = self._add_transformations_to_context(
            _ch4_context,
            "[methane]",
            self.CH4,
            "[carbon]",
            self.C,
            12 / 16,
        )
        self.add_context(_ch4_context)

        _n2o_context = pint.Context("N2O_conversions")
        _n2o_context = self._add_transformations_to_context(
            _n2o_context,
            "[nitrous_oxide]",
            self.nitrous_oxide,
            "[nitrogen]",
            self.nitrogen,
            14 / 44,
        )
        self.add_context(_n2o_context)

        _nox_context = pint.Context("NOx_conversions")
        _nox_context = self._add_transformations_to_context(
            _nox_context,
            "[nitrogen]",
            self.nitrogen,
            "[NOx]",
            self.NOx,
            (14 + 2 * 16) / 14,
        )
        self.add_context(_nox_context)

        _nh3_context = pint.Context("NH3_conversions")
        _nh3_context = self._add_transformations_to_context(
            _nh3_context,
            "[nitrogen]",
            self.nitrogen,
            "[NH3]",
            self.NH3,
            (14 + 3) / 14,
        )
        self.add_context(_nh3_context)

        self._load_metric_conversions()
Ejemplo n.º 4
0
def test_convert_with_context_dollars_euro(reg):
    c = pint.Context()
    c.add_transformation("[currency_USD]", "[currency_EUR]",
                         lambda r, u: 1.2 * r.EUR / r.USD * u)
    dollars = 5 * reg.USD
    euros = 6 * reg.EUR

    assert dollars.to("EUR", c) == euros
 def set_factor(self, factor: int) -> None:
     delay = pint.Context("delay", defaults={"n": 1, "num_pass": 2})
     delay.add_transformation(
         "[length]",
         "[time]",
         lambda ureg, x, n=1, num_pass=2: num_pass * x / ureg.speed_of_light * n
     )
     delay.add_transformation(
         "[time]",
         "[length]",
         lambda ureg, x, n=1, num_pass=2: x / num_pass * ureg.speed_of_light / n
     )
     self._ureg.enable_contexts("spectroscopy", delay)
Ejemplo n.º 6
0
def convert_unit(df,
                 current,
                 to,
                 factor=None,
                 registry=None,
                 context=None,
                 inplace=False):
    """Internal implementation of unit conversion with explicit kwargs"""
    ret = df.copy() if not inplace else df

    # Mask for rows having *current* units to be converted, args for replace
    try:
        where = ret._data.index.get_loc_level(current, 'unit')[0]
    except KeyError:
        where = [False] * len(ret)

    index_args = [ret._data, 'unit', {current: to}]

    if factor:
        # Short code path: use an explicit conversion factor, don't use pint
        ret._data[where] *= factor
        ret._data.index = replace_index_values(*index_args)
        return None if inplace else ret

    # Convert using a pint.UnitRegistry; default the one from iam_units
    registry = registry or iam_units.registry

    # Make versions without -equiv
    _current, _to = [i.replace('-equiv', '') for i in [current, to]]
    # Pair of (magnitude, unit)
    qty = [ret.data.loc[where, 'value'].values, _current]

    try:
        # Create a vector pint.Quantity
        qty = registry.Quantity(*qty)
    except pint.UndefinedUnitError:
        # *qty* might include a GHG species; try GWP conversion
        result, _to = convert_gwp(context, qty, _to)
    except AttributeError:
        # .Quantity() did not exist
        raise TypeError(f'{registry} must be `pint.UnitRegistry`') from None
    else:
        # Ordinary conversion, using an empty Context if none was provided
        result = qty.to(_to, context or pint.Context())

    # Copy values from the result Quantity and assign units
    ret._data[where] = result.magnitude
    ret._data.index = replace_index_values(*index_args)

    return None if inplace else ret
Ejemplo n.º 7
0
def convert_unit(df,
                 current,
                 to,
                 factor=None,
                 registry=None,
                 context=None,
                 inplace=False):
    """Internal implementation of unit conversion with explicit kwargs"""
    ret = df.copy() if not inplace else df

    # Mask for rows having *current* units, to be converted
    where = ret.data['unit'] == current

    if factor:
        # Short code path: use an explicit conversion factor, don't use pint
        ret.data.loc[where, 'value'] *= factor
        ret.data.loc[where, 'unit'] = to
        return None if inplace else ret

    # Convert using a pint.UnitRegistry; default the one from iam_units
    registry = registry or iam_units.registry

    # Tuple of (magnitude, unit)
    qty = (ret.data.loc[where, 'value'].values, current)

    try:
        # Create a vector pint.Quantity
        qty = registry.Quantity(*qty)
    except pint.UndefinedUnitError as exc:
        # *current* might include a GHG species
        if not context:
            # Can't do anything without a context
            raise UndefinedUnitError(*exc.args) from None

        result, to = convert_gwp(context, qty, to)
    except AttributeError:
        # .Quantity() did not exist
        raise TypeError(f'{registry} must be `pint.UnitRegistry`') from None
    else:
        # Ordinary conversion, using an empty Context if none was provided
        result = qty.to(to, context or pint.Context())

    # Copy values from the result Quantity
    ret.data.loc[where, 'value'] = result.magnitude

    # Assign output units
    ret.data.loc[where, 'unit'] = to

    return None if inplace else ret
Ejemplo n.º 8
0
def add_currency_ureg(initial=True):
    res = requests.get(
        "https://api.exchangeratesapi.io/latest?base=EUR").json()
    base = res["base"]
    # create base unit (can be anything)
    if initial:
        ureg.define(f"{base} = [currency]")
    currency_context = pint.Context("FX")  # create context
    for currency, rate in res["rates"].items():
        if currency != base:
            ureg.define(f"{currency} = nan {base}")
            currency_context.redefine(f"{currency} = {1/rate} {base}"
                                      )  # add exchange rate to context
    ureg.add_context(currency_context)  # add and enable context
    ureg.enable_contexts("FX")
Ejemplo n.º 9
0
    def _add_metric_conversions_from_df(self, metric_conversions):
        # could make this public in future
        for col in metric_conversions:
            metric_conversion = metric_conversions[col]
            transform_context = pint.Context(col)
            for label, val in metric_conversion.iteritems():
                transform_context = self._add_gwp_to_context(
                    transform_context, label, val)

            for mixture in MIXTURES:
                constituents = self.split_gas_mixture(1 * self(mixture))
                try:
                    val = sum(c.magnitude * metric_conversion[str(c.units)]
                              for c in constituents)
                except KeyError:  # gwp not available for all constituents
                    continue
                if math.isnan(val):
                    continue
                transform_context = self._add_gwp_to_context(
                    transform_context, mixture, val)

            self.add_context(transform_context)
Ejemplo n.º 10
0
    def _load_metric_conversions(self):
        """
        Load metric conversion contexts from file.

        This is done only when contexts are needed to avoid reading files on import.
        """
        metric_conversions = pd.read_csv(
            path.join(
                path.dirname(path.abspath(__file__)),
                "data",
                "metric_conversions.csv",
            ),
            skiprows=1,  # skip source row
            header=0,
            index_col=0,
        ).iloc[1:, :]  # drop out 'SCMData base unit' row

        for col in metric_conversions:
            metric_conversion = metric_conversions[col]
            transform_context = pint.Context(col)
            for label, val in metric_conversion.iteritems():
                transform_context = self._add_gwp_to_context(
                    transform_context, label, val)

            for mixture in MIXTURES:
                constituents = self.split_gas_mixture(1 * self(mixture))
                try:
                    val = sum(c.magnitude * metric_conversion[str(c.units)]
                              for c in constituents)
                except KeyError:  # gwp not available for all constituents
                    continue
                if math.isnan(val):
                    continue
                transform_context = self._add_gwp_to_context(
                    transform_context, mixture, val)

            self.add_context(transform_context)
Ejemplo n.º 11
0
    pint.unit.UnitDefinition('percent', '%', (),
                             pint.converters.ScaleConverter(0.01)))

# Define commonly encountered units not defined by pint
units.define(
    'degrees_north = degree = degrees_N = degreesN = degree_north = degree_N '
    '= degreeN')
units.define(
    'degrees_east = degree = degrees_E = degreesE = degree_east = degree_E = degreeE'
)
units.define("degC = kelvin; offset: 273.15 = celsius = C"
             )  # add 'C' as an abbrev for celsius (default Coulomb)
units.define("d = day")

# Default context.
null = pint.Context('none')
units.add_context(null)

# Precipitation units. This is an artificial unit that we're using to verify that a given unit can be converted into
# a precipitation unit. Ideally this could be checked through the `dimensionality`, but I can't get it to work.
units.define("[precipitation] = [mass] / [length] ** 2 / [time]")
units.define("mmday = 1000 kg / meter ** 2 / day")

units.define("[discharge] = [length] ** 3 / [time]")
units.define("cms = meter ** 3 / second")

hydro = pint.Context('hydro')
hydro.add_transformation('[mass] / [length]**2', '[length]',
                         lambda ureg, x: x / (1000 * ureg.kg / ureg.m**3))
hydro.add_transformation('[mass] / [length]**2 / [time]', '[length] / [time]',
                         lambda ureg, x: x / (1000 * ureg.kg / ureg.m**3))
Ejemplo n.º 12
0
    pint.unit.UnitDefinition("percent", "%", (),
                             pint.converters.ScaleConverter(0.01)))

# Define commonly encountered units not defined by pint
units.define(
    "degrees_north = degree = degrees_N = degreesN = degree_north = degree_N "
    "= degreeN")
units.define(
    "degrees_east = degree = degrees_E = degreesE = degree_east = degree_E = degreeE"
)
units.define("degC = kelvin; offset: 273.15 = celsius = C"
             )  # add 'C' as an abbrev for celsius (default Coulomb)
units.define("d = day")

# Default context.
null = pint.Context("none")
units.add_context(null)

# Precipitation units. This is an artificial unit that we're using to verify that a given unit can be converted into
# a precipitation unit. Ideally this could be checked through the `dimensionality`, but I can't get it to work.
units.define("[precipitation] = [mass] / [length] ** 2 / [time]")
units.define("mmday = 1000 kg / meter ** 2 / day")

units.define("[discharge] = [length] ** 3 / [time]")
units.define("cms = meter ** 3 / second")

hydro = pint.Context("hydro")
hydro.add_transformation(
    "[mass] / [length]**2",
    "[length]",
    lambda ureg, x: x / (1000 * ureg.kg / ureg.m**3),
Ejemplo n.º 13
0
def build_units_registry(context):
    """Builds a pint UnitRegistry based on a given PhysicalConstantsContext.

    Parameters
    ----------
    context : PhysicalConstantsContext
        The context to use for the values.
    """
    import pint

    phys_const = context.raw_codata
    ureg = pint.UnitRegistry(on_redefinition="ignore")

    # Explicitly update relevant 2014 codata

    # Definitions
    ureg.define("avogadro_constant = {} / mol = N_A".format(
        phys_const["avogadro constant"]["value"]))
    ureg.define("boltzmann_constant = {} * joule / kelvin".format(
        phys_const["boltzmann constant"]["value"]))
    ureg.define("speed_of_light = {} * meter / second".format(
        phys_const["speed of light in vacuum"]["value"]))
    ureg.define("hartree_inverse_meter = {} / hartree / m".format(
        phys_const["hartree-inverse meter relationship"]["value"]))
    ureg.define("plank_constant = planks_constant")
    ureg.define("plancks_constant = {} * joule * s".format(
        phys_const["planck constant"]["value"]))

    # Energy
    ureg.define(
        "hartree = {} * joule = E_h = hartree_energy = au_energy".format(
            phys_const["hartree energy"]["value"]))
    ureg.define("electron_volt = {} * J = eV".format(
        phys_const["electron volt-joule relationship"]["value"]))

    # Mass
    ureg.define("electron_mass = {} * kg = au_mass".format(
        phys_const["electron mass"]["value"]))
    ureg.define(
        "atomic_mass_unit = {} * kilogram = u = amu = dalton = Da".format(
            phys_const["atomic mass constant"]["value"]))

    # Charge
    ureg.define("elementary_charge = {} * coulomb = e = au_charge".format(
        phys_const["elementary charge"]["value"]))
    ureg.define("statcoulomb = coulomb / 2997924580 = statC")

    # Dipole moment
    ureg.define("debye = 1e-18 * statcoulomb * cm = D")

    # Distance
    ureg.define("bohr = {} * meter = bohr_radius = Bohr = au_length".format(
        phys_const["bohr radius"]["value"]))
    ureg.define("wavenumber = 1 / centimeter")
    ureg.define("Angstrom = angstrom")

    # Miscellaneous atomic units (https://en.wikipedia.org/wiki/Hartree_atomic_units)
    phys_const_map = {
        "au_1st_hyperpolarizability": "atomic unit of 1st hyperpolarizability",
        "au_2nd_hyperpolarizability": "atomic unit of 2nd hyperpolarizability",
        "au_action": "atomic unit of action",
        "au_charge_density": "atomic unit of charge density",
        "au_current": "atomic unit of current",
        "au_electric_dipole_moment": "atomic unit of electric dipole mom.",
        "au_electric_field": "atomic unit of electric field",
        "au_electric_field_gradient": "atomic unit of electric field gradient",
        "au_electric_polarizability": "atomic unit of electric polarizability",
        "au_electric_potential": "atomic unit of electric potential",
        "au_electric_quadrupole_moment":
        "atomic unit of electric quadrupole mom.",
        "au_force": "atomic unit of force",
        "au_magnetic_dipole_moment": "atomic unit of mag. dipole mom.",
        "au_magnetic_flux_density": "atomic unit of mag. flux density",
        "au_magnetizability": "atomic unit of magnetizability",
        "au_momentum": "atomic unit of mom.um",
        "au_permittivity": "atomic unit of permittivity",
        "au_time": "atomic unit of time",
        "au_velocity": "atomic unit of velocity",
    }

    # Accessing raw_codata here, so aliases in context.py not active
    if context.name == "CODATA2018":
        phys_const_map["au_momentum"] = "atomic unit of momentum"

    for k, v in phys_const_map.items():
        ureg.define(
            f"{k} = {phys_const[v]['value']} * {phys_const[v]['unit']}")

    ureg.define(f"au_pressure = au_energy / au_length**3")  # not in CODATA

    # Define relationships
    _const_rename = {
        "inverse meter": "inverse_meter",
        "atomic mass unit": "atomic_mass_unit",
        "electron volt": "electron_volt",
    }

    _nist_units = set()

    for k, v in phys_const.items():

        # Automatically builds the following:
        # electron_volt_to_kelvin = 1.16045221e4 / electron_volt * kelvin
        # hartree_to_atomic_mass_unit = 2.9212623197e-8 / hartree * atomic_mass_unit
        if not (("-" in k) and ("relationship" in k)):
            continue

        # Rename where needed
        left_unit, right_unit = k.split("-")
        left_unit = _const_rename.get(left_unit, left_unit)
        _nist_units.add(left_unit)

        right_unit = right_unit.replace(" relationship", "")
        right_unit = _const_rename.get(right_unit, right_unit)

        # Inverse is a special case

        if "inverse_meter" == left_unit:
            ratio1 = "* meter"
        else:
            ratio1 = "/ " + left_unit

        if "inverse_meter" == right_unit:
            ratio2 = "/ meter"
        else:
            ratio2 = "* " + right_unit

        definition = "{}_to_{} = {} {} {}".format(left_unit, right_unit,
                                                  v["value"], ratio1, ratio2)
        ureg.define(definition)
        # print(definition)

    # Add contexts

    def _find_nist_unit(unit):
        """Converts pint datatypes to NIST datatypes"""
        for value in unit.to_tuple()[1]:
            if value[1] < 1:
                continue
            if any(x in value[0] for x in _nist_units):
                return value[0]

        for value in unit.to_tuple()[1]:
            if (value[0] == "meter") and (value[1] == -1):
                return "inverse_meter"

        return None

    def build_transformer(right_unit, default):
        """Builds a transformer that attempts first to use the NIST values exactly and then falls back
        on to canonical Pint tech. The NIST values are not "exact" and will
        fail the triangle rule due to the inherent uncertainties of the values.

        Parameters
        ----------
        right_unit : str
            The NIST value to convert to
        default : str
            A fall back conversion rule to apply
        """
        def transformer(ureg, val):

            left_unit = _find_nist_unit(val)
            if left_unit is None:
                return val * ureg.parse_expression(default)
            else:
                return val * ureg.parse_expression("{}_to_{}".format(
                    left_unit, right_unit))

        return transformer

    # Allows hartree <-> frequency
    c1 = pint.Context("energy_frequency")
    c1.add_transformation("[energy]", "[frequency]",
                          build_transformer("hertz", "1 / plancks_constant"))
    c1.add_transformation("[frequency]", "[energy]",
                          build_transformer("hartree", "plancks_constant"))

    # Allows hartree <-> inverse_length
    c2 = pint.Context("energy_inverse_length")
    c2.add_transformation(
        "[energy]", "1 / [length]",
        build_transformer("inverse_meter", "hartree_to_inverse_meter"))
    c2.add_transformation(
        "1 / [length]", "[energy]",
        build_transformer("hartree", "inverse_meter_to_hartree"))

    # Allows hartree <-> mass
    c3 = pint.Context("energy_mass")
    c3.add_transformation("[energy]", "[mass]",
                          build_transformer("kilogram", "hartree_to_kilogram"))
    c3.add_transformation("[mass]", "[energy]",
                          build_transformer("hartree", "kilogram_to_hartree"))

    # Allows hartree <-> temperature
    c4 = pint.Context("energy_temperature")
    c4.add_transformation("[energy]", "[temperature]",
                          build_transformer("kelvin", "hartree_to_kelvin"))
    c4.add_transformation("[temperature]", "[energy]",
                          build_transformer("hartree", "kelvin_to_hartree"))

    # Allows energy <-> energy / mol
    c5 = pint.Context("substance_relation")
    c5.add_transformation("[energy]", "[energy] / [substance]",
                          lambda ureg, val: val * ureg.N_A)
    c5.add_transformation("[energy] / [substance]", "[energy]",
                          lambda ureg, val: val / ureg.N_A)

    # Add the context
    ureg.enable_contexts(c1, c2, c3, c4, c5)

    return ureg
Ejemplo n.º 14
0
    #     #        np.einsum('i, i', zernike[new_data_defined], zernike[new_data_defined])
    #     print(rms)
    #     fig, ax = plt.subplots()
    #     im = ax.imshow(zernike * a.data_defined, extent=a.extent)
    #     fig.colorbar(im, ax=ax)
    #     plt.show()


if __name__ == '__main__':
    # units = pint.UnitRegistry()
    units.setup_matplotlib(True)
    # units.load_definitions('pint_waves_def.txt')
    units.define('waves = radian * 2 * pi =  wave = wv')
    # units.define('waves = [] =  wave = wv')
    wavelength = 632.8 * units.nm
    c = pint.Context('optics')
    c.add_transformation('meter', 'radian',
                         lambda units, x: x * 2 * np.pi / wavelength)
    c.add_transformation('radian', 'meter',
                         lambda units, x: x * wavelength / (2 * np.pi))
    units.add_context(c)
    units.enable_contexts('optics')

    myval = 1 * units.wv
    # print(myval.to(units.nm))
    # print(myval.to(units.rad))

    units.disable_contexts()
    units.remove_context('optics')
    del (c)
    c = pint.Context('optics')
Ejemplo n.º 15
0
    'servings': 0,
    'ingredients': {},
    'instructions': "",
    'date': date.today(),
    'category': 'snack'
}

saved_diet = 'tracker.csv'
saved_recipes = 'Recipes/'
saved_meals = 'saved_meals.csv'

units = pint.UnitRegistry()

# Add context to convert volume to weight/mass and vice versa
density = (8 * units.oz).to_base_units() / (1 * units.cup).to_base_units()
ctx = pint.Context('kitchen')
ctx.add_transformation('[volume]', '[mass]',
                       lambda units, x: x.to_base_units() * density)
ctx.add_transformation('[mass]', '[volume]',
                       lambda units, x: x.to_base_units() / density)
units.add_context(ctx)
units.enable_contexts('kitchen')

measure_unit = units.g


def dict_to_pandas(foods):
    """ Converts a food:amount dictionary to a pandas dataframe """
    data = [[value.magnitude, value.units, key]
            for key, value in foods.items()]
    df = pd.DataFrame(data, columns=ingredient_columns)
Ejemplo n.º 16
0
    Add linear forward and inverse unit transformations.
    """
    context.add_transformation(
        source, dest, functools.partial(lambda scale, ureg, x: x * scale,
                                        scale))
    context.add_transformation(
        dest, source, functools.partial(lambda scale, ureg, x: x / scale,
                                        scale))


# Static energy components, their rates of change (1/s), their fluxes (m/s), and
# their *absolute* fluxes integrated over the latitude band (m^2/s).
# NOTE: Common to want to convert [energy] / [mass] to [energy] / [area] / [pressure]
# for displaying static or Lorenz energy terms. But this is already covered by
# the geopotential height transformations! Latter units are equivalent to [length]!
climo = pint.Context('climo')
for suffix1, suffix2 in itertools.product(
    ('', ' / [time]', ' * [velocity]', ' * [length] * [velocity]'),
    ('', ' * [mass] / [area]'),
):
    suffix = suffix1 + suffix2
    _add_transformation(
        climo,
        '[length]' + suffix,
        '[energy] / [mass]' + suffix,
        g,
    )
    _add_transformation(
        climo,
        '[temperature]' + suffix,
        '[energy] / [mass]' + suffix,
Ejemplo n.º 17
0
def build_units_registry(context):
    """Builds a pint UnitRegistry based on a given PhysicalConstantsContext.

    Parameters
    ----------
    context : PhysicalConstantsContext
        The context to use for the values.
    """
    phys_const = context.raw_codata
    ureg = pint.UnitRegistry(on_redefinition="ignore")

    # Explicitly update relevant 2014 codata

    # Definitions
    ureg.define("avogadro_constant = {} / mol = N_A".format(
        phys_const["avogadro constant"]["value"]))
    ureg.define("boltzmann_constant = {} * joule / kelvin".format(
        phys_const["boltzmann constant"]["value"]))
    ureg.define("speed_of_light = {} * meter / second".format(
        phys_const["speed of light in vacuum"]["value"]))
    ureg.define("hartree_inverse_meter = {} / hartree / m".format(
        phys_const["hartree-inverse meter relationship"]["value"]))

    # Energy
    ureg.define("hartree = {} * joule = E_h = hartree_energy".format(
        phys_const["hartree energy"]["value"]))
    ureg.define("electron_volt = {} * J = eV".format(
        phys_const["electron volt-joule relationship"]["value"]))

    # Constants
    ureg.define("electron_mass = {} * kg".format(
        phys_const["electron mass"]["value"]))
    ureg.define("elementary_charge = {} * coulomb = e".format(
        phys_const["elementary charge"]["value"]))
    ureg.define("plancks_constant = {} * joule * s".format(
        phys_const["planck constant"]["value"]))

    # Distance
    ureg.define("bohr = {} * meter = bohr_radius = Bohr".format(
        phys_const["bohr radius"]["value"]))
    ureg.define("wavenumber = 1 / centimeter")
    ureg.define("Angstrom = angstrom")

    # Masses
    ureg.define(
        "atomic_mass_unit = {} * kilogram = u = amu = dalton = Da".format(
            phys_const["atomic mass constant"]["value"]))

    # Define relationships
    _const_rename = {
        "inverse meter": "inverse_meter",
        "atomic mass unit": "atomic_mass_unit",
        "electron volt": "electron_volt"
    }

    _nist_units = set()

    for k, v in phys_const.items():

        # Automatically builds the following:
        # electron_volt_to_kelvin = 1.16045221e4 / electron_volt * kelvin
        # hartree_to_atomic_mass_unit = 2.9212623197e-8 / hartree * atomic_mass_unit
        if not (("-" in k) and ("relationship" in k)): continue

        # Rename where needed
        left_unit, right_unit = k.split('-')
        left_unit = _const_rename.get(left_unit, left_unit)
        _nist_units.add(left_unit)

        right_unit = right_unit.replace(" relationship", "")
        right_unit = _const_rename.get(right_unit, right_unit)

        # Inverse is a special case

        if "inverse_meter" == left_unit:
            ratio1 = "* meter"
        else:
            ratio1 = "/ " + left_unit

        if "inverse_meter" == right_unit:
            ratio2 = "/ meter"
        else:
            ratio2 = "* " + right_unit

        definition = "{}_to_{} = {} {} {}".format(left_unit, right_unit,
                                                  v["value"], ratio1, ratio2)
        ureg.define(definition)
        # print(definition)

    # Add contexts

    def _find_nist_unit(unit):
        """Converts pint datatypes to NIST datatypes
        """
        for value in unit.to_tuple()[1]:
            if value[1] < 1: continue
            if any(x in value[0] for x in _nist_units):
                return value[0]

        for value in unit.to_tuple()[1]:
            if (value[0] == "meter") and (value[1] == -1):
                return "inverse_meter"

        return None

    def build_transformer(right_unit, default):
        """Builds a transformer that attempts first to use the NIST values exactly and then falls back
        on to canonical Pint tech. The NIST values are not "exact" and will
        fail the triangle rule due to the inherent uncertainties of the values.

        Parameters
        ----------
        right_unit : str
            The NIST value to convert to
        default : str
            A fall back conversion rule to apply
        """
        def transformer(ureg, val):

            left_unit = _find_nist_unit(val)
            if left_unit is None:
                return val * ureg.parse_expression(default)
            else:
                return val * ureg.parse_expression("{}_to_{}".format(
                    left_unit, right_unit))

        return transformer

    # Allows hartree <-> frequency
    c1 = pint.Context("energy_frequency")
    c1.add_transformation("[energy]", "[frequency]",
                          build_transformer("hertz", "1 / plancks_constant"))
    c1.add_transformation("[frequency]", "[energy]",
                          build_transformer("hartree", "plancks_constant"))

    # Allows hartree <-> inverse_length
    c2 = pint.Context("energy_inverse_length")
    c2.add_transformation(
        "[energy]", "1 / [length]",
        build_transformer("inverse_meter", "hartree_to_inverse_meter"))
    c2.add_transformation(
        "1 / [length]", "[energy]",
        build_transformer("hartree", "inverse_meter_to_hartree"))

    # Allows hartree <-> mass
    c3 = pint.Context("energy_mass")
    c3.add_transformation("[energy]", "[mass]",
                          build_transformer("kilogram", "hartree_to_kilogram"))
    c3.add_transformation("[mass]", "[energy]",
                          build_transformer("hartree", "kilogram_to_hartree"))

    # Allows hartree <-> temperature
    c4 = pint.Context("energy_temperature")
    c4.add_transformation("[energy]", "[temperature]",
                          build_transformer("kelvin", "hartree_to_kelvin"))
    c4.add_transformation("[temperature]", "[energy]",
                          build_transformer("hartree", "kelvin_to_hartree"))

    # Allows energy <-> energy / mol
    c5 = pint.Context("substance_relation")
    c5.add_transformation("[energy]", "[energy] / [substance]",
                          lambda ureg, val: val * ureg.N_A)
    c5.add_transformation("[energy] / [substance]", "[energy]",
                          lambda ureg, val: val / ureg.N_A)

    # Add the context
    ureg.enable_contexts(c1, c2, c3, c4, c5)

    return ureg
Ejemplo n.º 18
0
LOG_DATEFMT = '%Y-%m-%d %H:%M:%S'
LOG_FORMAT = ('\n> %(asctime)s %(funcName)s:%(lineno)d\n> ' +
              '\n'.join(logging.BASIC_FORMAT.rsplit(':', 1)))
logging.basicConfig(datefmt=LOG_DATEFMT, format=LOG_FORMAT)
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)

# unit registry, quantity constructor and extra units registry definitions
UREG = pint.UnitRegistry()  # registry of units
Q_ = UREG.Quantity  # quantity constructor for ambiguous quantities like degC
UREG.define('fraction = []')  # define new dimensionless base unit for percents
UREG.define('percent = fraction / 100.0 = pct')  # can't use "%" only ascii
UREG.define('suns = []')  # dimensionless unit equivalent to 1000.0 [W/m/m]

# define PV solar context
_PV = pint.Context('pv')
# define transformation of suns to power flux and vice versa
E0 = 1000.0 * UREG.W / UREG.m / UREG.m  # 1 sun
_PV.add_transformation('[]', '[power] / [area]', lambda ureg, x: x * E0)
_PV.add_transformation('[power] / [area]', '[]', lambda ureg, x: x / E0)
UREG.add_context(_PV)


def _listify(x):
    """
    If x is not a list, make it a list.
    """
    return list(x) if isinstance(x, (list, tuple)) else [x]


class Registry(dict):
Ejemplo n.º 19
0
ureg.define("wavenumber = 1 / cm = cm^{-1} = wn")

# Aliases for backwards compatability
ureg.define("@alias s = s_t")
ureg.define("@alias min = m_t")
ureg.define("@alias hour = h_t")
ureg.define("@alias d = d_t")

ureg.define("@alias degC = deg_C")
ureg.define("@alias degF = deg_F")
ureg.define("@alias degR = deg_R")

ureg.define("@alias m = m_delay")

delay = pint.Context("delay", defaults={"n": 1, "num_pass": 2})
delay.add_transformation(
    "[length]",
    "[time]",
    lambda ureg, x, n=1, num_pass=2: num_pass * x / ureg.speed_of_light * n,
)
delay.add_transformation(
    "[time]",
    "[length]",
    lambda ureg, x, n=1, num_pass=2: x / num_pass * ureg.speed_of_light / n,
)
ureg.enable_contexts("spectroscopy", delay)

# --- functions -----------------------------------------------------------------------------------

Ejemplo n.º 20
0
__author__ = 'hartelt'

# Initialize Standard UnitRegistry:
ureg = pint.UnitRegistry()
Quantity = ureg.Quantity

# Custom units that we use frequently can be defined here:
# ureg.define('dog_year = 52 * day = dy')
ureg.define('pixel = []')
ureg.define('count = []')

# Custom prefixes we use frequently can be defined here:
# ureg.define('myprefix- = 30 = my-')

# Custom contexts we use frequently can be defined here:
c = pint.Context('light')
c.add_transformation('[length]', '[time]',
                     lambda ureg, x: x / ureg.speed_of_light)
c.add_transformation('[time]', '[length]',
                     lambda ureg, x: x * ureg.speed_of_light)
ureg.add_context(c)


def same_dimension(*args):
    """
	Checks if all of the given arguments are of the same (physical) dimension.

	:param args:

	:return: Boolean.
	"""
Ejemplo n.º 21
0
import pint
import pint_pandas

# setup the unit registry
ureg = pint.UnitRegistry()
Q_ = ureg.Quantity

pint.set_application_registry(ureg)
pint_pandas.PintType.ureg = ureg

# add wavenumbers to the pint spectroscopy context
_c = pint.Context('spectroscopy')
_c.add_transformation('[wavenumber]', '[frequency]',
                      lambda ureg, x: x * ureg.speed_of_light)
_c.add_transformation('[frequency]', '[wavenumber]',
                      lambda ureg, x: x / ureg.speed_of_light)
ureg.enable_contexts('spectroscopy')

c = ureg.speed_of_light
Hz = ureg.Hz
kHz = ureg.Hz * 1e3
MHz = ureg.Hz * 1e6
GHz = ureg.Hz * 1e9
THz = ureg.Hz * 1e12
G = ureg.G
Ejemplo n.º 22
0
    def _load_metric_conversions(self) -> None:
        """
        Load metric conversion contexts from file.

        This is done only when contexts are needed to avoid reading files on import.
        """
        import pandas as pd
        from os import path

        metric_conversions = pd.read_csv(
            path.join(path.dirname(path.abspath(__file__)), "metric_conversions.csv"),
            skiprows=1,  # skip source row
            header=0,
            index_col=0,
        ).iloc[
            1:, :
        ]  # drop out 'OpenSCM base unit' row

        def _get_transform_func(ureg_unit, conversion_factor, forward=True):
            if forward:

                def result_forward(ur, strt):
                    return strt * ur.carbon / ureg_unit * conversion_factor

                return result_forward

            def result_backward(ur, strt):
                return strt * ureg_unit / ur.carbon / conversion_factor

            return result_backward

        for col in metric_conversions:
            tc = pint.Context(col)
            for label, val in metric_conversions[col].iteritems():
                conv_val = (
                    val
                    * (self("CO2").to_base_units()).magnitude
                    / (self(label).to_base_units()).magnitude
                )
                base_unit = [
                    s
                    for s, _ in self._get_dimensionality(
                        self(label)  # pylint: disable=protected-access
                        .to_base_units()
                        ._units
                    ).items()
                ][0]

                unit_reg_unit = getattr(
                    self, base_unit.replace("[", "").replace("]", "")
                )
                tc.add_transformation(
                    base_unit, "[carbon]", _get_transform_func(unit_reg_unit, conv_val)
                )
                tc.add_transformation(
                    "[carbon]",
                    base_unit,
                    _get_transform_func(unit_reg_unit, conv_val, forward=False),
                )
                tc.add_transformation(
                    "[mass] * {} / [time]".format(base_unit),
                    "[mass] * [carbon] / [time]",
                    _get_transform_func(unit_reg_unit, conv_val),
                )
                tc.add_transformation(
                    "[mass] * [carbon] / [time]",
                    "[mass] * {} / [time]".format(base_unit),
                    _get_transform_func(unit_reg_unit, conv_val, forward=False),
                )
                tc.add_transformation(
                    "[mass] * {}".format(base_unit),
                    "[mass] * [carbon]",
                    _get_transform_func(unit_reg_unit, conv_val),
                )
                tc.add_transformation(
                    "[mass] * [carbon]",
                    "[mass] * {}".format(base_unit),
                    _get_transform_func(unit_reg_unit, conv_val, forward=False),
                )
                tc.add_transformation(
                    "{} / [time]".format(base_unit),
                    "[carbon] / [time]",
                    _get_transform_func(unit_reg_unit, conv_val),
                )
                tc.add_transformation(
                    "[carbon] / [time]",
                    "{} / [time]".format(base_unit),
                    _get_transform_func(unit_reg_unit, conv_val, forward=False),
                )

            self.add_context(tc)