Skip to content

Commit

Permalink
add teaching materials (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
ammedd authored Aug 18, 2024
1 parent aab602b commit 4a923a0
Show file tree
Hide file tree
Showing 26 changed files with 7,437 additions and 1 deletion.
Binary file added teaching_material/.DS_Store
Binary file not shown.
Binary file added teaching_material/Assignment/CodeOfConduct.docx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
345 changes: 345 additions & 0 deletions teaching_material/Assignment/Preparatory_exercises/A01_Q1.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,345 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0172ff30-bee8-4cc9-8146-97d65e5289fb",
"metadata": {},
"source": [
"### Python Assignment 1\n",
"\n",
"In this assignment you will get familiar with analyzing drifter data. The drifters that we will use were released during the Australasian Antarctic Expedition in December 2013, a project designed to characterize eddy dispersion and diffusivity along an Antarctic Circumpolar Current front. For more information you may take a look at [this scientific article](https://doi.org/10.1002/2015JC010972). An animation of the drifters can be found on http://oceanparcels.org/aaemap.\n",
"\n",
"We assume that you have completed all steps in the *Getting python-ready for Dynamical Oceanography* document and have a new environment called *dyoc*. Now check that you are in the right environment by running the following cell:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9256daff-3fdd-4893-aced-382f93bbb794",
"metadata": {},
"outputs": [],
"source": [
"!conda env list"
]
},
{
"cell_type": "markdown",
"id": "99ea69f2-3199-4a7d-b4e2-0d4bce78c7f0",
"metadata": {},
"source": [
"You should see an asterisk next to your *dyoc* environment. If this is not the case, you may stop the *Jupyter lab* instance using `ctrl + c` in your terminal (Mac) or Anaconda prompt (Windows). Then type `conda activate dyoc` to activate the environment and `jupyter lab` to start *Jupyter lab* again. \n",
"\n",
"Now import the following packages:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "09816b5e-3c73-48fa-98fa-81f2766743cf",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import numpy as np\n",
"import json\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.dates as mdates\n",
"import matplotlib.colors as mcolors\n",
"import matplotlib.cm\n",
"import cartopy\n",
"import cmocean\n",
"import geopy.distance"
]
},
{
"cell_type": "markdown",
"id": "257c5e38-a90c-49f2-bb2c-73b175d15b45",
"metadata": {},
"source": [
"Then download the file `aaedrifters.json` from http://oceanparcels.org/aaemap by clicking on the right-most of the four icons on the bottom-left. Put that file it in the same directory or folder as this notebook and load the data using the code below"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06e5f44e-7570-4e10-9d13-96a88b173a4e",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def reshape_jsonarrays(item):\n",
" time = np.array([d[0] for d in item[1]], dtype='datetime64')\n",
" lat = np.array([d[1] for d in item[1]], dtype='float')\n",
" lon = np.array([d[2] for d in item[1]], dtype='float')\n",
" return {'name':item[0], 'time':time, 'lat':lat, 'lon':lon}\n",
"\n",
"with open(\"aaedrifters.json\") as fp:\n",
" jsondata = json.load(fp)\n",
"\n",
"drifters = [reshape_jsonarrays(item) for item in jsondata.items()]"
]
},
{
"cell_type": "markdown",
"id": "7b2fbd30",
"metadata": {},
"source": [
"Have a quick look of the content of the new `drifter` list by running the following cell:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "440cae47",
"metadata": {},
"outputs": [],
"source": [
"drifters"
]
},
{
"cell_type": "markdown",
"id": "ee738656-47e6-4a19-9dcc-700c555f6a33",
"metadata": {},
"source": [
"The drifter pairs were deployed on a straight line along the cruise track between approximately (56.0°S, 157.2°E) and (58.8°S, 153.5°E) over a 25 h period starting on 11 December 2013. \n",
"\n",
"Make a simple plot of all trajectories in `drifters` using `plt.plot`, both for the complete duration of the experiment and the first ten days after release."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c5342e54-a195-4883-80ce-5c265ab9069f",
"metadata": {
"tags": []
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "6ce3b0b6-7469-41b2-9fcf-3b62d462d27e",
"metadata": {},
"source": [
"To get a better view on the trajectories, it might be nice to show the continents as well. For this we use the `cartopy` package. Now run the following cell and see the resulting map."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9de0bef7-36ae-4cc3-b025-bb1dcf89c242",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# We use the Platecarree projection centered at 180 degrees longitude\n",
"# on Cartopy's website you can find other projections to play around with\n",
"projection = cartopy.crs.PlateCarree(central_longitude=180)\n",
"\n",
"# whenever adding data having latitude-longitude coordinates, use PlateCarree() as coordinate reference system\n",
"data_crs = cartopy.crs.PlateCarree()\n",
"\n",
"# initialisation of the figure\n",
"fig = plt.figure(figsize=(12, 5))\n",
"ax = fig.add_subplot(1, 1, 1, projection=projection)\n",
"\n",
"# plot coastlines and colour the land surfaces\n",
"ax.coastlines(resolution='50m')\n",
"ax.add_feature(cartopy.feature.LAND)\n",
"\n",
"# plot trajectories\n",
"for d in drifters[:]:\n",
" ax.plot(d['lon'], d['lat'], transform=data_crs, lw=0.8)\n",
"\n",
"# plot grid lines and format the labels\n",
"# xlocs is needed because the locator does not work so well when crossing 180 degrees longitude\n",
"gl = ax.gridlines(crs=data_crs, draw_labels=['bottom','left'], linewidth=0.5,\n",
" color='gray', alpha=0.5, linestyle='--', xlocs=range(-180,181,10))\n",
"gl.xformatter = cartopy.mpl.gridliner.LONGITUDE_FORMATTER\n",
"gl.yformatter = cartopy.mpl.gridliner.LATITUDE_FORMATTER\n",
"\n",
"# zoom out to see more land masses\n",
"ax.set_extent((142,228,-77,-32), crs=data_crs)"
]
},
{
"cell_type": "markdown",
"id": "ccc5136f-377d-408d-a7c3-02254c2757e5",
"metadata": {},
"source": [
"Complete the function `drifter_velocity` below that computes the zonal and meridional velocities of a drifter. The function takes an element of `drifters` as an argument and returns two arrays, `u` and `v`. The remaining code will plot your results for drifter 130263. Make sure the vectors are aligned with the trajectory."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a605b9eb-6774-43cb-9a19-9bd8cd5f90a3",
"metadata": {},
"outputs": [],
"source": [
"# ANSWER\n",
"def drifter_velocity(data):\n",
" \"\"\"compute zonal and meridional velocities of drifter\n",
" data : dictionary containing arrays time, lat and lon\n",
" u, v : array, zonal (meridional) velocity\n",
" \"\"\"\n",
" # enter your code here\n",
" return u,v\n",
"\n",
"data = drifters[4]\n",
"u,v = drifter_velocity(data)\n",
"\n",
"crs = cartopy.crs.PlateCarree()\n",
"ax = plt.axes(projection=crs)\n",
"pids = slice(1200,1550,4)\n",
"Q = ax.quiver(data['lon'][pids], data['lat'][pids], u[pids], v[pids], transform=crs, lw=0.5)\n",
"ax.quiverkey(Q, 0.92, 0.05, 0.5, label='0.5 m/s')\n",
"ax.set_title(f\"velocity of drifter {data['name']}\")\n",
"ax.gridlines(draw_labels=['left','bottom'], dms=True)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "ad1b4032-437a-4797-9502-bb98e6e04409",
"metadata": {},
"source": [
"Now use the function `drifter_velocity` to create maps of zonal and meridional velocity for all drifters. Part of the code to plot the results has been given below. \n",
"Hint: use `ax.scatter` to change colour along the trajectories."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dc3be3f1-312f-472e-89b1-1d3a8d390cb3",
"metadata": {},
"outputs": [],
"source": [
"# compute velocities here"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac2f5a0d-7030-451f-91ef-9086075aa824",
"metadata": {},
"outputs": [],
"source": [
"ax = plt.axes(projection=cartopy.crs.PlateCarree(central_longitude=180))\n",
"\n",
"# plot results for u here\n",
"\n",
"ax.set_title(\"zonal velocity\")\n",
"ax.coastlines('50m')\n",
"ax.gridlines(draw_labels=['left','bottom'], transform=cartopy.crs.PlateCarree(), xlocs=range(-180,180,10))\n",
"ax.figure.colorbar(p, orientation='horizontal', extend='both', label=\"u (m/s)\", aspect=50, pad=0.08)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a7c7cfff-00de-4883-9e3c-a2ca77702ae0",
"metadata": {},
"outputs": [],
"source": [
"ax = plt.axes(projection=cartopy.crs.PlateCarree(central_longitude=180))\n",
"\n",
"# plot results for v here\n",
"\n",
"ax.set_title(\"meridional velocity\")\n",
"ax.coastlines('50m')\n",
"ax.gridlines(draw_labels=['left','bottom'], transform=cartopy.crs.PlateCarree(), xlocs=range(-180,180,10))\n",
"ax.figure.colorbar(p, orientation='horizontal', extend='both', label=\"v (m/s)\", aspect=50, pad=0.08)"
]
},
{
"cell_type": "markdown",
"id": "26b13693-4587-4d8a-9126-a24fe3146d4e",
"metadata": {},
"source": [
"The drifters have been released in pairs, about 13 meter apart on either side of the ship. This makes it possible to analyze the separation distance, which is a measure for dispersion. The cell below creates a list, `dists`, of dictionaries containing time, launching latitude, names and distance, $D$, between the drifters of each pair. \n",
"Run it now and plot the drifter separation as a function of time for all drifters for the first ten days after launch. You may change the scale of the y-axis to logarithmic or symmetric logarithmic with `ax.set_yscale`. How does the separation after ten days depend on launching latitude?"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "366a3e9c-14df-44b4-b8f2-25ce1ca75a16",
"metadata": {},
"outputs": [],
"source": [
"def separation(data1, data2):\n",
" \"\"\"calculate separation distance between two drifters\"\"\"\n",
" time1 = data1['time']\n",
" time2 = data2['time']\n",
" time = np.array(sorted(set(time1).intersection(set(time2))))\n",
" tids1 = np.searchsorted(time1, time)\n",
" tids2 = np.searchsorted(time2, time)\n",
" lats1 = data1['lat'][tids1]\n",
" lons1 = data1['lon'][tids1]\n",
" lats2 = data2['lat'][tids2]\n",
" lons2 = data2['lon'][tids2]\n",
" dist = [geopy.distance.distance((lat1,lon1),(lat2,lon2)).m for (lat1, lon1, lat2, lon2)\n",
" in zip(lats1, lons1, lats2, lons2)]\n",
" return {'name1':data1['name'], 'name2':data2['name'], 'time':time,\n",
" 'lat0':data1['lat'][0], 'distance':np.array(dist)}\n",
"\n",
"lats = np.array([d['lat'][0] for d in drifters])\n",
"pairids = lats.argsort().reshape((-1,2)).tolist()\n",
"dists = []\n",
"for n,(i,j) in enumerate(pairids):\n",
" print(f\"\\ranalyzing pair {n+1}/{len(pairids)}\", end=\"\")\n",
" dists.append(separation(drifters[i], drifters[j]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8416d797-094b-480c-b7dc-a1d1a2ec0b8d",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "840a24d2-b388-4489-ad0d-e478cefe3a91",
"metadata": {},
"source": [
"It is time to compare your results. Create a plot of the pairwise dispersion, $D^2$, similar to figure 5a in the [article](https://doi.org/10.1002/2015JC010972). You do not need to fit the data and calculate the slopes, but do check if the impact of the outlier drifter pair on the mean is similar."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ba5fe542-78fa-48f6-8ac9-baf9d276143e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading

0 comments on commit 4a923a0

Please sign in to comment.