def test_convert_gwp(units, metric, species_in, species_out, expected_value): # Bare masses can be converted qty = registry.Quantity(1.0, units.format("")) expected = registry(f"{expected_value} {units}") observed = convert_gwp(metric, qty, species_in, species_out) assert observed.units == expected.units np.testing.assert_almost_equal(observed.magnitude, expected.magnitude) # '[mass] [speciesname] (/ [time])' can be converted; the input species is extracted # from the *qty* argument qty = "1.0 " + units.format(species_in) expected = registry(f"{expected_value} {units}") observed = convert_gwp(metric, qty, species_out) assert observed.units == expected.units np.testing.assert_almost_equal(observed.magnitude, expected.magnitude) # Tuple of (vector magnitude, unit expression) can be converted where the # the unit expression contains the input species name arr = np.array([1.0, 2.5, 0.1]) qty = (arr, units.format(species_in)) expected = arr * expected_value # Conversion works result = convert_gwp(metric, qty, species_out) # Magnitudes are as expected assert_array_almost_equal(result.magnitude, expected)
def convert_units(df, units_from, units_to, cols=("Value", "Unit")): """Convert units of *df*. Uses a vector :class:`registry.Quantity` to convert an entire column of values efficiently. Parameters ---------- units_from : str or pint.Unit Units to convert from. units_to : str or pint.Unit Units to convert to. cols : 2-tuple of str Names of the columns in *df* containing the magnitude and unit, respectively. Returns ------- pandas.DataFrame """ # Create a vector pint.Quantity; convert units qty = registry.Quantity(df[cols[0]].values, units_from).to(units_to) # Assign magnitude and unit columns in output DataFrame return df.assign(**{cols[0]: qty.magnitude, cols[1]: f"{qty.units:~}"})
def test_format_mass(units_in, species_str, spec, output): # Quantity object can be formatted qty = registry.Quantity(3.5, units_in) assert format_mass(qty, species_str, spec) == output # Unit object can be formatted qty = registry.Unit(units_in) assert format_mass(qty, species_str, spec) == output
def _to_quantity(data): """Convert the values of an indexed pd.Series into pint.Quantity instances""" return pd.Series( [ registry.Quantity(v, u) for v, u in zip(data.values, data.index.get_level_values("unit")) ], index=data.reset_index("unit", drop=True).index, name=data.name, )
def test_convert_gwp_carbon(context): # CO2 can be converted to C qty = (44.0 / 12, "tonne CO2") result = convert_gwp(context, qty, "C") assert result.units == registry("tonne") assert_almost_equal(result.magnitude, 1.0) # C can be converted to CO2 qty = (1, "tonne C") expected = registry.Quantity(44.0 / 12, "tonne") assert convert_gwp(context, qty, "CO2e") == expected
def test_convert_gwp_carbon(): # CO2 can be converted to C qty = (44. / 12, 'tonne CO2') result = convert_gwp('AR5GWP100', qty, 'C') assert result.units == registry('tonne') assert_almost_equal(result.magnitude, 1.0) # C can be converted to CO2 qty = (1, 'tonne C') expected = registry.Quantity(44. / 12, 'tonne') assert convert_gwp('AR5GWP100', qty, 'CO2e') == expected
def convert_units( s: pd.Series, unit_info: Mapping[str, Tuple[float, str, Optional[str]]], store="magnitude", ) -> pd.Series: """Convert units of `s`, for use with :meth:`~pandas.DataFrame.apply`. ``s.name`` is used to retrieve a tuple of (`factor`, `input_unit`, `output_unit`) from `unit_info`. The (:class:`float`) values of `s` are converted to :class:`pint.Quantity` with the `input_unit` and factor; then cast to `output_unit`, if provided. Parameters ---------- s : pandas.Series unit_info : dict (str -> tuple) Mapping from quantity name (matched to ``s.name``) to 3-tuples of (`factor`, `input_unit`, `output_unit`). `output_unit` may be :obj:`None`. For example, see :data:`.ikarus.UNITS`. store : "magnitude" or "quantity" If "magnitude", the values of the returned series are the magnitudes of the results, with no output units. If "quantity", the values are scalar :class:`~pint.Quantity` objects. Returns ------- pandas.Series Same shape, index, and values as `s`, with output units. """ if store not in "magnitude quantity": raise ValueError(f"store={repr(store)}") # Retrieve the information from `unit_info` factor, unit_in, unit_out = unit_info[s.name] # Default: `unit_out` is the same as `unit_in` unit_out = unit_out or unit_in # - Convert the values to a pint.Quantity(array) with the input units # - Convert to output units # - According to `store`, either extract just the magnitude, or store scalar # pint.Quantity objects. # - Reassemble into a series with index matching `s` result = registry.Quantity(factor * s.values, unit_in).to(unit_out) return series_of_pint_quantity( result.magnitude if store == "magnitude" else result.tolist(), index=s.index, dtype=object, name=s.name, )
def convert_units(df: pd.DataFrame, units_from, units_to, cols: Optional[Sequence[str]] = None) -> pd.DataFrame: """Convert units of `df`. Uses a vector :class:`registry.Quantity` to convert an entire column of values efficiently. Parameters ---------- units_from : str or pint.Unit Units to convert from. units_to : str or pint.Unit Units to convert to. cols : 2-tuple of str Names of the columns in `df` containing the magnitude and unit, respectively. Default for the mangnitude is whichever column of `df` matches “value”, case- insensitive; if multiple columns have different cases of this name, the first is used. Returns ------- pandas.DataFrame """ # Default values cols = cols or [ next(filter(lambda name: name.lower() == "value", df.columns)), "UNIT", ] # Create a vector pint.Quantity; convert units qty = registry.Quantity(df[cols[0]].values, units_from).to(units_to) # Assign magnitude and unit columns in output DataFrame return df.assign(**{cols[0]: qty.magnitude, cols[1]: f"{qty.units:~}"})
"""Calling an operation with args that don't return an IamDataFrame raises""" match = "Value returned by `add` cannot be cast to an IamDataFrame: 5" with pytest.raises(ValueError, match=match): test_df_year.add(2, 3, "foo") @pytest.mark.parametrize( "arg, df_func, fillna, ignore_units", ( ("Primary Energy|Coal", df_ops_variable, None, False), ("Primary Energy|Coal", df_ops_variable_default, { "c": 7, "b": 5 }, "foo"), ("Primary Energy|Coal", df_ops_variable_default, 5, "foo"), (registry.Quantity(2, "EJ/yr"), df_ops_variable_number, None, False), (2, df_ops_variable_number, None, "foo"), ), ) @pytest.mark.parametrize("append", (False, True)) def test_add_variable(test_df_year, arg, df_func, fillna, ignore_units, append): """Verify that in-dataframe addition works on the default `variable` axis""" # change one unit to make ignore-units strictly necessary if ignore_units: test_df_year.rename( variable={"Primary Energy": "Primary Energy"}, unit={"EJ/yr": "custom_unit"}, inplace=True, )