def test_plumeplot_non_unique_lines(plumeplot_scmrun): quantile_over = "climate_model" quantile = 0.05 scenario = "a_scenario" variable = "Surface Air Temperature Change" summary_stats = ScmRun( plumeplot_scmrun.quantiles_over(quantile_over, quantiles=(0.05, 0.5, 0.95)) ) error_msg = re.escape( "More than one timeseries for " "quantile: {}, " "scenario: {}, " "variable: {}.\n" "Please process your data to create unique quantile timeseries " "before calling :meth:`plumeplot`.\n" "Found: {}".format( quantile, scenario, variable, summary_stats.filter( quantile=quantile, scenario=scenario, variable=variable ), ) ) with pytest.raises(ValueError, match=error_msg): summary_stats.plumeplot(pre_calculated=True)
def test_plumeplot_pre_calculated(plumeplot_scmrun, quantiles_plumes): 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( quantiles_plumes=quantiles_plumes, pre_calculated=True, )
def test_run_scenarios_multiple(self): ts1_erf = np.linspace(0, 4, 101) ts2_erf = np.sin(np.linspace(0, 4, 101)) inp = ScmRun( data=np.vstack([ts1_erf, ts2_erf]).T, index=np.linspace(1750, 1850, 101).astype(int), columns={ "scenario": ["test_scenario_1", "test_scenario_2"], "model": "unspecified", "climate_model": "junk input", "variable": "Effective Radiative Forcing", "unit": "W/m^2", "region": "World", }, ) model = self.tmodel() res = model.run_scenarios(inp) for scenario_ts in inp.groupby("scenario"): scenario = scenario_ts.get_unique_meta("scenario", no_duplicates=True) model.set_drivers( scenario_ts.values.squeeze() * ur(inp.get_unique_meta("unit", no_duplicates=True))) model.reset() model.run() res_scen = res.filter(scenario=scenario) npt.assert_allclose( res_scen.filter( variable="Surface Temperature|Upper").values.squeeze(), model._temp_upper_mag, ) assert (res.filter( variable="Surface Temperature|Upper").get_unique_meta( "unit", no_duplicates=True) == "delta_degC") npt.assert_allclose( res_scen.filter( variable="Surface Temperature|Lower").values.squeeze(), model._temp_lower_mag, ) assert (res.filter( variable="Surface Temperature|Lower").get_unique_meta( "unit", no_duplicates=True) == "delta_degC") npt.assert_allclose( res_scen.filter(variable="Heat Uptake").values.squeeze(), model._rndt_mag, ) assert (res.filter(variable="Heat Uptake").get_unique_meta( "unit", no_duplicates=True) == "W/m^2")
def test_convert_to_scen_units(): var_start_units_scen_units_conv_factor = ( ("Emissions|CO2", "Mt CO2/yr", "Gt C/yr", 12 / 44000, None), ("Emissions|CH4", "Mt C/yr", "Mt CH4/yr", (12 + 4) / 12, "CH4_conversions"), ( "Emissions|N2O", "kt N2O/yr", "Mt N2ON/yr", (2 * 14) / (1000 * (2 * 14 + 16)), None, ), ("Emissions|SOx", "Mt SO2/yr", "Mt S/yr", 32 / (32 + 2 * 16), None), ("Emissions|CO", "Mt CO/yr", "Mt CO/yr", 1, None), ("Emissions|NMVOC", "Mt VOC/yr", "Mt NMVOC/yr", 1, None), ( "Emissions|NOx", "Mt NOx/yr", "Mt N/yr", 14 / (14 + 2 * 16), "NOx_conversions", ), ("Emissions|BC", "Mt BC/yr", "Mt BC/yr", 1, None), ("Emissions|OC", "Mt OC/yr", "Mt OC/yr", 1, None), ("Emissions|NH3", "Mt NH3/yr", "Mt N/yr", 14 / (14 + 3), None), ("Emissions|CF4", "Mt CF4/yr", "kt CF4/yr", 1000, None), ("Emissions|HFC4310mee", "kt HFC4310mee/yr", "kt HFC4310/yr", 1, None), ("Emissions|SF6", "t SF6/yr", "kt SF6/yr", 1 / 1000, None), ) start = ScmRun( data=np.ones((1, len(var_start_units_scen_units_conv_factor))), index=np.array([2015]), columns={ "model": ["unspecified"], "scenario": ["test"], "region": ["World"], "variable": [v[0] for v in var_start_units_scen_units_conv_factor], "unit": [v[1] for v in var_start_units_scen_units_conv_factor], }, ) res = start.copy() for variable, _, target_unit, _, context in var_start_units_scen_units_conv_factor: res = res.convert_unit(target_unit, context=context, variable=variable) for ( variable, _, target_unit, conv_factor, _, ) in var_start_units_scen_units_conv_factor: np.testing.assert_allclose(res.filter(variable=variable).timeseries(), conv_factor, rtol=1e-15)
def values(self): """Emissions values from historical joint with ssp245""" if not self._loaded: tmp = ScmRun( os.path.join( os.path.dirname(__file__), "rcmip-emissions-annual-means-v5-1-0-historical-ssp245.csv", ), lowercase_cols=True, ) self._values = tmp.interpolate( [dt.datetime(y, 1, 1) for y in tmp["year"]]) self._loaded = True return self._values
def _single_fair_iteration(cfg): # pylint: disable=R0914 scenario = cfg.pop("scenario") model = cfg.pop("model") run_id = cfg.pop("run_id") factors = {} factors["gmst"] = cfg.pop("gmst_factor") factors["ohu"] = cfg.pop("ohu_factor") startyear = cfg.pop("startyear") output_vars = cfg.pop("output_vars") data, unit, nt = _process_output(fair_scm(**cfg), output_vars, factors) data_scmrun = [] variables = [] units = [] for key, variable in data.items(): variables.append(key) data_scmrun.append(variable) units.append(unit[key]) tempres = ScmRun( np.vstack(data_scmrun).T, index=np.arange(startyear, startyear + nt), columns={ "scenario": scenario, "model": model, "region": "World", "variable": variables, "unit": units, "run_id": run_id, }, ) return tempres
def test_scenario_ssp370_world(test_data_dir): scenario = ScmRun( os.path.join(test_data_dir, "rcmip-emissions-annual-means-v5-1-0-ssp370-world.csv"), lowercase_cols=True, ) return scenario
def _check_heat_content_heat_uptake_consistency(res): hc_deltas = ScmRun( res.filter(variable="Heat Content", region="World") .timeseries(time_axis="year") .diff(axis="columns") ) hc_deltas["unit"] = "{} / yr".format(hc_deltas.get_unique_meta("unit", True)) ratio = hc_deltas.divide( res.filter(variable="Heat Uptake", region="World"), op_cols={"variable": "Heat Content / Heat Uptake"}, ) earth_surface_area = 5.100536e14 npt.assert_allclose( earth_surface_area, ratio.convert_unit("m^2").timeseries(drop_all_nan_times=True), )
def test_run_to_nc_dimensions_cover_all_metadata(): start = ScmRun( np.arange(6).reshape(3, 2), index=[2010, 2020, 2030], columns={ "variable": "Surface Temperature", "unit": "K", "model": ["model_a", "model_b"], "scenario": "scen_a", "region": "World", }, ) with tempfile.TemporaryDirectory() as tempdir: out_fname = join(tempdir, "out.nc") start.to_nc(out_fname, dimensions=("region", "model", "scenario")) loaded = ScmRun.from_nc(out_fname) assert_scmdf_almost_equal(start, loaded, check_ts_names=False)
def run_fair(cfgs, output_vars): # pylint: disable=R0914 """ Run FaIR Parameters ---------- cfgs : list[dict] List of configurations with which to run FaIR output_vars : list[str] Variables to output Returns ------- :obj:`ScmRun` :obj:`ScmRun` instance with all results. """ res = [] for cfg in cfgs: scenario = cfg.pop("scenario") model = cfg.pop("model") run_id = cfg.pop("run_id") factors = {} factors["gmst"] = cfg.pop("gmst_factor") factors["ohu"] = cfg.pop("ohu_factor") data, unit, nt = _process_output(fair_scm(**cfg), output_vars, factors) data_scmrun = [] variables = [] units = [] for key, variable in data.items(): variables.append(key) data_scmrun.append(variable) units.append(unit[key]) tempres = ScmRun( np.vstack(data_scmrun).T, index=np.arange(1765, 1765 + nt), columns={ "scenario": scenario, "model": model, "region": "World", "variable": variables, "unit": units, "run_id": run_id, }, ) res.append(tempres) res = run_append(res) return res
def _run(self, scenarios, cfgs, output_variables, output_config): if output_config is not None: raise NotImplementedError( "`output_config` not implemented for FaIR") fair_df = ScmRun(scenarios.timeseries()) full_cfgs = self._make_full_cfgs(fair_df, cfgs) res = run_fair(full_cfgs, output_variables) res["climate_model"] = "FaIRv{}".format(self.get_version()) return res
def test_run_to_nc_extra_instead_of_dimension_run_id(scm_run): with tempfile.TemporaryDirectory() as tempdir: out_fname = join(tempdir, "out.nc") scm_run["run_id"] = [1, 2, 1] run_to_nc(scm_run, out_fname, dimensions=("scenario", ), extras=("run_id", )) loaded = ScmRun.from_nc(out_fname) assert_scmdf_almost_equal(scm_run, loaded, check_ts_names=False)
def run_over_cfgs(self, cfgs, output_variables): """ Run over each configuration parameter set write parameterfiles, run, read results and make an ScmRun with results """ runs = [] for i, pamset in enumerate(cfgs): self.pamfilewriter.write_parameterfile( pamset, os.path.join(self.rundir, re.sub("[^a-zA-Z0-9_-]", "", self.scen)), ) call = "{executable} {pamfile}".format( executable=os.path.join(self.rundir, "scm_vCH4fb"), pamfile=os.path.join( self.rundir, re.sub("[^a-zA-Z0-9_-]", "", self.scen), "inputfiles", "pam_current.scm", ), ) LOGGER.debug("Call, %s", call) subprocess.check_call( call, cwd=self.rundir, shell=True, # nosec # have to use subprocess ) for variable in output_variables: ( years, timeseries, unit, ) = self.resultsreader.read_variable_timeseries( self.scen, variable, self.sfilewriter ) if years.empty: # pragma: no cover continue # pragma: no cover runs.append( ScmRun( pd.Series(timeseries, index=years), columns={ "climate_model": "CICERO-SCM", "model": self.model, "run_id": pamset.get("Index", i), "scenario": self.scen, "region": ["World"], "variable": [variable], "unit": [unit], }, ) ) return run_append(runs)
def load(self, key): """ Parameters ---------- key: str Returns ------- :class:`scmdata.ScmRun` """ return ScmRun.from_nc(key)
def test_groupby_integer_metadata(): def increment_ensemble_member(scmrun): scmrun["ensemble_member"] += 10 return scmrun start = ScmRun( data=[[1, 2], [0, 1]], index=[2010, 2020], columns={ "model": "model", "scenario": "scenario", "variable": "variable", "unit": "unit", "region": "region", "ensemble_member": [0, 1], }, ) res = start.groupby(["variable", "region", "scenario", "ensemble_member"]).map(increment_ensemble_member) assert (res["ensemble_member"] == start["ensemble_member"] + 10).all()
def start_scmrun(): return ScmRun( np.arange(6).reshape(3, 2), [2010, 2020, 2030], columns={ "scenario": "scenario", "model": "model", "climate_model": ["cmodel_a", "cmodel_b"], "variable": "variable", "unit": "unit", "region": "region", "ensemble_member": 0, }, )
def values(self): if not self._loaded: self._values = (ScmRun(os.path.join( os.path.dirname(__file__), '../SSPs/data/rcmip-emissions-annual-means-4-0-0-ssp-only.csv' ), lowercase_cols=True).filter( scenario="ssp245", region="World", variable="Emissions*")) self._values = self._values.interpolate( [dt.datetime(y, 1, 1) for y in self._values["year"]]) self._loaded = True return self._values
def test_run_to_nc_loop_tricky_variable_name(scm_run, start_variable): # tests that the mapping between variable and units works even with # tricky variable names that get renamed in various was before serialising to # disk assert "Primary Energy|Coal" in scm_run.get_unique_meta("variable") scm_run["variable"] = scm_run["variable"].apply( lambda x: x.replace("Primary Energy|Coal", start_variable)) scm_run["unit"] = scm_run["variable"].apply( lambda x: "EJ/yr" if x != start_variable else "MJ / yr") with tempfile.TemporaryDirectory() as tempdir: out_fname = join(tempdir, "out.nc") scm_run.to_nc(out_fname, dimensions=("scenario", )) loaded = ScmRun.from_nc(out_fname) assert_scmdf_almost_equal(scm_run, loaded, check_ts_names=False)
def _run(self, scenarios, cfgs, output_variables, output_config): # TODO: add use of historical data properly # pylint:disable=fixme LOGGER.warning("Historical data has not been checked") magicc_df = scenarios.timeseries().reset_index() magicc_df["variable"] = magicc_df["variable"].apply( lambda x: x.replace("Sulfur", "SOx") .replace("HFC4310mee", "HFC4310") .replace("VOC", "NMVOC") ) magicc_scmdf = pymagicc.io.MAGICCData(magicc_df) emms_units = pymagicc.definitions.MAGICC7_EMISSIONS_UNITS emms_units["openscm_variable"] = emms_units["magicc_variable"].apply( lambda x: pymagicc.definitions.convert_magicc7_to_openscm_variables( "{}_EMIS".format(x) ) ) emms_units = emms_units.set_index("openscm_variable") for variable in magicc_scmdf["variable"].unique(): magicc_unit = emms_units.loc[variable, "emissions_unit"] magicc_scmdf = magicc_scmdf.convert_unit( magicc_unit, variable=variable, context="NOx_conversions" ) full_cfgs = self._write_scen_files_and_make_full_cfgs(magicc_scmdf, cfgs) pymagicc_vars = [ _VARIABLE_MAP[v] if v in _VARIABLE_MAP else v for v in output_variables ] res = run_magicc_parallel(full_cfgs, pymagicc_vars, output_config) LOGGER.debug("Dropping todo metadata") res = res.drop_meta("todo") res["climate_model"] = "MAGICC{}".format(self.get_version()) res = self._fix_pint_incompatible_units(res) LOGGER.debug("Mapping variables to OpenSCM conventions") inverse_map = {v: k for k, v in _VARIABLE_MAP.items()} res["variable"] = res["variable"].apply( lambda x: inverse_map[x] if x in inverse_map else x ) res = ScmRun(res) return res
def save(self, sr): """ Save a ScmRun to the database The dataset should not contain any duplicate metadata for the database levels Parameters ---------- sr : :class:`scmdata.ScmRun` Data to save Raises ------ ValueError If duplicate metadata are present for the requested database levels KeyError If metadata for the requested database levels are not found Returns ------- str Key where the data is saved """ key = self.get_key(sr) ensure_dir_exists(key) if os.path.exists(key): existing_run = ScmRun.from_nc(key) sr = run_append([existing_run, sr]) # Check for required extra dimensions dimensions = self.kwargs.get("dimensions", None) if not dimensions: nunique_meta_vals = sr.meta.nunique() dimensions = nunique_meta_vals[ nunique_meta_vals > 1].index.tolist() sr.to_nc(key, dimensions=dimensions) return key
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
class TwoLayerVariantIntegrationTester(ModelIntegrationTester): tinp = ScmRun( data=np.linspace(0, 4, 101), index=np.linspace(1750, 1850, 101).astype(int), columns={ "scenario": "test_scenario", "model": "unspecified", "climate_model": "junk input", "variable": "Effective Radiative Forcing", "unit": "W/m^2", "region": "World", }, ) def test_run_unit_handling(self, check_scmruns_allclose): inp = self.tinp.copy() model = self.tmodel() res = model.run_scenarios(inp) # scmdata bug # inp.convert_unit("kW/m^2") blows up inp_other_unit = inp.copy() inp_other_unit *= 10**-3 inp_other_unit["unit"] = "kW/m^2" res_other_unit = model.run_scenarios(inp_other_unit) assert res.get_unique_meta("climate_model", no_duplicates=True) == model._name check_scmruns_allclose( res.filter(variable="Effective Radiative Forcing", keep=False), res_other_unit.filter(variable="Effective Radiative Forcing", keep=False), ) def test_run_wrong_units(self): inp = self.tinp.copy() inp["unit"] = "W" model = self.tmodel() with pytest.raises(UnitError): model.run_scenarios(inp) def test_run_wrong_region(self): inp = self.tinp.copy() inp["region"] = "World|R5LAM" model = self.tmodel() error_msg = ( "No World data available for driver_var `Effective Radiative Forcing`" ) with pytest.raises(ValueError, match=error_msg): model.run_scenarios(inp) def test_run_wrong_driver(self): inp = self.tinp.copy() model = self.tmodel() error_msg = ( "No World data available for driver_var `Effective Radiative Forcing|CO2`" ) with pytest.raises(ValueError, match=error_msg): model.run_scenarios(inp, driver_var="Effective Radiative Forcing|CO2")
def _make_full_cfgs(self, scenarios, cfgs): # pylint: disable=R0201,R0914 full_cfgs = [] run_id_block = 0 startyear = _check_startyear(cfgs) for (scenario, model), smdf in progress( scenarios.timeseries().groupby(["scenario", "model"]), desc="Creating FaIR emissions inputs", ): smdf_in = ScmRun(smdf) scen_startyear = smdf_in.time_points.years()[0] endyear = smdf_in.time_points.years()[-1] if startyear < 1750: raise ValueError( "startyear must be 1750 or later (%d specified)" % startyear) if endyear > 2500: raise ValueError( "endyear must be 2500 or earlier (%d implied by scenario data)" % endyear) emissions = scmdf_to_emissions( smdf_in, startyear=startyear, scen_startyear=scen_startyear, endyear=endyear, ) nt = emissions.shape[0] natural_components = _get_natural_emissions_and_forcing( startyear, nt) ch4_n2o = natural_components["ch4_n2o"] solar_forcing = natural_components["solar_forcing"] volcanic_forcing = natural_components["volcanic_forcing"] scenario_cfg = [{ "scenario": scenario, "model": model, "run_id": run_id_block + i, "emissions": emissions, "natural": ch4_n2o, "F_volcanic": volcanic_forcing, "F_solar": solar_forcing, "efficacy": np.ones(45), "diagnostics": "AR6", "gir_carbon_cycle": True, "temperature_function": "Geoffroy", "aerosol_forcing": "aerocom+ghan2", "fixPre1850RCP": False, "b_tro3": np.array([ 1.77871043e-04, 5.80173377e-05, 1.94458719e-04, 2.09151270e-03 ]), "tropO3_forcing": "cmip6", "aCO2land": 0.0006394631886297174, "b_aero": np.array([-0.00503, 0.0, 0.0, 0.0, 0.0385, -0.0104, 0.0]), "ghan_params": np.array([1.232, 73.9, 63.0]), "gmst_factor": 1 / 1.04, "ohu_factor": 0.92, "startyear": startyear, **cfg, } for i, cfg in enumerate(cfgs)] run_id_block += len(scenario_cfg) full_cfgs += scenario_cfg return full_cfgs
def test_run( self, test_scenarios, test_data_dir, update_expected_values, shuffle_column_order, ): expected_output_file = os.path.join( test_data_dir, "expected-integration-output", "expected_ciceroscm_test_run_output.json", ) if shuffle_column_order: tmp = test_scenarios.data cols = tmp.columns.tolist() tmp = tmp[cols[1:] + cols[:1]] test_scenarios = ScmRun(test_scenarios) res = run( scenarios=test_scenarios.filter( scenario=["ssp126", "ssp245", "ssp370"]), climate_models_cfgs={ "CICEROSCM": [ { "model_end": 2100, "Index": 30040, "lambda": 0.540, "akapa": 0.341, "cpi": 0.556, "W": 1.897, "rlamdo": 16.618, "beto": 3.225, "mixed": 107.277, "dirso2_forc": -0.457, "indso2_forc": -0.514, "bc_forc": 0.200, "oc_forc": -0.103, }, { "model_end": 2100, "Index": 1, "lambda": 0.3925, "akapa": 0.2421, "cpi": 0.3745, "W": 0.8172, "rlamdo": 16.4599, "beto": 4.4369, "mixed": 35.4192, "dirso2_forc": -0.3428, "indso2_forc": -0.3856, "bc_forc": 0.1507, "oc_forc": -0.0776, }, ] }, output_variables=( "Surface Air Temperature Change", "Surface Air Ocean Blended Temperature Change", "Heat Content|Ocean", "Effective Radiative Forcing", "Effective Radiative Forcing|Anthropogenic", "Effective Radiative Forcing|Aerosols", "Effective Radiative Forcing|Greenhouse Gases", "Heat Uptake", "Atmospheric Concentrations|CO2", "Atmospheric Concentrations|CH4", "Atmospheric Concentrations|N2O", "Emissions|CO2", "Emissions|CH4", "Emissions|N2O", ), out_config=None, ) assert isinstance(res, ScmRun) assert res["run_id"].min() == 1 assert res["run_id"].max() == 30040 assert res.get_unique_meta("climate_model", no_duplicates=True) == "CICERO-SCM" assert set(res.get_unique_meta("variable")) == set([ "Surface Air Temperature Change", "Surface Air Ocean Blended Temperature Change", "Heat Content|Ocean", "Effective Radiative Forcing", "Effective Radiative Forcing|Anthropogenic", "Effective Radiative Forcing|Aerosols", "Effective Radiative Forcing|Greenhouse Gases", "Heat Uptake", "Atmospheric Concentrations|CO2", "Atmospheric Concentrations|CH4", "Atmospheric Concentrations|N2O", "Emissions|CO2", "Emissions|N2O", "Emissions|CH4", ]) # check we can also calcluate quantiles assert "run_id" in res.meta quantiles = calculate_quantiles(res, [0, 0.05, 0.17, 0.5, 0.83, 0.95, 1]) assert "run_id" not in quantiles.meta assert (res.filter( variable="Atmospheric Concentrations|CO2").get_unique_meta( "unit", True) == "ppm") assert (res.filter( variable="Atmospheric Concentrations|CH4").get_unique_meta( "unit", True) == "ppb") assert (res.filter( variable="Atmospheric Concentrations|N2O").get_unique_meta( "unit", True) == "ppb") assert (res.filter(variable="Emissions|CO2").get_unique_meta( "unit", True) == "PgC / yr") assert (res.filter(variable="Emissions|CH4").get_unique_meta( "unit", True) == "TgCH4 / yr") assert (res.filter(variable="Emissions|N2O").get_unique_meta( "unit", True) == "TgN2ON / yr") # check that emissions were passed through correctly for (scen, variable, unit, exp_val) in ( ("ssp126", "Emissions|CO2", "PgC/yr", -2.3503), ("ssp370", "Emissions|CO2", "PgC/yr", 22.562), ("ssp126", "Emissions|CH4", "TgCH4/yr", 122.195), ("ssp370", "Emissions|CH4", "TgCH4/yr", 777.732), ("ssp126", "Emissions|N2O", "TgN2ON/yr", 5.318), ("ssp370", "Emissions|N2O", "TgN2ON/yr", 13.144), ): res_scen_2100_emms = res.filter(variable=variable, year=2100, scenario=scen).convert_unit(unit) if res_scen_2100_emms.empty: raise AssertionError("No {} data for {}".format( variable, scen)) npt.assert_allclose( res_scen_2100_emms.values, exp_val, rtol=1e-4, ) for (scen, variable, unit, exp_val14, exp_val16) in ( ("ssp126", "Emissions|CH4", "TgCH4/yr", 387.874, 379.956), ("ssp370", "Emissions|CH4", "TgCH4/yr", 387.874, 394.149), ("ssp126", "Emissions|N2O", "TgN2ON/yr", 6.911, 6.858), ("ssp370", "Emissions|N2O", "TgN2ON/yr", 6.911, 7.0477), ): res_scen_2014_emms = res.filter(variable=variable, year=2014, scenario=scen).convert_unit(unit) if res_scen_2014_emms.empty: raise AssertionError("No {} data for {}".format( variable, scen)) res_scen_2016_emms = res.filter(variable=variable, year=2016, scenario=scen).convert_unit(unit) if res_scen_2016_emms.empty: raise AssertionError("No {} data for {}".format( variable, scen)) npt.assert_allclose( res_scen_2014_emms.values, exp_val14, rtol=1e-4, ) npt.assert_allclose( res_scen_2016_emms.values, exp_val16, rtol=1e-4, ) for (scen, variable) in ( ("ssp126", "Effective Radiative Forcing|Aerosols"), ("ssp370", "Effective Radiative Forcing|Aerosols"), ): res_scen_2015_emms = res.filter(variable=variable, year=2015, scenario=scen) if res_scen_2015_emms.empty: raise AssertionError( "No CO2 emissions data for {}".format(scen)) assert not np.equal(res_scen_2015_emms.values, 0).all() ssp245_ghg_erf_2015 = res.filter( variable="Effective Radiative Forcing|Greenhouse Gases", year=2015, scenario="ssp245", run_id=1, ) ssp245_ghg_erf_2014 = res.filter( variable="Effective Radiative Forcing|Greenhouse Gases", year=2014, scenario="ssp245", run_id=1, ) # check that jump in GHG ERF isn't there assert (ssp245_ghg_erf_2015.values.squeeze() - ssp245_ghg_erf_2014.values.squeeze()) < 0.1 ssp245_ch4_conc_2015 = res.filter( variable="Atmospheric Concentrations|CH4", year=2015, scenario="ssp245", run_id=1, ) ssp245_ch4_conc_2014 = res.filter( variable="Atmospheric Concentrations|CH4", year=2014, scenario="ssp245", run_id=1, ) # ch # check that jump in GHG ERF isn't there assert (ssp245_ch4_conc_2014.values.squeeze() - ssp245_ch4_conc_2015.values.squeeze()) < 0.1 self._check_output(res, expected_output_file, update_expected_values)
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])
def _make_full_cfgs(self, scenarios, cfgs): # pylint: disable=R0201 full_cfgs = [] run_id_block = 0 for (scenario, model), smdf in tqdm( scenarios.timeseries().groupby(["scenario", "model"]), desc="Creating FaIR emissions inputs", ): smdf_in = ScmRun(smdf) endyear = smdf_in.time_points.years()[-1] emissions = scmdf_to_emissions(smdf_in, endyear=endyear) emissions_pi = np.zeros(40) emissions_pi[5] = 1.2212429848636561 emissions_pi[6] = 348.5273588 emissions_pi[7] = 60.02182622 emissions_pi[8] = 3.8773253867471933 emissions_pi[9] = 2.097770755 emissions_pi[10] = 15.44766815 emissions_pi[11] = 6.92769009144426 nt = emissions.shape[0] scenario_cfg = [{ "scenario": scenario, "model": model, "run_id": run_id_block + i, "emissions": emissions, "natural": natural.Emissions.emissions[:nt, :], "F_volcanic": cmip6_volcanic.Forcing.volcanic[:nt], "F_solar": cmip6_solar.Forcing.solar[:nt], "efficacy": np.ones(45), "diagnostics": "AR6", "gir_carbon_cycle": True, "temperature_function": "Geoffroy", "aerosol_forcing": "aerocom+ghan2", "fixPre1850RCP": False, "E_pi": emissions_pi, "b_tro3": np.array([ 1.77871043e-04, 5.80173377e-05, 1.94458719e-04, 2.09151270e-03 ]), "tropO3_forcing": "cmip6", "aCO2land": 0.0006394631886297174, "b_aero": np.array([-0.00503, 0.0, 0.0, 0.0, 0.0385, -0.0104, 0.0]), "ghan_params": np.array([1.232, 73.9, 63.0]), "gmst_factor": 1 / 1.04, "ohu_factor": 0.92, **cfg, } for i, cfg in enumerate(cfgs)] run_id_block += len(scenario_cfg) full_cfgs += scenario_cfg return full_cfgs
import numpy as np from scmdata import ScmRun IDX = [2010, 2020, 2030] start = ScmRun( data=np.arange(18).reshape(3, 6), index=IDX, columns={ "variable": [ "Emissions|CO2|Fossil", "Emissions|CO2|AFOLU", "Emissions|CO2|Fossil", "Emissions|CO2|AFOLU", "Cumulative Emissions|CO2", "Surface Air Temperature Change", ], "unit": ["GtC / yr", "GtC / yr", "GtC / yr", "GtC / yr", "GtC", "K"], "region": ["World|NH", "World|NH", "World|SH", "World|SH", "World", "World"], "model": "idealised", "scenario": "idealised", }, ) start.head() fos = start.filter(variable="*Fossil") fos.head()