Part 5 - Global warming levels (ii)
Prepared by Mathias Hauser.
In the fifth part, we will continue our work on global warming. levels Instead of comparing the pattern of two models at the same warming levels, we want to compare the average over all available models for two different warming levels. At the end of this part we will have a figure that is very similar to one from Chapter 11 of the sixth (i.e. most recent) Assessment Report of Working Group I of the Intergovernmental Panel on Climate Change (IPCC AR6 WG1) - Figure 11.11.
Loading 20 (or so) models manually would be quite tedious. We will therefore introduce (or repeat) some python constructions that will hopefully make our lives easier.
The first problem we will tackle is how to handle the 20+ models in
python. We could store each model in a separate variable
(tas_model1 =
, tas_model2 =
, etc.), but this would become
annoying very quickly. There are many alternative ways to do this -
we’ll see one of them. What we need is some sort of “container” where we can
can store the data from more than one model. There are several options,
we could
combine all models into a single
DataArray
(orDataset
) as for the global mean temperaturesuse a tuple or a list,
a dictionary, or
something else.
There is no right solution - each of them would work and has different advantages and disadvanges. Here, we will go with dictionaries which are described below.
Then we also need a way to dynamically construct the filename and should be able to “insert” the model name into a template. We will use f-strings for this.
Learning goals
programming goals
get to know dictionaries and f-strings
using some new functions and methods
how to expand the analyis from single models to many models
scientific and data analyis goals
assess TXx at different global warming levels
see how spatial patterns are smoothed out when averaging over several climate models
Preparation
Create a new notebook with the name p5_warming_level_comparison_name.ipynb
.
Dictionaries
Dictionaries are a native python data container that store data as
key-value pairs. In the following example the "a"
is the key
and 5
the value
:
d = {"a": 5}
The key needs to be a string while the value can be any python object.
We will use this to work with data from different models - the name of
the model (e.g., "ACCESS-CM2"
) will be the key while its data (an
xarray DataArray
or Dataset
) will be the value. Passing the
key to the dictionary in square brackets, e.g. d["a"]
will then return the value.
Create a new dictionary named
d
(as above). Set"a"
to 5 and"b"
to 7.You can get the value from a dictionary using square brackets:
d["a"]
. Read back the value of"b"
.What happens if you pass a key that does not exist in the dictionary, e.g.
d["c"]
?There is an alternative way to get a key from a dictionary - using
d.get("c")
. What happens if you pass a key that does not exist in the dictionary toget
, e.g.,d.get("c")
?How can we adjust
d.get(key)
such that it returns 0 ifkey
is not ind
? Read the docstring ofd.get?
to find out.We can assign new values to an existing dictionary using
d["d"] = 9
. Assign11
to"e"
.What happens if you do
d["a"] = 7
? Is the old value overwritten?We have now learned how to get and assigned values from a dictionary. Before moving on we need to see how we can loop through a dictionary. There are three possibilities - per default it loops over the keys, but we can also loop through the values or both:
for key in d: print(f"{key=}") for value in d.values(): print(f"{value=}") for key, value in d.items(): print(f"{key=}, {value=}")
Copy the three for loops and execute them - do they do what you expect?
There are two ways to create dictionaries. Either with curly braces (d = {"a": 5}
)
or using d = dict(a=5)
. They result in the same
dictionary. However, if you want to use a key like "a b"
(with
space) or "ACCESS-CM2"
(with a dash) you need to use the constructor
with curly braces.
f-strings
To open the files with the data we need to pass the filename. Until now we constructed the filename manually, e.g.:
file1 = "tasmax_ann_ACCESS-CM2_historical_r1i1p1f1_g025.nc"
file2 = "tasmax_ann_GFDL-ESM4_historical_r1i1p1f1_g025.nc"
However, (i) this becomes cumbersome fast and (ii) the only part that is
different is the name of the model. Wouldn’t it be nice if we can
somehow substitute the model name in the string? And indeed this is
possible with so-called f-strings, which are strings where an “f” is
added before the quotes: f""
and the “f” stands for format. In
an f-string everything in curly braces (and including the braces) is
substituted by a variable of the same name. Thus, the following example will print
'tas'
:
var = "tas"
print(f"{var}")
Or for our case we can do:
model = "ACCESS-CM2"
f"tasmax_ann_{model}_historical_r1i1p1f1_g025.nc"
where "{model}"
would now be replaced by "ACCESS-CM2"
(test this
by copying it to a code cell).
Test this by copying the two lines to your notebook.
More on f-strings (optional)
f-strings can more than substitute values in a string - they also allow to customize the
format, you can round floating point numbers (e.g. 3.1415
->
"3.14"
) or pad integers with zeros (1
-> "01"
), etc.. This
is done with a format specifier, e.g. f"{pi:0.2f}"
where the format
specifier starts after the :
and this specific example rounds pi to
two decimal places.
Copy the following lines to a code cell and execute it so the variables are defined.
model = "model1" pi = 3.1415 i = 1
Run the following examples and try to understand what each line does:
print(f"{i}") print(f"{i:02d}") print(f"{i:03d}") print(f"{i: 2d}") print(f"{pi}") print(f"{pi:0.2f}") print(f"{pi:0.3f}") print(f"{pi:8.2f}") print(f"{10 * pi:0.2f}") print(f"{pi=}") print(f"{model = }")
Tip
The
d
in the format specifier stands for decimal and can be used to format integers whilef
stands for float.
There are several ways to create and concatenate strings in python. See the examples below for some variants that came to my mind. I often see variant (a) in code while I think variant (d) is much easier to write and understand - which is why we look at f-strings here! See also more examples at realpython/f-strings.
var = "tasmax"
time = "ann"
model = "model1"
scen = "historical"
num = 1
res = "g025"
a = var + "_" + time + "_" + model + "_" + scen + "_" + str(num) + res + ".nc"
b = "%s_%s_%s_%s_%d_%s.nc" % (var, time, model, scen, num, res)
c = "{}_{}_{}_{}_{}_{}.nc".format(var, time, model, scen, num, res)
d = f"{var}_{time}_{model}_{scen}_{num}_{res}.nc"
print(a)
print(b)
print(c)
print(d)
Run the code above and confirm they all lead to the same result.
Which do you find most readable? (Hopefully the f-string…)
Read global mean temperature
After these excursions let’s dive in to the analysis.
Add a new markdown title e.g.
# Analysis
.Open the netCDF file with annual mean global mean temperatures you saved in Part 2 (“Convert to a Dastaset”).
Compute anomalies w.r.t. 1850 - 1900 and select the variable tas.
Load tasmax data
Now we are finally ready to load the tasmax data of all the models. We want to load the netCDF files in a for loop over all model names, create the filename using a f-string and store it in a dictionary.
Find the filename of the tasmax data you opened in Part 4.
Create a new code cell
create an empty dictionary and name it
tasmax
(before the loop).create a loop over
tas.models.values
In the loop: adapt the “filename” and substitute the model name using an f-string.
Print the resulting filename.
If the resulting filename is correct, replace the
print
function and open the netCDF file using xarray and assign it to the variableds
.Select the variable
tasmax
fromds
.Calculate the anomalies of tasmax w.r.t 1850 - 1900 (in a new loop).
Assign the anomalies to the
tasmax
dict use the model name as key.
Test the dictionary
Read the model EC-Earth3 from the dict.
Select the first timestep and plot it.
Create a weighted or unweighted mean (over whole time period) and plot the resulting time series.
Calculate tasmax at the 1.5 °C warming level
The next step is to calculate tasmax for all models for a certain warming level. Again we will loop through all models, calculate the warming level period and select the respective years from the tasmax data and average over them.
Create a new code cell
create an empty dict and name it
_tasmax_at_15
(before of the loop).create a loop over
tas.models.values
In the loop select the model from
tas
(name it_tas
) and fromtasmax
(name it_tasmax
). Remember thattas
is aDataArray
whiletasmax
is a dictionary so you need to select them differently.Using
_tas
compute thewarming_level_period
for a warming level of 1.5 °C, and name itperiod
.Select the
period
from_tasmax
and calculate the mean over the years.Assign the mean over the selected 20-years to the
_tasmax_at_15
dict, use the model name as key.
Concatenate all models
Now we have one entry for each model in the _tasmax_at_15
dict. Next
we want to concatenate all models into one DataArray.
Concatenate all models to a single xarray Dataset using
xr.concat
over a new dimension named"models"
, naming the resulttasmax_at_15
. Because_tasmax_at_15
is a dict you have to pass the.values()
.Optional: Use
tasmax_at_15 = tasmax_at_15.assign_coords(models=list(_tasmax_at_15.keys()))
to assign the model names as coordinates.
Plot
Calculate the mean over the
"models"
dimension, and create a plot (no need to do a map).
Create a function
Create a function from the above steps. The function should have the following signature:
def at_warming_level(tas, index, warming_level):
...
where tas
is the DataArray
of global mean temperatures and
index
would the dict with the gridded data, here tasmax
. 1. Copy
the code from above and add it to the function. However, don’t calculate
the mean over the models in the function - this should happen outside of
it. 1. Rename the variables as necessary (e.g. tasmax
-> index
).
Comparison
Calculate
tasmax_15
again using the new function.Calculate the mean over the
"models"
dimension, and create a plot (no need to do a map).Make sure the plot shows the same as the one above.
Optional: copy the function to computation.py.
Calculate tasmax at the 2.0 °C warming level
Calculate
tasmax_20
, i.e. for a global warming level of 2.0 °C using the new function.
Create a plot of the two warming levels
Prepare a map plot with two subplots. Choose a projection of your liking. Add coastlines.
You can copy the code from Part 4 but be sure to adapt everything that is necessary.
Plot the mean over the models for
tasmax_15
andtasmax_20
.Make sure the two variables show the same color scale.
Add a the name of the model as title.
Compare your figure to the one from the IPCC: Figure 11.11.
This concludes Part 5.