Skip to content

Commit 03ec370

Browse files
authored
Merge branch 'main' into pre-commit-ci-update-config
2 parents cbffc60 + c7d2dce commit 03ec370

9 files changed

+1144
-7
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ The tool is based on the [`Parcels`](https://oceanparcels.org/) computational La
1313
conda install conda-forge::plasticparcels
1414
```
1515

16+
### Required data
17+
18+
`plasticparcels` has been developed for use with data from the Copernicus Marine Service, and requires the following data to run:
19+
20+
* Hydrodynamic model data: [MOI GLO12 (psy4v3r1)](https://www.mercator-ocean.eu/en/solutions-expertise/accessing-digital-data/product-details/?offer=4217979b-2662-329a-907c-602fdc69c3a3&system=d35404e4-40d3-59d6-3608-581c9495d86a)
21+
* Biogeochemical model data: [MOI BIO4 (biomer4v2r1)](https://www.mercator-ocean.eu/en/solutions-expertise/accessing-digital-data/product-details/?offer=8d0c01f3-81c7-0a59-0d06-602fdf63c5b6&system=dc40b324-7de7-0732-880b-5d9dcf7d344a)
22+
* Wave data: [ECMWF ERA5 Wave](https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels) (specifically, the variables `mean_wave_period`, `peak_wave_period`, `u_component_stokes_drift`, and `v_component_stokes_drift`.)
23+
* Wind data: [ECMWF ERA5 Wind](https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels) (specifically, the variables `10m_u_component_of_wind` and `10m_v_component_of_wind`)
24+
25+
For downloading the wind and wave data, we recommend using the [CDS API](https://cds.climate.copernicus.eu/api-how-to).
26+
27+
To run most of the examples, you will need to update the data directories in the relevant settings `.json` file.
28+
29+
Just like the `parcels` framework, `plasticparcels` can be adapted to use other hydrodynamic, biogeochemical, wave, and atmospheric models. If you require assistance, please contact us through the [`plasticparcels` discussions page](https://github.com/OceanParcels/plasticparcels/discussions).
30+
1631
### Community contributions and support
1732
#### Contributing code
1833
We welcome contributions to `plasticparcels`, especially example workbooks and analyses for our [public examples page](https://plastic.oceanparcels.org/en/latest/examples.html). To contribute to the project, please submit a [pull request](https://github.com/OceanParcels/plasticparcels/pulls).

docs/examples.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Examples
22
========
33

4-
``plasticparcels`` has a few example notebooks, see below.
4+
``plasticparcels`` has a few example notebooks, see below. Most of these examples require hydrodynamic, physical, and biogeochemical model data, however, the idealised flow example requires no additional data.
55

66

77

@@ -14,4 +14,5 @@ Examples
1414
examples/example_Croatian_fisheries.ipynb
1515
examples/example_add_your_own_kernel.ipynb
1616
examples/example_initialisation_maps.ipynb
17+
examples/example_idealised_flow.ipynb
1718

docs/examples/example_Croatian_fisheries.ipynb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
"metadata": {},
66
"source": [
77
"# Sensitivity of biofouling parameters - Plastic pollution from Croatian fishing vessels\n",
8-
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution emitted from Croatian registered fishing vessels. We will use the [Open-sea fishing-related plastic emissions dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html#open-sea-fishing-related-plastic-emissions) to release virtual particles in ocean model grid cells, using the 3D velocity fields to advect the particles. We also include the effects of biofouling and Stokes drift on the particles. We will run two simulations, one with the default biofouling parameters, and another where we vary some of the biofouling parameters."
8+
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution emitted from Croatian registered fishing vessels. We will use the [Open-sea fishing-related plastic emissions dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html#open-sea-fishing-related-plastic-emissions) to release virtual particles in ocean model grid cells, using the 3D velocity fields to advect the particles. We also include the effects of biofouling and Stokes drift on the particles. We will run two simulations, one with the default biofouling parameters, and another where we vary some of the biofouling parameters.\n",
9+
"<div class=\"alert alert-block alert-info\">\n",
10+
"\n",
11+
"<b>Note: </b> To run this example you will need to download the hydrodynamic, physical, and biogeochemical model data described [here](https://plastic.oceanparcels.org/en/latest/index.html#required-data).\n",
12+
"\n",
13+
"</div>"
914
]
1015
},
1116
{

docs/examples/example_Greece_coast.ipynb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
"metadata": {},
66
"source": [
77
"# The pathways and fate of existing plastic pollution along Greek coastlines\n",
8-
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution along the Greek coastline. We will use the [Current global ocean plastic concentrations dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html) to release virtual particles in coastal model grid cells, using the 2D surface velocity fields to advect the particles. We also include the effects of Stokes drift and wind-induced drift on the particles, but neglect any vertical motion (along with any biofouling, or vertical mixing)."
8+
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution along the Greek coastline. We will use the [Current global ocean plastic concentrations dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html) to release virtual particles in coastal model grid cells, using the 2D surface velocity fields to advect the particles. We also include the effects of Stokes drift and wind-induced drift on the particles, but neglect any vertical motion (along with any biofouling, or vertical mixing).\n",
9+
"<div class=\"alert alert-block alert-info\">\n",
10+
"\n",
11+
"<b>Note: </b> To run this example you will need to download the hydrodynamic, physical, and biogeochemical model data described [here](https://plastic.oceanparcels.org/en/latest/index.html#required-data).\n",
12+
"\n",
13+
"</div>"
914
]
1015
},
1116
{

docs/examples/example_Italy_coast.ipynb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
"metadata": {},
66
"source": [
77
"# The pathways and fate of Italian coastal plastic pollution\n",
8-
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution along the Italian coastline. We will use the [Coastal mismanaged plastic waste emissions dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html) to release virtual particles in coastal model grid cells, using the 2D surface velocity fields to advect the particles. We also include the effects of Stokes drift and wind-induced drift on the particles, but neglect any vertical motion (along with any biofouling, or vertical mixing)."
8+
"In this example, we will use `plasticparcels` to run a basic simulation of microplastic pollution along the Italian coastline. We will use the [Coastal mismanaged plastic waste emissions dataset](https://plastic.oceanparcels.org/en/latest/initialisationmaps.html) to release virtual particles in coastal model grid cells, using the 2D surface velocity fields to advect the particles. We also include the effects of Stokes drift and wind-induced drift on the particles, but neglect any vertical motion (along with any biofouling, or vertical mixing).\n",
9+
"<div class=\"alert alert-block alert-info\">\n",
10+
"\n",
11+
"<b>Note: </b> To run this example you will need to download the hydrodynamic, physical, and biogeochemical model data described [here](https://plastic.oceanparcels.org/en/latest/index.html#required-data).\n",
12+
"\n",
13+
"</div>"
914
]
1015
},
1116
{

docs/examples/example_add_your_own_kernel.ipynb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
"metadata": {},
66
"source": [
77
"# Add your own behaviour kernels\n",
8-
"In this example, we will show how to turn on/off existing behaviour kernels, and how to create and include your own behaviour kernel to use in `plasticparcels` simulations. We will start by importing some necessary packages."
8+
"In this example, we will show how to turn on/off existing behaviour kernels, and how to create and include your own behaviour kernel to use in `plasticparcels` simulations. We will start by importing some necessary packages.\n",
9+
"<div class=\"alert alert-block alert-info\">\n",
10+
"\n",
11+
"<b>Note: </b> To run this example you will need to download the hydrodynamic, physical, and biogeochemical model data described [here](https://plastic.oceanparcels.org/en/latest/index.html#required-data).\n",
12+
"\n",
13+
"</div>"
914
]
1015
},
1116
{

docs/examples/example_idealised_flow.ipynb

Lines changed: 843 additions & 0 deletions
Large diffs are not rendered by default.

docs/examples/idealised_flow.py

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import parcels
2+
import plasticparcels as pp
3+
4+
from datetime import timedelta, datetime
5+
import numpy as np
6+
import xarray as xr
7+
8+
def create_fieldset(indices=None):
9+
""" Create a fieldset with a Bickley Jet, temperature/salinity, biogeochemistry, wind and Stokes drift fields.
10+
To be used with the parcels.FieldSet.from_modulefile() method."""
11+
# List of times the analytic fieldset is evaluated on
12+
times = np.arange(0, 5.1, 0.1) * 86400
13+
14+
# Create the fieldset object
15+
fieldset = bickleyjet_fieldset_3d(times=times)
16+
fieldset = add_uniform_temp_salt_field(fieldset, times)
17+
fieldset = add_biogeochemistry_field(fieldset, times)
18+
fieldset = add_wind_field(fieldset, times)
19+
fieldset = add_stokes_field(fieldset, times)
20+
21+
return fieldset
22+
23+
def bickleyjet_fieldset_3d(times, xdim=51, ydim=51, zdim=11):
24+
""" A Bickley Jet Field based on Hadjighasem et al 2017, 10.1063/1.4982720,
25+
with a vertical dimension introduced via a linear decay of the 2D field in depth."""
26+
27+
U0 = 0.06266
28+
L = 1770.0
29+
r0 = 6371.0
30+
k1 = 2 * 1 / r0
31+
k2 = 2 * 2 / r0
32+
k3 = 2 * 3 / r0
33+
eps1 = 0.075
34+
eps2 = 0.4
35+
eps3 = 0.3
36+
c3 = 0.461 * U0
37+
c2 = 0.205 * U0
38+
c1 = c3 + ((np.sqrt(5) - 1) / 2.0) * (k2 / k1) * (c2 - c3)
39+
40+
a, b = np.pi * r0, 7000.0 # domain size
41+
lon = np.linspace(0, a, xdim, dtype=np.float32)
42+
lat = np.linspace(-b / 2, b / 2, ydim, dtype=np.float32)
43+
depth = np.linspace(0, 1000, zdim, dtype=np.float32)
44+
dx, dy = lon[2] - lon[1], lat[2] - lat[1]
45+
46+
U = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
47+
V = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
48+
W = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
49+
50+
for i in range(lon.size):
51+
for j in range(lat.size):
52+
x1 = lon[i] - dx / 2
53+
x2 = lat[j] - dy / 2
54+
for t in range(len(times)):
55+
time = times[t]
56+
57+
f1 = eps1 * np.exp(-1j * k1 * c1 * time)
58+
f2 = eps2 * np.exp(-1j * k2 * c2 * time)
59+
f3 = eps3 * np.exp(-1j * k3 * c3 * time)
60+
F1 = f1 * np.exp(1j * k1 * x1)
61+
F2 = f2 * np.exp(1j * k2 * x1)
62+
F3 = f3 * np.exp(1j * k3 * x1)
63+
G = np.real(np.sum([F1, F2, F3]))
64+
G_x = np.real(np.sum([1j * k1 * F1, 1j * k2 * F2, 1j * k3 * F3]))
65+
U[t, 0, j, i] = (
66+
U0 / (np.cosh(x2 / L) ** 2)
67+
+ 2 * U0 * np.sinh(x2 / L) / (np.cosh(x2 / L) ** 3) * G
68+
)
69+
V[t, 0, j, i] = U0 * L * (1.0 / np.cosh(x2 / L)) ** 2 * G_x
70+
71+
# Add a linear decay in depth
72+
for k in range(1, depth.size):
73+
U[:, k, :, :] = U[:, 0, :, :] * ( (depth.size - k) / depth.size)
74+
V[:, k, :, :] = V[:, 0, :, :] * ( (depth.size - k) / depth.size)
75+
76+
# Construct the fieldset
77+
data = {"U": U, "V": V, "W": W}
78+
dimensions = {"lon": lon, "lat": lat, "depth": depth, "time": times}
79+
allow_time_extrapolation = True if len(times) == 1 else False
80+
fieldset = parcels.FieldSet.from_data(
81+
data, dimensions, mesh="flat", allow_time_extrapolation=allow_time_extrapolation
82+
)
83+
84+
fieldset.U.interp_method = "cgrid_velocity"
85+
fieldset.V.interp_method = "cgrid_velocity"
86+
fieldset.W.interp_method = "cgrid_velocity"
87+
88+
# Add a flat bathymetry field
89+
bathymetry = np.zeros((lat.size, lon.size), dtype=np.float32)
90+
bathymetry[:, :] = depth[-1]
91+
data = {"bathymetry": bathymetry}
92+
dimensions = {"lon": lon, "lat": lat}
93+
94+
fieldsetBathymetry = parcels.FieldSet.from_data(
95+
data, dimensions, mesh="flat"
96+
)
97+
98+
fieldset.add_field(fieldsetBathymetry.bathymetry)
99+
100+
# Add in an unbeaching field
101+
unbeach_U = np.zeros((lat.size, lon.size), dtype=np.float32)
102+
unbeach_V = np.zeros((lat.size, lon.size), dtype=np.float32)
103+
104+
unbeach_V[0,:] = 1.0 # Meridional unbeaching at the top and bottom of the domain
105+
unbeach_V[-1,:] = -1.0
106+
107+
data = {"unbeach_U": unbeach_U, "unbeach_V": unbeach_V}
108+
dimensions = {"lon": lon, "lat": lat}
109+
110+
fieldsetunbeaching = parcels.FieldSet.from_data(
111+
data, dimensions, mesh="flat"
112+
)
113+
114+
fieldset.add_field(fieldsetunbeaching.unbeach_U)
115+
fieldset.add_field(fieldsetunbeaching.unbeach_V)
116+
117+
118+
return fieldset
119+
120+
def add_uniform_temp_salt_field(fieldset, times):
121+
""" Add a uniform temperature and salinity field to the fieldset.
122+
The temperature/salinity field is time-invariant and has a linear decay with depth.
123+
Of course, this makes no sense in reality, but it is a simple example."""
124+
lon = fieldset.U.grid.lon
125+
lat = fieldset.U.grid.lat
126+
depth = fieldset.U.grid.depth
127+
128+
T = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
129+
S = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
130+
131+
T[:, 0, :, :] = 25.0
132+
S[:, 0, :, :] = 35.0
133+
134+
for d in range(1, depth.size):
135+
T[:, d, :, :] = T[:, 0, :, :]
136+
S[:, d, :, :] = S[:, 0, :, :]
137+
138+
data = {"conservative_temperature": T, "absolute_salinity": S}
139+
140+
dimensions = {"lon": lon, "lat": lat, "depth": depth, "time": times}
141+
allow_time_extrapolation = True if len(times) == 1 else False
142+
fieldsetTS = parcels.FieldSet.from_data(
143+
data, dimensions, mesh="flat", allow_time_extrapolation=allow_time_extrapolation
144+
)
145+
146+
#fieldsetTS.add_periodic_halo(zonal=True)
147+
fieldset.add_field(fieldsetTS.conservative_temperature)
148+
fieldset.add_field(fieldsetTS.absolute_salinity)
149+
150+
return fieldset
151+
152+
def add_biogeochemistry_field(fieldset, times):
153+
lon = fieldset.U.grid.lon # Is this right?
154+
lat = fieldset.U.grid.lat
155+
depth = fieldset.U.grid.depth
156+
157+
pp_phyto = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
158+
bio_nanophy = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
159+
bio_diatom = np.zeros((times.size, depth.size, lat.size, lon.size), dtype=np.float32)
160+
161+
162+
_, yy = np.meshgrid(fieldset.U.grid.lon, fieldset.U.grid.lat)
163+
r0 = 6371.0
164+
_, dy = np.pi * r0, 7000.0 # domain size
165+
f_pp_phyto = np.abs(np.cos(16. * yy / dy))
166+
f_bio_nanophy = np.abs(np.cos(8. * yy / dy + np.pi / 24.)) # shifted
167+
f_bio_diatom = np.abs(np.cos(4. * yy / dy - np.pi / 24.)) # shifted
168+
169+
pp_phyto[:, 0, :, :] = 50. * f_pp_phyto # TODO: Get the units right!
170+
bio_nanophy[:, 0, :, :] = 5. * f_bio_nanophy
171+
bio_diatom[:, 0, :, :] = 10. * f_bio_diatom
172+
173+
for d in range(1, depth.size):
174+
pp_phyto[:, d, :, :] = pp_phyto[:, 0, :, :] * ( (depth.size - 0.5 * d) / depth.size)
175+
bio_nanophy[:, d, :, :] = bio_nanophy[:, 0, :, :] * ( (depth.size - 0.5 * d) / depth.size)
176+
bio_diatom[:, d, :, :] = bio_diatom[:, 0, :, :] * ( (depth.size - 0.5 * d) / depth.size)
177+
178+
data = {"pp_phyto": pp_phyto, "bio_nanophy": bio_nanophy, "bio_diatom": bio_diatom}
179+
180+
dimensions = {"lon": lon, "lat": lat, "depth": depth, "time": times}
181+
allow_time_extrapolation = True if len(times) == 1 else False
182+
fieldsetbgc = parcels.FieldSet.from_data(
183+
data, dimensions, mesh="flat", allow_time_extrapolation=allow_time_extrapolation
184+
)
185+
186+
fieldset.add_field(fieldsetbgc.pp_phyto)
187+
fieldset.add_field(fieldsetbgc.bio_nanophy)
188+
fieldset.add_field(fieldsetbgc.bio_diatom)
189+
190+
return fieldset
191+
192+
193+
def add_wind_field(fieldset, times):
194+
""" Horizontal wind field with a sinusoidal variation in time."""
195+
lon = fieldset.U.grid.lon
196+
lat = fieldset.U.grid.lat
197+
198+
wind_U = np.zeros((times.size, lat.size, lon.size), dtype=np.float32)
199+
wind_V = np.zeros((times.size, lat.size, lon.size), dtype=np.float32)
200+
201+
_, yy = np.meshgrid(fieldset.U.grid.lon, fieldset.U.grid.lat)
202+
r0 = 6371.0
203+
_, dy = np.pi * r0, 7000.0 # domain size
204+
f_wind = np.cos(yy/dy)
205+
206+
wind_U[0, :, :] = 10. * f_wind
207+
208+
# Vary the wind speed with time
209+
for time in range(1, times.size):
210+
wind_U[time, :, :] = wind_U[0, :, :] * np.sin(2. * np.pi * time / times.size)
211+
212+
data = {"Wind_U": wind_U, "Wind_V": wind_V}
213+
214+
dimensions = {"lon": lon, "lat": lat, "time": times}
215+
allow_time_extrapolation = True if len(times) == 1 else False
216+
fieldsetwind = parcels.FieldSet.from_data(
217+
data, dimensions, mesh="flat", allow_time_extrapolation=allow_time_extrapolation
218+
)
219+
220+
fieldset.add_field(fieldsetwind.Wind_U)
221+
fieldset.add_field(fieldsetwind.Wind_V)
222+
223+
return fieldset
224+
225+
def add_stokes_field(fieldset, times):
226+
""" Horizontal wave field that varies in time."""
227+
lon = fieldset.U.grid.lon
228+
lat = fieldset.U.grid.lat
229+
230+
stokes_U = np.zeros((times.size, lat.size, lon.size), dtype=np.float32)
231+
stokes_V = np.zeros((times.size, lat.size, lon.size), dtype=np.float32)
232+
wave_Tp = np.zeros((times.size, lat.size, lon.size), dtype=np.float32)
233+
234+
xx, yy = np.meshgrid(fieldset.U.grid.lon, fieldset.U.grid.lat)
235+
r0 = 6371.0
236+
dx, dy = np.pi * r0, 7000.0 # domain size
237+
238+
stokes_U[0, :, :] = 5. * np.sin(xx * np.pi / (dx) )
239+
wave_Tp[0, :, :] = 10. * np.cos(yy/dy)
240+
241+
# Vary in time
242+
for time in range(1, times.size):
243+
stokes_U[time, :, :] = stokes_U[0, :, :] * np.sin(2. * np.pi * time / times.size)
244+
wave_Tp[time, :, :] = wave_Tp[0, :, :]
245+
246+
data = {"Stokes_U": stokes_U, "Stokes_V": stokes_V, 'wave_Tp': wave_Tp}
247+
248+
dimensions = {"lon": lon, "lat": lat, "time": times}
249+
allow_time_extrapolation = True if len(times) == 1 else False
250+
fieldsetStokes = parcels.FieldSet.from_data(
251+
data, dimensions, mesh="flat", allow_time_extrapolation=allow_time_extrapolation
252+
)
253+
254+
fieldset.add_field(fieldsetStokes.Stokes_U)
255+
fieldset.add_field(fieldsetStokes.Stokes_V)
256+
fieldset.add_field(fieldsetStokes.wave_Tp)
257+
258+
return fieldset

docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ Required Data
3434
* Wave data: `ECMWF ERA5 Wave <https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels>`_ (specifically, the variables ``mean_wave_period``, ``peak_wave_period``, ``u_component_stokes_drift``, and ``v_component_stokes_drift``.)
3535
* Wind data: `ECMWF ERA5 Wind <https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels>`_ (specifically, the variables ``10m_u_component_of_wind`` and ``10m_v_component_of_wind``)
3636

37-
For the wind and wave data, we recommend using the `CDS API <https://cds.climate.copernicus.eu/api-how-to>`_.
37+
For downloading the wind and wave data, we recommend using the `CDS API <https://cds.climate.copernicus.eu/api-how-to>`_.
3838

39-
To run the examples, you will need to update the data directories in settings ``.json`` files.
39+
To run the examples, you will need to update the data directories in the relevant settings ``.json`` file.
4040

4141
Just like the ``parcels`` framework, ``plasticparcels`` can be adapted to use other hydrodynamic, biogeochemical, wave, and atmospheric models. If you require assistance, please contact us through the `Discussions page on GitHub <https://github.com/OceanParcels/plasticparcels/discussions>`_.
4242

0 commit comments

Comments
 (0)