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)
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()
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()
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)
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
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
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")
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)
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)
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))
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),
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
# # 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')
'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)
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,
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
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):
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 -----------------------------------------------------------------------------------
__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. """
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
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)