示例#1
0
文件: scmdf.py 项目: znicholls/FAIR
def scmdf_to_emissions(scmdf, include_cfcs=True, startyear=1765, endyear=2100):
    """
    Opens an ScmDataFrame and extracts the data. Interpolates linearly
    between non-consecutive years in the SCEN file. Fills in chlorinated gases
    from a specified SSP scenario.

    Note this is a temporary fix for FaIR 1.6.

    Inputs:
        scmdf: ScmDataFrame

    Keywords:
        include_cfcs: bool
            MAGICC files do not come loaded with CFCs (indices 24-39).
            - if True, use the values from RCMIP for SSPs (all scenarios are
                the same).
            - Use False to ignore and create a 23-species emission file.
        startyear: First year of output file.
        endyear: Last year of output file.

    Returns:
        nt x 40 numpy emissions array (nt x 23 if ``include_cfcs`` is ``False``)
    """

    # We expect that aeneris and silicone are going to give us a nicely
    # formatted ScmDataFrame with all 23 species present and correct at
    # timesteps 2015, 2020 and ten-yearly to 2100.
    # We also implicitly assume that data up until 2014 will follow SSP
    # historical.
    # This adapter will not be tested on anything else!

    n_cols = 40
    nt = endyear - startyear + 1

    data_out = np.ones((nt, n_cols)) * np.nan
    data_out[:, 0] = np.arange(startyear, endyear + 1)

    if not has_scmdata:
        raise ImportError(
            "This is not going to work without having scmdata installed")

    if not isinstance(scmdf, ScmDataFrame):
        raise TypeError("scmdf must be an scmdata.ScmDataFrame instance")

    if not include_cfcs:
        raise NotImplementedError("include_cfcs equal to False")

    if scmdf[["model", "scenario"]].drop_duplicates().shape[0] != 1:
        raise AssertionError("Should only have one model-scenario pair")

    scen_start_year = 2015

    scmdf = ScmRun(scmdf.timeseries()).interpolate(
        [dt.datetime(y, 1, 1) for y in range(scen_start_year, endyear + 1)])

    years = scmdf["year"].values
    first_scenyear = years[0]
    first_scen_row = int(first_scenyear - startyear)

    # if correct units and interpolation were guaranteed we could do this for scenario too which is quicker
    hist_df = ssp245_world_emms_holder.values_fair_units.filter(
        year=range(startyear, 2015)).timeseries()

    future_ssp245_df = ssp245_world_emms_holder.values_fair_units.filter(
        year=range(2015, endyear + 1)).timeseries()

    for species in EMISSIONS_SPECIES_UNITS_CONTEXT["species"]:
        fair_col, _, _ = _get_fair_col_unit_context(species)

        hist_df_row = hist_df.index.get_level_values("variable").str.endswith(
            species)

        data_out[:first_scen_row,
                 fair_col] = hist_df[hist_df_row].values.squeeze()

        future_ssp245_df_row = future_ssp245_df.index.get_level_values(
            "variable").str.endswith(species)

        data_out[first_scen_row:, fair_col] = future_ssp245_df[
            future_ssp245_df_row].values.squeeze()

    for var_df in scmdf.groupby("variable"):
        variable = var_df.get_unique_meta("variable", no_duplicates=True)
        in_unit = var_df.get_unique_meta("unit", no_duplicates=True)
        fair_col, fair_unit, context = _get_fair_col_unit_context(variable)

        if in_unit != fair_unit:
            var_df_fair_unit = var_df.convert_unit(fair_unit, context=context)
        else:
            var_df_fair_unit = var_df

        data_out[first_scen_row:, fair_col] = var_df_fair_unit.values.squeeze()

    return data_out
def test_plumeplot_values(plumeplot_scmrun, quantiles_plumes, time_axis, linewidth):
    mock_ax = MagicMock()

    palette = {"a_model": "tab:blue", "a_model_2": "tab:red"}
    dashes = {"a_scenario": "-", "a_scenario_2": "--"}

    quantiles = [v for qv in quantiles_plumes for v in qv[0]]
    summary_stats = ScmRun(
        plumeplot_scmrun.quantiles_over("ensemble_member", quantiles=quantiles)
    )
    summary_stats.plumeplot(
        ax=mock_ax,
        quantiles_plumes=quantiles_plumes,
        pre_calculated=True,
        hue_var="climate_model",
        palette=palette,
        style_var="scenario",
        dashes=dashes,
        time_axis=time_axis,
        linewidth=linewidth,
    )

    xaxis = summary_stats.timeseries(time_axis=time_axis).columns.tolist()

    def _is_in_calls(call_to_check, call_args_list):
        pargs_to_check = call_to_check[1]
        kargs_to_check = call_to_check[2]
        in_call = False
        for ca in call_args_list:
            pargs = ca[0]
            pargs_match = True
            for i, p in enumerate(pargs):
                if isinstance(p, np.ndarray):
                    if not np.allclose(p, pargs_to_check[i]):
                        pargs_match = False
                else:
                    if not p == pargs_to_check[i]:
                        pargs_match = False

                if not pargs_match:
                    print(p)
                    print(pargs_to_check[i])

            kargs = ca[1]
            if pargs_match and kargs == kargs_to_check:
                in_call = True

        return in_call

    def _get_with_empty_check(idf_filtered):
        if idf_filtered.empty:
            raise ValueError("Empty")

        return idf_filtered.values.squeeze()

    def _make_fill_between_call(idf, cm, scen, quant_alpha):
        quantiles = quant_alpha[0]
        alpha = quant_alpha[1]

        return call(
            xaxis,
            _get_with_empty_check(
                idf.filter(climate_model=cm, scenario=scen, quantile=quantiles[0])
            ),
            _get_with_empty_check(
                idf.filter(climate_model=cm, scenario=scen, quantile=quantiles[1])
            ),
            alpha=alpha,
            color=palette[cm],
            label="{:.0f}th - {:.0f}th".format(quantiles[0] * 100, quantiles[1] * 100),
        )

    def _make_plot_call(idf, cm, scen, quant_alpha):
        quantiles = quant_alpha[0]
        alpha = quant_alpha[1]

        return call(
            xaxis,
            _get_with_empty_check(
                idf.filter(climate_model=cm, scenario=scen, quantile=quantiles[0])
            ),
            color=palette[cm],
            linestyle=dashes[scen],
            linewidth=linewidth,
            label="{:.0f}th".format(quantiles[0] * 100),
            alpha=alpha,
        )

    cm_scen_combos = summary_stats.meta[["climate_model", "scenario"]].drop_duplicates()
    cm_scen_combos = [v[1].values.tolist() for v in cm_scen_combos.iterrows()]

    plume_qa = [q for q in quantiles_plumes if len(q[0]) == 2]
    fill_between_calls = [
        _make_fill_between_call(summary_stats, cm, scen, qa)
        for cm, scen in cm_scen_combos
        for qa in plume_qa
    ]

    # debug by looking at mock_ax.fill_between.call_args_list
    assert all(
        [
            _is_in_calls(c, mock_ax.fill_between.call_args_list)
            for c in fill_between_calls
        ]
    )

    line_qa = [q for q in quantiles_plumes if len(q[0]) == 1]
    plot_calls = [
        _make_plot_call(summary_stats, cm, scen, qa)
        for cm, scen in cm_scen_combos
        for qa in line_qa
    ]

    # debug by looking at mock_ax.plot.call_args_list
    assert all([_is_in_calls(c, mock_ax.plot.call_args_list) for c in plot_calls])