Ejemplo n.º 1
0
def test_metric_conversion(metric_name, species, conversion):
    base_str_formats = ["{}", "kg {} / yr", "kg {}", "{} / yr"]
    for base_str_format in base_str_formats:
        base = unit_registry(base_str_format.format(species))
        dest = unit_registry(base_str_format.format("CO2"))
        with unit_registry.context(metric_name):
            np.testing.assert_allclose(base.to(dest).magnitude, conversion)
            np.testing.assert_allclose(dest.to(base).magnitude, 1 / conversion)
Ejemplo n.º 2
0
def test_context():
    CO2 = unit_registry("CO2")
    N2ON = unit_registry("N2ON")
    N2O = unit_registry("N2O")
    with unit_registry.context("AR4GWP100"):
        np.testing.assert_allclose(CO2.to("N2ON").magnitude, 28 / (44 * 298))
        np.testing.assert_allclose(N2ON.to("CO2").magnitude, 44 * 298 / 28)

        np.testing.assert_allclose(CO2.to("N2O").magnitude, 1 / 298)
        np.testing.assert_allclose(N2O.to("CO2").magnitude, 298)
Ejemplo n.º 3
0
def test_methane():
    CH4 = unit_registry("CH4")
    with pytest.raises(DimensionalityError):
        CH4.to("C")

    C = unit_registry("C")
    with unit_registry.context("CH4_conversions"):
        np.testing.assert_allclose(CH4.to("C").magnitude, 12 / 16)
        np.testing.assert_allclose(C.to("CH4").magnitude, 16 / 12)
        # this also becomes allowed, unfortunately...
        np.testing.assert_allclose(CH4.to("CO2").magnitude, 44 / 16)
Ejemplo n.º 4
0
def test_pint_array_comparison():
    a = np.array([0, 2]) * unit_registry("GtC")
    b = np.array([0, 2]) * unit_registry("MtC")

    # no error but does raise warning about stripping units
    with warnings.catch_warnings(record=True):
        np.testing.assert_allclose(a, b)

    # actually gives an error as we want
    with pytest.raises(AssertionError):
        assert_pint_equal(a, b)
Ejemplo n.º 5
0
def test_assert_same_unit(unit_1, unit_2, error, unit_1_type, unit_2_type):
    if unit_1_type == "pint_unit":
        unit_1 = unit_registry(unit_1)

    if unit_2_type == "pint_unit":
        unit_2 = unit_registry(unit_2)

    if error:
        with pytest.raises(AssertionError):
            assert_same_unit(unit_1, unit_2)
    else:
        assert_same_unit(unit_1, unit_2)
Ejemplo n.º 6
0
def test_nox():
    NOx = unit_registry("NOx")

    # can only convert to N with right context
    with pytest.raises(DimensionalityError):
        NOx.to("N")

    N = unit_registry("N")
    NO2 = unit_registry("NO2")
    with unit_registry.context("NOx_conversions"):
        np.testing.assert_allclose(NOx.to("N").magnitude, 14 / 46)
        np.testing.assert_allclose(N.to("NOx").magnitude, 46 / 14)
        np.testing.assert_allclose(NO2.to("NOx").magnitude, 1)
        np.testing.assert_allclose(NOx.to("NO2").magnitude, 1)
        with pytest.raises(DimensionalityError):
            NOx.to("N2O")
Ejemplo n.º 7
0
def convert_lambda_to_ecs(lambda_val, f2x=3.74 * unit_registry("W/m^2")):
    """
    Convert a lambda value to equilibrium climate sensitivity (ECS)

    Parameters
    ----------
    lambda_val : :obj:`pint.Quantity`
        Value of lambda to convert to ECS

    f2x : :obj:`pint.Quantity`
        Value of the forcing due to a doubling of atmospheric |CO2|
        to assume during the conversion

    Returns
    -------
    :obj:`pint.Quantity`
        ECS value

    Raises
    ------
    TypeError
        ``lambda_val`` or ``f2x`` is not a :obj:`pint.Quantity`.
    """
    if not isinstance(lambda_val, pint.Quantity):
        raise TypeError("lambda_val is not a pint.Quantity")

    if not isinstance(f2x, pint.Quantity):
        raise TypeError("f2x is not a pint.Quantity")

    return -f2x / lambda_val
Ejemplo n.º 8
0
def test_mixtures_constituents_no_gwp(metric_name, mixture, conversion):
    error_msg = re.escape(
        f"Cannot convert from '{mixture}' ([{mixture}]) to 'CO2' ([carbon])"
    )
    with pytest.raises(DimensionalityError, match=error_msg):
        gwp = (  # noqa: F841
            (1 * unit_registry(mixture)).to("CO2", metric_name).magnitude
        )
Ejemplo n.º 9
0
def test_split_invalid():
    with pytest.raises(ValueError, match="Dimensions don't contain a gas mixture."):
        unit_registry.split_gas_mixture(1 * unit_registry("CO2"))

    with pytest.raises(
        NotImplementedError,
        match="More than one gas mixture in dimensions is not supported.",
    ):
        unit_registry.split_gas_mixture(
            1 * unit_registry("CFC400") * unit_registry("HFC423a")
        )

    with pytest.raises(
        NotImplementedError,
        match="Mixture has dimensionality 2 != 1, which is not supported.",
    ):
        unit_registry.split_gas_mixture(1 * unit_registry("CFC400") ** 2)
Ejemplo n.º 10
0
def test_convert_lambda_to_ecs_with_units(ecs, f2x, test_units):
    ecs = ecs * unit_registry("delta_degC")
    f2x = f2x * unit_registry("W/m^2")
    default_f2x = 3.74 * unit_registry("W/m^2")

    call_kwargs = {}
    if f2x is None:
        f2x_expected = default_f2x
    else:
        f2x_expected = f2x
        call_kwargs["f2x"] = f2x

    in_lambda = -f2x_expected / ecs
    npt.assert_allclose(
        convert_lambda_to_ecs(in_lambda,
                              **call_kwargs).to(test_units).magnitude,
        ecs.to(test_units).magnitude,
    )
Ejemplo n.º 11
0
def test_ammonia():
    NH3 = unit_registry("NH3")

    # can only convert to N with right context
    with pytest.raises(DimensionalityError):
        NH3.to("N")

    # can not convert to CO2 even in GWP contexts
    with pytest.raises(DimensionalityError):
        with unit_registry.context("AR5GWP100"):
            NH3.to("CO2")

    N = unit_registry("N")
    with unit_registry.context("NH3_conversions"):
        np.testing.assert_allclose(NH3.to("N").magnitude, 14 / 17)
        np.testing.assert_allclose(N.to("NH3").magnitude, 17 / 14)
        # can not convert to CO2 even in NH3 context
        with pytest.raises(DimensionalityError):
            NH3.to("CO2")
Ejemplo n.º 12
0
def test_nitrogen():
    N = unit_registry("N")
    np.testing.assert_allclose(N.to("NO2").magnitude, 46 / 14)

    # can only convert to N with right context
    with pytest.raises(DimensionalityError):
        N.to("N2ON")

    with unit_registry.context("N2O_conversions"):
        np.testing.assert_allclose(N.to("N2ON").magnitude, 28 / 14)
        np.testing.assert_allclose(N.to("N2O").magnitude, 44 / 14)
Ejemplo n.º 13
0
def calc_dGSAT(var, ds, ds_out, scenario='scenario'):
    s_y = int(ds.isel(year=0)['year'].values)
    _erf_tmp = ds['ERF'].sel(variable=var).to_pandas()
    unit = "W/m^2"

    driver = ScmRun(
        data=_erf_tmp,
        index=s_y + np.arange(len(_erf_tmp)),
        columns={
            "unit": unit,
            "model": "custom",
            "scenario": scenario,
            "region": "World",
            "variable": "Effective Radiative Forcing",
        },
    )

    impulse_res = ImpulseResponseModel(
        d1=d1 * unit_registry("yr"),
        d2=d2 * unit_registry("yr"),
        q1=q1 * unit_registry("delta_degC / (W / m^2)"),
        q2=q2 * unit_registry("delta_degC / (W / m^2)"),
        efficacy=eff * unit_registry("dimensionless"),
    )
    dt_tmp = impulse_res.run_scenarios(driver)

    df_tmp = dt_tmp.filter(
        variable='Surface Temperature').timeseries()  #.lineplot()#['Surface']
    #_ds_dT[var] =df_tmp.transpose()

    #ds_out[var]  =
    df_tmp = df_tmp.reset_index().iloc[:, 12:].transpose().rename(
        {0: var}, axis=1)  #.to_xarray()
    year_index = pd.to_datetime(df_tmp.index).year
    df_tmp['year'] = year_index
    df_tmp = df_tmp.set_index('year')

    ds_out[var] = df_tmp.to_xarray()[var]

    return ds_out
Ejemplo n.º 14
0
def linear_regression(self):
    """
    Calculate linear regression of each timeseries

    Note
    ----
    Times in seconds since 1970-01-01 are used as the x-axis for the
    regressions. Such values can be accessed with
    ``self.time_points.values.astype("datetime64[s]").astype("int")``. This
    decision does not matter for the gradients, but is important for the
    intercept values.

    Returns
    -------
    list of dict[str : Any]
        List of dictionaries. Each dictionary contains the metadata for the
        timeseries plus the gradient (with key ``"gradient"``) and intercept (
        with key ``"intercept"``). The gradient and intercept are stored as
        :class:`pint.Quantity`.
    """
    _, _, time_unit, gradients, intercepts, meta = _calculate_linear_regression(
        self)

    out = []
    for row_meta, gradient, intercept in zip(
            meta.to_dict("records"),
            gradients,
            intercepts,
    ):
        unit = row_meta.pop("unit")

        row_meta["gradient"] = gradient * unit_registry("{} / {}".format(
            unit, time_unit))
        row_meta["intercept"] = intercept * unit_registry(unit)

        out.append(row_meta)

    return out
Ejemplo n.º 15
0
def test_scalar_multiply_pint_by_run():
    scalar = 1 * unit_registry("MtC / yr")
    start = get_multiple_ts(variable="Emissions|CO2",
                            unit="GtC / yr",
                            scenario=["scen_a", "scen_b"])

    exp_ts = perform_pint_op(start, scalar, "multiply_inverse")
    exp = ScmRun(exp_ts)

    exp["unit"] = "megatC * gigatC / a**2"

    res = scalar * start

    assert_scmdf_almost_equal(res,
                              exp,
                              allow_unordered=True,
                              check_ts_names=False)
Ejemplo n.º 16
0
def get_ecs_from_diagnosis_results(results_ecs_run):
    global_co2_concs = results_ecs_run.filter(
        variable='Atmospheric Concentrations|CO2', region='World')
    ecs_time, ecs_start_time = get_ecs_ecs_start_yr_from_CO2_concs(
        global_co2_concs)

    global_total_rf = results_ecs_run.filter(variable='Radiative Forcing',
                                             region='World')

    global_temp = results_ecs_run.filter(variable='Surface Temperature',
                                         region='World')

    ecs = float(global_temp.filter(time=ecs_time).values.squeeze())
    ecs = abs(ecs)
    unit = global_temp.get_unique_meta('unit', no_duplicates=True)
    ecs = ecs * unit_registry(unit)
    return ecs
Ejemplo n.º 17
0
def test_vector_ops_pint_wrong_unit(op, start_unit):
    vector = np.arange(3) * unit_registry("Mt CH4 / yr")
    start = get_multiple_ts(variable="Emissions|Gas",
                            unit=start_unit,
                            scenario=["scen_a", "scen_b"])

    error_msg = re.escape(
        "Cannot convert from 'gigatC / a' ([carbon] * [mass] / [time]) "
        "to 'CH4 * megametric_ton / a' ([mass] * [methane] / [time])")
    with pytest.raises(DimensionalityError, match=error_msg):
        if op == "add":
            start + vector

        elif op == "subtract":
            start - vector

        else:
            raise NotImplementedError(op)
Ejemplo n.º 18
0
def test_vector_ops_pint(op):
    vector = np.arange(3) * unit_registry("MtC / yr")
    start = get_multiple_ts(variable="Emissions|CO2",
                            unit="GtC / yr",
                            scenario=["scen_a", "scen_b"])

    exp_ts = perform_pint_op(start, vector, op)
    exp = ScmRun(exp_ts)

    if op in ["add", "subtract"]:
        exp["unit"] = "gigatC / a"

    elif op == "multiply":
        exp["unit"] = "gigatC * megatC / a ** 2"

    elif op == "divide":
        exp["unit"] = "gigatC / megatC"

    if op == "add":
        res = start + vector

    elif op == "subtract":
        res = start - vector

    elif op == "divide":
        res = start / vector

    elif op == "multiply":
        res = start * vector

    else:
        raise NotImplementedError(op)

    assert_scmdf_almost_equal(res,
                              exp,
                              allow_unordered=True,
                              check_ts_names=False)
Ejemplo n.º 19
0
def test_mixture_conversion(metric_name, mixture, conversion):
    gwp = (1 * unit_registry(mixture)).to("CO2", metric_name).magnitude
    # wikipedia values are rounded, therefore atol
    np.testing.assert_allclose(conversion, gwp, atol=0.5)
Ejemplo n.º 20
0
def delta_per_delta_time(self, out_var=None):
    """
    Calculate change in timeseries values for each timestep, divided by the size of the timestep

    The output is placed on the middle of each timestep and is one timestep
    shorter than the input.

    Parameters
    ----------
    out_var : str
        If provided, the variable column of the output is set equal to
        ``out_var``. Otherwise, the output variables are equal to the input
        variables, prefixed with "Delta " .

    Returns
    -------
    :class:`scmdata.ScmRun <scmdata.run.ScmRun>`
        :class:`scmdata.ScmRun <scmdata.run.ScmRun>` containing the changes in values of ``self``,
        normalised by the change in time

    Warns
    -----
    UserWarning
        The data contains nans. If this happens, the output data will also
        contain nans.
    """
    time_unit = "s"
    times_numpy = self.time_points.values.astype(
        "datetime64[{}]".format(time_unit))
    times_deltas_numpy = times_numpy[1:] - times_numpy[:-1]
    times_in_s = times_numpy.astype("int")
    time_deltas_in_s = times_in_s[1:] - times_in_s[:-1]

    ts = self.timeseries()
    if ts.isnull().sum().sum() > 0:
        warnings.warn(
            "You are calculating deltas of data which contains nans so your "
            "result will also contain nans. Perhaps you want to remove the "
            "nans before calculating the deltas using a combination of "
            ":meth:`filter` and :meth:`interpolate`?")

    out = ts.diff(periods=1, axis="columns")
    if not out.iloc[:, 0].isnull().all():  # pragma: no cover
        raise AssertionError(
            "Did pandas change their API? The first timestep is not all nan.")

    out = out.iloc[:, 1:] / time_deltas_in_s

    new_times = times_numpy[:-1] + times_deltas_numpy / 2
    out.columns = TimePoints(new_times).to_index()

    out = type(self)(out)
    out /= unit_registry(time_unit)

    try:
        out_unit = out.get_unique_meta("unit",
                                       no_duplicates=True).replace(" ", "")
        out_unit = str(unit_registry(out_unit).to_reduced_units().units)
        out = out.convert_unit(out_unit)

    except ValueError:
        # more than one unit, don't try to clean up
        pass

    if out_var is None:
        out["variable"] = "Delta " + out["variable"]
    else:
        out["variable"] = out_var

    return out
Ejemplo n.º 21
0
def integrate(self, out_var=None):
    """
    Integrate with respect to time

    Parameters
    ----------
    out_var : str
        If provided, the variable column of the output is set equal to
        ``out_var``. Otherwise, the output variables are equal to the input
        variables, prefixed with "Cumulative " .

    Returns
    -------
    :class:`scmdata.ScmRun <scmdata.run.ScmRun>`
        :class:`scmdata.ScmRun <scmdata.run.ScmRun>` containing the integral of ``self`` with respect
        to time

    Warns
    -----
    UserWarning
        The data being integrated contains nans. If this happens, the output
        data will also contain nans.
    """
    if not has_scipy:
        raise ImportError("scipy is not installed. Run 'pip install scipy'")

    time_unit = "s"
    times_in_s = self.time_points.values.astype(
        "datetime64[{}]".format(time_unit)).astype("int")

    ts = self.timeseries()
    if ts.isnull().sum().sum() > 0:
        warnings.warn(
            "You are integrating data which contains nans so your result will "
            "also contain nans. Perhaps you want to remove the nans before "
            "performing the integration using a combination of :meth:`filter` "
            "and :meth:`interpolate`?")
    # If required, we can remove the hard-coding of initial, it just requires
    # some thinking about unit handling
    _initial = 0.0
    out = pd.DataFrame(
        scipy.integrate.cumtrapz(y=ts, x=times_in_s, axis=1, initial=_initial))
    out.index = ts.index
    out.columns = ts.columns

    out = type(self)(out)
    out *= unit_registry(time_unit)

    try:
        out_unit = out.get_unique_meta("unit",
                                       no_duplicates=True).replace(" ", "")
        out_unit = str(unit_registry(out_unit).to_reduced_units().units)
        out = out.convert_unit(out_unit)

    except ValueError:
        # more than one unit, don't try to clean up
        pass

    if out_var is None:
        out["variable"] = "Cumulative " + out["variable"]
    else:
        out["variable"] = out_var

    return out
Ejemplo n.º 22
0
def test_short_definition():
    tC = unit_registry("tC")
    np.testing.assert_allclose(tC.to("tCO2").magnitude, 44 / 12)
    np.testing.assert_allclose(tC.to("gC").magnitude, 10 ** 6)
Ejemplo n.º 23
0
def test_ppt():
    ppt = unit_registry("ppt")
    np.testing.assert_allclose(ppt.to("ppb").magnitude, 1 / 1000)
Ejemplo n.º 24
0
def test_ppm():
    ppm = unit_registry("ppm")
    np.testing.assert_allclose(ppm.to("ppb").magnitude, 1000)
Ejemplo n.º 25
0
def test_alias():
    CO2 = unit_registry("carbon_dioxide")
    np.testing.assert_allclose(CO2.to("C").magnitude, 12 / 44)
Ejemplo n.º 26
0
def test_a():
    a = unit_registry("a")
    np.testing.assert_allclose(a.to("day").magnitude, 365.25, rtol=1e-4)
Ejemplo n.º 27
0
def test_context_compound_unit():
    CO2 = 1 * unit_registry("kg CO2 / yr")
    N2ON = 1 * unit_registry("kg N2ON / yr")
    with unit_registry.context("AR4GWP100"):
        np.testing.assert_allclose(CO2.to("kg N2ON / yr").magnitude, 28 / (44 * 298))
        np.testing.assert_allclose(N2ON.to("kg CO2 / yr").magnitude, 44 * 298 / 28)
Ejemplo n.º 28
0
def test_context_dimensionality_error():
    CO2 = unit_registry("CO2")
    with pytest.raises(DimensionalityError):
        CO2.to("N2O")
Ejemplo n.º 29
0
def test_mixture_constituent_sum_one():
    for mixture in MIXTURES:
        constituents = unit_registry.split_gas_mixture(1 * unit_registry(mixture))
        np.testing.assert_allclose(sum((c.magnitude for c in constituents)), 1)
Ejemplo n.º 30
0
def test_base_unit():
    assert unit_registry("carbon") == unit_registry("C")