Group project: the Climate System¶
Stefan Müller, Amelie Linha
Instructions¶
Objectives
In this final project, you will apply the methods you learned over the past weeks to answer the questions below.
Deadline
Please submit your project via OLAT before Thursday January 12 at 00H (in the night from Wednesday to Thursday).
Formal requirements
You will work in groups of two. If we are an odd number of students, one group can have three participants. (Tip: I recommend that students who have not followed my programming class to team up with students who have).
Each group will submit one (executed) jupyter notebook containing the code, plots, and answers to the questions (text in the markdown format). Please also submit an HTML version of the notebook. Each group member must contribute to the notebook. The notebook should be self-contained and the answers must be well structured. The plots must be as understandable as possible (title, units, x and y axis labels, appropriate colors and levels…).
Please be concise in your answer. I expect a few sentences per answer at most - there is no need to write a new text book in this project! Use links and references to the literature or your class slides where appropriate.
Grading
I will give one grade per project, according to the following table (total 10 points):
- correctness of the code and the plots: content, legends, colors, units, etc. (3 points)
- quality of the answers: correctness, preciseness, appropriate use of links and references to literature or external resources (5 points)
- originality and quality of the open research question (2 points)
1 2 3 4 5 6 7 8 9 | # Import the tools we are going to need today: import matplotlib.pyplot as plt # plotting library import numpy as np # numerical library import xarray as xr # netCDF library import pandas as pd # tabular library import cartopy # Map projections libary import cartopy.crs as ccrs # Projections list # Some defaults: plt.rcParams['figure.figsize'] = (12, 5) # Default plot size |
Part 1 - temperature climatology¶
Open the ERA5 temperature data:
1 | ds = xr.open_dataset('../VU_ClimateSystem/data/ERA5_LowRes_Monthly_t2m.nc') |
Plot three global maps:
- Compute and plot the temporal mean temperature $\overline{T}$ for the entire period (unit °C)
- Compute and plot $\overline{T^{*}}$ (see lesson), the zonal anomaly map of average temperature.
- Compute the monthly average temperature for each month $\overline{T_M}$ (annual cycle). I expect a variable of dimensions (month: 12, latitude: 241, longitude: 480). Hint: remember the
.groupby()
command we learned in the lesson. Now plot the average monthly temperature range, i.e. $\overline{T_M}max$ - $\overline{T_M}min$ on a map.
Questions:
- Look at the zonal temperature anomaly map.
- Explain why norther Europe and the North Atlantic region is significantly warmer than the same latitudes in North America or Russia.
- Explain why the Northern Pacific Ocean does not have a similar pattern.
- Look at the average monthly temperature range map.
- Explain why the temperature range is smaller in the tropics than at higher latitudes
- Explain why the temperature range is smaller over oceans than over land
- Where is the temperature range largest? Explain why.
1 2 3 4 5 6 7 | # temporal mean temperature for the entire period in °C temp_mean = ds.t2m.mean(dim='time') temp_C = temp_mean - 273.15 # convert to °C ax = plt.axes(projection=ccrs.EqualEarth()) temp_C.plot(ax=ax, transform=ccrs.PlateCarree(), cmap= 'seismic', vmin=-55, vmax=35, levels=19, cbar_kwargs={'label': '°C'}) ax.coastlines(); ax.gridlines(); # Add gridlines and coastlines to the plot ax.set_title('Temporal mean 2m air temperature, 1979-2018'); |
1 2 3 4 5 6 | # T∗, the zonal anomaly map of average temperature t_zon_an = temp_C - temp_C.mean(dim='longitude') ax = plt.axes(projection=ccrs.EqualEarth()) t_zon_an.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'temperature anomaly in °C'}) ax.coastlines(); ax.gridlines(); ax.set_title('Zonal anomaly of average temperature, 1979-2018'); |
Questions:
- Look at the zonal temperature anomaly map.
- Explain why norther Europe and the North Atlantic region is significantly warmer than the same latitudes in North America or Russia.
- Explain why the Northern Pacific Ocean does not have a similar pattern.
Answer:
The gulf stream brings heat from the tropics to these latitudes whereas in the Pacific or east Russia there is no such ocean current. In the Pacific the current transporting heat from the tropics exist east of Japan but due to the huge extent of the Pacific that heat doesn’t reach Alaska for example but is distributed in the water before (see slide 26, Lecture 01).
1 2 3 4 5 6 7 | # annual cycle t_mon_avg = ds.t2m.groupby('time.month').mean(dim='time') # monthly average temperature for each month t_range = t_mon_avg.max(dim='month') - t_mon_avg.min(dim='month') # average monthly temperature range ax = plt.axes(projection=ccrs.EqualEarth()) t_range.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': '°C'}) ax.coastlines(); ax.gridlines(); ax.set_title('Average monthly 2m temperature range, 1979-2018'); |
Questions:
- Look at the average monthly temperature range map.
- Explain why the temperature range is smaller in the tropics than at higher latitudes
- Explain why the temperature range is smaller over oceans than over land
- Where is the temperature range largest? Explain why.
Answer:
The difference between the seasons in incoming solar radiation is bigger in the higher latitudes than in the tropics. This leads to a bigger temperature range.
Water has a bigger specific heat content, meaning that water can store heat better than land. That means water can act as a heat source or absorbent when solar radiation is missing or abundant. This effect helps flattening out temperature curves. It is largest over eastern Russia because there is no big body of water nearby, so heat is lost very fast. And in addition, there are very high differences in incoming solar radiation over the seasons with almost none in the winter and very high in the summer.
Part 2 - Precipitation climatology¶
Open the precipitation file and explore it. The units of monthly precipitation are wrongly labeled (unfortunately). They should read: m per day.
1 | prec = xr.open_dataset('../VU_ClimateSystem/data/ERA5_LowRes_Monthly_tp.nc') |
Using .groupby()
, compute the average daily precipitation for each month of the year (I expect a variable of dimensions (month: 12, latitude: 241, longitude: 480)). Convert the units to mm per day. Plot a map of average daily precipitation in January and in August with the levels [0.5, 1, 2, 3, 4, 5, 7, 10, 15, 20, 40]
and the colormap `YlGnBu'
Questions:
- Describe the location of the ITCZ in January and February. Without going into the details, explain (in one or two sentences)
- Describe the precipitation seasonality in West Africa and in India. Name the phenomenon at play.
1 2 3 | # average daily precipitation for each month p_mon_avg = prec.tp.groupby('time.month').mean(dim='time') # average daily precipitation for each month p_mon_avg_mm = p_mon_avg * 1000 # convert to mm per day |
1 2 3 4 5 6 | # plot January ax = plt.axes(projection=ccrs.EqualEarth()) p_January = p_mon_avg_mm.sel(month=1) p_January.plot(ax=ax, transform=ccrs.PlateCarree(), cmap = 'YlGnBu', levels = [0.5, 1, 2, 3, 4, 5, 7, 10, 15, 20, 40], cbar_kwargs={'label': 'mm per day'}) ax.coastlines(); ax.gridlines(); ax.set_title('Average daily precipitation in January, 1979-2018'); |
1 2 3 4 5 6 | # plot August ax = plt.axes(projection=ccrs.EqualEarth()) p_August = p_mon_avg_mm.sel(month=8) p_August.plot(ax=ax, transform=ccrs.PlateCarree(), cmap = 'YlGnBu', levels = [0.5, 1, 2, 3, 4, 5, 7, 10, 15, 20, 40], cbar_kwargs={'label': 'mm per day'}) ax.coastlines(); ax.gridlines(); ax.set_title('Average daily precipitation in August, 1979-2018'); |
Questions:
- Describe the location of the ITCZ in January and February. Without going into the details, explain (in one or two sentences)
- Describe the precipitation seasonality in West Africa and in India. Name the phenomenon at play.
Answer:
- Over the eastern pacific it is just slightly north of the equator. Over south America it diverges further south due to the land. Over the Atlantic it is again closer to the equator before going drastically to the south over Africa to almost 20 deg. Over the Indian ocean and Australia, it stays in that range with the same tendencies land vs sea.
- In winter, the regions of West Africa and India are dry as there is very few precipitation. In summer, the precipitation amounts in these regions are high. The phenomenon at play is the monsoon. As the ITCZ approaches these locations, it brings strong precipitation due to the lifting of the moist air in the convergence in the ITCZ.
Part 3: sea-level pressure and surface winds¶
Open the file containing the surface winds (u10
and v10
) and sea-level pressure (msl
).
1 | uvslp = xr.open_dataset('../VU_ClimateSystem/data/ERA5_LowRes_Monthly_uvslp.nc') |
Compute $\left[ \overline{SLP} \right]$ (the temporal and zonal average of sea-level pressure). Convert it to hPa, and plot it (line plot). With the help of plt.axhline, add the standard atmosphere pressure line to the plot to emphasize high and low pressure regions. Repeat with $\left[ \overline{u_{10}} \right]$ and $\left[ \overline{v_{10}} \right]$ (in m s$^{-1}$) and add the 0 horizontal line to the plot (to detect surface westerlies from easterlies for example).
Questions:
- Based on your knowledge about the general circulation of the atmosphere, explain the latitude location of the climatological high and low pressure systems of Earth.
- Similarly, explain the direction and strength of the zonal and meridional winds on earth (tip: the sea-level pressure plot helps)
1 2 3 4 5 6 7 8 9 10 | # temporal and zonal average of sea level pressure zonal_mean_msl = uvslp.msl.mean(dim='time').mean(dim='longitude') zonal_avg_msl = zonal_mean_msl / 100 # convert to hPa plt.plot(uvslp.latitude,zonal_avg_msl) plt.axhline(y=1013.25, color='r') plt.text(-89, 1014, 'standard atmosphere pressure', color='r') plt.xlabel('latitude in °') plt.ylabel('temporal and zonal average of sea-level pressure in hPa') plt.title('temporal and zonal average of sea-level pressure, 1979-2018') plt.xlim(-90,90); |
1 2 3 4 5 6 7 8 9 10 | # temporal and zonal average of u10 zonal_mean_u = uvslp.u10.mean(dim='time').mean(dim='longitude') plt.plot(uvslp.latitude,zonal_mean_u) plt.axhline(y=0, color='r') plt.text(-7, 2, 'westerlies', color='r') # positive u is from from the west plt.text(-7, -2, 'easterlies', color='r') # negative u is from from the east plt.xlabel('latitude in °') plt.ylabel('temporal and zonal average of u10 in m s^{-1}') plt.title('temporal and zonal average of u10, 1979-2018') plt.xlim(-90,90); |
1 2 3 4 5 6 7 8 9 10 | # temporal and zonal average of v10 zonal_mean_v = uvslp.v10.mean(dim='time').mean(dim='longitude') plt.plot(uvslp.latitude,zonal_mean_v) plt.axhline(y=0, color='r') plt.text(-7, 0.75, 'southerlies', color='r') # positive v is from from the south plt.text(-7, -0.75, 'northerlies', color='r') # negative v is from from the north plt.xlabel('latitude in °') plt.ylabel('temporal and zonal average of v10 in m s$^-1$') plt.title('temporal and zonal average of v10, 1979-2018') plt.xlim(-90,90); |
Questions:
- Based on your knowledge about the general circulation of the atmosphere, explain the latitude location of the climatological high and low pressure systems of Earth.
- Similarly, explain the direction and strength of the zonal and meridional winds on earth (tip: the sea-level pressure plot helps)
Answer:
- In the tropics the intense solar radiation lifts air and causes a generally low pressure at ground levels. This air diverts south and north before subsidizing again in the extra tropics causing high pressure at ground levels. In the mid latitudes the strong westerlies form climatological lows and highs mostly due to change from land to sea and vice versa. In the northern hemisphere the jet has many Rossby waves producing lows at ground level. In the southern hemisphere these waves are not as abundant and thus do not form these strong lows. In the Polar Cells the higher pressure is explained by cold and dry air subsiding. This air flows towards the equator before it has warmed enough to rise again in the mid latitudes (see slide 12, Lecture 01).
- Strong meridional winds can only be found where air is flowing towards a zonal low pressure for example the ITCZ. These are deflected by Coriolis force, so they also have a zonal component. The strongest zonal winds are in the westerlies in the mid latitudes. These form due to the air from the polar cells moving to the equator and from the Ferrell Cell moving polarwards both being deflected by Coriolis force to the right of their heading (see slide 12, Lecture 01).
Part 4: temperature change and CO$_2$ concentrations¶
Download the global average CO$_2$ concentration timeseries data in the CSV format (source: NOAA). Here, let me help your read them using pandas:
1 | df = pd.read_csv('../VU_ClimateSystem/data/co2_mm_gl.csv', skiprows=55, parse_dates={'date' : [0, 1]}, index_col='date') |
Prepare three plots:
- plot the monthly global CO$_2$ concentration as a function of time.
- plot the annual average timeseries of global CO$_2$ concentration as a function of time.
- plot the annual average timeseries of global CO$_2$ concentration and of global 2m temperature from ERA5 on the same plot (using a secondary y axis for temperature).
Questions:
- Describe and explain the annual cycle of CO$_2$ concentrations
- What was the CO$_2$ concentration in the atmosphere in the pre-industrial era? Compute the annual increase in CO$_2$ concentration (unit: ppm per year) between 1980 and 1985 and between 2016 and 2021.
- Describe the relationship between global temperatures and CO$_2$ concentrations. Beside CO$_2$, name three processes that can influence temperature variability and change at the global scale.
1 2 3 4 | # monthly global CO2 concentration as a function of time df.average.plot() plt.ylabel("global CO$_2$ concentration in ppm") plt.title('monthly global CO$_2$ concentration'); |
1 2 3 | # annual average timeseries of global CO2 concentration as a function of time annual_CO2 = df.average.groupby(df.index.year).mean() annual_CO2.plot(xlabel= 'time', ylabel = 'global CO$_2$ concentration in ppm', title= 'Annual average timeseries of global CO$_2$ concentration',xlim=(1979,2018)); |
Question:
- Describe and explain the annual cycle of CO$_2$ concentrations.
Answer:
From September to around May CO$_2$ accumulates in the atmosphere by anthropogenic sources and the lack of vegetation in the northern hemisphere. The southern hemisphere has too little landmass to counteract this trend. Around May enough vegetation is build up to start reducing the concentration of CO$_2$. So throughout the summer months of the northern hemisphere the CO$_2$ concentration is reduced due to photosynthesis.
1 2 3 4 5 6 7 8 9 | # annual average timeseries of global CO2 concentration and of global 2m temperature from ERA5 # on the same plot (using a secondary y axis for temperature) # compute the global 2m temperature weight = np.cos(np.deg2rad(ds.latitude)) weight = weight / weight.sum() temp = ds.t2m.groupby('time.year').mean(dim='time') zonal_avg = temp.mean(dim='longitude') # important! Always average over longitudes first weighted_zonal_avg = zonal_avg * weight # multiply two arrays of 180 elements together weighted_avg = weighted_zonal_avg.sum(dim='latitude') -273.15 # convert from K to °C |
1 2 3 4 5 6 7 8 9 10 | # plot global CO2 concentration ax = annual_CO2.plot(ylabel="global CO$_2$ concentration in ppm", xlabel='time', title ='Annual average timeseries of global CO$_2$ concentration and global 2m temperature', label='global CO$_2$ concentration') ax.legend(loc='upper center') # plot global 2m temperature ax1 = ax.twinx() weighted_avg.plot(ax=ax1, color='r', label='global 2m temperature') plt.ylabel('global 2m temperature in °C') plt.legend(loc='upper left') plt.xlim(1979,2018); |
Question:
- What was the CO$_2$ concentration in the atmosphere in the pre-industrial era? Compute the annual increase in CO$_2$ concentration (unit: ppm per year) between 1980 and 1985 and between 2016 and 2021.
Answer:
The approximate CO$_2$ concentration in the pre industrial era was approximately 280 ppm ( https://www.noaa.gov/news-release/carbon-dioxide-now-more-than-50-higher-than-pre-industrial-levels ) During 1980 to 1985 CO$_2$ concentration increased on average by 1.1 ppm annually. From 2016 to 2021 it had accelerated to 1.94 ppm annually.
1 2 3 4 5 6 7 | # annual increase between 1980 and 1985 and between 2016 and 2021 CO2_years = df.average.groupby(df.index.year).mean() diff_1 = CO2_years[1985] - CO2_years[1980] diff_2 = CO2_years[2021] - CO2_years[2016] avg_1 = diff_1 / 6 avg_2 = diff_2 / 6 avg_1 |
1.1043055555555459
1 | avg_2
|
1.9413888888888853
Question:
- Describe the relationship between global temperatures and CO$_2$ concentrations. Beside CO$_2$, name three processes that can influence temperature variability and change at the global scale.
Answer:
CO$_2$ is a greenhouse gas, that means it can absorb longwave radiation from the earth and keep that heat in the atmosphere, which otherwise would have radiated into space. This is increasing the global temperature. So if the CO$_2$ concentration increases, global mean temperature will follow and increase as well.
Since CO$_2$ concentration isn’t the only factor in the global mean temperature, the signal can be weaker or stronger at times. But viewed over a long period of time, temperatures nicely follow CO$_2$ concentration.
Other factors contributing to temperature variability on a global scale are a change in the planetary albedo, a change in incoming radiation or a change in land and sea distribution due to plate tectonics. Large scale Oscillations like the ENSO can have an impact as well.
For example, the continent of Antarctica moving to the south pole significantly changed the global mean temperature because it developed a big icesheet. This in turn changed the albedo of the earth.
Part 5: variability and ENSO (open research question)¶
Using the available data, describe the global effect of an El Niño year and a La Niña year on sea-surface temperature, precipitation, and air temperature. I suggest to look for literature or a google search on strong ENSO events in the past 40 years, and select one good example for a positive and a negative phase. Then use annual or seasonal anomaly maps to show the patterns of SST, temperature and precipitation anomalies during these events. With citation or links, explain why you picked these years as examples.
1 | sea = xr.open_dataset('../VU_ClimateSystem/data/ERA5_LowRes_Monthly_sst.nc') |
These are the data frames of the available data:
ds: 2m temperature
prec: total precipitation
sea: sea surface temperatures
selected time of the ENSO events:
El Nino: May-December 1997
La Nina: 1999 (whole year)
El Nino¶
May-December 1997
1 2 3 4 5 6 7 8 9 10 | # El Nino 1997 - sst ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) sst_1997_months = sea.sst.sel(time=slice('1997-05', '1997-12')).mean(dim='time') sst_avg = sea.sst.groupby('time.month').mean() sst_years_months = sst_avg.sel(month=[5,6,7,8,9,10,11,12]).mean(dim='month') anomaly = sst_1997_months - sst_years_months anomaly.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'temperature anomaly in K'}) ax.coastlines(); ax.gridlines(); ax.set_title('Anomaly map of sea surface temperature May-December, 1997 to 1979-2018'); |
1 2 3 4 5 6 7 8 9 10 | # El Nino 1997 - 2m temperature ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) t2m_1997 = ds.t2m.sel(time=slice('1997-05', '1997-12')).mean(dim='time') t2m_avg = ds.t2m.groupby('time.month').mean() t2m_years_months = t2m_avg.sel(month=[5,6,7,8,9,10,11,12]).mean(dim='month') anomaly = t2m_1997 - t2m_years_months anomaly.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'temperature anomaly in K'}) ax.coastlines(); ax.gridlines(); ax.set_title('Anomaly map of 2m air temperature May-December, 1997 to 1979-2018'); |
1 2 3 4 5 6 7 8 9 10 | # El Nino 1997 - total precipitation ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) tp_1997 = prec.tp.sel(time=slice('1997-05','1997-12')).mean(dim='time') # averge tp per day during El Nino tp_avg = prec.tp.groupby('time.month').mean() # average tp per day in monthly groups tp_years_months = tp_avg.sel(month=[5,6,7,8,9,10,11,12]).mean(dim='month') # average tp per day during the considered months anomaly = (tp_1997 - tp_years_months) * 1000 # convert from m to mm anomaly.plot.imshow(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'precipitation anomaly in mm'}) ax.coastlines(); ax.gridlines(); ax.set_title('Anomaly map of precipitation per day, May-December, 1997 compared to 1979-2018'); |
La Nina¶
1997
1 2 3 4 5 6 7 8 9 | # La Nina 1999 - sst ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) sst_avg_year = sea.sst.groupby('time.year').mean(dim='time') # average sst for each year sst_1999 = sst_avg_year.sel(year=1999) anomaly = sst_1999 - sst_avg_year.mean(dim='year') anomaly.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'temperature anomaly in K'}) ax.coastlines(); ax.gridlines(); ax.set_title('Annual anomaly map of sea surface temperature, 1999 to 1979-2018'); |
1 2 3 4 5 6 7 8 9 | # La Nina 1999 - 2m temperature ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) t2m_avg_year = ds.t2m.groupby('time.year').mean(dim='time') # average t2m for each year t2m_1999 = t2m_avg_year.sel(year=1999) anomaly = t2m_1999 - t2m_avg_year.mean(dim='year') anomaly.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'temperature anomaly in K'}) ax.coastlines(); ax.gridlines(); ax.set_title('Anomaly map of 2m air temperature, 1999 to 1979-2018'); |
1 2 3 4 5 6 7 8 9 10 | # La Nina 1999 - total precipitation ax = plt.axes(projection=ccrs.EqualEarth(central_longitude=-130)) tp_avg_year = prec.tp.groupby('time.year').mean(dim='time') # average tp per day for each year tp_avg_year = tp_avg_year * 1000 # convert from m to mm tp_1999 = tp_avg_year.sel(year=1999) # average tp per day in 1999 anomaly = tp_1999 - tp_avg_year.mean(dim='year') anomaly.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'precipitation anomaly in mm'}) ax.coastlines(); ax.gridlines(); ax.set_title('Anomaly map of precipitation per day, 1997 compared to 1979-2018'); |
We picked the years 1997 and 1999 as examples of strong ENSO events because of the strong anomalies present. This is outlined in a assessment done by NOAA (https://www.cpc.ncep.noaa.gov/products/assessments/assess_97/enso.html).
El Nino conditions were strongest in the period May-December 1997.
For the La Nina event, it was hard to find the exact date.
This is what we found in a paper of Kumar and Kamra (https://www.sciencedirect.com/science/article/pii/S0169809512001792?via%3Dihub): "A La Nina event started in the winter of 1998 and continued for more than a year and then disappeared in the spring of 2000."
We used the whole year of 1999 for the La Nina event because it is sure that there were La Nina conditions in that year.
During the warm phase of the ENSO, named El Nino, sea surface temperatures are higher than normally in the central and east pacific along the equator. During La Nina this warm anomaly shifts towards the west with colder than average sea surface temperatures observed in the east and central pacific.
Precipitation along the equator is mostly formed due to deep convection. This convection is favored over the warm ocean so positive precipitation anomalies are observed in the central and eastern pacific with the west pacific being much drier than normally during El Nino.
La Nina events produce strong positive precipitation anomalies over Indonesia and northern Australia where the warmer ocean water lies. Air temperature anomalies follow sea surface temperature anomalies.
That means during an El Nino event warmer than average conditions occur in the east and central pacific while colder than average conditions occur over the western pacific.
During La Nina warmer than average air temperatures are observed over Indonesia and eastern Australia. Chile on the other side of the pacific observes colder than average temperatures. In our figures these anomalies are very well visible.