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 level, 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 (or Dataset) as for the global mean temperatures

  • use 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 analysis from single models to many models

  • scientific and data analysis goals

    • assess TXx at different global warming levels

    • see how spatial patterns are smoothed when averaging across multiple 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 = dict(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.

  1. Create a new dictionary named d (as above). Set "a" to 5 and "b" to 7.

  2. You can get the value from a dictionary using square brackets: d["a"]. Read back the value of "b".

  3. What happens if you pass a key that does not exist in the dictionary, e.g. d["c"]?

  4. There is an alternative way to get a key from a dictionary - using d.get("b"). What happens if you pass a key that does not exist in the dictionary to get, e.g., d.get("c")?

  5. We can assign new values to an existing dictionary using d["d"] = 9. Assign 11 to "e".

  6. 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=}")
    
  7. 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.

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).

  1. Test this by copying the two lines to your notebook.

Read global mean temperature

After these excursions let’s dive in to the analysis.

  1. Add a new markdown title e.g. # Analysis.

  2. Open the netCDF file with annual mean global mean temperatures you saved in Part 2 (“Convert to a Dastaset”).

  3. 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.

Create filename dynamically

  1. Start with the filename and adapt it such that it shows "EC-Earth3" instead of "MIROC6" using an f-string:

    model = "EC-Earth3"
    filename = "../data/cmip6/tasmax/txx/txx_tasmax_day_MIROC6_historical-ssp585_r1i1p1f1_g025.nc
    print(filename)
    
  2. Create the new filename in a loop:

    • create a loop over tas.models.values

    • Copy the adapted “filename” from above and print the result.

Load data

To load the data we need to we need to have the following structure:

# create dictionary to store the data
tasmax_dict = dict()

# loop over models
for model in tas.models.values:

    # create filename
    filename = ...

    # read netcdf
    ds = xr.open_dataset(filename)

    # get the DataArray from the Dataset
    da = ds.tasmax

    # calculate the anomaly
    da = ...

    # assign to dict
    tasmax_dict[model] = da
  1. Update the code above to load and process all models.

Test the dictionary

  1. Read the model "EC-Earth3" from the dict.

  2. Select the first timestep and plot it.

  3. 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. Thus adapt the following code:

tasmax_at_15_dict = dict()

for model in tas.models.values:

    # select global mean temperature for the model
    tas_ = ...

    # select TXx for the model
    tasmax = ...

    # compute the warming level period
    period = ...

    # average over the warming level period
    tasmax = tasmax.sel(year=period).mean("year")

    # assign to dict
    tasmax_at_15_dict[model] = tasmax

Tip

tas is a DataArray while tasmax_dict is a dictionary so you need to select the model differently.

Concatenate all models

Now we have one entry for each model in the tasmax_at_15_dict. The dictionary was helpful to read and process each individual model. However, we now want to average over all the models, for this it’s better to have all models in the same xr.DataArray (as tas). Therefore we concatenate all models into one DataArray:

  1. Using xr.concat() concatenate all models into a single DataArray over a new dimension named "models". Because tasmax_at_15_dict is a dict you have to pass the .values() to the function.

  2. Use

    tasmax_at_15 = tasmax_at_15.assign_coords(models=list(tasmax_at_15_dict.keys()))
    

    to assign the model names as coordinates.

Plot

  1. Calculate the mean over the "models" dimension, and create a plot.

Check the function

  1. There is a function

    def at_warming_level(tas, index, warming_level):
       ...
    

    in computation.py. Have a look at the it to see how it compares with yours.

Comparison

  1. Calculate tasmax_at_15 again using the function.

  2. Calculate the mean over the "models" dimension, and create a plot.

  3. Make sure the plot shows the same as the one above.

Calculate tasmax at the 2.0 °C warming level

  1. Calculate tasmax_at_20, i.e. for a global warming level of 2.0 °C using the new function.

Create a plot of the two warming levels

  1. 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.

  2. Plot the mean over the models for tasmax_at_15 and tasmax_at_20.

  3. Make sure the two variables show the same color scale.

  4. 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.