Parcels (Probably A Really Computationally Efficient Lagrangian Simulator) is a set of Python classes and methods to create customisable particle tracking simulations using output from Ocean Circulation models. Parcels focusses on tracking of passive water parcels, as well as active particulates such as plankton, plastic and fish.
The Parcels code is licensed under an open source MIT license and can be downloaded from https://github.com/OceanParcels/parcels.
There is also an extensive documentation of all methods and classes in Parcels.
FieldSet
object. The general method
to use is FieldSet.from_netcdf()
,
which requires filenames
,
variables
and
dimensions
. Each of these is a
dictionary, and variables
requires at
least a U
and
V
, but any other
variable
can be added too (e.g.
temperature, mixedlayerdepth, etc). Note also that
filenames
can contain wildcards. For
example, the GlobCurrent data that is shipped with Parcels can be read
with:
fname = 'GlobCurrent_example_data/*.nc'
filenames = {'U': fname, 'V': fname}
variables = {'U': 'eastward_eulerian_current_velocity', 'V': 'northward_eulerian_current_velocity'}
dimensions = {'lat': 'lat', 'lon': 'lon', 'depth': 'depth', 'time': 'time'}
fset = FieldSet.from_netcdf(filenames, variables, dimensions)
Note that dimensions
can also be a
dictionary-of-dictionaries. For example, if you have wind data on a
completely different grid (and without
depth
dimension), you can do:
fname = 'GlobCurrent_example_data/*.nc'
wname = 'path_to_your_windfiles'
filenames = {'U': fname, 'V': fname, 'wind': wname}
variables = {'U': 'eastward_eulerian_current_velocity', 'V': 'northward_eulerian_current_velocity', 'wind': 'wind'}
dimensions = {}
dimensions['U'] = {'lat': 'lat', 'lon': 'lon', 'depth': 'depth', 'time': 'time'}
dimensions['V'] = {'lat': 'lat', 'lon': 'lon', 'depth': 'depth', 'time': 'time'}
dimensions['wind'] = {'lat': 'latw', 'lon': 'lonw', 'time': 'time'}
fset = FieldSet.from_netcdf(filenames, variables, dimensions)
In a similar way, you can add U
and
V
fields that are on different grids
(e.g. Arakawa C-grids). Parcels will take care under the hood that the
different grids are dealt with properly.
(particle, fieldset, time)
(note that before Parcels v2.0, Kernels also required a
dt
argument)
+
, -
,
*
,
/
,
**
) and assignments (=
).
<
,
==
,
!=
,
>
,
&
,
|
). Note that you can use a
statement like
particle.lon != particle.lon
to
check if particle.lon
is NaN
(since math.nan != math.nan
)
if
and
while
loops, as well as
break
statements. Note that
for
-loops are not supported in
JIT mode
Field
from
the FieldSet
at a
(time, depth, lat, lon)
point,
using using square brackets notation. value = fieldset.U[time, particle.depth, particle.lat, particle.lon]
Also note that it is possible to add the
particle
as an additional
argument to the Field Sampling, so
value = fieldset.U[time, depth, lat, lon, particle]
or simply
value = fieldset.U[particle]
Adding the particle to the sampling can dramatically speed up
simulations in Scipy-mode on Curvilinear Grids, see als the
JIT-vs_Scipy tutorial.
maths
standard library.
ParcelsRandom
library at
parcels.rng
. Note that these
have to be used as
ParcelsRandom.random()
,
ParcelsRandom.uniform()
etc for
the code to compile.
print
statements, such
as:
print("Some print")
print(particle.lon)
print("particle id: %d" % particle.id)
print("lon: %f, lat: %f" % (particle.lon, particle.lat))
ParticleFile
class. The
file/directory contains arrays of at least the
time
,
lon
,
lat
and
z
(depth) of each particle
trajectory, plus any extra custom
Variables
defined in the
pclass
.
Each row in these arrays corresponds to a particle, and each column is an
'observation'. Note that, when particles are added during runtime, their
first position is still stored in the first column, so that not all
particles in the same column necessarily share the same
time
. The time of each observation is
stored in the time
array. See
the output tutorial notebook
for more information.
pset = ParticleSet(fieldset=fieldset, pclass=JITParticle,
lon=np.random.rand(16,1), lat=np.random.rand(16,1))
repeatdt
, e.g. change
pset = ParticleSet(..., lat=np.random.rand(16,1),
repeatdt=timedelta(hours=1))
to
pset = ParticleSet(..., lat=np.random.rand(16,1))
fieldset = FieldSet.from_netcdf(files, variables, dimensions)
fieldset = FieldSet.from_netcdf(files, variables, dimensions,
deferred_load=True, field_chunksize='auto')
Hence, if you are using an older version of Parcels (<= 2.1.0), or you
have accidentally switched of chunking via
fieldset = FieldSet.from_netcdf(..., field_chunksize=False)
, then you may exceed your available memory. Try out the latest version
of Parcels and activate field chunking.
(time steps, depth size, latitude size, longitude size)
, so e.g.
fieldset = FieldSet.from_netcdf(files, variables, dimensions,
field_chunksize=(1,8,128,128))
fieldset = FieldSet.from_netcdf(files, variables, dimensions,
field_chunksize={'time_counter': 1, 'depth': 8, 'nav_lat': 128,
'nav_lon': 128})
field_chunksize='auto'
may not
provided you with the expected result. If you want to adapt this
behaviour without manually tuning every application and scenario
script, then you can configure the auto-chunking function itself.
Information on how to adapt the auto-chunking can be found in the
Dask documentation. Dask itself can use a term in the Dask configuration file, which
defines a new upper limit for a chunked array. Detailed
information and guidance on the configuration file can be found in the
Dask guidelines.
As a short summary: when having installed Dask, there is a (hidden)
user-defined folder in your home directory
${HOME}/.config/dask
that has two files:
dask.yaml
and distributed.yaml
. The second
one is of less interest for you unless you have distributed file
management (if unsure, contact your system administrator). Under
normal conditions, Dask will read configuration parameters from
dask.yaml
. That file could look like this (default
after installation):
# temporary-directory: null # Directory for local disk like /tmp, /scratch, or /local # array: # svg: # size: 120 # pixelsYou can adapt this so the chunks, for example, are smaller, which improves loading and allows multiple simultaneous fields being accessed without exceeding memory.
temporary-directory: /tmp array: svg: size: 120 # pixels chunk-size: 128 MiBAnother very important change is that we removed the
#
from the start of the lines,
which transforms them from being comments into actual
information. Of course, if you have e.g. 4 fields, then you may
want to change 128 MiB into 32 MiB. Power-of-two sizes
here are also advantageous, although not strictly necessary.