🎓 Parcels v4 migration guide#

This migration guide gives some tips if you want to migrate your Parcels v3 code to Parcels v4. The biggest changes are in the Kernel API and the way that FieldSets are created. The other changes are mostly small and should be easy to fix.

Description of change
How to migrate

Kernels#

The Kernel API has had some major changes (see also below)
Add the @parcels.validate_kernel decorator above your Kernel function definition to check for errors and warnings.

The Kernel loop is 'vectorized': the input of a Kernel is a collection of particles
Replace if-statements with numpy.where statements or boolean indexing

Functions should work on a collection of particles instead of a single particle
Use numpy functions instead of math functions

Functions shouldn't be converted to Kernel objects in a pset.execute() call
Simply pass the function(s) as a list to pset.execute()

The time argument in the Kernel signature is removed
Use particle.t

particle.lon, particle.lat and particle.depth are renamed
Use particles.x, particles.y and particles.z

particle_dlon particle_dlat and particle_ddepth are renamed
Use particles.dx, particles.dy and particles.dz

The particle argument in the Kernel signature is renamed to particles
Change the argument name in your Kernel signature to particles

particle.delete() is no longer valid
Use StatusCode.Delete in combination with boolean indexing - as detailed here

Kernels are not concatenated under the hood, so can't access each others variables or states
Use fieldset.context or particle data to share information between kernels

The InteractionKernel class is removed as normal Kernels now have access to all particles
Particle-particle interaction can be performed within normal Kernels

Automatic conversion from depth to sigma grids under the hood is removed
Explicitly use convert_z_to_sigma_croco in sampling kernels (such as the AdvectionRK4_3D_CROCO or SampleOMegaCroco kernels) when working with CROCO data

The default advection scheme is changed from RK4 to RK2 as it is faster while the accuracy is comparable for most applications
Use pset.execute(parcels.AdvectionRK2) for advection

FieldSet#

FieldSet.from_<modelname>() is removed
Convert the model data first to SGrid (for example with a parcels.covert_<MODEL>_to_sgrid() function) and then use FieldSet.from_sgrid_conventions(), as also described in the Quickstart tutorial

FieldSet.interp_method doesn't accept a string (e.g. "linear" or "nearest")
Use an Interpolation function such as parcels.interpolators.Linear or parcels.interpolators.Nearest

FieldSet.add_constant is removed to reflect that this value no longer has to be constant
Use FieldSet.add_context to add a context variable to the FieldSet

Particle#

Particle.add_variable() is removed
Use Particle.add_variables(), which also takes a list of Variables

Parameters indices, timestamps, and time_periodic removed from FieldSet constructors.
Simply manipulate the datasets with Xarray to the same effect before passing them to Parcels.

ParticleSet#

pset.execute() does not require Kernel objects
Simply pass the function(s) as a list to pset.execute()

repeatdt is removed
See the Delayed starts tutorial for how to implement repeated releases of particles

lonlatdepth_dtype is removed
Set the dtype of your particle variables directly

ParticleSet.execute() expects datatime, numpy.datetime64 or numpy.timedelta.64 for runtime and endtime
Update runtime and endtime to use numpy.datetime64 or numpy.timedelta.64

ParticleSet.from_field(), ParticleSet.from_line(), ParticleSet.from_list() are removed
Use the ParticleSet constructor directly

ParticleFile#

ParticleFiles output is in parquet format
Read the output with polars.read_parquet() or (to automatically handle cftime) parcels.read_particlefile(). For compatility with old postprocessing codes, convert the new Parquet output to v3-style zarr output using parcels.particlefile_to_v3_zarr()

ParticleFile is not a method of the ParticleSet class
Use ParticleFile(...) instead of pset.ParticleFile(...)

ParticleFile errors out if there's existing output
Remove the existing output file or add mode="w" to overwrite

The output file does not have a trajectory dimension
Use particle_id instead of trajectory in your code

ParticleFile does not have a name attribute
Use ParticleFile.path, which can be a string or a Path

ParticleFile does not have a chunks argument
Remove the chunks argument from your code

ParticleFile does not have a to_write="once" argument
Either write all timesteps of a variable, or none

Particles are not written when they are deleted
Call ParticleFile.write() inside a kernel to write out deleted particles

Field#

Calling Field.eval() directly gives a warning if any values are out of bounds
Use Field.eval() as before, but check for warnings

Field.eval() returns an array of floats (related to the vectorization)
Use Field.eval() as before, but expect an array of floats instead of a single float

The NestedField class is removed
See the Nested Grids tutorial for how to set up Nested Grids in v4

applyConversion is removed
Interpolation on VectorFields automatically converts from m/s to degrees/s for spherical meshes. Other conversion of units should be handled in Interpolators or Kernels

GridSet#

GridSet is a list
Change fieldset.gridset.grids[0] to fieldset.gridset[0]

UnitConverters#

The UnitConverter class is removed
Remove any UnitConverter usage from your code and Interpolation functions should handle unit conversion internally, based on the units of the coordinate values in the Dataset, or the value of SphericalMesh(radius=...)".