Repository: OceanParcels/Parcels (language: python)

Issue:
Documentation revamp
I'll use this issue to outline the ideas I have for the documentation, so that discussion can be centralised here with PRs linking back to this. Any of these points are up for discussion. I'm happy to work on all of these (although may need some additional help with config). If anyone else would like to contribute to a bulletpoint, drop a comment 🙂 (although there's no expectation on my end).

As these changes get implemented, I will edit this description adding the PR numbers to the bullet points.

# Changes
## Major changes
- [x] Documentation restructure
  - Add sectioning to the documentation, breaking apart the documentation into its conceptual components so that it isn't one large page.
- [x] Migrate to PyData theme (#1321)
  - The PyData theme is a much cleaner theme, with more features.
- [x] Create contribution guidelines for `parcels`
  - Having guidelines that contributors can follow would be good to communicate the standards adopted by the codebase.
  - The contributing [guidelines from geopandas](https://geopandas.org/en/stable/community/contributing.html) might be good to copy and slightly adapt to our purposes (ie. we only support Python 3.8+ (@erikvansebille it would be good to confirm this, I'm going off the `environment_*.yml` files), we don't use `black`, and [commit message conventions](https://geopandas.org/en/stable/community/contributing.html#commit-message-conventions) might be a bit extra for the size of this project).
  - The contribution guidelines can be its own page on the documentation website.
  - Perhaps [oceanparcels.org](https://oceanparcels.org) can be updated to link to the contributing page for dev installs.
- [x] Use [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) to monitor docstring quality (#1321)
- [x] Migrate docstring format to the [Numpy Docstring Standard](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard)
  - The `rst` format is quite difficult to read when displayed in IDEs.
  - Due to this ^, the Numpy Docstring Standard has been adopted by many other scientific packages (numpy, pandas, geopandas, xarray, to name a few).
  - Existing docstrings can be easily converted from `rst` format into Numpy format using [`pyment`](https://pypi.org/project/pyment/).
  - Compiling and [validation](https://numpydoc.readthedocs.io/en/latest/validation.html) of Numpy docstrings is possible in the build process through Sphinx with the `numpydoc` package. This validation is in extension to `flake8-docstrings`, making sure that the docstring is in the Numpy standard format.
  - The validation step is particularly important to make sure breaking documentation changes fail CI/CD on pull requests, allowing them to be changed before being merged into main (the ReadTheDocs integration feature just below will greatly help with viewing documentation changes, and failing builds that break validation rules).
- [x] ReadTheDocs build on pull requests
  - ReadTheDocs can [build on pull requests, and report build status back to GitHub](https://docs.readthedocs.io/en/stable/pull-requests.html#features). This can be [set up in the ReadTheDocs panel](https://docs.readthedocs.io/en/stable/guides/pull-requests.html) (@erikvansebille your help here would be great).
- [x] Type annotations and static typechecking
  - Having type annotations will greatly help with documentation, and reduce ambiguity amongst users on the types of different parameters.
  - Using `mypy` to do static typechecking will validate type annotations, making sure internally `parcels` is correctly typed.
- [x] Improve support for documentation notebooks
  - Automatically link functions/classes to example notebooks in which they are called.
  - Generally increase the visibility of the example notebooks (eg. perhaps creating a gallery; although [oceanparcels.org](https://oceanparcels.org) does a good job of that already).
  - Still need to explore the viability of this feature, and how it will be implemented 🤔

## Minor changes
- [x] Have "view source" links in documentation link directly back to GitHub (#1321)
- [x] Disable search engine indexing of old documentation

## Bugfixes
- [x] ReadTheDocs + Pydata theme compatability
  - Currently on [my ReadTheDocs (`docs` branch)](https://veckoparcels.readthedocs.io/en/docs/) the PyData theme makes the dropdown (to switch between the different versions) completely disappear.

# Notes
PRs will be made into the `new_docs` branch to act as a staging area before they are rolled out to the community. Once this issue is completed, we'll merge `new_docs` to `master`.

---
The type annotation and docstring specific changes will mainly be applied to the following modules which are currently part of the documentation website as defined in the `.. automodule::` calls in `docs/index.rst`:

- `parcels.particleset.particlesetsoa`
- `parcels.fieldset`
- `parcels.field`
- `parcels.gridset`
- `parcels.grid`
- `parcels.particle`
- `parcels.application_kernels.advection`
- `parcels.application_kernels.advectiondiffusion`
- `parcels.application_kernels.EOSseawaterproperties`
- `parcels.application_kernels.TEOSseawaterdensity`
- `parcels.compilation`
- `parcels.interaction`
- `parcels.interaction.neighborsearch`
- `parcels.kernel.basekernel`
- `parcels.kernel.kernelaos`
- `parcels.kernel.kernelsoa`
- `parcels.particlefile.baseparticlefile`
- `parcels.particlefile.particlefileaos`
- `parcels.particlefile.particlefilesoa`
- `parcels.rng`
- `parcels.particleset.baseparticleset`
- `parcels.particleset.particlesetaos`
- `parcels.tools.statuscodes`
- `parcels.tools.converters`
- `parcels.tools.loggers`
- `parcels.plotting`
- `parcels.scripts.plottrajectoriesfile`
- `parcels.scripts.get_examples`

DOC: API reference restructure, contributing guidelines, and more...
Part of #1324

- [x] API reference sectioning (making it easier to navigate)
  - Used the same modules that were covered in the prior documentation
- [x] Add contributing guidelines
- [x] Version switcher
  - Waiting on feedback from https://github.com/pydata/pydata-sphinx-theme/pull/1005#issuecomment-1493381984 about whether the version switcher from RTD can be used by default on desktop machines. Will see how to proceed from there.
    - Won't fix
- [x] Disable search engine indexing of previous versions
- [x] Automatic updating of copyright year (as per https://github.com/OceanParcels/parcels/pull/1341#issuecomment-1493318063)
- [x] Add support for markdown
- [x] Add backlink in navbar to OceanParcels website
- [x] Render grids in docstrings as raw text (rather than HTML table)
- [x] Rendering improvements (fixing numbered lists, inline code formatting)

[RTD deployment](https://veckoparcels.readthedocs.io/en/my_docs-new_layout/). Keen to hear what you think about these changes @erikvansebille


Discussion / hints:

Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5405bdd93..fca003d17 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,6 +10,10 @@ repos:
     rev: '6.0.0'
     hooks:
     -   id: flake8
+-   repo: https://github.com/pycqa/pydocstyle
+    rev: 4.0.0  # pick a git hash / tag to point to
+    hooks:
+    -   id: pydocstyle
 -   repo: https://github.com/pycqa/isort
     rev: 5.12.0
     hooks:
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index e6d49aa27..05ea1a4fa 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -3,5 +3,9 @@ build:
   os: ubuntu-22.04
   tools:
     python: mambaforge-4.10
+
+sphinx:
+  configuration: docs/conf.py
+
 conda:
   environment: environment_py3_linux.yml
diff --git a/README.md b/README.md
index 68e710a98..79da95707 100644
--- a/README.md
+++ b/README.md
@@ -10,15 +10,19 @@
 
 The manuscript detailing the first release of Parcels, version 0.9, has been published in [Geoscientific Model Development](https://www.geosci-model-dev.net/10/4175/2017/gmd-10-4175-2017.html) and can be cited as
 
-*Lange, M. and E van Sebille (2017) Parcels v0.9: prototyping a Lagrangian Ocean Analysis framework for the petascale age. Geoscientific Model Development, 10, 4175-4186. https://doi.org/10.5194/gmd-2017-167*
+*Lange, M and E van Sebille (2017) Parcels v0.9: prototyping a Lagrangian Ocean Analysis framework for the petascale age. Geoscientific Model Development, 10, 4175-4186. https://doi.org/10.5194/gmd-2017-167*
 
 The manuscript detailing version 2.0 of Parcels is available at [Geoscientific Model Development](https://www.geosci-model-dev.net/12/3571/2019/gmd-12-3571-2019-discussion.html) and can be cited as:
 
-*Delandmeter P. and E van Sebille (2019) The Parcels v2.0 Lagrangian framework: new field interpolation schemes. Geoscientific Model Development, 12, 3571-3584. https://doi.org/10.5194/gmd-12-3571-2019*
+*Delandmeter, P and E van Sebille (2019) The Parcels v2.0 Lagrangian framework: new field interpolation schemes. Geoscientific Model Development, 12, 3571-3584. https://doi.org/10.5194/gmd-12-3571-2019*
+
+The manuscript detailing the performance of Parcels v2.4 is available at [Computers & Geosciences](https://doi.org/10.1016/j.cageo.2023.105322) and can be cited as:
+
+*Kehl, C, PD Nooteboom, MLA Kaandorp and E van Sebille (2023) Efficiently simulating Lagrangian particles in large-scale ocean flows — Data structures and their impact on geophysical applications, Computers and Geosciences, 175, 105322. https://doi.org/10.1016/j.cageo.2023.105322*
 
 ### Further information
 
-See [oceanparcels.org](http://oceanparcels.org/) for further information about [installing](http://oceanparcels.org/#installing) and [running](http://oceanparcels.org/#tutorials) the Parcels code, as well as extended [documentation](http://oceanparcels.org/gh-pages/html/) of the methods and classes.
+See [oceanparcels.org](http://oceanparcels.org/) for further information about [installing](http://oceanparcels.org/#installing) and [running](http://oceanparcels.org/#tutorials) the Parcels code, as well as extended [documentation](https://parcels.readthedocs.io) of the methods and classes.
 
 
 ### Launch Parcels Tutorials on mybinder.org
diff --git a/docs/Makefile b/docs/Makefile
index 8db75bac0..580347a22 100755
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -5,7 +5,7 @@
 SPHINXOPTS    =
 SPHINXBUILD   = sphinx-build
 PAPER         =
-BUILDDIR      = ../../oceanparcels_website/gh-pages
+BUILDDIR      = _build
 
 # User-friendly check for sphinx-build
 ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
diff --git a/docs/ParticleSetHierarchy_basic_framework.drawio b/docs/_static/diagrams/ParticleSetHierarchy_basic_framework.drawio
similarity index 100%
rename from docs/ParticleSetHierarchy_basic_framework.drawio
rename to docs/_static/diagrams/ParticleSetHierarchy_basic_framework.drawio
diff --git a/docs/ParticleSet_UML.drawio b/docs/_static/diagrams/ParticleSet_UML.drawio
similarity index 100%
rename from docs/ParticleSet_UML.drawio
rename to docs/_static/diagrams/ParticleSet_UML.drawio
diff --git a/docs/_static/parcelslogo-inverted.png b/docs/_static/parcelslogo-inverted.png
new file mode 100644
index 000000000..89aa520a3
Binary files /dev/null and b/docs/_static/parcelslogo-inverted.png differ
diff --git a/docs/parcelslogo.png b/docs/_static/parcelslogo.png
similarity index 100%
rename from docs/parcelslogo.png
rename to docs/_static/parcelslogo.png
diff --git a/docs/conf.py b/docs/conf.py
index d304cfd89..fa6fc5998 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -11,8 +11,11 @@
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
+import datetime
+import inspect
 import os
 import sys
+import warnings
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -30,7 +33,11 @@
 extensions = [
     'sphinx.ext.autodoc',
     'sphinx.ext.todo',
-    'sphinx.ext.viewcode',
+    "sphinx.ext.linkcode",
+    "sphinx.ext.mathjax",
+    "sphinx.ext.napoleon",
+    "myst_parser",
+    "numpydoc",
 ]
 
 # Add any paths that contain templates here, relative to this directory.
@@ -49,7 +56,7 @@
 
 # General information about the project.
 project = 'Parcels'
-copyright = '2022, The OceanParcels Team'
+copyright = f'{datetime.datetime.now().year}, The OceanParcels Team'
 author = 'The OceanParcels Team'
 
 # The version info for the project you're documenting, acts as replacement for
@@ -57,9 +64,11 @@
 # built documents.
 #
 # The short X.Y version.
-version = '2.4.0'
+import parcels  # noqa: E402
+
+version = parcels.__version__
 # The full version, including alpha/beta/rc tags.
-release = '2.4.0'
+release = version
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -94,7 +103,7 @@
 # show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = 'monokai'
 
 # A list of ignored prefixes for module index sorting.
 # modindex_common_prefix = []
@@ -105,12 +114,11 @@
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = True
 
-
 # -- Options for HTML output ----------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'bizstyle'
+html_theme = 'pydata_sphinx_theme'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -127,24 +135,119 @@
 # A shorter title for the navigation bar.  Default is the same as html_title.
 # html_short_title = None
 
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-html_logo = 'parcelslogo.png'
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-# html_favicon = None
+html_favicon = "favicon.ico"
+
+# numpydoc support
+# ----------------
+numpydoc_class_members_toctree = False  # https://stackoverflow.com/a/73294408
+
+# full list of numpydoc error codes: https://numpydoc.readthedocs.io/en/latest/validation.html
+numpydoc_validation_checks = {
+    "GL05",
+    "GL06",
+    "GL07",
+    "GL10",
+    "PR05",
+    "PR10",
+    "RT02",
+}
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
+html_theme_options = {
+    "logo": {
+        "image_light": "parcelslogo.png",
+        "image_dark": "parcelslogo-inverted.png",
+    },
+    "use_edit_page_button": True,
+    "github_url": "https://github.com/OceanParcels/parcels",
+    "icon_links": [
+        {
+            "name": "Conda Forge",
+            "url": "https://anaconda.org/conda-forge/parcels",  # required
+            "icon": "fa-solid fa-box",
+            "type": "fontawesome",
+        }
+    ]
+}
+
+html_context = {
+    "github_user": "OceanParcels",
+    "github_repo": "parcels",
+    "github_version": "master",
+    "doc_path": "docs",
+}
+
+
+# based on pandas doc/source/conf.py
+def linkcode_resolve(domain, info):
+    """Determine the URL corresponding to Python object."""
+    if domain != "py":
+        return None
+
+    modname = info["module"]
+    fullname = info["fullname"]
+
+    submod = sys.modules.get(modname)
+    if submod is None:
+        return None
+
+    obj = submod
+    for part in fullname.split("."):
+        try:
+            with warnings.catch_warnings():
+                # Accessing deprecated objects will generate noisy warnings
+                warnings.simplefilter("ignore", FutureWarning)
+                obj = getattr(obj, part)
+        except AttributeError:
+            return None
+
+    try:
+        fn = inspect.getsourcefile(inspect.unwrap(obj))
+    except TypeError:
+        try:  # property
+            fn = inspect.getsourcefile(inspect.unwrap(obj.fget))
+        except (AttributeError, TypeError):
+            fn = None
+    if not fn:
+        return None
+
+    try:
+        source, lineno = inspect.getsourcelines(obj)
+    except TypeError:
+        try:  # property
+            source, lineno = inspect.getsourcelines(obj.fget)
+        except (AttributeError, TypeError):
+            lineno = None
+    except OSError:
+        lineno = None
+
+    if lineno:
+        linespec = f"#L{lineno}-L{lineno + len(source) - 1}"
+    else:
+        linespec = ""
+
+    fn = os.path.relpath(fn, start=os.path.dirname(parcels.__file__))
+
+    if "-" in parcels.__version__:
+        return f"https://github.com/OceanParcels/parcels/blob/master/parcels/{fn}{linespec}"
+    else:
+        return (
+            f"https://github.com/OceanParcels/parcels/blob/"
+            f"{parcels.__version__}/parcels/{fn}{linespec}"
+        )
+
 
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
 # directly to the root of the documentation.
-# html_extra_path = []
+html_extra_path = ["robots.txt"]
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 000000000..5a12dbc2f
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,54 @@
+# Contributing to parcels
+
+We welcome all contributions to the OceanParcels project! Whether you're a seasoned programmer or just getting started, there are many ways you can help us make our project better.
+Even if you don't want to contribute directly to the codebase, getting involved in discussions and issues are great ways to help out with the project.
+
+This document outlines some guidelines for contributing to the parcels codebase. If you have any questions or suggestions for how we can improve this document, please let us know.
+
+## Getting Started
+
+To get started contributing to parcels, you'll need to do a few things:
+
+1. [Fork our repository](https://github.com/OceanParcels/parcels/fork) on GitHub.
+
+2. Clone your fork of the repository to your local machine, and `cd` into your project folder.
+
+3. Install [Anaconda](https://www.anaconda.com/products/distribution) (if you haven't already).
+
+4. Install the development Anaconda environment by installing from the environment file corresponding to your OS (`environment_py3_linux.yml`, `environment_py3_osx.yml` or `environment_py3_win.yml`) then activate it. E.g. on Linux: `conda env create -f environment_py3_linux.yml` then `conda activate py3_parcels`.
+
+5. Install your local copy of parcels in editable mode by running `pip install -e .`.
+
+6. **Optional:** Setup `pre-commit` hooks by running `pre-commit install`. This ensures that code is formatted correctly before you commit it.
+
+
+## Making Changes
+
+Once you have a working environment, you can start making changes to the code! Here are some general guidelines to follow when making changes:
+
+* Follow the [NumPy docstring conventions](https://numpydoc.readthedocs.io/en/latest/format.html) when adding or modifying docstrings.
+
+* Follow the [PEP 8](https://peps.python.org/pep-0008/) style guide when writing code. This codebase also uses [flake8](https://flake8.pycqa.org/en/latest/) and [isort](https://pycqa.github.io/isort/) to ensure a consistent code style (these tools are run automatically by pre-commit).
+
+* Use Git to manage your changes. Create a new branch for each feature or bug fix.
+
+* Write clear commit messages that explain the changes you've made.
+
+* Include tests for any new code you write.
+
+* Submit your changes as a pull request to the `master` branch, and wait for feedback!
+
+
+```{note}
+Feel free to create an issue for your proposed feature or change to the codebase so that feedback can be given.
+Submitting a "draft pull request" is also a great way to give visibility to your branch during development, allowing for faster feedback.
+```
+
+
+## Working with documentation
+
+The documentation for this project is processed by Sphinx. To view documentation from your changes, you can run
+`sphinx-autobuild docs docs/_build` to create a server to automatically rebuild the documentation when you make changes.
+
+
+If you have any questions or issues while contributing to parcels, please feel free to [open a discussion](https://github.com/OceanParcels/parcels/discussions). Thank you for your contributions!
diff --git a/docs/favicon.ico b/docs/favicon.ico
new file mode 100644
index 000000000..cef0c2da1
Binary files /dev/null and b/docs/favicon.ico differ
diff --git a/docs/index.rst b/docs/index.rst
index 8a3ec22ad..18b20930c 100755
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,221 +1,18 @@
-.. parcels documentation master file, created by
-   sphinx-quickstart on Tue Oct 20 09:58:20 2015.
-   You can adapt this file completely to your liking, but it should at least
-   contain the root `toctree` directive.
-
-:tocdepth: 2
-
 Parcels documentation
 ===================================
 
-Welcome to the documentation of parcels. This page provides detailed documentation for each method, class and function.
-The documentation corresponds to the latest conda release, for newer documentation see the docstrings in the code.
-
-See http://www.oceanparcels.org for general information on the Parcels project, including how to install and use.
-
-parcels.particleset module
---------------------------
-
-.. automodule:: parcels.particleset.particlesetsoa
-    :members:
-    :show-inheritance:
-
-parcels.fieldset module
------------------------
-
-.. automodule:: parcels.fieldset
-    :members:
-    :show-inheritance:
-
-parcels.field module
---------------------
-
-.. automodule:: parcels.field
-    :members:
-    :show-inheritance:
-
-parcels.gridset module
-----------------------
-
-.. automodule:: parcels.gridset
-    :members:
-    :show-inheritance:
-
-parcels.grid module
--------------------
-
-.. automodule:: parcels.grid
-    :members:
-    :show-inheritance:
-
-parcels.particle module
------------------------
-
-.. automodule:: parcels.particle
-    :members:
-    :show-inheritance:
-
-parcels.application_kernels.advection module
---------------------------------------------
-
-.. automodule:: parcels.application_kernels.advection
-    :members:
-    :show-inheritance:
-
-parcels.application_kernels.advectiondiffusion module
------------------------------------------------------
-
-
-.. automodule:: parcels.application_kernels.advectiondiffusion
-    :members:
-    :show-inheritance:
-
-parcels.application_kernels.EOSseawaterproperties module
---------------------------------------------------------
-
-
-.. automodule:: parcels.application_kernels.EOSseawaterproperties
-    :members:
-    :show-inheritance:
-
-parcels.application_kernels.TEOSseawaterdensity module
-------------------------------------------------------
-
-
-.. automodule:: parcels.application_kernels.TEOSseawaterdensity
-    :members:
-    :show-inheritance:
-
-parcels.compilation module
---------------------------
-
-.. automodule:: parcels.compilation
-    :members:
-    :show-inheritance: yes
-
-parcels.interaction module
---------------------------
-
-.. automodule:: parcels.interaction
-    :members:
-    :show-inheritance: yes
-
-parcels.interaction.neighborsearch module
------------------------------------------
-
-.. automodule:: parcels.interaction.neighborsearch
-    :members:
-    :show-inheritance: yes
-
-parcels.kernel.basekernel module
---------------------------------
-
-.. automodule:: parcels.kernel.basekernel
-    :members:
-    :undoc-members:
-
-parcels.kernel.kernelaos module
--------------------------------
-
-.. automodule:: parcels.kernel.kernelaos
-    :members:
-    :undoc-members:
-
-parcels.kernel.kernelsoa module
--------------------------------
-
-.. automodule:: parcels.kernel.kernelsoa
-    :members:
-    :undoc-members:
-
-parcels.particlefile.baseparticlefile module
---------------------------------------------
-
-.. automodule:: parcels.particlefile.baseparticlefile
-    :members:
-    :show-inheritance: yes
-
-parcels.particlefile.particlefileaos module
--------------------------------------------
-
-.. automodule:: parcels.particlefile.particlefileaos
-    :members:
-    :show-inheritance: yes
-
-parcels.particlefile.particlefilesoa module
--------------------------------------------
-
-.. automodule:: parcels.particlefile.particlefilesoa
-    :members:
-    :show-inheritance: yes
-
-parcels.rng module
-------------------
-
-.. automodule:: parcels.rng
-    :members:
-    :undoc-members:
-
-parcels.particleset.baseparticleset module
--------------------------------------------
-
-.. automodule:: parcels.particleset.baseparticleset
-    :members:
-    :show-inheritance:
-
-parcels.particleset.particlesetaos module
------------------------------------------
-
-.. automodule:: parcels.particleset.particlesetaos
-    :members:
-    :show-inheritance:
-
-parcels.tools.statuscodes module
---------------------------------
-
-.. automodule:: parcels.tools.statuscodes
-    :members:
-    :show-inheritance:
-
-parcels.tools.converters module
--------------------------------
-
-.. automodule:: parcels.tools.converters
-    :members:
-    :show-inheritance:
-
-parcels.tools.loggers module
-----------------------------
-
-.. automodule:: parcels.tools.loggers
-    :members:
-    :undoc-members:
-
-parcels.plotting module
------------------------
-
-.. automodule:: parcels.plotting
-    :members:
-    :undoc-members:
-
-parcels.scripts.plottrajectoriesfile module
------------------------------------
-
-.. automodule:: parcels.scripts.plottrajectoriesfile
-    :members:
-    :undoc-members:
-
-parcels.scripts.get_examples module
----------------------------
-
-.. automodule:: parcels.scripts.get_examples
-    :members:
-    :undoc-members:
+Welcome to the documentation of Parcels.
+Here, you find the API reference for some recent releases and the latest version of Parcels.
 
+.. note::
+   For background on how to use Parcels for your simulations, see the `tutorials section <https://oceanparcels.org/#tutorials>`_
+   on the `oceanparcels.org <http://oceanparcels.org>`_ site.
 
-Indices and tables
-==================
+.. toctree::
+   :maxdepth: 2
+   :hidden:
 
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+   Home <self>
+   API reference <reference>
+   Contributing <contributing>
+   OceanParcels Website <https://oceanparcels.org/>
diff --git a/docs/make.bat b/docs/make.bat
index 5076bd6f3..9a7cbd8fd 100755
--- a/docs/make.bat
+++ b/docs/make.bat
@@ -5,7 +5,7 @@ REM Command file for Sphinx documentation
 if "%SPHINXBUILD%" == "" (
 	set SPHINXBUILD=sphinx-build
 )
-set BUILDDIR=../../oceanparcels_website/gh-pages
+set BUILDDIR=_build
 set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
 set I18NSPHINXOPTS=%SPHINXOPTS% .
 if NOT "%PAPER%" == "" (
diff --git a/docs/reference.rst b/docs/reference.rst
new file mode 100644
index 000000000..67062e6cf
--- /dev/null
+++ b/docs/reference.rst
@@ -0,0 +1,15 @@
+Parcels API
+===================================
+
+.. toctree::
+  :maxdepth: 2
+
+  Fieldsets and Fields <reference/fields>
+  Particles and particle sets <reference/particles>
+  Particlefile <reference/particlefile>
+  Predefined Kernels <reference/predefined_kernels>
+  User-defined Kernels <reference/userdefined_kernels>
+  Particle-particle interaction <reference/interaction>
+  Gridsets and grids <reference/grids>
+  C Code Generation <reference/code_generation>
+  Miscellaneous <reference/misc>
diff --git a/docs/reference/code_generation.rst b/docs/reference/code_generation.rst
new file mode 100644
index 000000000..780633424
--- /dev/null
+++ b/docs/reference/code_generation.rst
@@ -0,0 +1,16 @@
+C Code Generation
+=================
+
+parcels.compilation.codegenerator module
+--------------------------
+
+.. automodule:: parcels.compilation.codegenerator
+    :members:
+    :show-inheritance: yes
+
+parcels.compilation.codecompiler module
+--------------------------
+
+.. automodule:: parcels.compilation.codecompiler
+    :members:
+    :show-inheritance: yes
diff --git a/docs/reference/fields.rst b/docs/reference/fields.rst
new file mode 100644
index 000000000..9a26548fe
--- /dev/null
+++ b/docs/reference/fields.rst
@@ -0,0 +1,16 @@
+Fieldsets and Fields
+====================
+
+parcels.fieldset module
+-----------------------
+
+.. automodule:: parcels.fieldset
+    :members:
+    :show-inheritance:
+
+parcels.field module
+--------------------
+
+.. automodule:: parcels.field
+    :members:
+    :show-inheritance:
diff --git a/docs/reference/grids.rst b/docs/reference/grids.rst
new file mode 100644
index 000000000..9c9a54e07
--- /dev/null
+++ b/docs/reference/grids.rst
@@ -0,0 +1,16 @@
+Gridsets and grids
+==================
+
+parcels.gridset module
+----------------------
+
+.. automodule:: parcels.gridset
+    :members:
+    :show-inheritance:
+
+parcels.grid module
+-------------------
+
+.. automodule:: parcels.grid
+    :members:
+    :show-inheritance:
diff --git a/docs/reference/interaction.rst b/docs/reference/interaction.rst
new file mode 100644
index 000000000..e9cd525d6
--- /dev/null
+++ b/docs/reference/interaction.rst
@@ -0,0 +1,16 @@
+Particle-field interaction
+==========================
+
+parcels.interaction module
+--------------------------
+
+.. automodule:: parcels.interaction
+    :members:
+    :show-inheritance: yes
+
+parcels.interaction.neighborsearch module
+-----------------------------------------
+
+.. automodule:: parcels.interaction.neighborsearch
+    :members:
+    :show-inheritance: yes
diff --git a/docs/reference/misc.rst b/docs/reference/misc.rst
new file mode 100644
index 000000000..ebb5aca12
--- /dev/null
+++ b/docs/reference/misc.rst
@@ -0,0 +1,51 @@
+Miscellaneous
+=============
+
+parcels.rng module
+------------------
+
+.. automodule:: parcels.rng
+    :members:
+    :undoc-members:
+
+parcels.tools.statuscodes module
+--------------------------------
+
+.. automodule:: parcels.tools.statuscodes
+    :members:
+    :show-inheritance:
+
+parcels.tools.converters module
+-------------------------------
+
+.. automodule:: parcels.tools.converters
+    :members:
+    :show-inheritance:
+
+parcels.tools.loggers module
+----------------------------
+
+.. automodule:: parcels.tools.loggers
+    :members:
+    :undoc-members:
+
+parcels.plotting module
+-----------------------
+
+.. automodule:: parcels.plotting
+    :members:
+    :undoc-members:
+
+parcels.scripts.plottrajectoriesfile module
+-------------------------------------------
+
+.. automodule:: parcels.scripts.plottrajectoriesfile
+    :members:
+    :undoc-members:
+
+parcels.scripts.get_examples module
+-----------------------------------
+
+.. automodule:: parcels.scripts.get_examples
+    :members:
+    :undoc-members:
diff --git a/docs/reference/particlefile.rst b/docs/reference/particlefile.rst
new file mode 100644
index 000000000..125840c7b
--- /dev/null
+++ b/docs/reference/particlefile.rst
@@ -0,0 +1,23 @@
+Particlefile
+============
+
+parcels.particlefile.baseparticlefile module
+--------------------------------------------
+
+.. automodule:: parcels.particlefile.baseparticlefile
+    :members:
+    :show-inheritance: yes
+
+parcels.particlefile.particlefileaos module
+-------------------------------------------
+
+.. automodule:: parcels.particlefile.particlefileaos
+    :members:
+    :show-inheritance: yes
+
+parcels.particlefile.particlefilesoa module
+-------------------------------------------
+
+.. automodule:: parcels.particlefile.particlefilesoa
+    :members:
+    :show-inheritance: yes
diff --git a/docs/reference/particles.rst b/docs/reference/particles.rst
new file mode 100644
index 000000000..aa5ff4848
--- /dev/null
+++ b/docs/reference/particles.rst
@@ -0,0 +1,30 @@
+Particles and particle sets
+===========================
+
+parcels.particle module
+-----------------------
+
+.. automodule:: parcels.particle
+    :members:
+    :show-inheritance:
+
+parcels.particleset module
+--------------------------
+
+.. automodule:: parcels.particleset.particlesetsoa
+    :members:
+    :show-inheritance:
+
+parcels.particleset.baseparticleset module
+-------------------------------------------
+
+.. automodule:: parcels.particleset.baseparticleset
+    :members:
+    :show-inheritance:
+
+parcels.particleset.particlesetaos module
+-----------------------------------------
+
+.. automodule:: parcels.particleset.particlesetaos
+    :members:
+    :show-inheritance:
diff --git a/docs/reference/predefined_kernels.rst b/docs/reference/predefined_kernels.rst
new file mode 100644
index 000000000..c168a4356
--- /dev/null
+++ b/docs/reference/predefined_kernels.rst
@@ -0,0 +1,33 @@
+Predefined Kernels
+===================
+
+parcels.application_kernels.advection module
+--------------------------------------------
+
+.. automodule:: parcels.application_kernels.advection
+    :members:
+    :show-inheritance:
+
+parcels.application_kernels.advectiondiffusion module
+-----------------------------------------------------
+
+
+.. automodule:: parcels.application_kernels.advectiondiffusion
+    :members:
+    :show-inheritance:
+
+parcels.application_kernels.EOSseawaterproperties module
+--------------------------------------------------------
+
+
+.. automodule:: parcels.application_kernels.EOSseawaterproperties
+    :members:
+    :show-inheritance:
+
+parcels.application_kernels.TEOSseawaterdensity module
+------------------------------------------------------
+
+
+.. automodule:: parcels.application_kernels.TEOSseawaterdensity
+    :members:
+    :show-inheritance:
diff --git a/docs/reference/userdefined_kernels.rst b/docs/reference/userdefined_kernels.rst
new file mode 100644
index 000000000..6dbead60d
--- /dev/null
+++ b/docs/reference/userdefined_kernels.rst
@@ -0,0 +1,23 @@
+User-defined Kernels
+====================
+
+parcels.kernel.basekernel module
+--------------------------------
+
+.. automodule:: parcels.kernel.basekernel
+    :members:
+    :undoc-members:
+
+parcels.kernel.kernelaos module
+-------------------------------
+
+.. automodule:: parcels.kernel.kernelaos
+    :members:
+    :undoc-members:
+
+parcels.kernel.kernelsoa module
+-------------------------------
+
+.. automodule:: parcels.kernel.kernelsoa
+    :members:
+    :undoc-members:
diff --git a/docs/robots.txt b/docs/robots.txt
new file mode 100644
index 000000000..df810cf3b
--- /dev/null
+++ b/docs/robots.txt
@@ -0,0 +1,6 @@
+User-agent: *
+Allow: /*/latest/
+Allow: /en/latest/   # Fallback for bots that don't understand wildcards
+Allow: /*/stable/
+Allow: /en/stable/   # Fallback for bots that don't understand wildcards
+Disallow: /
diff --git a/environment_py3_linux.yml b/environment_py3_linux.yml
index ee8d8f812..a2fbaef60 100644
--- a/environment_py3_linux.yml
+++ b/environment_py3_linux.yml
@@ -39,6 +39,11 @@ dependencies:
   # Linting
   - flake8>=2.1.0
   - pre_commit
+  - pydocstyle
 
   # Docs
+  - numpydoc
   - sphinx<6
+  - pydata-sphinx-theme
+  - sphinx-autobuild
+  - myst-parser
diff --git a/environment_py3_osx.yml b/environment_py3_osx.yml
index 9bf9c1028..7280b4d96 100644
--- a/environment_py3_osx.yml
+++ b/environment_py3_osx.yml
@@ -39,6 +39,11 @@ dependencies:
   # Linting
   - flake8>=2.1.0
   - pre_commit
+  - pydocstyle
 
   # Docs
+  - numpydoc
   - sphinx<6
+  - pydata-sphinx-theme
+  - sphinx-autobuild
+  - myst-parser
diff --git a/environment_py3_win.yml b/environment_py3_win.yml
index 9030b1b65..d4c838d1a 100644
--- a/environment_py3_win.yml
+++ b/environment_py3_win.yml
@@ -36,6 +36,11 @@ dependencies:
   # Linting
   - flake8>=2.1.0
   - pre_commit
+  - pydocstyle
 
   # Docs
+  - numpydoc
   - sphinx<6
+  - pydata-sphinx-theme
+  - sphinx-autobuild
+  - myst-parser
diff --git a/parcels/application_kernels/EOSseawaterproperties.py b/parcels/application_kernels/EOSseawaterproperties.py
index baf2ff254..50f6cf156 100644
--- a/parcels/application_kernels/EOSseawaterproperties.py
+++ b/parcels/application_kernels/EOSseawaterproperties.py
@@ -1,4 +1,4 @@
-"""Collection of pre-built eos sea water property kernels"""
+"""Collection of pre-built eos sea water property kernels."""
 import math
 
 __all__ = ['PressureFromLatDepth', 'AdiabticTemperatureGradient', 'PtempFromTemp', 'TempFromPtemp', 'UNESCODensity']
@@ -11,14 +11,13 @@ def PressureFromLatDepth(particle, fieldset, time):
     Returns
     -------
     p : array_like
-           pressure [db]
+        pressure [db]
 
     References
     ----------
-    .. [1] Saunders, Peter M., 1981: Practical Conversion of Pressure to Depth.
+    1. Saunders, Peter M., 1981: Practical Conversion of Pressure to Depth.
        J. Phys. Oceanogr., 11, 573-574.
        doi: 10.1175/1520-0485(1981)011<0573:PCOPTD>2.0.CO;2
-
     """
     # Angle conversions.
     deg2rad = math.pi / 180.0
@@ -29,31 +28,36 @@ def PressureFromLatDepth(particle, fieldset, time):
 
 
 def AdiabticTemperatureGradient(particle, fieldset, time):
-    """
-    Calculates adiabatic temperature gradient as per UNESCO 1983 routines.
+    """Calculates adiabatic temperature gradient as per UNESCO 1983 routines.
+
 
     Parameters
     ----------
-    :param particle.S: salinity [psu (PSS-78)]
-    :type particle.S: array_like
-    :param particle.T: temperature [℃ (ITS-90)]
-    :type particle.T: array_like
-    :param particle.pressure: pressure [db]
-    :type particle.pressure: array_like
+    particle :
+        The particle object with the following attributes:
+            - S : array_like
+                Salinity in psu (PSS-78).
+            - T : array_like
+                Temperature in ℃ (ITS-90).
+            - pressure : array_like
+                Pressure in db.
+    fieldset :
+        The fieldset object
 
     Returns
     -------
-    :return: adiabatic temperature gradient [℃ db :sup:`-1`]
-    :type: array_like
+    array_like
+        Adiabatic temperature gradient in ℃ db⁻¹.
+
 
     References
     ----------
-    .. [1] Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
+    1. Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
        computation of fundamental properties of seawater. UNESCO Tech. Pap. in
        Mar. Sci., No. 44, 53 pp.
        http://unesdoc.unesco.org/images/0005/000598/059832eb.pdf
 
-    .. [2] Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
+    2. Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
        temperature gradient and potential temperature of sea water. Deep-Sea
        Res. Vol20,401-408. doi:10.1016/0011-7471(73)90063-6
 
@@ -80,33 +84,39 @@ def PtempFromTemp(particle, fieldset, time):
 
     Parameters
     ----------
-    :param particle.S: salinity [psu (PSS-78)]
-    :type particle.S: array_like
-    :param particle.T: temperature [℃ (ITS-90)]
-    :type particle.T: array_like
-    :param particle.pressure: pressure [db]
-    :type particle.pressure: array_like
-    :param fieldset.refpressure: reference pressure [db], default = 0
-    :type fieldset.refpressure: array_like
+    particle :
+        The particle object with the following attributes:
+            - S : array_like
+                Salinity in psu (PSS-78).
+            - T : array_like
+                Temperature in ℃ (ITS-90).
+            - pressure : array_like
+                Pressure in db.
+    fieldset :
+        The fieldset object with the following attributes:
+            - refpressure : array_like, optional
+                Reference pressure in db (default is 0).
+    time : float
+        Simulation time (not used in this function but required for consistency with other kernels).
 
     Returns
     -------
-    :return: potential temperature relative to PR [℃ (ITS-90)]
-    :type: array_like
+    array_like
+        Potential temperature relative to reference pressure in ℃ (ITS-90).
+
 
     References
     ----------
-    .. [1] Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
+    1. Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
        computation of fundamental properties of seawater. UNESCO Tech. Pap. in
        Mar. Sci., No. 44, 53 pp.  Eqn.(31) p.39.
        http://unesdoc.unesco.org/images/0005/000598/059832eb.pdf
 
-    .. [2] Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
+    2. Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
        temperature gradient and potential temperature of sea water. Deep-Sea
        Res. Vol20,401-408. doi:10.1016/0011-7471(73)90063-6
 
     """
-
     s = fieldset.psu_salinity[time, particle.depth, particle.lat, particle.lon]
     t = fieldset.temperature[time, particle.depth, particle.lat, particle.lon]
     pres, pr = particle.pressure, fieldset.refpressure
@@ -174,28 +184,34 @@ def TempFromPtemp(particle, fieldset, time):
 
     Parameters
     ----------
-    :param particle.S: salinity [psu (PSS-78)]
-    :type particle.S: array_like
-    :param particle.T: potential temperature [℃ (ITS-90)]
-    :type particle.T: array_like
-    :param particle.pressure: pressure [db]
-    :type particle.pressure: array_like
-    :param fieldset.refpressure: reference pressure [db], default = 0
-    :type fieldset.refpressure: array_like
+    particle :
+        The particle object with the following attributes:
+            - S : array_like
+                Salinity in psu (PSS-78).
+            - T : array_like
+                Potential temperature in ℃ (ITS-90).
+            - pressure : array_like
+                Pressure in db.
+    fieldset :
+        The fieldset object with the following attributes:
+            - refpressure : array_like, optional
+                Reference pressure in db (default is 0).
+    time : float
+        Simulation time (not used in this function but required for consistency with other kernels).
 
     Returns
     -------
-    :return: temperature [℃ (ITS-90)]
-    :type: array_like
+    array_like
+        Temperature in ℃ (ITS-90).
 
     References
     ----------
-    .. [1] Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
+    1. Fofonoff, P. and Millard, R.C. Jr UNESCO 1983. Algorithms for
        computation of fundamental properties of seawater. UNESCO Tech. Pap. in
        Mar. Sci., No. 44, 53 pp.  Eqn.(31) p.39.
        http://unesdoc.unesco.org/images/0005/000598/059832eb.pdf
 
-    .. [2] Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
+    2. Bryden, H. 1973. New Polynomials for thermal expansion, adiabatic
        temperature gradient and potential temperature of sea water. Deep-Sea
        Res.  Vol20,401-408. doi:10.1016/0011-7471(73)90063-6
 
diff --git a/parcels/application_kernels/TEOSseawaterdensity.py b/parcels/application_kernels/TEOSseawaterdensity.py
index e02d162bf..18bff5880 100644
--- a/parcels/application_kernels/TEOSseawaterdensity.py
+++ b/parcels/application_kernels/TEOSseawaterdensity.py
@@ -1,26 +1,27 @@
-"""Collection of pre-built sea water density kernels"""
+"""Collection of pre-built sea water density kernels."""
 import math
 
 __all__ = ['PolyTEOS10_bsq']
 
 
 def PolyTEOS10_bsq(particle, fieldset, time):
-    '''
-    calculates density based on the polyTEOS10-bsq algorithm from Appendix A.2 of
+    """Calculates density based on the polyTEOS10-bsq algorithm from Appendix A.2 of
     https://www.sciencedirect.com/science/article/pii/S1463500315000566
     requires fieldset.abs_salinity and fieldset.cons_temperature Fields in the fieldset
     and a particle.density Variable in the ParticleSet
 
-    References:
-    Roquet, F., Madec, G., McDougall, T. J., Barker, P. M., 2014: Accurate
-    polynomial expressions for the density and specific volume of
-    seawater using the TEOS-10 standard. Ocean Modelling.
-    McDougall, T. J., D. R. Jackett, D. G. Wright and R. Feistel, 2003:
-    Accurate and computationally efficient algorithms for potential
-    temperature and density of seawater.  Journal of Atmospheric and
-    Oceanic Technology, 20, 730-741.
-    '''
+    References
+    ----------
+    1. Roquet, F., Madec, G., McDougall, T. J., Barker, P. M., 2014: Accurate
+       polynomial expressions for the density and specific volume of
+       seawater using the TEOS-10 standard. Ocean Modelling.
 
+    2. McDougall, T. J., D. R. Jackett, D. G. Wright and R. Feistel, 2003:
+       Accurate and computationally efficient algorithms for potential
+       temperature and density of seawater.  Journal of Atmospheric and
+       Oceanic Technology, 20, 730-741.
+
+    """
     Z = - math.fabs(particle.depth)  # Z needs to be negative
     SA = fieldset.abs_salinity[time, particle.depth, particle.lat, particle.lon]
     CT = fieldset.cons_temperature[time, particle.depth, particle.lat, particle.lon]
diff --git a/parcels/application_kernels/advection.py b/parcels/application_kernels/advection.py
index 800e0f02e..c2a441c6c 100644
--- a/parcels/application_kernels/advection.py
+++ b/parcels/application_kernels/advection.py
@@ -1,4 +1,4 @@
-"""Collection of pre-built advection kernels"""
+"""Collection of pre-built advection kernels."""
 import math
 
 from parcels.tools.statuscodes import OperationCode
@@ -10,7 +10,8 @@
 def AdvectionRK4(particle, fieldset, time):
     """Advection of particles using fourth-order Runge-Kutta integration.
 
-    Function needs to be converted to Kernel object before execution"""
+    Function needs to be converted to Kernel object before execution.
+    """
     (u1, v1) = fieldset.UV[particle]
     lon1, lat1 = (particle.lon + u1*.5*particle.dt, particle.lat + v1*.5*particle.dt)
     (u2, v2) = fieldset.UV[time + .5 * particle.dt, particle.depth, lat1, lon1, particle]
@@ -25,7 +26,8 @@ def AdvectionRK4(particle, fieldset, time):
 def AdvectionRK4_3D(particle, fieldset, time):
     """Advection of particles using fourth-order Runge-Kutta integration including vertical velocity.
 
-    Function needs to be converted to Kernel object before execution"""
+    Function needs to be converted to Kernel object before execution.
+    """
     (u1, v1, w1) = fieldset.UVW[particle]
     lon1 = particle.lon + u1*.5*particle.dt
     lat1 = particle.lat + v1*.5*particle.dt
@@ -47,7 +49,8 @@ def AdvectionRK4_3D(particle, fieldset, time):
 def AdvectionEE(particle, fieldset, time):
     """Advection of particles using Explicit Euler (aka Euler Forward) integration.
 
-    Function needs to be converted to Kernel object before execution"""
+    Function needs to be converted to Kernel object before execution.
+    """
     (u1, v1) = fieldset.UV[particle]
     particle.lon += u1 * particle.dt
     particle.lat += v1 * particle.dt
@@ -58,7 +61,8 @@ def AdvectionRK45(particle, fieldset, time):
 
     Times-step dt is halved if error is larger than tolerance, and doubled
     if error is smaller than 1/10th of tolerance, with tolerance set to
-    1e-5 * dt by default."""
+    1e-5 * dt by default.
+    """
     rk45tol = 1e-5
     c = [1./4., 3./8., 12./13., 1., 1./2.]
     A = [[1./4., 0., 0., 0., 0.],
@@ -103,11 +107,12 @@ def AdvectionRK45(particle, fieldset, time):
 
 
 def AdvectionAnalytical(particle, fieldset, time):
-    """Advection of particles using 'analytical advection' integration
+    """Advection of particles using 'analytical advection' integration.
 
     Based on Ariane/TRACMASS algorithm, as detailed in e.g. Doos et al (https://doi.org/10.5194/gmd-10-1733-2017).
     Note that the time-dependent scheme is currently implemented with 'intermediate timesteps'
-    (default 10 per model timestep) and not yet with the full analytical time integration"""
+    (default 10 per model timestep) and not yet with the full analytical time integration.
+    """
     import numpy as np
 
     import parcels.tools.interpolation_utils as i_u
diff --git a/parcels/application_kernels/advectiondiffusion.py b/parcels/application_kernels/advectiondiffusion.py
index 7a9760d08..c41919bdd 100644
--- a/parcels/application_kernels/advectiondiffusion.py
+++ b/parcels/application_kernels/advectiondiffusion.py
@@ -1,6 +1,7 @@
-"""Collection of pre-built advection-diffusion kernels
+"""Collection of pre-built advection-diffusion kernels.
 
-See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`_ for a detailed explanation"""
+See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`__ for a detailed explanation.
+"""
 import math
 
 import parcels.rng as ParcelsRandom
@@ -9,8 +10,7 @@
 
 
 def AdvectionDiffusionM1(particle, fieldset, time):
-    """Kernel for 2D advection-diffusion, solved using the Milstein scheme
-    at first order (M1).
+    """Kernel for 2D advection-diffusion, solved using the Milstein scheme at first order (M1).
 
     Assumes that fieldset has fields `Kh_zonal` and `Kh_meridional`
     and variable `fieldset.dres`, setting the resolution for the central
@@ -47,8 +47,7 @@ def AdvectionDiffusionM1(particle, fieldset, time):
 
 
 def AdvectionDiffusionEM(particle, fieldset, time):
-    """Kernel for 2D advection-diffusion, solved using the Euler-Maruyama
-    scheme (EM).
+    """Kernel for 2D advection-diffusion, solved using the Euler-Maruyama scheme (EM).
 
     Assumes that fieldset has fields `Kh_zonal` and `Kh_meridional`
     and variable `fieldset.dres`, setting the resolution for the central
@@ -88,9 +87,9 @@ def DiffusionUniformKh(particle, fieldset, time):
 
     Assumes that fieldset has constant fields `Kh_zonal` and `Kh_meridional`.
     These can be added via e.g.
-        fieldset.add_constant_field("Kh_zonal", kh_zonal, mesh=mesh)
-
-        fieldset.add_constant_field("Kh_meridional", kh_meridional, mesh=mesh)
+    `fieldset.add_constant_field("Kh_zonal", kh_zonal, mesh=mesh)`
+    or
+    `fieldset.add_constant_field("Kh_meridional", kh_meridional, mesh=mesh)`
     where mesh is either 'flat' or 'spherical'
 
     This kernel assumes diffusivity gradients are zero and is therefore more efficient.
diff --git a/parcels/application_kernels/interaction.py b/parcels/application_kernels/interaction.py
index 7b6ed62aa..3cd5cc268 100644
--- a/parcels/application_kernels/interaction.py
+++ b/parcels/application_kernels/interaction.py
@@ -1,4 +1,4 @@
-"""Collection of pre-built interaction kernels"""
+"""Collection of pre-built interaction kernels."""
 import numpy as np
 
 from parcels.tools.statuscodes import OperationCode, StateCode
@@ -8,7 +8,7 @@
 
 
 def NearestNeighborWithinRange(particle, fieldset, time, neighbors, mutator):
-    """Computes the nearest neighbor within range for each particle
+    """Computes the nearest neighbor within range for each particle.
 
     Particle has to have the nearest_neighbor property. If no particle
     is in range, set nearest_neighbor property to -1.
diff --git a/parcels/collection/collectionaos.py b/parcels/collection/collectionaos.py
index 66710b152..e33dfd2cd 100644
--- a/parcels/collection/collectionaos.py
+++ b/parcels/collection/collectionaos.py
@@ -36,10 +36,12 @@ class ParticleCollectionAOS(ParticleCollection):
 
     def __init__(self, pclass, lon, lat, depth, time, lonlatdepth_dtype, pid_orig, partitions=None, ngrid=1, **kwargs):
         """
-        :param ngrid: number of grids in the fieldset of the overarching ParticleSet - required for initialising the
-        field references of the ctypes-link of particles that are allocated
+        Parameters
+        ----------
+        ngrid :
+            number of grids in the fieldset of the overarching ParticleSet - required for initialising the
+            field references of the ctypes-link of particles that are allocated
         """
-
         super(ParticleCollection, self).__init__()
 
         assert pid_orig is not None, "particle IDs are None - incompatible with the collection. Invalid state."
@@ -152,9 +154,7 @@ def __init__(self, pclass, lon, lat, depth, time, lonlatdepth_dtype, pid_orig, p
         self._riterator = None
 
     def __del__(self):
-        """
-        Collection - Destructor
-        """
+        """Collection - Destructor."""
         super().__del__()
 
     def iterator(self):
@@ -183,7 +183,10 @@ def __getitem__(self, index):
         Access a particle in this collection using the fastest access
         method for this collection - by its index.
 
-        :param index: int or np.int32 index of a particle in this collection
+        Parameters
+        ----------
+        index : int
+            Index of the particle to access
         """
         return self.get_single_by_index(index)
 
@@ -192,7 +195,10 @@ def __getattr__(self, name):
         Access a single property of all particles.
         CAUTION: this function is not(!) in-place and is quite slow
 
-        :param name: name of the property
+        Parameters
+        ----------
+        name : str
+            Name of the property to access
         """
         pdtype = None
         for var in self._ptype.variables:
@@ -879,9 +885,7 @@ def clear(self):
         self._ncount = 0
 
     def cstruct(self):
-        """
-        'cstruct' returns the ctypes mapping of the particle data. This depends on the specific structure in question.
-        """
+        """Returns the ctypes mapping of the particle data. This depends on the specific structure in question."""
         cstruct = self._data_c.ctypes.data_as(c_void_p)
         return cstruct
 
@@ -914,8 +918,7 @@ def setallvardata(self, var, val):
             setattr(self._data[i], var, val)
 
     def toArray(self):
-        """
-        This function converts (or: transforms; reformats; translates) this collection into an array-like structure
+        """This function converts (or: transforms; reformats; translates) this collection into an array-like structure
         (e.g. Python list or numpy nD array) that can be addressed by index. In the common case of 'no ID recovery',
         the global ID and the index match exactly.
 
@@ -929,10 +932,15 @@ def toArray(self):
         return self._data.tolist()
 
     def set_variable_write_status(self, var, write_status):
-        """
-        Method to set the write status of a Variable
-        :param var: Name of the variable (string)
-        :param status: Write status of the variable (True, False or 'once')
+        """Method to set the write status of a Variable
+
+        Parameters
+        ----------
+        var :
+            Name of the variable (string)
+        write_status :
+            Write status of the variable (True, False or 'once')
+
         """
         var_changed = False
         for v in self._ptype.variables:
@@ -953,12 +961,17 @@ class ParticleAccessorAOS(BaseParticleAccessor):
     """Wrapper that provides access to particle data in the collection,
     as if interacting with the particle itself.
 
-    :param pcoll: ParticleCollection that the represented particle
-                  belongs to.
-    :param index: The index at which the data for the represented
-                  particle is stored in the corresponding data arrays
-                  of the ParticleCollecion.
+    Parameters
+    ----------
+    pcoll :
+        ParticleCollection that the represented particle
+        belongs to.
+    index :
+        The index at which the data for the represented
+        particle is stored in the corresponding data arrays
+        of the ParticleCollecion.
     """
+
     _index = 0
     _next_dt = None
 
@@ -971,11 +984,18 @@ def __init__(self, pcoll, index):
         self._next_dt = None
 
     def __getattr__(self, name):
-        """Get the value of an attribute of the particle.
+        """
+        Get the value of an attribute of the particle.
+
+        Parameters
+        ----------
+        name : str
+            Name of the requested particle attribute.
 
-        :param name: Name of the requested particle attribute.
-        :return: The value of the particle attribute in the underlying
-                 collection data array.
+        Returns
+        -------
+        any
+            The value of the particle attribute in the underlying collection data array.
         """
         if name in BaseParticleAccessor.__dict__.keys():
             result = super().__getattr__(name)
@@ -986,11 +1006,15 @@ def __getattr__(self, name):
         return result
 
     def __setattr__(self, name, value):
-        """Set the value of an attribute of the particle.
+        """
+        Set the value of an attribute of the particle.
 
-        :param name: Name of the particle attribute.
-        :param value: Value that will be assigned to the particle
-                      attribute in the underlying collection data array.
+        Parameters
+        ----------
+        name : str
+            Name of the particle attribute.
+        value : any
+            Value that will be assigned to the particle attribute in the underlying collection data array.
         """
         if name in BaseParticleAccessor.__dict__.keys():
             super().__setattr__(name, value)
@@ -1026,12 +1050,17 @@ def __iter__(self):
 class ParticleCollectionIteratorAOS(BaseParticleCollectionIterator):
     """Iterator for looping over the particles in the ParticleCollection.
 
-    :param pcoll: ParticleCollection that stores the particles.
-    :param reverse: Flag to indicate reverse iteration (i.e. starting at
-                    the largest index, instead of the smallest).
-    :param subset: Subset of indices to iterate over, this allows the
-                   creation of an iterator that represents part of the
-                   collection.
+    Parameters
+    ----------
+    pcoll :
+        ParticleCollection that stores the particles.
+    reverse :
+        Flag to indicate reverse iteration (i.e. starting at
+        the largest index, instead of the smallest).
+    subset :
+        Subset of indices to iterate over, this allows the
+        creation of an iterator that represents part of the
+        collection.
     """
 
     def __init__(self, pcoll, reverse=False, subset=None):
diff --git a/parcels/collection/collections.py b/parcels/collection/collections.py
index 68ef700ae..68cfde945 100644
--- a/parcels/collection/collections.py
+++ b/parcels/collection/collections.py
@@ -20,7 +20,8 @@ class Collection(ABC):
     @abstractmethod
     def __init__(self):
         """
-        Collection - Constructor
+        Collection - Constructor.
+
         Initializes a collection by pre-allocating memory (where needed), initialising indexing structures
         (where needed), initialising iterators and preparing the C-JIT-glue.
         """
@@ -28,9 +29,7 @@ def __init__(self):
 
     @abstractmethod
     def __del__(self):
-        """
-        Collection - Destructor
-        """
+        """Collection - Destructor."""
         pass
 
     @property
@@ -749,9 +748,7 @@ def toArray(self):
         pass
 
     def __len__(self):
-        """
-        This function returns the length, in terms of 'number of elements, of a collection.
-        """
+        """This function returns the length, in terms of 'number of elements, of a collection."""
         return self._ncount
 
     @abstractmethod
@@ -790,8 +787,8 @@ class ParticleCollection(Collection):
     _data = None  # formerly: particle_data
 
     def __init__(self):
-        """
-        ParticleCollection - Constructor
+        """Constructor for ParticleCollection.
+
         Initializes a particle collection by pre-allocating memory (where needed), initialising indexing structures
         (where needed), initialising iterators (if maintaining a persistent iterator) and preparing the C-JIT-glue.
 
@@ -808,9 +805,7 @@ def __init__(self):
         super().__init__()
 
     def __del__(self):
-        """
-        ParticleCollection - Destructor
-        """
+        """Destructor for ParticleCollection."""
         pass
 
     @property
@@ -834,9 +829,7 @@ def pu_centers(self):
 
     @property
     def pclass(self):
-        """
-        'pclass' stores the actual class type of the particles allocated and managed in this collection
-        """
+        """Stores the actual class type of the particles allocated and managed in this collection."""
         return self._pclass
 
     @property
@@ -877,19 +870,24 @@ def particle_data(self):
 
     @abstractmethod
     def cstruct(self):
-        """
-        'cstruct' returns the ctypes mapping of the particle data. This depends on the specific structure in question.
-        """
+        """Returns the ctypes mapping of the particle data. This depends on the specific structure in question."""
         pass
 
     @abstractmethod
     def __getattr__(self, name):
         """
         Access a single property of all particles.
-        NOTE: This is a fallback implementation, and it is NOT efficient.
-        Specific datastructures may implement a more efficient variant.
 
-        :param name: name of the property
+        Parameters
+        ----------
+        name : str
+            Name of the property to access
+
+
+        Notes
+        -----
+        This is a fallback implementation, and it is NOT efficient.
+        Specific datastructures may implement a more efficient variant.
         """
         for v in self.ptype.variables:
             if v.name == name:
@@ -917,10 +915,15 @@ def setvardata(self, var, index, val):
     def set_variable_write_status(self, var, write_status):
         """
         Method to set the write status of a Variable
-        :param var: Name of the variable (string)
-        :param status: Write status of the variable (True, False or 'once')
 
-         This function depends on the specific collection in question and thus needs to be specified in specific
+        This function depends on the specific collection in question and thus needs to be specified in specific
          derivatives classes.
+
+        Parameters
+        ----------
+        var : str
+            Name of the variable
+        write_status : bool, str
+            Write status of the variable (True, False or 'once')
         """
         pass
diff --git a/parcels/collection/collectionsoa.py b/parcels/collection/collectionsoa.py
index 733f2b948..8665cdb39 100644
--- a/parcels/collection/collectionsoa.py
+++ b/parcels/collection/collectionsoa.py
@@ -31,10 +31,12 @@ class ParticleCollectionSOA(ParticleCollection):
 
     def __init__(self, pclass, lon, lat, depth, time, lonlatdepth_dtype, pid_orig, partitions=None, ngrid=1, **kwargs):
         """
-        :param ngrid: number of grids in the fieldset of the overarching ParticleSet - required for initialising the
-        field references of the ctypes-link of particles that are allocated
+        Parameters
+        ----------
+        ngrid :
+            number of grids in the fieldset of the overarching ParticleSet - required for initialising the
+            field references of the ctypes-link of particles that are allocated
         """
-
         super(ParticleCollection, self).__init__()
 
         assert pid_orig is not None, "particle IDs are None - incompatible with the collection. Invalid state."
@@ -166,9 +168,7 @@ def __init__(self, pclass, lon, lat, depth, time, lonlatdepth_dtype, pid_orig, p
         self._riterator = None
 
     def __del__(self):
-        """
-        Collection - Destructor
-        """
+        """Collection - Destructor"""
         super().__del__()
 
     def iterator(self):
@@ -197,7 +197,10 @@ def __getitem__(self, index):
         Access a particle in this collection using the fastest access
         method for this collection - by its index.
 
-        :param index: int or np.int32 index of a particle in this collection
+        Parameters
+        ----------
+        index : int
+            Index of the particle to access
         """
         return self.get_single_by_index(index)
 
@@ -205,7 +208,10 @@ def __getattr__(self, name):
         """
         Access a single property of all particles.
 
-        :param name: name of the property
+        Parameters
+        ----------
+        name : str
+            Name of the property to access
         """
         for v in self.ptype.variables:
             if v.name == name and name in self._data:
@@ -344,9 +350,14 @@ def _recursive_ID_lookup(self, low, high, sublist):
         """Identify the middle element of the sublist and perform binary
         search on it.
 
-        :param low: Lowerbound on the indices to search for IDs.
-        :param high: Upperbound on the indices to search for IDs.
-        :param sublist: (Sub)list of IDs to look for.
+        Parameters
+        ----------
+        low :
+            Lowerbound on the indices to search for IDs.
+        high :
+            Upperbound on the indices to search for IDs.
+        sublist : list
+            Sublist of IDs to look for.
         """
         raise NotTestedError
         # median = floor(len(sublist) / 2)
@@ -781,9 +792,7 @@ def clear(self):
         raise NotImplementedError
 
     def cstruct(self):
-        """
-        'cstruct' returns the ctypes mapping of the particle data. This depends on the specific structure in question.
-        """
+        """Returns the ctypes mapping of the particle data. This depends on the specific structure in question."""
         class CParticles(Structure):
             _fields_ = [(v.name, POINTER(np.ctypeslib.as_ctypes_type(v.dtype))) for v in self._ptype.variables]
 
@@ -837,10 +846,15 @@ def toArray(self):
         raise NotImplementedError
 
     def set_variable_write_status(self, var, write_status):
-        """
-        Method to set the write status of a Variable
-        :param var: Name of the variable (string)
-        :param status: Write status of the variable (True, False or 'once')
+        """Method to set the write status of a Variable
+
+        Parameters
+        ----------
+        var :
+            Name of the variable (string)
+        status :
+            Write status of the variable (True, False or 'once')
+        write_status :
         """
         var_changed = False
         for v in self._ptype.variables:
@@ -855,12 +869,17 @@ class ParticleAccessorSOA(BaseParticleAccessor):
     """Wrapper that provides access to particle data in the collection,
     as if interacting with the particle itself.
 
-    :param pcoll: ParticleCollection that the represented particle
-                  belongs to.
-    :param index: The index at which the data for the represented
-                  particle is stored in the corresponding data arrays
-                  of the ParticleCollecion.
+    Parameters
+    ----------
+    pcoll :
+        ParticleCollection that the represented particle
+        belongs to.
+    index :
+        The index at which the data for the represented
+        particle is stored in the corresponding data arrays
+        of the ParticleCollecion.
     """
+
     _index = 0
     _next_dt = None
 
@@ -873,11 +892,18 @@ def __init__(self, pcoll, index):
         self._next_dt = None
 
     def __getattr__(self, name):
-        """Get the value of an attribute of the particle.
+        """
+        Get the value of an attribute of the particle.
 
-        :param name: Name of the requested particle attribute.
-        :return: The value of the particle attribute in the underlying
-                 collection data array.
+        Parameters
+        ----------
+        name : str
+            Name of the requested particle attribute.
+
+        Returns
+        -------
+        any
+            The value of the particle attribute in the underlying collection data array.
         """
         if name in BaseParticleAccessor.__dict__.keys():
             result = super().__getattr__(name)
@@ -888,11 +914,15 @@ def __getattr__(self, name):
         return result
 
     def __setattr__(self, name, value):
-        """Set the value of an attribute of the particle.
+        """
+        Set the value of an attribute of the particle.
 
-        :param name: Name of the particle attribute.
-        :param value: Value that will be assigned to the particle
-                      attribute in the underlying collection data array.
+        Parameters
+        ----------
+        name : str
+            Name of the particle attribute.
+        value : any
+            Value that will be assigned to the particle attribute in the underlying collection data array.
         """
         if name in BaseParticleAccessor.__dict__.keys():
             super().__setattr__(name, value)
@@ -941,12 +971,17 @@ def __getitem__(self, items):
 class ParticleCollectionIteratorSOA(BaseParticleCollectionIterator):
     """Iterator for looping over the particles in the ParticleCollection.
 
-    :param pcoll: ParticleCollection that stores the particles.
-    :param reverse: Flag to indicate reverse iteration (i.e. starting at
-                    the largest index, instead of the smallest).
-    :param subset: Subset of indices to iterate over, this allows the
-                   creation of an iterator that represents part of the
-                   collection.
+    Parameters
+    ----------
+    pcoll :
+        ParticleCollection that stores the particles.
+    reverse :
+        Flag to indicate reverse iteration (i.e. starting at
+        the largest index, instead of the smallest).
+    subset :
+        Subset of indices to iterate over, this allows the
+        creation of an iterator that represents part of the
+        collection.
     """
 
     def __init__(self, pcoll, reverse=False, subset=None):
diff --git a/parcels/collection/iterators.py b/parcels/collection/iterators.py
index b8d2b0917..f57b6547d 100644
--- a/parcels/collection/iterators.py
+++ b/parcels/collection/iterators.py
@@ -22,6 +22,7 @@ class BaseParticleCollectionIterator(ABC):
     """Interface for the ParticleCollection iterator. Provides the
     ability to iterate over the particles in the ParticleCollection.
     """
+
     def ___init___(self):
         self._head = None
         self._tail = None
@@ -29,42 +30,33 @@ def ___init___(self):
 
     @abstractmethod
     def __next__(self):
-        """Returns a ParticleAccessor for the next particle in the
-        ParticleSet.
-        """
+        """Returns a ParticleAccessor for the next particle in the ParticleSet."""
         pass
 
     @property
     def head(self):
-        """Returns a ParticleAccessor for the first particle in the
-        ParticleSet.
-        """
+        """Returns a ParticleAccessor for the first particle in the ParticleSet."""
         return self._head
 
     @property
     def tail(self):
-        """Returns a ParticleAccessor for the last particle in the
-        ParticleSet.
-        """
+        """Returns a ParticleAccessor for the last particle in the ParticleSet."""
         return self._tail
 
     @property
     def current(self):
-        """Returns a ParticleAccessor for the particle that the iteration
-        is currently at.
-        """
+        """Returns a ParticleAccessor for the particle that the iteration currently at."""
         return self._current
 
     @abstractmethod
     def __repr__(self):
-        """Represents the current position in the iteration.
-        """
+        """Represents the current position in the iteration."""
         pass
 
 
 class BaseParticleAccessor(ABC):
-    """Interface for the ParticleAccessor. Implements a wrapper around
-    particles to provide easy access."""
+    """Interface for the ParticleAccessor. Implements a wrapper around particles to provide easy access."""
+
     _pcoll = None
 
     def __init__(self, pcoll):
@@ -82,9 +74,7 @@ def delete(self):
         self.state = OperationCode.Delete
 
     def set_state(self, state):
-        """Syntactic sugar for changing the state of the underlying
-        particle.
-        """
+        """Syntactic sugar for changing the state of the underlying particle."""
         self.state = state
 
     def succeeded(self):
diff --git a/parcels/compilation/codecompiler.py b/parcels/compilation/codecompiler.py
index b8e6f7948..b8f57eb13 100644
--- a/parcels/compilation/codecompiler.py
+++ b/parcels/compilation/codecompiler.py
@@ -197,9 +197,15 @@ def __init__(self, cppargs=None, ldargs=None, incdirs=None, libdirs=None, libs=N
 class CCompiler:
     """A compiler object for creating and loading shared libraries.
 
-    :arg cc: C compiler executable (uses environment variable ``CC`` if not provided).
-    :arg cppargs: A list of arguments to the C compiler (optional).
-    :arg ldargs: A list of arguments to the linker (optional)."""
+    Parameters
+    ----------
+    cc :
+        C compiler executable (uses environment variable ``CC`` if not provided).
+    cppargs :
+        A list of arguments to the C compiler (optional).
+    ldargs :
+        A list of arguments to the linker (optional).
+    """
 
     def __init__(self, cc=None, cppargs=None, ldargs=None, incdirs=None, libdirs=None, libs=None, tmp_dir=os.getcwd()):
         if cppargs is None:
@@ -241,9 +247,8 @@ def _create_compile_process_(self, cmd, src, log):
 
 
 class CCompiler_SS(CCompiler):
-    """
-    single-stage C-compiler; used for a SINGLE source file
-    """
+    """Single-stage C-compiler; used for a SINGLE source file."""
+
     def __init__(self, cc=None, cppargs=None, ldargs=None, incdirs=None, libdirs=None, libs=None, tmp_dir=os.getcwd()):
         super().__init__(cc=cc, cppargs=cppargs, ldargs=ldargs, incdirs=incdirs, libdirs=libdirs, libs=libs, tmp_dir=tmp_dir)
 
@@ -268,9 +273,15 @@ def compile(self, src, obj, log):
 class GNUCompiler_SS(CCompiler_SS):
     """A compiler object for the GNU Linux toolchain.
 
-    :arg cppargs: A list of arguments to pass to the C compiler
-         (optional).
-    :arg ldargs: A list of arguments to pass to the linker (optional)."""
+    Parameters
+    ----------
+    cppargs :
+        A list of arguments to pass to the C compiler
+        (optional).
+    ldargs :
+        A list of arguments to pass to the linker (optional).
+    """
+
     def __init__(self, cppargs=None, ldargs=None, incdirs=None, libdirs=None, libs=None, tmp_dir=os.getcwd()):
         c_params = GNU_parameters(cppargs, ldargs, incdirs, libdirs, libs)
         super().__init__(c_params.compiler, cppargs=c_params.cppargs, ldargs=c_params.ldargs, incdirs=c_params.incdirs, libdirs=c_params.libdirs, libs=c_params.libs, tmp_dir=tmp_dir)
diff --git a/parcels/compilation/codegenerator.py b/parcels/compilation/codegenerator.py
index 83b0ad70f..daef66580 100644
--- a/parcels/compilation/codegenerator.py
+++ b/parcels/compilation/codegenerator.py
@@ -273,7 +273,8 @@ def __getattr__(self, attr):
 class IntrinsicTransformer(ast.NodeTransformer):
     """AST transformer that catches any mention of intrinsic variable
     names, such as 'particle' or 'fieldset', inserts placeholder objects
-    and propagates attribute access."""
+    and propagates attribute access.
+    """
 
     def __init__(self, fieldset=None, ptype=JITParticle):
         self.fieldset = fieldset
@@ -286,14 +287,14 @@ def __init__(self, fieldset=None, ptype=JITParticle):
         self.stmt_stack = []
 
     def get_tmp(self):
-        """Create a new temporary veriable name"""
+        """Create a new temporary veriable name."""
         tmp = "parcels_tmpvar%d" % self._tmp_counter
         self._tmp_counter += 1
         self.tmp_vars += [tmp]
         return tmp
 
     def visit_Name(self, node):
-        """Inject IntrinsicNode objects into the tree according to keyword"""
+        """Inject IntrinsicNode objects into the tree according to keyword."""
         if node.id == 'fieldset' and self.fieldset is not None:
             node = FieldSetNode(self.fieldset, ccode='fset')
         elif node.id == 'particle':
@@ -480,8 +481,7 @@ def visit_Call(self, node):
 
 
 class TupleSplitter(ast.NodeTransformer):
-    """AST transformer that detects and splits Pythonic tuple
-    assignments into multiple statements for conversion to C."""
+    """AST transformer that detects and splits Pythonic tuple assignments into multiple statements for conversion to C."""
 
     def visit_Assign(self, node):
         if isinstance(node.targets[0], ast.Tuple) \
@@ -498,9 +498,10 @@ def visit_Assign(self, node):
 
 
 class AbstractKernelGenerator(ABC, ast.NodeVisitor):
-    """Code generator class that translates simple Python kernel
-    functions into C functions by populating and accessing the `ccode`
-    attriibute on nodes in the Python AST."""
+    """Code generator class that translates simple Python kernel functions into C functions.
+
+    Works by populating and accessing the `ccode` attriibute on nodes in the Python AST.
+    """
 
     # Intrinsic variables that appear as function arguments
     kernel_vars = ['particle', 'fieldset', 'time', 'output_time', 'tol']
@@ -559,9 +560,11 @@ def visit_FunctionDef(self, node):
         pass
 
     def visit_Call(self, node):
-        """Generate C code for simple C-style function calls. Please
-        note that starred and keyword arguments are currently not
-        supported."""
+        """Generate C code for simple C-style function calls.
+
+        Please note that starred and keyword arguments are currently not
+        supported.
+        """
         pointer_args = False
         parcels_customed_Cfunc = False
         if isinstance(node.func, PrintNode):
@@ -624,8 +627,7 @@ def visit_Call(self, node):
                 raise RuntimeError("Error in converting Kernel to C. See https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_parcels_structure.ipynb#3.-Kernel-execution for hints and tips")
 
     def visit_Name(self, node):
-        """Catches any mention of intrinsic variable names, such as
-        'particle' or 'fieldset' and inserts our placeholder objects"""
+        """Catches any mention of intrinsic variable names such as 'particle' or 'fieldset' and inserts our placeholder objects."""
         if node.id == 'True':
             node.id = "1"
         if node.id == 'False':
@@ -811,30 +813,30 @@ def visit_Pass(self, node):
         node.ccode = c.Statement("")
 
     def visit_FieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         self.field_args[node.obj.ccode_name] = node.obj
 
     def visit_SummedFieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         for fld in node.obj:
             self.field_args[fld.ccode_name] = fld
 
     def visit_NestedFieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         for fld in node.obj:
             self.field_args[fld.ccode_name] = fld
 
     def visit_VectorFieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         self.vector_field_args[node.obj.ccode_name] = node.obj
 
     def visit_SummedVectorFieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         for fld in node.obj:
             self.vector_field_args[fld.ccode_name] = fld
 
     def visit_NestedVectorFieldNode(self, node):
-        """Record intrinsic fields used in kernel"""
+        """Record intrinsic fields used in kernel."""
         for fld in node.obj:
             self.vector_field_args[fld.ccode_name] = fld
 
@@ -1205,8 +1207,7 @@ def visit_NestedVectorFieldEvalNode(self, node):
 
 
 class LoopGenerator:
-    """Code generator class that adds type definitions and the outer
-    loop around kernel functions to generate compilable C code."""
+    """Code generator class that adds type definitions and the outer loop around kernel functions to generate compilable C code."""
 
     def __init__(self, fieldset, ptype=None):
         self.fieldset = fieldset
@@ -1353,8 +1354,7 @@ def generate(self, funcname, field_args, const_args, kernel_ast, c_include):
 
 
 class ParticleObjectLoopGenerator:
-    """Code generator class that adds type definitions and the outer
-    loop around kernel functions to generate compilable C code."""
+    """Code generator class that adds type definitions and the outer loop around kernel functions to generate compilable C code."""
 
     def __init__(self, fieldset=None, ptype=None):
         self.fieldset = fieldset
diff --git a/parcels/examples/example_mitgcm.py b/parcels/examples/example_mitgcm.py
index ade100bcb..372dbb8a4 100644
--- a/parcels/examples/example_mitgcm.py
+++ b/parcels/examples/example_mitgcm.py
@@ -17,8 +17,7 @@
 
 
 def run_mitgcm_zonally_reentrant(mode):
-    """Function that shows how to load MITgcm data in a zonally periodic domain"""
-
+    """Function that shows how to load MITgcm data in a zonally periodic domain."""
     data_path = path.join(path.dirname(__file__), "MITgcm_example_data/")
     filenames = {
         "U": data_path + "mitgcm_UV_surface_zonally_reentrant.nc",
diff --git a/parcels/examples/example_moving_eddies.py b/parcels/examples/example_moving_eddies.py
index fd5c629ea..1dfe6a80f 100644
--- a/parcels/examples/example_moving_eddies.py
+++ b/parcels/examples/example_moving_eddies.py
@@ -25,17 +25,28 @@ def moving_eddies_fieldset(xdim=200, ydim=350, mesh='flat'):
     """Generate a fieldset encapsulating the flow field consisting of two
     moving eddies, one moving westward and the other moving northwestward.
 
-    :param xdim: Horizontal dimension of the generated fieldset
-    :param xdim: Vertical dimension of the generated fieldset
-    :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical: Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat  (default): No conversion, lat/lon are assumed to be in m.
-
+    Parameters
+    ----------
+    xdim :
+        Horizontal dimension of the generated fieldset (Default value = 200)
+    xdim :
+        Vertical dimension of the generated fieldset (Default value = 200)
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical: Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat  (default): No conversion, lat/lon are assumed to be in m.
+    ydim :
+         (Default value = 350)
+
+
+    Notes
+    -----
     Note that this is not a proper geophysical flow. Rather, a Gaussian eddy is moved
     artificially with uniform velocities. Velocities are calculated from geostrophy.
+
     """
     # Set Parcels FieldSet variables
     time = np.arange(0., 8. * 86400., 86400., dtype=np.float64)
@@ -91,11 +102,24 @@ def cosd(x):
 
 def moving_eddies_example(fieldset, outfile, npart=2, mode='jit', verbose=False,
                           method=AdvectionRK4):
-    """Configuration of a particle set that follows two moving eddies
-
-    :arg fieldset: :class FieldSet: that defines the flow field
-    :arg npart: Number of particles to initialise"""
-
+    """Configuration of a particle set that follows two moving eddies.
+
+
+    Parameters
+    ----------
+    fieldset :
+        :class FieldSet: that defines the flow field
+    outfile :
+
+    npart :
+         Number of particles to initialise. (Default value = 2)
+    mode :
+         (Default value = 'jit')
+    verbose :
+         (Default value = False)
+    method :
+         (Default value = AdvectionRK4)
+    """
     # Determine particle class according to mode
     start = (3.3, 46.) if fieldset.U.grid.mesh == 'spherical' else (3.3e5, 1e5)
     finish = (3.3, 47.8) if fieldset.U.grid.mesh == 'spherical' else (3.3e5, 2.8e5)
@@ -163,7 +187,7 @@ def test_moving_eddies_fieldset(mode, mesh, tmpdir):
 
 
 def fieldsetfile(mesh, tmpdir):
-    """Generate fieldset files for moving_eddies test"""
+    """Generate fieldset files for moving_eddies test."""
     filename = tmpdir.join('moving_eddies')
     fieldset = moving_eddies_fieldset(200, 350, mesh=mesh)
     fieldset.write(filename)
diff --git a/parcels/examples/example_nemo_curvilinear.py b/parcels/examples/example_nemo_curvilinear.py
index a138aec92..abd5d7583 100644
--- a/parcels/examples/example_nemo_curvilinear.py
+++ b/parcels/examples/example_nemo_curvilinear.py
@@ -21,7 +21,7 @@
 
 
 def run_nemo_curvilinear(mode, outfile, advtype='RK4'):
-    """Function that shows how to read in curvilinear grids, in this case from NEMO"""
+    """Function that shows how to read in curvilinear grids, in this case from NEMO."""
     data_path = path.join(path.dirname(__file__), 'NemoCurvilinear_data/')
 
     filenames = {'U': {'lon': data_path + 'mesh_mask.nc4',
diff --git a/parcels/examples/example_peninsula.py b/parcels/examples/example_peninsula.py
index 1268a089a..2c383efb1 100644
--- a/parcels/examples/example_peninsula.py
+++ b/parcels/examples/example_peninsula.py
@@ -23,25 +23,32 @@
 
 
 def peninsula_fieldset(xdim, ydim, mesh='flat', grid_type='A'):
-    """Construct a fieldset encapsulating the flow field around an
-    idealised peninsula.
-
-    :param xdim: Horizontal dimension of the generated fieldset
-    :param xdim: Vertical dimension of the generated fieldset
-    :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical: Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat  (default): No conversion, lat/lon are assumed to be in m.
-    :param grid_type: Option whether grid is either Arakawa A (default) or C
-
-    The original test description can be found in Fig. 2.2.3 in:
-    North, E. W., Gallego, A., Petitgas, P. (Eds). 2009. Manual of
-    recommended practices for modelling physical - biological
-    interactions during fish early life.
-    ICES Cooperative Research Report No. 295. 111 pp.
-    http://archimer.ifremer.fr/doc/00157/26792/24888.pdf
+    """Construct a fieldset encapsulating the flow field around an idealised peninsula.
+
+    Parameters
+    ----------
+    xdim :
+        Horizontal dimension of the generated fieldset
+    xdim :
+        Vertical dimension of the generated fieldset
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical: Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat  (default): No conversion, lat/lon are assumed to be in m.
+    grid_type :
+        Option whether grid is either Arakawa A (default) or C
+
+        The original test description can be found in Fig. 2.2.3 in:
+        North, E. W., Gallego, A., Petitgas, P. (Eds). 2009. Manual of
+        recommended practices for modelling physical - biological
+        interactions during fish early life.
+        ICES Cooperative Research Report No. 295. 111 pp.
+        http://archimer.ifremer.fr/doc/00157/26792/24888.pdf
+    ydim :
+
 
     """
     # Set Parcels FieldSet variables
@@ -98,9 +105,26 @@ def peninsula_example(fieldset, outfile, npart, mode='jit', degree=1,
                       verbose=False, output=True, method=AdvectionRK4):
     """Example configuration of particle flow around an idealised Peninsula
 
-    :arg filename: Basename of the input fieldset
-    :arg npart: Number of particles to intialise"""
+    Parameters
+    ----------
+    fieldset :
+
+    outfile : str
+        Basename of the input fieldset.
+    npart : int
+        Number of particles to intialise.
+    mode :
+         (Default value = 'jit')
+    degree :
+         (Default value = 1)
+    verbose :
+         (Default value = False)
+    output :
+         (Default value = True)
+    method :
+         (Default value = AdvectionRK4)
 
+    """
     # First, we define a custom Particle class to which we add a
     # custom variable, the initial stream function value p.
     # We determine the particle base class according to mode.
@@ -140,7 +164,7 @@ class MyParticle(ptype[mode]):
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 @pytest.mark.parametrize('mesh', ['flat', 'spherical'])
 def test_peninsula_fieldset(mode, mesh, tmpdir):
-    """Execute peninsula test from fieldset generated in memory"""
+    """Execute peninsula test from fieldset generated in memory."""
     fieldset = peninsula_fieldset(100, 50, mesh)
     outfile = tmpdir.join("Peninsula")
     pset = peninsula_example(fieldset, outfile, 5, mode=mode, degree=1)
@@ -155,7 +179,7 @@ def test_peninsula_fieldset(mode, mesh, tmpdir):
 @pytest.mark.parametrize('mode', ['scipy'])  # Analytical Advection only implemented in Scipy mode
 @pytest.mark.parametrize('mesh', ['flat', 'spherical'])
 def test_peninsula_fieldset_AnalyticalAdvection(mode, mesh, tmpdir):
-    """Execute peninsula test using Analytical Advection on C grid"""
+    """Execute peninsula test using Analytical Advection on C grid."""
     fieldset = peninsula_fieldset(101, 51, 'flat', grid_type='C')
     outfile = tmpdir.join("PeninsulaAA")
     pset = peninsula_example(fieldset, outfile, npart=10, mode=mode,
@@ -166,7 +190,7 @@ def test_peninsula_fieldset_AnalyticalAdvection(mode, mesh, tmpdir):
 
 
 def fieldsetfile(mesh, tmpdir):
-    """Generate fieldset files for peninsula test"""
+    """Generate fieldset files for peninsula test."""
     filename = tmpdir.join('peninsula')
     fieldset = peninsula_fieldset(100, 50, mesh=mesh)
     fieldset.write(filename)
@@ -176,7 +200,7 @@ def fieldsetfile(mesh, tmpdir):
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 @pytest.mark.parametrize('mesh', ['flat', 'spherical'])
 def test_peninsula_file(mode, mesh, tmpdir):
-    """Open fieldset files and execute"""
+    """Open fieldset files and execute."""
     gc.collect()
     fieldset = FieldSet.from_parcels(fieldsetfile(mesh, tmpdir), extra_fields={'P': 'P'}, allow_time_extrapolation=True)
     outfile = tmpdir.join("Peninsula")
diff --git a/parcels/examples/example_recursive_errorhandling.py b/parcels/examples/example_recursive_errorhandling.py
index 5c3e2f2ca..36f72eb4d 100644
--- a/parcels/examples/example_recursive_errorhandling.py
+++ b/parcels/examples/example_recursive_errorhandling.py
@@ -27,8 +27,8 @@ def test_recursive_errorhandling(mode, xdim=2, ydim=2):
 
     This behaviour can be useful if particles need to be 'pushed out'
     from e.g. land. Note however that current under-the-hood
-    implementation is not extremely efficient, so code could be slow."""
-
+    implementation is not extremely efficient, so code could be slow.
+    """
     dimensions = {'lon': np.linspace(0., 1., xdim, dtype=np.float32),
                   'lat': np.linspace(0., 1., ydim, dtype=np.float32)}
     data = {'U': np.zeros((ydim, xdim), dtype=np.float32),
@@ -44,13 +44,17 @@ def test_recursive_errorhandling(mode, xdim=2, ydim=2):
 
     def TestLon(particle, fieldset, time):
         """Kernel to check whether a longitude is larger than fieldset.minlon.
-        If not, the Kernel throws an error"""
+
+        If not, the Kernel throws an error.
+        """
         if particle.lon <= fieldset.minlon:
             return ErrorCode.Error
 
     def Error_RandomiseLon(particle, fieldset, time):
         """Error handling kernel that draws a new longitude.
-        Note that this new longitude can be smaller than fieldset.minlon"""
+
+        Note that this new longitude can be smaller than fieldset.minlon.
+        """
         particle.lon = ParcelsRandom.uniform(0., 1.)
 
     ParcelsRandom.seed(123456)
diff --git a/parcels/examples/tutorial_nemo_3D.ipynb b/parcels/examples/tutorial_nemo_3D.ipynb
index a1b7fe2b5..1adf95f58 100644
--- a/parcels/examples/tutorial_nemo_3D.ipynb
+++ b/parcels/examples/tutorial_nemo_3D.ipynb
@@ -132,7 +132,7 @@
    "metadata": {},
    "source": [
     "## Adding other fields like cell edges\n",
-    "It is quite straightforward to add other gridded data, on the same curvilinear or any other type of grid, to the fieldset. Because it is good practice to make no changes to a `FieldSet` once a `ParticleSet` has been defined in it, we redefine the fieldset and add the fields with the cell edges from the coordinates file using [`FieldSet.add_field()`](https://oceanparcels.org/gh-pages/html/#parcels.fieldset.FieldSet.add_field)"
+    "It is quite straightforward to add other gridded data, on the same curvilinear or any other type of grid, to the fieldset. Because it is good practice to make no changes to a `FieldSet` once a `ParticleSet` has been defined in it, we redefine the fieldset and add the fields with the cell edges from the coordinates file using [`FieldSet.add_field()`](https://parcels.readthedocs.io/en/latest/reference/fields.html#parcels.fieldset.FieldSet.add_field)"
    ]
   },
   {
diff --git a/parcels/examples/tutorial_output.ipynb b/parcels/examples/tutorial_output.ipynb
index 05f7e43a8..d04a98189 100644
--- a/parcels/examples/tutorial_output.ipynb
+++ b/parcels/examples/tutorial_output.ipynb
@@ -345,7 +345,7 @@
    "metadata": {},
    "source": [
     "## Plotting\n",
-    "Parcels output consists of particle trajectories through time and space. An important way to explore patterns in this information is to draw the trajectories in space. Parcels provides the [`ParticleSet.show()`](https://oceanparcels.org/gh-pages/html/#parcels.particleset.ParticleSet.show) method and the [`plotTrajectoryFile`](https://oceanparcels.org/gh-pages/html/#module-scripts.plottrajectoriesfile) script to quickly plot at results, but users are encouraged to create their own figures, for example by using the comprehensive [**matplotlib**](https://matplotlib.org/) library. Here we show a basic setup on how to process the parcels output into trajectory plots and animations.\n",
+    "Parcels output consists of particle trajectories through time and space. An important way to explore patterns in this information is to draw the trajectories in space. Parcels provides the `ParticleSet.show()` method and the `plotTrajectoryFile` script to quickly plot at results, but users are encouraged to create their own figures, for example by using the comprehensive [**matplotlib**](https://matplotlib.org/) library. Here we show a basic setup on how to process the parcels output into trajectory plots and animations.\n",
     "\n",
     "Some other packages to help you make beautiful figures are:\n",
     "* [**cartopy**](https://scitools.org.uk/cartopy/docs/latest/), a map-drawing tool especially compatible with matplotlib\n",
diff --git a/parcels/examples/tutorial_parcels_structure.ipynb b/parcels/examples/tutorial_parcels_structure.ipynb
index 91f963d86..dfb684492 100644
--- a/parcels/examples/tutorial_parcels_structure.ipynb
+++ b/parcels/examples/tutorial_parcels_structure.ipynb
@@ -60,14 +60,14 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Parcels provides a framework to simulate the movement of particles **within an existing flow field environment**. To start a parcels simulation we must define this environment with the [**`FieldSet`** class](https://oceanparcels.org/gh-pages/html/#module-parcels.fieldset). The minimal requirements for this Fieldset are that it must contain the `'U'` and `'V'` fields: the 2D hydrodynamic data that will move the particles in a horizontal direction. Additionally, it can contain e.g. a temperature or vertical flow field."
+    "Parcels provides a framework to simulate the movement of particles **within an existing flow field environment**. To start a parcels simulation we must define this environment with the [**`FieldSet`** class](https://parcels.readthedocs.io/en/latest/reference/fields.html#module-parcels.fieldset). The minimal requirements for this Fieldset are that it must contain the `'U'` and `'V'` fields: the 2D hydrodynamic data that will move the particles in a horizontal direction. Additionally, it can contain e.g. a temperature or vertical flow field."
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "A fieldset can be loaded with [**`FieldSet.from_netcdf`**](https://oceanparcels.org/gh-pages/html/#parcels.fieldset.FieldSet.from_netcdf), if the model output with the fields is written in NetCDF files. This function requires `filenames`, `variables` and `dimensions`. "
+    "A fieldset can be loaded with [**`FieldSet.from_netcdf`**](https://parcels.readthedocs.io/en/latest/reference/fields.html#parcels.fieldset.FieldSet.from_netcdf), if the model output with the fields is written in NetCDF files. This function requires `filenames`, `variables` and `dimensions`. "
    ]
   },
   {
@@ -170,10 +170,10 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Once the environment has a `FieldSet` object, you can start defining your particles in a [**`ParticleSet`** object](https://oceanparcels.org/gh-pages/html/#module-parcels.particleset). This object requires:\n",
-    "1. The [**`FieldSet`**](https://oceanparcels.org/gh-pages/html/#module-parcels.fieldset) object in which the particles will be released.\n",
-    "2. The type of [**`Particle`**](https://oceanparcels.org/gh-pages/html/#module-parcels.particle): Either a JITParticle or ScipyParticle.\n",
-    "3. Initial conditions for each [**`Variable`**](https://oceanparcels.org/gh-pages/html/#parcels.particle.Variable) defined in the `Particle`, most notably the release locations in `lon` and `lat`."
+    "Once the environment has a `FieldSet` object, you can start defining your particles in a [**`ParticleSet`** object](https://parcels.readthedocs.io/en/latest/reference/particles.html#module-parcels.particleset.particlesetsoa). This object requires:\n",
+    "1. The [**`FieldSet`**](https://parcels.readthedocs.io/en/latest/reference/fields.html#module-parcels.fieldset) object in which the particles will be released.\n",
+    "2. The type of [**`Particle`**](https://parcels.readthedocs.io/en/latest/reference/particles.html#module-parcels.particle): Either a JITParticle or ScipyParticle.\n",
+    "3. Initial conditions for each [**`Variable`**](https://parcels.readthedocs.io/en/latest/reference/particles.html#parcels.particle.Variable) defined in the `Particle`, most notably the release locations in `lon` and `lat`."
    ]
   },
   {
@@ -218,7 +218,7 @@
    "metadata": {},
    "source": [
     "Kernels are little snippets of code, which are applied to every particle in the `ParticleSet`, for every time step during a simulation.\n",
-    "Basic kernels are [included in Parcels](https://oceanparcels.org/gh-pages/html/#module-parcels.kernels.advection), among which several types of advection kernels. `AdvectionRK4` is the main advection kernel for two-dimensional advection, which is also used in this example.\n",
+    "Basic kernels are [included in Parcels](https://parcels.readthedocs.io/en/latest/reference/predefined_kernels.html#predefined-kernels), among which several types of advection kernels. `AdvectionRK4` is the main advection kernel for two-dimensional advection, which is also used in this example.\n",
     "\n",
     "One can also write custom kernels, to add certain types of 'behaviour' to the particles."
    ]
@@ -260,7 +260,7 @@
     "    * Interpolation of a `Field` from the `FieldSet` at a `[time, depth, lat, lon]` point, using square brackets notation.\n",
     "    For example, to interpolate the zonal velocity (U) field at the particle location, use the following statement:\n",
     "    `value = fieldset.U[time, particle.depth, particle.lat, particle.lon]`\n",
-    "    * Functions from the `math` standard library and from the custom `ParcelsRandom` library at [`parcels.rng`](https://oceanparcels.org/gh-pages/html/#module-parcels.rng)\n",
+    "    * Functions from the `math` standard library and from the custom `ParcelsRandom` library at [`parcels.rng`](https://parcels.readthedocs.io/en/latest/reference/misc.html#module-parcels.rng)\n",
     "    * Simple `print` statements, such as:\n",
     "        * `print(\"Some print\")`\n",
     "        * `print(particle.lon)`\n",
@@ -294,7 +294,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The final part executes the simulation, given the `ParticleSet`, `FieldSet` and `Kernels`, that have been defined in the previous steps. If you like to store the particle data generated in the simulation, you define the [**`ParticleFile`**](https://oceanparcels.org/gh-pages/html/#parcels.particlefile.ParticleFile) to which the output of the kernel execution will be written. Then, on the [`ParticleSet`](#ParticleSet) you have defined, you can use the method [**`ParticleSet.execute()`**](https://oceanparcels.org/gh-pages/html/#parcels.particleset.ParticleSet.execute) which requires the following arguments:\n",
+    "The final part executes the simulation, given the `ParticleSet`, `FieldSet` and `Kernels`, that have been defined in the previous steps. If you like to store the particle data generated in the simulation, you define the [**`ParticleFile`**](https://parcels.readthedocs.io/en/latest/reference/particlefile.html#particlefile) to which the output of the kernel execution will be written. Then, on the [`ParticleSet`](#ParticleSet) you have defined, you can use the method [**`ParticleSet.execute()`**](https://parcels.readthedocs.io/en/latest/reference/particles.html#parcels.particleset.baseparticleset.BaseParticleSet.execute) which requires the following arguments:\n",
     "1. The kernels to be executed.\n",
     "2. The `runtime` defining how long the execution loop runs. Alternatively, you may define the `endtime` at which the execution loop stops.\n",
     "3. The timestep `dt` at which to execute the kernels.\n",
diff --git a/parcels/examples/tutorial_sampling.ipynb b/parcels/examples/tutorial_sampling.ipynb
index e5d354e06..8eab44977 100644
--- a/parcels/examples/tutorial_sampling.ipynb
+++ b/parcels/examples/tutorial_sampling.ipynb
@@ -13,7 +13,7 @@
    "source": [
     "The particle trajectories allow us to study fields like temperature, plastic concentration or chlorophyll from a Lagrangian perspective. \n",
     "\n",
-    "In this tutorial we will go through how particles can sample `Fields`, using temperature as an example. Along the way we will get to know the parcels class `Variable` (see [here](https://oceanparcels.org/gh-pages/html/#parcels.particle.Variable) for the documentation) and some of its methods. This tutorial covers several applications of a sampling setup:\n",
+    "In this tutorial we will go through how particles can sample `Fields`, using temperature as an example. Along the way we will get to know the parcels class `Variable` (see [here](https://parcels.readthedocs.io/en/latest/reference/particles.html#parcels.particle.Variable) for the documentation) and some of its methods. This tutorial covers several applications of a sampling setup:\n",
     "* [**Basic along trajectory sampling**](#Basic-sampling)\n",
     "* [**Sampling velocity fields**](#Sampling-velocity-fields)\n",
     "* [**Sampling initial conditions**](#Sampling-initial-values)\n",
diff --git a/parcels/field.py b/parcels/field.py
index f0e991e30..7106f3b1b 100644
--- a/parcels/field.py
+++ b/parcels/field.py
@@ -45,54 +45,79 @@ def _isParticle(key):
 class Field:
     """Class that encapsulates access to field data.
 
-    :param name: Name of the field
-    :param data: 2D, 3D or 4D numpy array of field data.
-
-           1. If data shape is [xdim, ydim], [xdim, ydim, zdim], [xdim, ydim, tdim] or [xdim, ydim, zdim, tdim],
-              whichever is relevant for the dataset, use the flag transpose=True
-           2. If data shape is [ydim, xdim], [zdim, ydim, xdim], [tdim, ydim, xdim] or [tdim, zdim, ydim, xdim],
-              use the flag transpose=False
-           3. If data has any other shape, you first need to reorder it
-    :param lon: Longitude coordinates (numpy vector or array) of the field (only if grid is None)
-    :param lat: Latitude coordinates (numpy vector or array) of the field (only if grid is None)
-    :param depth: Depth coordinates (numpy vector or array) of the field (only if grid is None)
-    :param time: Time coordinates (numpy vector) of the field (only if grid is None)
-    :param mesh: String indicating the type of mesh coordinates and
-           units used during velocity interpolation: (only if grid is None)
-
-           1. spherical: Lat and lon in degree, with a
-              correction for zonal velocity U near the poles.
-           2. flat (default): No conversion, lat/lon are assumed to be in m.
-    :param timestamps: A numpy array containing the timestamps for each of the files in filenames, for loading
-           from netCDF files only. Default is None if the netCDF dimensions dictionary includes time.
-    :param grid: :class:`parcels.grid.Grid` object containing all the lon, lat depth, time
-           mesh and time_origin information. Can be constructed from any of the Grid objects
-    :param fieldtype: Type of Field to be used for UnitConverter when using SummedFields
-           (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-    :param transpose: Transpose data to required (lon, lat) layout
-    :param vmin: Minimum allowed value on the field. Data below this value are set to zero
-    :param vmax: Maximum allowed value on the field. Data above this value are set to zero
-    :param cast_data_dtype: Cast Field data to dtype. Supported dtypes are np.float32 (default) and np.float64.
-           Note that dtype can only be float32 in JIT mode
-    :param time_origin: Time origin (TimeConverter object) of the time axis (only if grid is None)
-    :param interp_method: Method for interpolation. Options are 'linear' (default), 'nearest',
-           'linear_invdist_land_tracer', 'cgrid_velocity', 'cgrid_tracer' and 'bgrid_velocity'
-    :param allow_time_extrapolation: boolean whether to allow for extrapolation in time
-           (i.e. beyond the last available time snapshot)
-    :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object).
-           The last value of the time series can be provided (which is the same as the initial one) or not (Default: False)
-           This flag overrides the allow_time_interpolation and sets it to False
-    :param chunkdims_name_map (opt.): gives a name map to the FieldFileBuffer that declared a mapping between chunksize name, NetCDF dimension and Parcels dimension;
-           required only if currently incompatible OCM field is loaded and chunking is used by 'chunksize' (which is the default)
-    :param to_write: Write the Field in NetCDF format at the same frequency as the ParticleFile outputdt,
-           using a filenaming scheme based on the ParticleFile name
-
+    Parameters
+    ----------
+    name : str
+        Name of the field
+    data : np.ndarray
+        2D, 3D or 4D numpy array of field data.
+
+        1. If data shape is [xdim, ydim], [xdim, ydim, zdim], [xdim, ydim, tdim] or [xdim, ydim, zdim, tdim],
+           whichever is relevant for the dataset, use the flag transpose=True
+        2. If data shape is [ydim, xdim], [zdim, ydim, xdim], [tdim, ydim, xdim] or [tdim, zdim, ydim, xdim],
+           use the flag transpose=False
+        3. If data has any other shape, you first need to reorder it
+    lon : np.ndarray or list
+        Longitude coordinates (numpy vector or array) of the field (only if grid is None)
+    lat : np.ndarray or list
+        Latitude coordinates (numpy vector or array) of the field (only if grid is None)
+    depth : np.ndarray or list
+        Depth coordinates (numpy vector or array) of the field (only if grid is None)
+    time : np.ndarray
+        Time coordinates (numpy vector) of the field (only if grid is None)
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation: (only if grid is None)
+
+        1. spherical: Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat (default): No conversion, lat/lon are assumed to be in m.
+    timestamps : np.ndarray
+        A numpy array containing the timestamps for each of the files in filenames, for loading
+        from netCDF files only. Default is None if the netCDF dimensions dictionary includes time.
+    grid : parcels.grid.Grid
+        :class:`parcels.grid.Grid` object containing all the lon, lat depth, time
+        mesh and time_origin information. Can be constructed from any of the Grid objects
+    fieldtype : str
+        Type of Field to be used for UnitConverter when using SummedFields
+        (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+    transpose : bool
+        Transpose data to required (lon, lat) layout
+    vmin : float
+        Minimum allowed value on the field. Data below this value are set to zero
+    vmax : float
+        Maximum allowed value on the field. Data above this value are set to zero
+    cast_data_dtype : str
+        Cast Field data to dtype. Supported dtypes are "float32" (np.float32 (default)) and "float64 (np.float64).
+        Note that dtype can only be "float32" in JIT mode
+    time_origin : parcels.tools.converters.TimeConverter
+        Time origin of the time axis (only if grid is None)
+    interp_method : str
+        Method for interpolation. Options are 'linear' (default), 'nearest',
+        'linear_invdist_land_tracer', 'cgrid_velocity', 'cgrid_tracer' and 'bgrid_velocity'
+    allow_time_extrapolation : bool
+        boolean whether to allow for extrapolation in time
+        (i.e. beyond the last available time snapshot)
+    time_periodic : bool, float or datetime.timedelta
+        To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object).
+        The last value of the time series can be provided (which is the same as the initial one) or not (Default: False)
+        This flag overrides the allow_time_extrapolation and sets it to False
+    chunkdims_name_map : str, optional
+        Gives a name map to the FieldFileBuffer that declared a mapping between chunksize name, NetCDF dimension and Parcels dimension;
+        required only if currently incompatible OCM field is loaded and chunking is used by 'chunksize' (which is the default)
+    to_write : bool
+        Write the Field in NetCDF format at the same frequency as the ParticleFile outputdt,
+        using a filenaming scheme based on the ParticleFile name
+
+    Examples
+    --------
     For usage examples see the following tutorials:
 
-    * `Nested Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`_
+    * `Nested Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`__
 
-    * `Summed Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_SummedFields.ipynb>`_
+    * `Summed Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_SummedFields.ipynb>`__
     """
+
     def __init__(self, name, data, lon=None, lat=None, depth=None, time=None, grid=None, mesh='flat', timestamps=None,
                  fieldtype=None, transpose=False, vmin=None, vmax=None, cast_data_dtype='float32', time_origin=None,
                  interp_method='linear', allow_time_extrapolation=None, time_periodic=False, gridindexingtype='nemo',
@@ -267,43 +292,64 @@ def collect_timeslices(timestamps, data_filenames, _grid_fb_class, dimensions, i
     def from_netcdf(cls, filenames, variable, dimensions, indices=None, grid=None,
                     mesh='spherical', timestamps=None, allow_time_extrapolation=None, time_periodic=False,
                     deferred_load=True, **kwargs):
-        """Create field from netCDF file
-
-        :param filenames: list of filenames to read for the field. filenames can be a list [files] or
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data)
-               In the latter case, time values are in filenames[data]
-        :param variable: Tuple mapping field name to variable name in the NetCDF file.
-        :param dimensions: Dictionary mapping variable names for the relevant dimensions in the NetCDF file
-        :param indices: dictionary mapping indices for each dimension to read from file.
-               This can be used for reading in only a subregion of the NetCDF file.
-               Note that negative indices are not allowed.
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param timestamps: A numpy array of datetime64 objects containing the timestamps for each of the files in filenames.
-               Default is None if dimensions includes time.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation in time
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: boolean whether to loop periodically over the time component of the FieldSet
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param deferred_load: boolean whether to only pre-load data (in deferred mode) or
-               fully load them (default: True). It is advised to deferred load the data, since in
-               that case Parcels deals with a better memory management during particle set execution.
-               deferred_load=False is however sometimes necessary for plotting the fields.
-        :param gridindexingtype: The type of gridindexing. Either 'nemo' (default) or 'mitgcm' are supported.
-               See also the Grid indexing documentation on oceanparcels.org
-        :param chunksize: size of the chunks in dask loading
-        :param netcdf_decodewarning: boolean whether to show a warning id there is a problem decoding the netcdf files.
-               Default is True, but in some cases where these warnings are expected, it may be useful to silence them
-               by setting netcdf_decodewarning=False.
-
+        """Create field from netCDF file.
+
+        Parameters
+        ----------
+        filenames : list of str or dict
+            list of filenames to read for the field. filenames can be a list ``[files]`` or
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data)
+            In the latter case, time values are in filenames[data]
+        variable : tuple of str or str
+            Tuple mapping field name to variable name in the NetCDF file.
+        dimensions : dict
+            Dictionary mapping variable names for the relevant dimensions in the NetCDF file
+        indices :
+            dictionary mapping indices for each dimension to read from file.
+            This can be used for reading in only a subregion of the NetCDF file.
+            Note that negative indices are not allowed. (Default value = None)
+        mesh :
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        timestamps :
+            A numpy array of datetime64 objects containing the timestamps for each of the files in filenames.
+            Default is None if dimensions includes time.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation in time
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            boolean whether to loop periodically over the time component of the FieldSet
+            This flag overrides the allow_time_extrapolation and sets it to False (Default value = False)
+        deferred_load : bool
+            boolean whether to only pre-load data (in deferred mode) or
+            fully load them (default: True). It is advised to deferred load the data, since in
+            that case Parcels deals with a better memory management during particle set execution.
+            deferred_load=False is however sometimes necessary for plotting the fields.
+        gridindexingtype : str
+            The type of gridindexing. Either 'nemo' (default) or 'mitgcm' are supported.
+            See also the Grid indexing documentation on oceanparcels.org
+        chunksize :
+            size of the chunks in dask loading
+        netcdf_decodewarning : bool
+            Whether to show a warning id there is a problem decoding the netcdf files.
+            Default is True, but in some cases where these warnings are expected, it may be useful to silence them
+            by setting netcdf_decodewarning=False.
+        grid :
+             (Default value = None)
+        **kwargs :
+            Keyword arguments passed to the :class:`Field` constructor.
+
+        Examples
+        --------
         For usage examples see the following tutorial:
 
-        * `Timestamps <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timestamps.ipynb>`_
+        * `Timestamps <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timestamps.ipynb>`__
+
         """
         # Ensure the timestamps array is compatible with the user-provided datafiles.
         if timestamps is not None:
@@ -486,24 +532,33 @@ def from_netcdf(cls, filenames, variable, dimensions, indices=None, grid=None,
     @classmethod
     def from_xarray(cls, da, name, dimensions, mesh='spherical', allow_time_extrapolation=None,
                     time_periodic=False, **kwargs):
-        """Create field from xarray Variable
-
-        :param da: Xarray DataArray
-        :param name: Name of the Field
-        :param dimensions: Dictionary mapping variable names for the relevant dimensions in the DataArray
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation in time
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: boolean whether to loop periodically over the time component of the FieldSet
-               This flag overrides the allow_time_interpolation and sets it to False
+        """Create field from xarray Variable.
+
+        Parameters
+        ----------
+        da : xr.DataArray
+            Xarray DataArray
+        name : str
+            Name of the Field
+        dimensions : dict
+            Dictionary mapping variable names for the relevant dimensions in the DataArray
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation in time
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            boolean whether to loop periodically over the time component of the FieldSet
+            This flag overrides the allow_time_extrapolation and sets it to False (Default value = False)
+        **kwargs :
+            Keyword arguments passed to the :class:`Field` constructor.
         """
-
         data = da.data
         interp_method = kwargs.pop('interp_method', 'linear')
 
@@ -573,11 +628,17 @@ def reshape(self, data, transpose=False):
     def set_scaling_factor(self, factor):
         """Scales the field data by some constant factor.
 
-        :param factor: scaling factor
+        Parameters
+        ----------
+        factor :
+            scaling factor
+
 
+        Examples
+        --------
         For usage examples see the following tutorial:
 
-        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_
+        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__
         """
         if self._scaling_factor:
             raise NotImplementedError(f'Scaling factor for field {self.name} already defined.')
@@ -586,10 +647,12 @@ def set_scaling_factor(self, factor):
             self.data *= factor
 
     def set_depth_from_field(self, field):
-        """Define the depth dimensions from another (time-varying) field
+        """Define the depth dimensions from another (time-varying) field.
 
-        See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timevaryingdepthdimensions.ipynb>`_
-        for a detailed explanation on how to set up time-evolving depth dimensions
+        Notes
+        -----
+        See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timevaryingdepthdimensions.ipynb>`__
+        for a detailed explanation on how to set up time-evolving depth dimensions.
 
         """
         self.grid.depth_field = field
@@ -597,8 +660,10 @@ def set_depth_from_field(self, field):
             field.grid.depth_field = field
 
     def calc_cell_edge_sizes(self):
-        """Method to calculate cell sizes based on numpy.gradient method
-                Currently only works for Rectilinear Grids"""
+        """Method to calculate cell sizes based on numpy.gradient method.
+
+        Currently only works for Rectilinear Grids
+        """
         if not self.grid.cell_edge_sizes:
             if self.grid.gtype in (GridCode.RectilinearZGrid, GridCode.RectilinearSGrid):
                 self.grid.cell_edge_sizes['x'] = np.zeros((self.grid.ydim, self.grid.xdim), dtype=np.float32)
@@ -618,8 +683,10 @@ def calc_cell_edge_sizes(self):
                 exit(-1)
 
     def cell_areas(self):
-        """Method to calculate cell sizes based on cell_edge_sizes
-                Currently only works for Rectilinear Grids"""
+        """Method to calculate cell sizes based on cell_edge_sizes.
+
+        Currently only works for Rectilinear Grids
+        """
         if not self.grid.cell_edge_sizes:
             self.calc_cell_edge_sizes()
         return self.grid.cell_edge_sizes['x'] * self.grid.cell_edge_sizes['y']
@@ -1038,13 +1105,15 @@ def interpolator3D(self, ti, z, y, x, time, particle=None):
             raise RuntimeError(self.interp_method+" is not implemented for 3D grids")
 
     def temporal_interpolate_fullfield(self, ti, time):
-        """Calculate the data of a field between two snapshots,
-        using linear interpolation
-
-        :param ti: Index in time array associated with time (via :func:`time_index`)
-        :param time: Time to interpolate to
-
-        :rtype: Linearly interpolated field"""
+        """Calculate the data of a field between two snapshots using linear interpolation.
+
+        Parameters
+        ----------
+        ti :
+            Index in time array associated with time (via :func:`time_index`)
+        time :
+            Time to interpolate to
+        """
         t0 = self.grid.time[ti]
         if time == t0:
             return self.data[ti, :]
@@ -1057,8 +1126,7 @@ def temporal_interpolate_fullfield(self, ti, time):
             return f0 + (f1 - f0) * ((time - t0) / (t1 - t0))
 
     def spatial_interpolation(self, ti, z, y, x, time, particle=None):
-        """Interpolate horizontal field values using a SciPy interpolator"""
-
+        """Interpolate horizontal field values using a SciPy interpolator."""
         if self.grid.zdim == 1:
             val = self.interpolator2D(ti, z, y, x, particle=particle)
         else:
@@ -1072,7 +1140,7 @@ def spatial_interpolation(self, ti, z, y, x, time, particle=None):
             return val
 
     def time_index(self, time):
-        """Find the index in the time array associated with a given time
+        """Find the index in the time array associated with a given time.
 
         Note that we normalize to either the first or the last index
         if the sampled value is outside the time value range.
@@ -1214,9 +1282,7 @@ def chunk_data(self):
 
     @property
     def ctypes_struct(self):
-        """Returns a ctypes struct object containing all relevant
-        pointers and sizes for this field."""
-
+        """Returns a ctypes struct object containing all relevant pointers and sizes for this field."""
         # Ctypes struct corresponding to the type definition in parcels.h
         class CField(Structure):
             _fields_ = [('xdim', c_int), ('ydim', c_int), ('zdim', c_int),
@@ -1247,17 +1313,30 @@ class CField(Structure):
 
     def show(self, animation=False, show_time=None, domain=None, depth_level=0, projection='PlateCarree', land=True,
              vmin=None, vmax=None, savefile=None, **kwargs):
-        """Method to 'show' a Parcels Field
-
-        :param animation: Boolean whether result is a single plot, or an animation
-        :param show_time: Time in seconds from start after which to show the Field (only in single-plot mode)
-        :param domain: dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show
-        :param depth_level: depth level to be plotted (default 0)
-        :param projection: type of cartopy projection to use (default PlateCarree)
-        :param land: Boolean whether to show land. This is ignored for flat meshes
-        :param vmin: minimum colour scale (only in single-plot mode)
-        :param vmax: maximum colour scale (only in single-plot mode)
-        :param savefile: Name of a file to save the plot to
+        """Method to 'show' a Parcels Field.
+
+        Parameters
+        ----------
+        animation : bool
+            Whether result is a single plot, or an animation (Default value = False)
+        show_time : float
+            Time in seconds from start after which to show the Field (only in single-plot mode) (Default value = None)
+        domain : dict
+            dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show (Default value = None)
+        depth_level :
+            depth level to be plotted (default 0)
+        projection :
+            type of cartopy projection to use (default PlateCarree)
+        land : bool
+            Whether to show land. This is ignored for flat meshes (Default value = True)
+        vmin : float
+            minimum colour scale (only in single-plot mode) (Default value = None)
+        vmax : float
+            maximum colour scale (only in single-plot mode) (Default value = None)
+        savefile : str, opptional
+            Name of a file to save the plot to (Default value = None)
+        **kwargs :
+            Additional keyword arguments to pass to :func:`parcels.plotting.plotfield`
         """
         from parcels.plotting import plotfield
         plt, _, _, _ = plotfield(self, animation=animation, show_time=show_time, domain=domain, depth_level=depth_level,
@@ -1266,17 +1345,25 @@ def show(self, animation=False, show_time=None, domain=None, depth_level=0, proj
             plt.show()
 
     def add_periodic_halo(self, zonal, meridional, halosize=5, data=None):
-        """Add a 'halo' to all Fields in a FieldSet, through extending the Field (and lon/lat)
+        """Add a 'halo' to all Fields in a FieldSet.
+
+        Add a 'halo' to all Fields in a FieldSet, through extending the Field (and lon/lat)
         by copying a small portion of the field on one side of the domain to the other.
         Before adding a periodic halo to the Field, it has to be added to the Grid on which the Field depends
 
-        See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_periodic_boundaries.ipynb>`_
+        See `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_periodic_boundaries.ipynb>`__
         for a detailed explanation on how to set up periodic boundaries
 
-        :param zonal: Create a halo in zonal direction (boolean)
-        :param meridional: Create a halo in meridional direction (boolean)
-        :param halosize: size of the halo (in grid points). Default is 5 grid points
-        :param data: if data is not None, the periodic halo will be achieved on data instead of self.data and data will be returned
+        Parameters
+        ----------
+        zonal : bool
+            Create a halo in zonal direction.
+        meridional : bool
+            Create a halo in meridional direction.
+        halosize : int
+            Size of the halo (in grid points). Default is 5 grid points
+        data :
+            if data is not None, the periodic halo will be achieved on data instead of self.data and data will be returned (Default value = None)
         """
         dataNone = not isinstance(data, (np.ndarray, da.core.Array))
         if self.grid.defer_load and dataNone:
@@ -1310,10 +1397,15 @@ def add_periodic_halo(self, zonal, meridional, halosize=5, data=None):
             return data
 
     def write(self, filename, varname=None):
-        """Write a :class:`Field` to a netcdf file
-
-        :param filename: Basename of the file
-        :param varname: Name of the field, to be appended to the filename"""
+        """Write a :class:`Field` to a netcdf file.
+
+        Parameters
+        ----------
+        filename : str
+            Basename of the file (i.e. '{filename}{Field.name}.nc')
+        varname : str
+            Name of the field, to be appended to the filename. (Default value = None)
+        """
         filepath = str(Path(f'{filename}{self.name}.nc'))
         if varname is None:
             varname = self.name
@@ -1424,11 +1516,18 @@ class VectorField:
     """Class VectorField stores 2 or 3 fields which defines together a vector field.
     This enables to interpolate them as one single vector field in the kernels.
 
-    :param name: Name of the vector field
-    :param U: field defining the zonal component
-    :param V: field defining the meridional component
-    :param W: field defining the vertical component (default: None)
+    Parameters
+    ----------
+    name : str
+        Name of the vector field
+    U : parcels.field.Field
+        field defining the zonal component
+    V : parcels.field.Field
+        field defining the meridional component
+    W : parcels.field.Field
+        field defining the vertical component (default: None)
     """
+
     def __init__(self, name, U, V, W=None):
         self.name = name
         self.U = U
@@ -1640,14 +1739,15 @@ def spatial_c_grid_interpolation3D_full(self, ti, z, y, x, time, particle=None):
         return (u, v, w)
 
     def spatial_c_grid_interpolation3D(self, ti, z, y, x, time, particle=None, applyConversion=True):
-        """
-        +---+---+---+
-        |   |V1 |   |
-        +---+---+---+
-        |U0 |   |U1 |
-        +---+---+---+
-        |   |V0 |   |
-        +---+---+---+
+        """Perform C grid interpolation in 3D. ::
+
+            +---+---+---+
+            |   |V1 |   |
+            +---+---+---+
+            |U0 |   |U1 |
+            +---+---+---+
+            |   |V0 |   |
+            +---+---+---+
 
         The interpolation is done in the following by
         interpolating linearly U depending on the longitude coordinate and
@@ -1824,7 +1924,8 @@ def ccode_eval_object(self, varU, varV, varW, U, V, W, t, z, y, x):
 
 
 class DeferredArray():
-    """Class used for throwing error when Field.data is not read in deferred loading mode"""
+    """Class used for throwing error when Field.data is not read in deferred loading mode."""
+
     data_shape = ()
 
     def __init__(self):
@@ -1847,21 +1948,33 @@ def __getitem__(self, key):
 
 
 class SummedField(list):
-    """Class SummedField is a list of Fields over which Field interpolation
-    is summed. This can e.g. be used when combining multiple flow fields,
+    """Class SummedField is a list of Fields over which Field interpolation is summed.
+
+    This can e.g. be used when combining multiple flow fields,
     where the total flow is the sum of all the individual flows.
     Note that the individual Fields can be on different Grids.
     Also note that, since SummedFields are lists, the individual Fields can
     still be queried through their list index (e.g. SummedField[1]).
     SummedField is composed of either Fields or VectorFields.
 
-    See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_SummedFields.ipynb>`_
+
+    Parameters
+    ----------
+    name : str
+        Name of the SummedField
+    F : list of Field
+        List of fields. F can be a scalar Field, a VectorField, or the zonal component (U) of the VectorField
+    V : list of Field
+        List of fields defining the meridional component of a VectorField, if F is the zonal component. (default: None)
+    W : list of Field
+        List of fields defining the vertical component of a VectorField, if F and V are the zonal and meridional components (default: None)
+
+
+    Examples
+    --------
+    See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_SummedFields.ipynb>`__
     for a detailed tutorial
 
-    :param name: Name of the SummedField
-    :param F: List of fields. F can be a scalar Field, a VectorField, or the zonal component (U) of the VectorField
-    :param V: List of fields defining the meridional component of a VectorField, if F is the zonal component. (default: None)
-    :param W: List of fields defining the vertical component of a VectorField, if F and V are the zonal and meridional components (default: None)
     """
 
     def __init__(self, name, F, V=None, W=None):
@@ -1917,20 +2030,32 @@ def __add__(self, field):
 
 
 class NestedField(list):
-    """Class NestedField is a list of Fields from which the first one to be not declared out-of-boundaries
-    at particle position is interpolated. This induces that the order of the fields in the list matters.
+    """NestedField is a class that allows for interpolation of fields on different grids of potentially varying resolution.
+
+    The NestedField class is a list of Fields where the first Field that contains the particle within the domain is then used for interpolation.
+    This induces that the order of the fields in the list matters.
     Each one it its turn, a field is interpolated: if the interpolation succeeds or if an error other
     than `ErrorOutOfBounds` is thrown, the function is stopped. Otherwise, next field is interpolated.
     NestedField returns an `ErrorOutOfBounds` only if last field is as well out of boundaries.
     NestedField is composed of either Fields or VectorFields.
 
-    See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`_
+    Parameters
+    ----------
+    name : str
+        Name of the NestedField
+    F : list of Field
+        List of fields (order matters). F can be a scalar Field, a VectorField, or the zonal component (U) of the VectorField
+    V : list of Field
+        List of fields defining the meridional component of a VectorField, if F is the zonal component. (default: None)
+    W : list of Field
+        List of fields defining the vertical component of a VectorField, if F and V are the zonal and meridional components (default: None)
+
+
+    Examples
+    --------
+    See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`__
     for a detailed tutorial
 
-    :param name: Name of the NestedField
-    :param F: List of fields (order matters). F can be a scalar Field, a VectorField, or the zonal component (U) of the VectorField
-    :param V: List of fields defining the meridional component of a VectorField, if F is the zonal component. (default: None)
-    :param W: List of fields defining the vertical component of a VectorField, if F and V are the zonal and meridional components (default: None)
     """
 
     def __init__(self, name, F, V=None, W=None):
diff --git a/parcels/fieldfilebuffer.py b/parcels/fieldfilebuffer.py
index 923214cc1..85e8339d0 100644
--- a/parcels/fieldfilebuffer.py
+++ b/parcels/fieldfilebuffer.py
@@ -299,7 +299,8 @@ def __enter__(self):
         return self
 
     def __exit__(self, type, value, traceback):
-        """
+        """Function releases the file handle.
+
         This function releases the file handle. Hence access to the dataset and its header-information is lost. The
         previously executed chunking is lost. Furthermore, if the file access required file locking, the lock-handle
         is freed so other processes can now access the file again.
@@ -307,7 +308,8 @@ def __exit__(self, type, value, traceback):
         self.close()
 
     def close(self):
-        """
+        """Teardown FileBuffer object with dask.
+
         This function can be called to initialise an orderly teardown of a FileBuffer object with dask, meaning
         to release the file handle, deposing the dataset, and releasing the file lock (if required).
         """
@@ -357,9 +359,8 @@ def add_to_dimension_name_map(self, name_map):
             self._static_name_maps[pcls_dim_name].append(name_map[pcls_dim_name])
 
     def _get_available_dims_indices_by_request(self):
-        """
-        [private function - not to be called from outside the class]
-        Returns a dict mapping 'parcels_dimname' -> [None, int32_index_data_array].
+        """Returns a dict mapping 'parcels_dimname' -> [None, int32_index_data_array].
+
         This dictionary is based on the information provided by the requested dimensions.
         Example: {'time': 0, 'depth': None, 'lat': 1, 'lon': 2}
         """
@@ -382,7 +383,6 @@ def _get_available_dims_indices_by_request(self):
 
     def _get_available_dims_indices_by_namemap(self):
         """
-        [private function - not to be called from outside the class]
         Returns a dict mapping 'parcels_dimname' -> [None, int32_index_data_array].
         This dictionary is based on the information provided by the requested dimensions.
         Example: {'time': 0, 'depth': 1, 'lat': 2, 'lon': 3}
@@ -394,7 +394,6 @@ def _get_available_dims_indices_by_namemap(self):
 
     def _get_available_dims_indices_by_netcdf_file(self):
         """
-        [private function - not to be called from outside the class]
         [File needs to be open (i.e. self.dataset is not None) for this to work - otherwise generating an error]
         Returns a dict mapping 'parcels_dimname' -> [None, int32_index_data_array].
         This dictionary is based on the information provided by the requested dimensions.
@@ -419,7 +418,6 @@ def _get_available_dims_indices_by_netcdf_file(self):
 
     def _is_dimension_available(self, dimension_name):
         """
-        [private function - not to be called from outside the class]
         This function returns a boolean value indicating if a certain variable (name) is avaialble in the
         requested dimensions as well as in the actual dataset of the file. If any of the two conditions is not met,
         if returns 'False'.
@@ -430,7 +428,6 @@ def _is_dimension_available(self, dimension_name):
 
     def _is_dimension_chunked(self, dimension_name):
         """
-        [private function - not to be called from outside the class]
         This functions returns a boolean value indicating if a certain variable is available in the requested
         dimensions, the NetCDF file dataset, and is also required to be chunked according to the requested
         chunksize dictionary. If any of the two conditions is not met, if returns 'False'.
@@ -444,7 +441,6 @@ def _is_dimension_chunked(self, dimension_name):
 
     def _is_dimension_in_dataset(self, parcels_dimension_name, netcdf_dimension_name=None):
         """
-        [private function - not to be called from outside the class]
         [File needs to be open (i.e. self.dataset is not None) for this to work - otherwise generating an error]
         This function returns the index, the name and the size of a NetCDF dimension in the file (in order: index, name, size).
         It requires as input the name of the related parcels dimension (i.e. one of ['time', 'depth', 'lat', 'lon']. If
@@ -472,7 +468,6 @@ def _is_dimension_in_dataset(self, parcels_dimension_name, netcdf_dimension_name
 
     def _is_dimension_in_chunksize_request(self, parcels_dimension_name):
         """
-        [private function - not to be called from outside the class]
         This function returns the dense-array index, the NetCDF dimension name and the requested chunsize of a requested
         parcels dimension(in order: index, name, size). This only works if the chunksize is provided as a dictionary
         of tuples of parcels dimensions and their chunk mapping (i.e. dict(parcels_dim_name => (netcdf_dim_name, chunksize)).
@@ -490,16 +485,12 @@ def _is_dimension_in_chunksize_request(self, parcels_dimension_name):
         return k, dname, dvalue
 
     def _netcdf_DimNotFound_warning_message(self, dimension_name):
-        """
-        [private function - not to be called from outside the class]
-        Helper function that issues a warning message if a certain requested NetCDF dimension is not found in the file.
-        """
+        """Helper function that issues a warning message if a certain requested NetCDF dimension is not found in the file."""
         display_name = dimension_name if (dimension_name not in self.dimensions) else self.dimensions[dimension_name]
         return f"Did not find {display_name} in NetCDF dims. Please specifiy chunksize as dictionary for NetCDF dimension names, e.g.\n chunksize={{ '{display_name}': <number>, ... }}."
 
     def _chunkmap_to_chunksize(self):
         """
-        [private function - not to be called from outside the class]
         [File needs to be open via the '__enter__'-method for this to work - otherwise generating an error]
         This functions translates the array-index-to-chunksize chunk map into a proper fieldsize dictionary that
         can later be used for re-qunking, if a previously-opened file is re-opened again.
@@ -539,7 +530,6 @@ def _chunkmap_to_chunksize(self):
 
     def _get_initial_chunk_dictionary_by_dict_(self):
         """
-        [private function - not to be called from outside the class]
         [File needs to be open (i.e. self.dataset is not None) for this to work - otherwise generating an error]
         Maps and correlates the requested dictionary-style chunksize with the requested parcels dimensions, variables
         and the NetCDF-available dimensions. Thus, it takes care to remove chunksize arguments that are not in the
@@ -590,10 +580,7 @@ def _get_initial_chunk_dictionary_by_dict_(self):
         return chunk_dict, chunk_index_map
 
     def _failsafe_parse_(self):
-        """
-        [private function - not to be called from outside the class]
-        ['name' need to be initialised]
-        """
+        """['name' need to be initialised]"""
         # ==== fail - open it as a normal array and deduce the dimensions from the variable-function names ==== #
         # ==== done by parsing ALL variables in the NetCDF, and comparing their call-parameters with the   ==== #
         # ==== name map available here.                                                                    ==== #
@@ -638,7 +625,6 @@ def _failsafe_parse_(self):
 
     def _get_initial_chunk_dictionary(self):
         """
-        [private function - not to be called from outside the class]
         Super-function that maps and correlates the requested chunksize with the requested parcels dimensions, variables
         and the NetCDF-available dimensions. Thus, it takes care to remove chunksize arguments that are not in the
         Parcels- or NetCDF dimensions, or whose chunking would be omitted due to an empty chunk dimension.
diff --git a/parcels/fieldset.py b/parcels/fieldset.py
index f83e9685c..db3ba389b 100644
--- a/parcels/fieldset.py
+++ b/parcels/fieldset.py
@@ -23,12 +23,19 @@
 
 
 class FieldSet:
-    """FieldSet class that holds hydrodynamic data needed to execute particles
-
-    :param U: :class:`parcels.field.Field` object for zonal velocity component
-    :param V: :class:`parcels.field.Field` object for meridional velocity component
-    :param fields: Dictionary of additional :class:`parcels.field.Field` objects
+    """FieldSet class that holds hydrodynamic data needed to execute particles.
+
+    Parameters
+    ----------
+    U : parcels.field.Field
+        Field object for zonal velocity component
+    V : parcels.field.Field
+        Field object for meridional velocity component
+    fields : dict mapping str to Field
+        Additional fields to include in the FieldSet. These fields can be used
+        in custom kernels.
     """
+
     def __init__(self, U, V, fields=None):
         self.gridset = GridSet()
         self.completed = False
@@ -55,48 +62,57 @@ def checkvaliddimensionsdict(dims):
     @classmethod
     def from_data(cls, data, dimensions, transpose=False, mesh='spherical',
                   allow_time_extrapolation=None, time_periodic=False, **kwargs):
-        """Initialise FieldSet object from raw data
-
-        :param data: Dictionary mapping field names to numpy arrays.
-               Note that at least a 'U' and 'V' numpy array need to be given, and that
-               the built-in Advection kernels assume that U and V are in m/s
-
-               1. If data shape is [xdim, ydim], [xdim, ydim, zdim], [xdim, ydim, tdim] or [xdim, ydim, zdim, tdim],
-                  whichever is relevant for the dataset, use the flag transpose=True
-               2. If data shape is [ydim, xdim], [zdim, ydim, xdim], [tdim, ydim, xdim] or [tdim, zdim, ydim, xdim],
-                  use the flag transpose=False (default value)
-               3. If data has any other shape, you first need to reorder it
-        :param dimensions: Dictionary mapping field dimensions (lon,
-               lat, depth, time) to numpy arrays.
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable
-               (e.g. dimensions['U'], dimensions['V'], etc).
-        :param transpose: Boolean whether to transpose data on read-in
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-
-        Usage examples
-        ==============
-
-        * `Analytical advection <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_analyticaladvection.ipynb>`_
-
-        * `Diffusion <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`_
-
-        * `Interpolation <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_interpolation.ipynb>`_
-
-        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_
+        """Initialise FieldSet object from raw data.
+
+        Parameters
+        ----------
+        data :
+            Dictionary mapping field names to numpy arrays.
+            Note that at least a 'U' and 'V' numpy array need to be given, and that
+            the built-in Advection kernels assume that U and V are in m/s
+
+            1. If data shape is [xdim, ydim], [xdim, ydim, zdim], [xdim, ydim, tdim] or [xdim, ydim, zdim, tdim],
+               whichever is relevant for the dataset, use the flag transpose=True
+            2. If data shape is [ydim, xdim], [zdim, ydim, xdim], [tdim, ydim, xdim] or [tdim, zdim, ydim, xdim],
+               use the flag transpose=False (default value)
+            3. If data has any other shape, you first need to reorder it
+        dimensions : dict
+            Dictionary mapping field dimensions (lon,
+            lat, depth, time) to numpy arrays.
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable
+            (e.g. dimensions['U'], dimensions['V'], etc).
+        transpose : bool
+            Whether to transpose data on read-in (Default value = False)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        **kwargs :
+            Keyword arguments passed to the :class:`Field` constructor.
+
+        Examples
+        --------
+        For usage examples see the following tutorials:
 
-        """
+        * `Analytical advection <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_analyticaladvection.ipynb>`__
 
+        * `Diffusion <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`__
+
+        * `Interpolation <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_interpolation.ipynb>`__
+
+        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__
+        """
         fields = {}
         for name, datafld in data.items():
             # Use dimensions[name] if dimensions is a dict of dicts
@@ -127,16 +143,23 @@ def from_data(cls, data, dimensions, transpose=False, mesh='spherical',
         return cls(u, v, fields=fields)
 
     def add_field(self, field, name=None):
-        """Add a :class:`parcels.field.Field` object to the FieldSet
+        """Add a :class:`parcels.field.Field` object to the FieldSet.
 
-        :param field: :class:`parcels.field.Field` object to be added
-        :param name: Name of the :class:`parcels.field.Field` object to be added
+        Parameters
+        ----------
+        field : parcels.field.Field
+            Field object to be added
+        name : str
+            Name of the :class:`parcels.field.Field` object to be added
 
+
+        Examples
+        --------
         For usage examples see the following tutorials:
 
-        * `Nested Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`_
+        * `Nested Fields <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_NestedFields.ipynb>`__
 
-        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_
+        * `Unit converters <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__ (Default value = None)
 
         """
         if self.completed:
@@ -166,17 +189,29 @@ def add_constant_field(self, name, value, mesh='flat'):
         """Wrapper function to add a Field that is constant in space,
            useful e.g. when using constant horizontal diffusivity
 
-        :param name: Name of the :class:`parcels.field.Field` object to be added
-        :param value: Value of the constant field (stored as 32-bit float)
-        :param units: Optional UnitConverter object, to convert units
-                      (e.g. for Horizontal diffusivity from m2/s to degree2/s)
+        Parameters
+        ----------
+        name : str
+            Name of the :class:`parcels.field.Field` object to be added
+        value : float
+            Value of the constant field (stored as 32-bit float)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
         """
         self.add_field(Field(name, value, lon=0, lat=0, mesh=mesh))
 
     def add_vector_field(self, vfield):
-        """Add a :class:`parcels.field.VectorField` object to the FieldSet
+        """Add a :class:`parcels.field.VectorField` object to the FieldSet.
 
-        :param vfield: :class:`parcels.field.VectorField` object to be added
+        Parameters
+        ----------
+        vfield : parcels.VectorField
+            class:`parcels.field.VectorField` object to be added
         """
         setattr(self, vfield.name, vfield)
         for v in vfield.__dict__.values():
@@ -291,66 +326,87 @@ def parse_wildcards(cls, paths, filenames, var):
     def from_netcdf(cls, filenames, variables, dimensions, indices=None, fieldtype=None,
                     mesh='spherical', timestamps=None, allow_time_extrapolation=None, time_periodic=False,
                     deferred_load=True, chunksize=None, **kwargs):
-        """Initialises FieldSet object from NetCDF files
-
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}.
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable names in the netCDF file(s).
-               Note that the built-in Advection kernels assume that U and V are in m/s
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable
-               (e.g. dimensions['U'], dimensions['V'], etc).
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also `this tuturial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param timestamps: list of lists or array of arrays containing the timestamps for
-               each of the files in filenames. Outer list/array corresponds to files, inner
-               array corresponds to indices within files.
-               Default is None if dimensions includes time.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param deferred_load: boolean whether to only pre-load data (in deferred mode) or
-               fully load them (default: True). It is advised to deferred load the data, since in
-               that case Parcels deals with a better memory management during particle set execution.
-               deferred_load=False is however sometimes necessary for plotting the fields.
-        :param interp_method: Method for interpolation. Options are 'linear' (default), 'nearest',
-               'linear_invdist_land_tracer', 'cgrid_velocity', 'cgrid_tracer' and 'bgrid_velocity'
-        :param gridindexingtype: The type of gridindexing. Either 'nemo' (default) or 'mitgcm' are supported.
-               See also the Grid indexing documentation on oceanparcels.org
-        :param chunksize: size of the chunks in dask loading. Default is None (no chunking). Can be None or False (no chunking),
-               'auto' (chunking is done in the background, but results in one grid per field individually), or a dict in the format
-               '{parcels_varname: {netcdf_dimname : (parcels_dimname, chunksize_as_int)}, ...}', where 'parcels_dimname' is one of ('time', 'depth', 'lat', 'lon')
-        :param netcdf_engine: engine to use for netcdf reading in xarray. Default is 'netcdf',
-               but in cases where this doesn't work, setting netcdf_engine='scipy' could help
-
+        """Initialises FieldSet object from NetCDF files.
+
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``.
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable names in the netCDF file(s).
+            Note that the built-in Advection kernels assume that U and V are in m/s
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable
+            (e.g. dimensions['U'], dimensions['V'], etc).
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None) (Default value = None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tuturial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        timestamps :
+            list of lists or array of arrays containing the timestamps for
+            each of the files in filenames. Outer list/array corresponds to files, inner
+            array corresponds to indices within files.
+            Default is None if dimensions includes time.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        deferred_load : bool
+            boolean whether to only pre-load data (in deferred mode) or
+            fully load them (default: True). It is advised to deferred load the data, since in
+            that case Parcels deals with a better memory management during particle set execution.
+            deferred_load=False is however sometimes necessary for plotting the fields.
+        interp_method : str
+            Method for interpolation. Options are 'linear' (default), 'nearest',
+            'linear_invdist_land_tracer', 'cgrid_velocity', 'cgrid_tracer' and 'bgrid_velocity'
+        gridindexingtype : str
+            The type of gridindexing. Either 'nemo' (default) or 'mitgcm' are supported.
+            See also the Grid indexing documentation on oceanparcels.org
+        chunksize :
+            size of the chunks in dask loading. Default is None (no chunking). Can be None or False (no chunking),
+            'auto' (chunking is done in the background, but results in one grid per field individually), or a dict in the format
+            ``{parcels_varname: {netcdf_dimname : (parcels_dimname, chunksize_as_int)}, ...}``, where ``parcels_dimname`` is one of ('time', 'depth', 'lat', 'lon')
+        netcdf_engine :
+            engine to use for netcdf reading in xarray. Default is 'netcdf',
+            but in cases where this doesn't work, setting netcdf_engine='scipy' could help
+        **kwargs :
+            Keyword arguments passed to the :class:`parcels.Field` constructor.
+
+
+        Examples
+        --------
         For usage examples see the following tutorials:
 
-        * `Basic Parcels setup <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/parcels_tutorial.ipynb>`_
+        * `Basic Parcels setup <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/parcels_tutorial.ipynb>`__
 
-        * `Argo floats <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_Argofloats.ipynb>`_
+        * `Argo floats <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_Argofloats.ipynb>`__
 
-        * `Timestamps <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timestamps.ipynb>`_
+        * `Timestamps <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timestamps.ipynb>`__
 
-        * `Time-evolving depth dimensions <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timevaryingdepthdimensions.ipynb>`_
+        * `Time-evolving depth dimensions <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_timevaryingdepthdimensions.ipynb>`__
 
         """
         # Ensure that times are not provided both in netcdf file and in 'timestamps'.
@@ -426,65 +482,78 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
                   tracer_interp_method='cgrid_tracer', chunksize=None, **kwargs):
         """Initialises FieldSet object from NetCDF files of Curvilinear NEMO fields.
 
-        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_nemo_curvilinear.ipynb>`_
-        for a detailed tutorial on the setup for 2D NEMO fields and `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_nemo_3D.ipynb>`_
+        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_nemo_curvilinear.ipynb>`__
+        for a detailed tutorial on the setup for 2D NEMO fields and `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_nemo_3D.ipynb>`__
         for the tutorial on the setup for 3D NEMO fields.
 
-        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb>`_
+        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb>`__
         for a more detailed explanation of the different methods that can be used for c-grid datasets.
 
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files,
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable names in the netCDF file(s).
-               Note that the built-in Advection kernels assume that U and V are in m/s
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable.
-               Watch out: NEMO is discretised on a C-grid:
-               U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html ).
-
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |         V[k,j+1,i+1]        |                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j+1,i]                   |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|U[k,j+1,i+1]                 |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |         V[k,j,i+1]          +                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-
-               To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
-               which are located on the corners of the cells.
-               (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
-               In 3D, the depth is the one corresponding to W nodes
-               The gridindexingtype is set to 'nemo'. See also the Grid indexing documentation on oceanparcels.org
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'cgrid_tracer' (default)
-               Note that in the case of from_nemo() and from_cgrid(), the velocity fields are default to 'cgrid_velocity'
-        :param chunksize: size of the chunks in dask loading. Default is None (no chunking)
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files,
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable names in the netCDF file(s).
+            Note that the built-in Advection kernels assume that U and V are in m/s
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable.
+            Watch out: NEMO is discretised on a C-grid:
+            U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html). ::
+
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |         V[k,j+1,i+1]        |                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j+1,i]                   |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|U[k,j+1,i+1]                 |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |         V[k,j,i+1]          |                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+
+            To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
+            which are located on the corners of the cells.
+            (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
+            In 3D, the depth is the one corresponding to W nodes
+            The gridindexingtype is set to 'nemo'. See also the Grid indexing documentation on oceanparcels.org
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        tracer_interp_method : str
+            Method for interpolation of tracer fields. It is recommended to use 'cgrid_tracer' (default)
+            Note that in the case of from_nemo() and from_cgrid(), the velocity fields are default to 'cgrid_velocity'
+        chunksize :
+            size of the chunks in dask loading. Default is None (no chunking)
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_c_grid_dataset` constructor.
 
         """
-
         if 'creation_log' not in kwargs.keys():
             kwargs['creation_log'] = 'from_nemo'
         if kwargs.pop('gridindexingtype', 'nemo') != 'nemo':
@@ -501,19 +570,19 @@ def from_mitgcm(cls, filenames, variables, dimensions, indices=None, mesh='spher
                     allow_time_extrapolation=None, time_periodic=False,
                     tracer_interp_method='cgrid_tracer', chunksize=None, **kwargs):
         """Initialises FieldSet object from NetCDF files of MITgcm fields.
-           All parameters and keywords are exactly the same as for FieldSet.from_nemo(), except that
-           gridindexing is set to 'mitgcm' for grids that have the shape
-
-           +-----------------------------+-----------------------------+-----------------------------+
-           |                             |         V[k,j+1,i]          |                             |
-           +-----------------------------+-----------------------------+-----------------------------+
-           |U[k,j,i]                     |    W[k-1:k,j,i], T[k,j,i]   |U[k,j,i+1]                   |
-           +-----------------------------+-----------------------------+-----------------------------+
-           |                             |         V[k,j,i]            +                             |
-           +-----------------------------+-----------------------------+-----------------------------+
-
-           For indexing details: https://mitgcm.readthedocs.io/en/latest/algorithm/algorithm.html#spatial-discretization-of-the-dynamical-equations
-           Note that vertical velocity (W) is assumed postive in the positive z direction (which is upward in MITgcm)
+        All parameters and keywords are exactly the same as for FieldSet.from_nemo(), except that
+        gridindexing is set to 'mitgcm' for grids that have the shape::
+
+            +-----------------------------+-----------------------------+-----------------------------+
+            |                             |         V[k,j+1,i]          |                             |
+            +-----------------------------+-----------------------------+-----------------------------+
+            |U[k,j,i]                     |    W[k-1:k,j,i], T[k,j,i]   |U[k,j,i+1]                   |
+            +-----------------------------+-----------------------------+-----------------------------+
+            |                             |         V[k,j,i]            |                             |
+            +-----------------------------+-----------------------------+-----------------------------+
+
+        For indexing details: https://mitgcm.readthedocs.io/en/latest/algorithm/algorithm.html#spatial-discretization-of-the-dynamical-equations
+        Note that vertical velocity (W) is assumed postive in the positive z direction (which is upward in MITgcm)
         """
         if 'creation_log' not in kwargs.keys():
             kwargs['creation_log'] = 'from_mitgcm'
@@ -530,62 +599,75 @@ def from_c_grid_dataset(cls, filenames, variables, dimensions, indices=None, mes
                             tracer_interp_method='cgrid_tracer', gridindexingtype='nemo', chunksize=None, **kwargs):
         """Initialises FieldSet object from NetCDF files of Curvilinear NEMO fields.
 
-        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb>`_
+        See `here <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb>`__
         for a more detailed explanation of the different methods that can be used for c-grid datasets.
 
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files,
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable
-               names in the netCDF file(s).
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable.
-               Watch out: NEMO is discretised on a C-grid:
-               U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html ).
-
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |         V[k,j+1,i+1]        |                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j+1,i]                   |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|U[k,j+1,i+1]                 |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |         V[k,j,i+1]          +                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-
-               To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
-               which are located on the corners of the cells.
-               (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
-               In 3D, the depth is the one corresponding to W nodes.
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'cgrid_tracer' (default)
-               Note that in the case of from_nemo() and from_cgrid(), the velocity fields are default to 'cgrid_velocity'
-        :param gridindexingtype: The type of gridindexing. Set to 'nemo' in FieldSet.from_nemo()
-               See also the Grid indexing documentation on oceanparcels.org
-        :param chunksize: size of the chunks in dask loading
-
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files,
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable
+            names in the netCDF file(s).
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable.
+            Watch out: NEMO is discretised on a C-grid:
+            U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html ). ::
+
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |         V[k,j+1,i+1]        |                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j+1,i]                   |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|U[k,j+1,i+1]                 |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |         V[k,j,i+1]          |                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+
+            To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
+            which are located on the corners of the cells.
+            (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
+            In 3D, the depth is the one corresponding to W nodes.
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        tracer_interp_method : str
+            Method for interpolation of tracer fields. It is recommended to use 'cgrid_tracer' (default)
+            Note that in the case of from_nemo() and from_cgrid(), the velocity fields are default to 'cgrid_velocity'
+        gridindexingtype : str
+            The type of gridindexing. Set to 'nemo' in FieldSet.from_nemo()
+            See also the Grid indexing documentation on oceanparcels.org (Default value = 'nemo')
+        chunksize :
+            size of the chunks in dask loading. (Default value = None)
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_netcdf` constructor.
         """
-
         if 'U' in dimensions and 'V' in dimensions and dimensions['U'] != dimensions['V']:
             raise ValueError("On a C-grid, the dimensions of velocities should be the corners (f-points) of the cells, so the same for U and V. "
                              "See also https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb")
@@ -615,64 +697,78 @@ def from_pop(cls, filenames, variables, dimensions, indices=None, mesh='spherica
         """Initialises FieldSet object from NetCDF files of POP fields.
             It is assumed that the velocities in the POP fields is in cm/s.
 
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files,
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable names in the netCDF file(s).
-               Note that the built-in Advection kernels assume that U and V are in m/s
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable.
-               Watch out: POP is discretised on a B-grid:
-               U and V velocity nodes are not located as W velocity and T tracer nodes (see http://www.cesm.ucar.edu/models/cesm1.0/pop2/doc/sci/POPRefManual.pdf ).
-
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j+1,i],V[k,j+1,i]        |                             |U[k,j+1,i+1],V[k,j+1,i+1]    |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j,i],V[k,j,i]            |                             +U[k,j,i+1],V[k,j,i+1]        |
-               +-----------------------------+-----------------------------+-----------------------------+
-
-               In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
-                      T node is at the cell centre and interpolated constant per cell as a C-grid.
-               In 3D: U and V nodes are at the middle of the cell vertical edges,
-                      They are interpolated bilinearly (independently of z) in the cell.
-                      W nodes are at the centre of the horizontal interfaces.
-                      They are interpolated linearly (as a function of z) in the cell.
-                      T node is at the cell centre, and constant per cell.
-                      Note that Parcels assumes that the length of the depth dimension (at the W-points)
-                      is one larger than the size of the velocity and tracer fields in the depth dimension.
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
-               Note that in the case of from_pop() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
-        :param chunksize: size of the chunks in dask loading
-        :param depth_units: The units of the vertical dimension. Default in Parcels is 'm',
-               but many POP outputs are in 'cm'
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files,
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable names in the netCDF file(s).
+            Note that the built-in Advection kernels assume that U and V are in m/s
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable.
+            Watch out: POP is discretised on a B-grid:
+            U and V velocity nodes are not located as W velocity and T tracer nodes (see http://www.cesm.ucar.edu/models/cesm1.0/pop2/doc/sci/POPRefManual.pdf ). ::
+
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j+1,i],V[k,j+1,i]        |                             |U[k,j+1,i+1],V[k,j+1,i+1]    |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j,i],V[k,j,i]            |                             |U[k,j,i+1],V[k,j,i+1]        |
+                +-----------------------------+-----------------------------+-----------------------------+
+
+            In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
+            T node is at the cell centre and interpolated constant per cell as a C-grid.
+            In 3D: U and V nodes are at the middle of the cell vertical edges,
+            They are interpolated bilinearly (independently of z) in the cell.
+            W nodes are at the centre of the horizontal interfaces.
+            They are interpolated linearly (as a function of z) in the cell.
+            T node is at the cell centre, and constant per cell.
+            Note that Parcels assumes that the length of the depth dimension (at the W-points)
+            is one larger than the size of the velocity and tracer fields in the depth dimension.
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        tracer_interp_method : str
+            Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
+            Note that in the case of from_pop() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
+        chunksize :
+            size of the chunks in dask loading (Default value = None)
+        depth_units :
+            The units of the vertical dimension. Default in Parcels is 'm',
+            but many POP outputs are in 'cm'
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_b_grid_dataset` constructor.
 
         """
-
         if 'creation_log' not in kwargs.keys():
             kwargs['creation_log'] = 'from_pop'
         fieldset = cls.from_b_grid_dataset(filenames, variables, dimensions, mesh=mesh, indices=indices, time_periodic=time_periodic,
@@ -698,61 +794,72 @@ def from_mom5(cls, filenames, variables, dimensions, indices=None, mesh='spheric
                   tracer_interp_method='bgrid_tracer', chunksize=None, **kwargs):
         """Initialises FieldSet object from NetCDF files of MOM5 fields.
 
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files,
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable names in the netCDF file(s).
-               Note that the built-in Advection kernels assume that U and V are in m/s
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable.
-
-               +-------------------------------+-------------------------------+-------------------------------+
-               |U[k,j+1,i],V[k,j+1,i]          |                               |U[k,j+1,i+1],V[k,j+1,i+1]      |
-               +-------------------------------+-------------------------------+-------------------------------+
-               |                               |W[k-1:k+1,j+1,i+1],T[k,j+1,i+1]|                               |
-               +-------------------------------+-------------------------------+-------------------------------+
-               |U[k,j,i],V[k,j,i]              |                               +U[k,j,i+1],V[k,j,i+1]          |
-               +-------------------------------+-------------------------------+-------------------------------+
-
-               In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
-                      T node is at the cell centre and interpolated constant per cell as a C-grid.
-               In 3D: U and V nodes are at the midlle of the cell vertical edges,
-                      They are interpolated bilinearly (independently of z) in the cell.
-                      W nodes are at the centre of the horizontal interfaces, but below the U and V.
-                      They are interpolated linearly (as a function of z) in the cell.
-                      Note that W is normally directed upward in MOM5, but Parcels requires W
-                      in the positive z-direction (downward) so W is multiplied by -1.
-                      T node is at the cell centre, and constant per cell.
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
-               Note that in the case of from_mom5() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
-        :param chunksize: size of the chunks in dask loading
-
-
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files,
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable names in the netCDF file(s).
+            Note that the built-in Advection kernels assume that U and V are in m/s
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable. ::
+
+                +-------------------------------+-------------------------------+-------------------------------+
+                |U[k,j+1,i],V[k,j+1,i]          |                               |U[k,j+1,i+1],V[k,j+1,i+1]      |
+                +-------------------------------+-------------------------------+-------------------------------+
+                |                               |W[k-1:k+1,j+1,i+1],T[k,j+1,i+1]|                               |
+                +-------------------------------+-------------------------------+-------------------------------+
+                |U[k,j,i],V[k,j,i]              |                               |U[k,j,i+1],V[k,j,i+1]          |
+                +-------------------------------+-------------------------------+-------------------------------+
+
+            In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
+            T node is at the cell centre and interpolated constant per cell as a C-grid.
+            In 3D: U and V nodes are at the midlle of the cell vertical edges,
+            They are interpolated bilinearly (independently of z) in the cell.
+            W nodes are at the centre of the horizontal interfaces, but below the U and V.
+            They are interpolated linearly (as a function of z) in the cell.
+            Note that W is normally directed upward in MOM5, but Parcels requires W
+            in the positive z-direction (downward) so W is multiplied by -1.
+            T node is at the cell centre, and constant per cell.
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also the `Unit converters tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic:
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        tracer_interp_method : str
+            Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
+            Note that in the case of from_mom5() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
+        chunksize :
+            size of the chunks in dask loading (Default value = None)
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_b_grid_dataset` constructor.
         """
-
         if 'creation_log' not in kwargs.keys():
             kwargs['creation_log'] = 'from_mom5'
         fieldset = cls.from_b_grid_dataset(filenames, variables, dimensions, mesh=mesh, indices=indices, time_periodic=time_periodic,
@@ -768,59 +875,71 @@ def from_b_grid_dataset(cls, filenames, variables, dimensions, indices=None, mes
                             tracer_interp_method='bgrid_tracer', chunksize=None, **kwargs):
         """Initialises FieldSet object from NetCDF files of Bgrid fields.
 
-        :param filenames: Dictionary mapping variables to file(s). The
-               filepath may contain wildcards to indicate multiple files,
-               or be a list of file.
-               filenames can be a list [files], a dictionary {var:[files]},
-               a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
-               or a dictionary of dictionaries {var:{dim:[files]}}
-               time values are in filenames[data]
-        :param variables: Dictionary mapping variables to variable
-               names in the netCDF file(s).
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the netCF file(s).
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable.
-               U and V velocity nodes are not located as W velocity and T tracer nodes (see http://www.cesm.ucar.edu/models/cesm1.0/pop2/doc/sci/POPRefManual.pdf ).
-
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j+1,i],V[k,j+1,i]        |                             |U[k,j+1,i+1],V[k,j+1,i+1]    |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |                             |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|                             |
-               +-----------------------------+-----------------------------+-----------------------------+
-               |U[k,j,i],V[k,j,i]            |                             +U[k,j,i+1],V[k,j,i+1]        |
-               +-----------------------------+-----------------------------+-----------------------------+
-
-               In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
-                      T node is at the cell centre and interpolated constant per cell as a C-grid.
-               In 3D: U and V nodes are at the midlle of the cell vertical edges,
-                      They are interpolated bilinearly (independently of z) in the cell.
-                      W nodes are at the centre of the horizontal interfaces.
-                      They are interpolated linearly (as a function of z) in the cell.
-                      T node is at the cell centre, and constant per cell.
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
-               Note that in the case of from_pop() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
-        :param chunksize: size of the chunks in dask loading
-
+        Parameters
+        ----------
+        filenames :
+            Dictionary mapping variables to file(s). The
+            filepath may contain wildcards to indicate multiple files,
+            or be a list of file.
+            filenames can be a list ``[files]``, a dictionary ``{var:[files]}``,
+            a dictionary ``{dim:[files]}`` (if lon, lat, depth and/or data not stored in same files as data),
+            or a dictionary of dictionaries ``{var:{dim:[files]}}``
+            time values are in ``filenames[data]``
+        variables : dict
+            Dictionary mapping variables to variable
+            names in the netCDF file(s).
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the netCF file(s).
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable.
+            U and V velocity nodes are not located as W velocity and T tracer nodes (see http://www.cesm.ucar.edu/models/cesm1.0/pop2/doc/sci/POPRefManual.pdf ). ::
+
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j+1,i],V[k,j+1,i]        |                             |U[k,j+1,i+1],V[k,j+1,i+1]    |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |                             |W[k:k+2,j+1,i+1],T[k,j+1,i+1]|                             |
+                +-----------------------------+-----------------------------+-----------------------------+
+                |U[k,j,i],V[k,j,i]            |                             |U[k,j,i+1],V[k,j,i+1]        |
+                +-----------------------------+-----------------------------+-----------------------------+
+
+            In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
+            T node is at the cell centre and interpolated constant per cell as a C-grid.
+            In 3D: U and V nodes are at the midlle of the cell vertical edges,
+            They are interpolated bilinearly (independently of z) in the cell.
+            W nodes are at the centre of the horizontal interfaces.
+            They are interpolated linearly (as a function of z) in the cell.
+            T node is at the cell centre, and constant per cell.
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        tracer_interp_method : str
+            Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
+            Note that in the case of from_pop() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
+        chunksize :
+            size of the chunks in dask loading (Default value = None)
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_netcdf` constructor.
         """
-
         if 'U' in dimensions and 'V' in dimensions and dimensions['U'] != dimensions['V']:
             raise ValueError("On a B-grid, the dimensions of velocities should be the (top) corners of the grid cells, so the same for U and V. "
                              "See also https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb")
@@ -849,28 +968,42 @@ def from_parcels(cls, basename, uvar='vozocrtx', vvar='vomecrty', indices=None,
                      chunksize=None, **kwargs):
         """Initialises FieldSet data from NetCDF files using the Parcels FieldSet.write() conventions.
 
-        :param basename: Base name of the file(s); may contain
-               wildcards to indicate multiple files.
-        :param indices: Optional dictionary of indices for each dimension
-               to read from file(s), to allow for reading of subset of data.
-               Default is to read the full extent of each dimension.
-               Note that negative indices are not allowed.
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param extra_fields: Extra fields to read beyond U and V
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
-        :param deferred_load: boolean whether to only pre-load data (in deferred mode) or
-               fully load them (default: True). It is advised to deferred load the data, since in
-               that case Parcels deals with a better memory management during particle set execution.
-               deferred_load=False is however sometimes necessary for plotting the fields.
-        :param chunksize: size of the chunks in dask loading
-
+        Parameters
+        ----------
+        basename : str
+            Base name of the file(s); may contain
+            wildcards to indicate multiple files.
+        indices :
+            Optional dictionary of indices for each dimension
+            to read from file(s), to allow for reading of subset of data.
+            Default is to read the full extent of each dimension.
+            Note that negative indices are not allowed.
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        extra_fields :
+            Extra fields to read beyond U and V (Default value = None)
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        deferred_load : bool
+            boolean whether to only pre-load data (in deferred mode) or
+            fully load them (default: True). It is advised to deferred load the data, since in
+            that case Parcels deals with a better memory management during particle set execution.
+            deferred_load=False is however sometimes necessary for plotting the fields.
+        chunksize :
+            size of the chunks in dask loading (Default value = None)
+        uvar :
+             (Default value = 'vozocrtx')
+        vvar :
+             (Default value = 'vomecrty')
+        **kwargs :
+            Keyword arguments passed to the :func:`Fieldset.from_netcdf` constructor.
         """
-
         if extra_fields is None:
             extra_fields = {}
         if 'creation_log' not in kwargs.keys():
@@ -894,29 +1027,39 @@ def from_xarray_dataset(cls, ds, variables, dimensions, mesh='spherical', allow_
                             time_periodic=False, **kwargs):
         """Initialises FieldSet data from xarray Datasets.
 
-        :param ds: xarray Dataset.
-               Note that the built-in Advection kernels assume that U and V are in m/s
-        :param variables: Dictionary mapping parcels variable names to data variables in the xarray Dataset.
-        :param dimensions: Dictionary mapping data dimensions (lon,
-               lat, depth, time, data) to dimensions in the xarray Dataset.
-               Note that dimensions can also be a dictionary of dictionaries if
-               dimension names are different for each variable
-               (e.g. dimensions['U'], dimensions['V'], etc).
-        :param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
-               (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
-        :param mesh: String indicating the type of mesh coordinates and
-               units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`_:
-
-               1. spherical (default): Lat and lon in degree, with a
-                  correction for zonal velocity U near the poles.
-               2. flat: No conversion, lat/lon are assumed to be in m.
-        :param allow_time_extrapolation: boolean whether to allow for extrapolation
-               (i.e. beyond the last available time snapshot)
-               Default is False if dimensions includes time, else True
-        :param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
-               This flag overrides the allow_time_interpolation and sets it to False
+        Parameters
+        ----------
+        ds : xr.Dataset
+            xarray Dataset.
+            Note that the built-in Advection kernels assume that U and V are in m/s
+        variables : dict
+            Dictionary mapping parcels variable names to data variables in the xarray Dataset.
+        dimensions : dict
+            Dictionary mapping data dimensions (lon,
+            lat, depth, time, data) to dimensions in the xarray Dataset.
+            Note that dimensions can also be a dictionary of dictionaries if
+            dimension names are different for each variable
+            (e.g. dimensions['U'], dimensions['V'], etc).
+        fieldtype :
+            Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
+            (either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
+        mesh : str
+            String indicating the type of mesh coordinates and
+            units used during velocity interpolation, see also `this tutorial <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb>`__:
+
+            1. spherical (default): Lat and lon in degree, with a
+               correction for zonal velocity U near the poles.
+            2. flat: No conversion, lat/lon are assumed to be in m.
+        allow_time_extrapolation : bool
+            boolean whether to allow for extrapolation
+            (i.e. beyond the last available time snapshot)
+            Default is False if dimensions includes time, else True
+        time_periodic : bool, float or datetime.timedelta
+            To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
+            This flag overrides the allow_time_interpolation and sets it to False
+        **kwargs :
+            Keyword arguments passed to the :func:`Field.from_xarray` constructor.
         """
-
         fields = {}
         if 'creation_log' not in kwargs.keys():
             kwargs['creation_log'] = 'from_xarray_dataset'
@@ -937,7 +1080,8 @@ def from_xarray_dataset(cls, ds, variables, dimensions, mesh='spherical', allow_
 
     def get_fields(self):
         """Returns a list of all the :class:`parcels.field.Field` and :class:`parcels.field.VectorField`
-        objects associated with this FieldSet"""
+        objects associated with this FieldSet.
+        """
         fields = []
         for v in self.__dict__.values():
             if type(v) in [Field, VectorField]:
@@ -956,13 +1100,20 @@ def add_constant(self, name, value):
         stored as 32-bit floats. While constants can be updated during
         execution in SciPy mode, they can not be updated in JIT mode.
 
-        Tutorials using fieldset.add_constant:
-        `Analytical advection <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_analyticaladvection.ipynb>`_
-        `Diffusion <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`_
-        `Periodic boundaries <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_periodic_boundaries.ipynb>`_
+        Parameters
+        ----------
+        name : str
+            Name of the constant
+        value :
+            Value of the constant (stored as 32-bit float)
 
-        :param name: Name of the constant
-        :param value: Value of the constant (stored as 32-bit float)
+
+        Examples
+        --------
+        Tutorials using fieldset.add_constant:
+        `Analytical advection <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_analyticaladvection.ipynb>`__
+        `Diffusion <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_diffusion.ipynb>`__
+        `Periodic boundaries <https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_periodic_boundaries.ipynb>`__
         """
         setattr(self, name, value)
 
@@ -971,11 +1122,15 @@ def add_periodic_halo(self, zonal=False, meridional=False, halosize=5):
         through extending the Field (and lon/lat) by copying a small portion
         of the field on one side of the domain to the other.
 
-        :param zonal: Create a halo in zonal direction (boolean)
-        :param meridional: Create a halo in meridional direction (boolean)
-        :param halosize: size of the halo (in grid points). Default is 5 grid points
+        Parameters
+        ----------
+        zonal : bool
+            Create a halo in zonal direction (Default value = False)
+        meridional : bool
+            Create a halo in meridional direction (Default value = False)
+        halosize : int
+            size of the halo (in grid points). Default is 5 grid points
         """
-
         for grid in self.gridset.grids:
             grid.add_periodic_halo(zonal, meridional, halosize)
         for attr, value in iter(self.__dict__.items()):
@@ -983,10 +1138,13 @@ def add_periodic_halo(self, zonal=False, meridional=False, halosize=5):
                 value.add_periodic_halo(zonal, meridional, halosize)
 
     def write(self, filename):
-        """Write FieldSet to NetCDF file using NEMO convention
-
-        :param filename: Basename of the output fileset"""
+        """Write FieldSet to NetCDF file using NEMO convention.
 
+        Parameters
+        ----------
+        filename : str
+            Basename of the output fileset.
+        """
         if MPI is None or MPI.COMM_WORLD.Get_rank() == 0:
             logger.info(f"Generating FieldSet output with basename: {filename}")
 
@@ -1005,8 +1163,12 @@ def computeTimeChunk(self, time, dt):
         with default option deferred_load. The loaded time steps are at or immediatly before time
         and the two time steps immediately following time if dt is positive (and inversely for negative dt)
 
-        :param time: Time around which the FieldSet chunks are to be loaded. Time is provided as a double, relatively to Fieldset.time_origin
-        :param dt: time step of the integration scheme
+        Parameters
+        ----------
+        time :
+            Time around which the FieldSet chunks are to be loaded. Time is provided as a double, relatively to Fieldset.time_origin
+        dt :
+            time step of the integration scheme
         """
         signdt = np.sign(dt)
         nextTime = np.infty if dt > 0 else -np.infty
diff --git a/parcels/grid.py b/parcels/grid.py
index 3a6849418..9c1ba4739 100644
--- a/parcels/grid.py
+++ b/parcels/grid.py
@@ -23,9 +23,7 @@ class CGrid(Structure):
 
 
 class Grid:
-    """Grid class that defines a (spatial and temporal) grid on which Fields are defined
-
-    """
+    """Grid class that defines a (spatial and temporal) grid on which Fields are defined."""
 
     def __init__(self, lon, lat, time, time_origin, mesh):
         self.xi = None
@@ -96,8 +94,8 @@ def ctypes_struct(self):
     @property
     def child_ctypes_struct(self):
         """Returns a ctypes struct object containing all relevant
-        pointers and sizes for this grid."""
-
+        pointers and sizes for this grid.
+        """
         class CStructuredGrid(Structure):
             # z4d is only to have same cstruct as RectilinearSGrid
             _fields_ = [('xdim', c_int), ('ydim', c_int), ('zdim', c_int),
@@ -240,8 +238,9 @@ def chunk_loaded(self):
 
 
 class RectilinearGrid(Grid):
-    """Rectilinear Grid
-       Private base class for RectilinearZGrid and RectilinearSGrid
+    """Rectilinear Grid class
+
+    Private base class for RectilinearZGrid and RectilinearSGrid
 
     """
 
@@ -266,9 +265,14 @@ def add_periodic_halo(self, zonal, meridional, halosize=5):
         """Add a 'halo' to the Grid, through extending the Grid (and lon/lat)
         similarly to the halo created for the Fields
 
-        :param zonal: Create a halo in zonal direction (boolean)
-        :param meridional: Create a halo in meridional direction (boolean)
-        :param halosize: size of the halo (in grid points). Default is 5 grid points
+        Parameters
+        ----------
+        zonal : bool
+            Create a halo in zonal direction
+        meridional : bool
+            Create a halo in meridional direction
+        halosize : int
+            size of the halo (in grid points). Default is 5 grid points
         """
         if zonal:
             lonshift = (self.lon[-1] - 2 * self.lon[0] + self.lon[1])
@@ -293,20 +297,28 @@ def add_periodic_halo(self, zonal, meridional, halosize=5):
 
 
 class RectilinearZGrid(RectilinearGrid):
-    """Rectilinear Z Grid
-
-    :param lon: Vector containing the longitude coordinates of the grid
-    :param lat: Vector containing the latitude coordinates of the grid
-    :param depth: Vector containing the vertical coordinates of the grid, which are z-coordinates.
-           The depth of the different layers is thus constant.
-    :param time: Vector containing the time coordinates of the grid
-    :param time_origin: Time origin (TimeConverter object) of the time axis
-    :param mesh: String indicating the type of mesh coordinates and
-           units used during velocity interpolation:
-
-           1. spherical (default): Lat and lon in degree, with a
-              correction for zonal velocity U near the poles.
-           2. flat: No conversion, lat/lon are assumed to be in m.
+    """Rectilinear Z Grid.
+
+    Parameters
+    ----------
+    lon :
+        Vector containing the longitude coordinates of the grid
+    lat :
+        Vector containing the latitude coordinates of the grid
+    depth :
+        Vector containing the vertical coordinates of the grid, which are z-coordinates.
+        The depth of the different layers is thus constant.
+    time :
+        Vector containing the time coordinates of the grid
+    time_origin : parcels.tools.converters.TimeConverter
+        Time origin of the time axis
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical (default): Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat: No conversion, lat/lon are assumed to be in m.
     """
 
     def __init__(self, lon, lat, depth=None, time=None, time_origin=None, mesh='flat'):
@@ -328,23 +340,31 @@ class RectilinearSGrid(RectilinearGrid):
     """Rectilinear S Grid. Same horizontal discretisation as a rectilinear z grid,
        but with s vertical coordinates
 
-    :param lon: Vector containing the longitude coordinates of the grid
-    :param lat: Vector containing the latitude coordinates of the grid
-    :param depth: 4D (time-evolving) or 3D (time-independent) array containing the vertical coordinates of the grid,
-           which are s-coordinates.
-           s-coordinates can be terrain-following (sigma) or iso-density (rho) layers,
-           or any generalised vertical discretisation.
-           The depth of each node depends then on the horizontal position (lon, lat),
-           the number of the layer and the time is depth is a 4D array.
-           depth array is either a 4D array[xdim][ydim][zdim][tdim] or a 3D array[xdim][ydim[zdim].
-    :param time: Vector containing the time coordinates of the grid
-    :param time_origin: Time origin (TimeConverter object) of the time axis
-    :param mesh: String indicating the type of mesh coordinates and
-           units used during velocity interpolation:
-
-           1. spherical (default): Lat and lon in degree, with a
-              correction for zonal velocity U near the poles.
-           2. flat: No conversion, lat/lon are assumed to be in m.
+    Parameters
+    ----------
+    lon :
+        Vector containing the longitude coordinates of the grid
+    lat :
+        Vector containing the latitude coordinates of the grid
+    depth :
+        4D (time-evolving) or 3D (time-independent) array containing the vertical coordinates of the grid,
+        which are s-coordinates.
+        s-coordinates can be terrain-following (sigma) or iso-density (rho) layers,
+        or any generalised vertical discretisation.
+        The depth of each node depends then on the horizontal position (lon, lat),
+        the number of the layer and the time is depth is a 4D array.
+        depth array is either a 4D array[xdim][ydim][zdim][tdim] or a 3D array[xdim][ydim[zdim].
+    time :
+        Vector containing the time coordinates of the grid
+    time_origin : parcels.tools.converters.TimeConverter
+        Time origin of the time axis
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical (default): Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat: No conversion, lat/lon are assumed to be in m.
     """
 
     def __init__(self, lon, lat, depth, time=None, time_origin=None, mesh='flat'):
@@ -391,9 +411,14 @@ def add_periodic_halo(self, zonal, meridional, halosize=5):
         """Add a 'halo' to the Grid, through extending the Grid (and lon/lat)
         similarly to the halo created for the Fields
 
-        :param zonal: Create a halo in zonal direction (boolean)
-        :param meridional: Create a halo in meridional direction (boolean)
-        :param halosize: size of the halo (in grid points). Default is 5 grid points
+        Parameters
+        ----------
+        zonal : bool
+            Create a halo in zonal direction
+        meridional : bool
+            Create a halo in meridional direction
+        halosize : int
+            size of the halo (in grid points). Default is 5 grid points
         """
         if zonal:
             lonshift = self.lon[:, -1] - 2 * self.lon[:, 0] + self.lon[:, 1]
@@ -429,18 +454,26 @@ def add_periodic_halo(self, zonal, meridional, halosize=5):
 class CurvilinearZGrid(CurvilinearGrid):
     """Curvilinear Z Grid.
 
-    :param lon: 2D array containing the longitude coordinates of the grid
-    :param lat: 2D array containing the latitude coordinates of the grid
-    :param depth: Vector containing the vertical coordinates of the grid, which are z-coordinates.
-           The depth of the different layers is thus constant.
-    :param time: Vector containing the time coordinates of the grid
-    :param time_origin: Time origin (TimeConverter object) of the time axis
-    :param mesh: String indicating the type of mesh coordinates and
-           units used during velocity interpolation:
-
-           1. spherical (default): Lat and lon in degree, with a
-              correction for zonal velocity U near the poles.
-           2. flat: No conversion, lat/lon are assumed to be in m.
+    Parameters
+    ----------
+    lon :
+        2D array containing the longitude coordinates of the grid
+    lat :
+        2D array containing the latitude coordinates of the grid
+    depth :
+        Vector containing the vertical coordinates of the grid, which are z-coordinates.
+        The depth of the different layers is thus constant.
+    time :
+        Vector containing the time coordinates of the grid
+    time_origin : parcels.tools.converters.TimeConverter
+        Time origin of the time axis
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical (default): Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat: No conversion, lat/lon are assumed to be in m.
     """
 
     def __init__(self, lon, lat, depth=None, time=None, time_origin=None, mesh='flat'):
@@ -461,23 +494,31 @@ def __init__(self, lon, lat, depth=None, time=None, time_origin=None, mesh='flat
 class CurvilinearSGrid(CurvilinearGrid):
     """Curvilinear S Grid.
 
-    :param lon: 2D array containing the longitude coordinates of the grid
-    :param lat: 2D array containing the latitude coordinates of the grid
-    :param depth: 4D (time-evolving) or 3D (time-independent) array containing the vertical coordinates of the grid,
-           which are s-coordinates.
-           s-coordinates can be terrain-following (sigma) or iso-density (rho) layers,
-           or any generalised vertical discretisation.
-           The depth of each node depends then on the horizontal position (lon, lat),
-           the number of the layer and the time is depth is a 4D array.
-           depth array is either a 4D array[xdim][ydim][zdim][tdim] or a 3D array[xdim][ydim[zdim].
-    :param time: Vector containing the time coordinates of the grid
-    :param time_origin: Time origin (TimeConverter object) of the time axis
-    :param mesh: String indicating the type of mesh coordinates and
-           units used during velocity interpolation:
-
-           1. spherical (default): Lat and lon in degree, with a
-              correction for zonal velocity U near the poles.
-           2. flat: No conversion, lat/lon are assumed to be in m.
+    Parameters
+    ----------
+    lon :
+        2D array containing the longitude coordinates of the grid
+    lat :
+        2D array containing the latitude coordinates of the grid
+    depth :
+        4D (time-evolving) or 3D (time-independent) array containing the vertical coordinates of the grid,
+        which are s-coordinates.
+        s-coordinates can be terrain-following (sigma) or iso-density (rho) layers,
+        or any generalised vertical discretisation.
+        The depth of each node depends then on the horizontal position (lon, lat),
+        the number of the layer and the time is depth is a 4D array.
+        depth array is either a 4D array[xdim][ydim][zdim][tdim] or a 3D array[xdim][ydim[zdim].
+    time :
+        Vector containing the time coordinates of the grid
+    time_origin : parcels.tools.converters.TimeConverter
+        Time origin of the time axis
+    mesh : str
+        String indicating the type of mesh coordinates and
+        units used during velocity interpolation:
+
+        1. spherical (default): Lat and lon in degree, with a
+           correction for zonal velocity U near the poles.
+        2. flat: No conversion, lat/lon are assumed to be in m.
     """
 
     def __init__(self, lon, lat, depth, time=None, time_origin=None, mesh='flat'):
diff --git a/parcels/gridset.py b/parcels/gridset.py
index 5ab5f36f8..46a431fa6 100644
--- a/parcels/gridset.py
+++ b/parcels/gridset.py
@@ -4,9 +4,7 @@
 
 
 class GridSet:
-    """GridSet class that holds the Grids on which the Fields are defined
-
-    """
+    """GridSet class that holds the Grids on which the Fields are defined."""
 
     def __init__(self):
         self.grids = []
@@ -47,10 +45,10 @@ def add_grid(self, field):
 
     def dimrange(self, dim):
         """Returns maximum value of a dimension (lon, lat, depth or time)
-           on 'left' side and minimum value on 'right' side for all grids
-           in a gridset. Useful for finding e.g. longitude range that
-           overlaps on all grids in a gridset"""
-
+        on 'left' side and minimum value on 'right' side for all grids
+        in a gridset. Useful for finding e.g. longitude range that
+        overlaps on all grids in a gridset.
+        """
         maxleft, minright = (-np.inf, np.inf)
         for g in self.grids:
             if getattr(g, dim).size == 1:
diff --git a/parcels/interaction/baseinteractionkernel.py b/parcels/interaction/baseinteractionkernel.py
index 6390aedb2..057bb7060 100644
--- a/parcels/interaction/baseinteractionkernel.py
+++ b/parcels/interaction/baseinteractionkernel.py
@@ -64,7 +64,7 @@ def check_fieldsets_in_kernels(self, pyfunc):
 
     def check_kernel_signature_on_version(self):
         """
-        returns numkernelargs
+        Returns numkernelargs.
         Adaptation of this method in the BaseKernel that works with
         lists of functions.
         """
diff --git a/parcels/interaction/interactionkernelsoa.py b/parcels/interaction/interactionkernelsoa.py
index c3683bdc4..40d6ea345 100644
--- a/parcels/interaction/interactionkernelsoa.py
+++ b/parcels/interaction/interactionkernelsoa.py
@@ -69,7 +69,7 @@ def __radd__(self, kernel):
         return kernel.merge(self, InteractionKernelSOA)
 
     def execute_python(self, pset, endtime, dt):
-        """Performs the core update loop via Python
+        """Performs the core update loop via Python.
 
         InteractionKernels do not implement ways to catch or recover from
         errors caused during execution of the kernel function(s).
@@ -122,7 +122,7 @@ def execute_python(self, pset, endtime, dt):
                 pset[particle_idx].dt = dt
 
     def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_once=False):
-        """Execute this Kernel over a ParticleSet for several timesteps
+        """Execute this Kernel over a ParticleSet for several timesteps.
 
         InteractionKernels do not implement ways to catch or recover from
         errors caused during execution of the kernel function(s).
diff --git a/parcels/interaction/neighborsearch/base.py b/parcels/interaction/neighborsearch/base.py
index 206d42df2..a5d44fc1a 100644
--- a/parcels/interaction/neighborsearch/base.py
+++ b/parcels/interaction/neighborsearch/base.py
@@ -18,10 +18,15 @@ def __init__(self, inter_dist_vert, inter_dist_horiz,
                  max_depth=100000, periodic_domain_zonal=None):
         """Initialize neighbor search
 
-        :param inter_dist_vert: interaction distance (vertical) in m
-        :param inter_dist_horiz: interaction distance (horizontal in m
-        :param max_depth: maximum depth of the particles (i.e. 100km)
-        :param zperiodic_bc_domain: zonal domain if zonal periodic boundary
+
+        Parameters
+        ----------
+        inter_dist_vert : float
+            Interaction distance (vertical) in m.
+        inter_dist_horiz : float
+            interaction distance (horizontal) in m
+        max_depth : float, optional
+            Maximum depth of the particles (default is 100000m).
         """
         self.inter_dist_vert = inter_dist_vert
         self.inter_dist_horiz = inter_dist_horiz
@@ -41,42 +46,66 @@ def __init__(self, inter_dist_vert, inter_dist_horiz,
 
     @abstractmethod
     def find_neighbors_by_coor(self, coor):
-        '''Get the neighbors around a certain location.
+        """Get the neighbors around a certain location.
+
+        Parameters
+        ----------
+        coor :
+            Numpy array with [depth, lat, lon].
 
-        :param coor: Numpy array with [depth, lat, lon].
-        :returns List of particle indices.
-        '''
+        Returns
+        -------
+        type
+            List of particle indices.
+
+        """
         raise NotImplementedError
 
     def find_neighbors_by_idx(self, particle_idx):
-        '''Get the neighbors around a certain particle.
+        """Get the neighbors around a certain particle.
 
         Mainly useful for Structure of Array (SoA) datastructure
 
-        :param particle_idx: index of the particle (SoA).
-        :returns List of particle indices
-        '''
+        Parameters
+        ----------
+        particle_idx :
+            index of the particle (SoA).
+
+        Returns
+        -------
+        type
+            List of particle indices
+
+        """
         coor = self._values[:, particle_idx].reshape(3, 1)
         return self.find_neighbors_by_coor(coor)
 
     def update_values(self, new_values, new_active_mask=None):
-        '''Update the coordinates of the particles.
+        """Update the coordinates of the particles.
 
         This is a default implementation simply rebuilds the structure.
         If the rebuilding is slow, a faster implementation can be provided.
 
-        :param new_values: numpy array ([depth, lat, lon], n_particles) with
-                           new coordinates of the particles.
-        :param new_active_mask: boolean array indicating active particles.
-        '''
+        Parameters
+        ----------
+        new_values :
+            numpy array ([depth, lat, lon], n_particles) with
+            new coordinates of the particles.
+        new_active_mask :
+            boolean array indicating active particles. (Default value = None)
+        """
         self.rebuild(new_values, new_active_mask)
 
     def rebuild(self, values, active_mask=-1):
         """Rebuild the neighbor structure from scratch.
 
-        :param values: numpy array with coordinates of particles
-                       (same as update).
-        :param active_mask: boolean array indicating active particles.
+        Parameters
+        ----------
+        values :
+            numpy array with coordinates of particles
+            (same as update).
+        active_mask :
+            boolean array indicating active particles. (Default value = -1)
         """
         if values is not None:
             self._values = values
@@ -90,7 +119,7 @@ def rebuild(self, values, active_mask=-1):
 
     @property
     def active_idx(self):
-        "Indices of the currently active mask."
+        """Indices of the currently active mask."""
         # See __init__ comments for a more detailed explanation.
         if self._active_mask is None:
             return np.arange(self._values.shape[1])
@@ -102,20 +131,36 @@ def _distance(self, coor, subset_idx):
 
         Distance depends on the mesh (spherical/flat).
 
-        :param coor: Numpy array with 3D coordinates ([depth, lat, lon]).
-        :param subset_idx: Indices of the particles to compute the distance to.
-        :returns horiz_dist: distance in the horizontal direction
-        :returns vert_dist: distance in the vertical direction.
+        Parameters
+        ----------
+        coor :
+            Numpy array with 3D coordinates ([depth, lat, lon]).
+        subset_idx :
+            Indices of the particles to compute the distance to.
+
+        Returns
+        -------
+        type
+            horiz_dist: distance in the horizontal direction
+
         """
         raise NotImplementedError
 
     def _get_close_neighbor_dist(self, coor, subset_idx):
         """Compute distances and remove non-neighbors.
 
-        :param coor: Numpy array with 3D coordinates ([depth, lat, lon]).
-        :param subset_idx: Indices of the particles to compute the distance to.
-        :returns neighbor_idx: Indices within the interaction distance.
-        :returns distances: Distance between coor and the neighbor particles.
+        Parameters
+        ----------
+        coor :
+            Numpy array with 3D coordinates ([depth, lat, lon]).
+        subset_idx :
+            Indices of the particles to compute the distance to.
+
+        Returns
+        -------
+        type
+            neighbor_idx: Indices within the interaction distance.
+
         """
         vert_distance, horiz_distance = self._distance(coor, subset_idx)
         rel_distances = np.sqrt((horiz_distance/self.inter_dist_horiz)**2
@@ -128,7 +173,8 @@ def _get_close_neighbor_dist(self, coor, subset_idx):
 
 
 class BaseFlatNeighborSearch(BaseNeighborSearch):
-    "Base class for neighbor searches with a flat mesh."
+    """Base class for neighbor searches with a flat mesh."""
+
     def _distance(self, coor, subset_idx):
         coor = coor.reshape(3, 1)
         horiz_distance = np.sqrt(np.sum((
@@ -158,7 +204,8 @@ def _distance(self, coor, subset_idx):
 
 
 class BaseSphericalNeighborSearch(BaseNeighborSearch):
-    "Base class for a neighbor search with a spherical mesh."
+    """Base class for a neighbor search with a spherical mesh."""
+
     def _distance(self, coor, subset_idx):
         vert_distances, horiz_distances = spherical_distance(
             *coor,
diff --git a/parcels/interaction/neighborsearch/basehash.py b/parcels/interaction/neighborsearch/basehash.py
index 17b9ecedd..9150241a3 100644
--- a/parcels/interaction/neighborsearch/basehash.py
+++ b/parcels/interaction/neighborsearch/basehash.py
@@ -5,23 +5,39 @@
 
 class BaseHashNeighborSearch(ABC):
     def find_neighbors_by_coor(self, coor):
-        '''Get the neighbors around a certain location.
+        """Get the neighbors around a certain location.
 
-        :param coor: Numpy array with [depth, lat, lon].
-        :returns List of particle indices.
-        '''
+        Parameters
+        ----------
+        coor :
+            Numpy array with [depth, lat, lon].
+
+        Returns
+        -------
+        type
+            List of particle indices.
+
+        """
         coor = coor.reshape(3, 1)
         hash_id = self._values_to_hashes(coor)[0]
         return self._find_neighbors(hash_id, coor)
 
     def find_neighbors_by_idx(self, particle_idx):
-        '''Get the neighbors around a certain particle.
+        """Get the neighbors around a certain particle.
 
         Mainly useful for Structure of Array (SoA) datastructure
 
-        :param particle_idx: index of the particle (SoA).
-        :returns List of particle indices
-        '''
+        Parameters
+        ----------
+        particle_idx :
+            index of the particle (SoA).
+
+        Returns
+        -------
+        type
+            List of particle indices
+
+        """
         hash_id = self._particle_hashes[particle_idx]
         coor = self._values[:, particle_idx].reshape(3, 1)
         return self._find_neighbors(hash_id, coor)
@@ -31,10 +47,10 @@ def _find_neighbors(self, hash_id, coor):
         raise NotImplementedError
 
     def consistency_check(self):
-        '''See if all values are in their proper place.
+        """See if all values are in their proper place.
 
         Only used for debugging purposes.
-        '''
+        """
         active_idx = self.active_idx
         if active_idx is None:
             active_idx = np.arange(self._values.shape[1])
@@ -54,13 +70,18 @@ def consistency_check(self):
         assert np.all(cur_hashes == self._particle_hashes[active_idx])
 
     def update_values(self, new_values, new_active_mask=None):
-        '''Update the locations of (some) of the particles.
+        """Update the locations of (some) of the particles.
 
         Particles that stay in the same location are computationally cheap.
         The order and number of the particles is assumed to remain the same.
 
-        :param new_values: new (depth, lat, lon) values for particles.
-        '''
+        Parameters
+        ----------
+        new_values :
+            new (depth, lat, lon) values for particles.
+        new_active_mask :
+             (Default value = None)
+        """
         if self._values is None:
             self.rebuild(new_values, new_active_mask)
             return
@@ -103,14 +124,23 @@ def _values_to_hashes(self, values, active_idx=None):
 
         The hashes correspond to the cells that particles reside in.
 
-        :param values: 3D coordinates to be hashed.
-        :param active_idx: Active particle indices (relative to values).
-        :returns all_hashes: An array of length len(values) with hashes.
+        Parameters
+        ----------
+        values :
+            3D coordinates to be hashed.
+        active_idx :
+            Active particle indices (relative to values). (Default value = None)
+
+        Returns
+        -------
+        type
+            all_hashes: An array of length len(values) with hashes.
+
         """
         raise NotImplementedError
 
     def _deactivate_particles(self, particle_idx):
-        "Remove particles from the hashtable."
+        """Remove particles from the hashtable."""
         # Get the hashes of the particles to be removed.
         remove_split = hash_split(self._particle_hashes[particle_idx])
         for cur_hash, remove_idx in remove_split.items():
@@ -127,7 +157,7 @@ def _deactivate_particles(self, particle_idx):
                     len(self._hashtable[cur_hash]))
 
     def _activate_particles(self, particle_idx):
-        "Add particles to the hashtable"
+        """Add particles to the hashtable"""
         # See _deactivate_particles.
         add_split = hash_split(self._particle_hashes[particle_idx])
         for cur_hash, add_idx in add_split.items():
@@ -143,15 +173,24 @@ def _activate_particles(self, particle_idx):
 
 
 def hash_split(hash_ids, active_idx=None):
-    '''Create a hashtable.
+    """Create a hashtable.
 
     Multiple particles that are found in the same cell are put in a list
     with that particular hash.
 
-    :param hash_ids: Hash values for the particles.
-    :param active_idx: Subset on which to compute the hash split.
-    :returns hash_split: Dictionary with {hash: [idx_1, idx_2, ..], ..}
-    '''
+    Parameters
+    ----------
+    hash_ids :
+        Hash values for the particles.
+    active_idx :
+        Subset on which to compute the hash split. (Default value = None)
+
+    Returns
+    -------
+    type
+        hash_split: Dictionary with {hash: [idx_1, idx_2, ..], ..}
+
+    """
     if len(hash_ids) == 0:
         return {}
     if active_idx is not None:
diff --git a/parcels/interaction/neighborsearch/bruteforce.py b/parcels/interaction/neighborsearch/bruteforce.py
index 22b2301df..f61df9005 100644
--- a/parcels/interaction/neighborsearch/bruteforce.py
+++ b/parcels/interaction/neighborsearch/bruteforce.py
@@ -5,14 +5,14 @@
 
 
 class BruteFlatNeighborSearch(BaseFlatNeighborSearch):
-    '''Brute force implementation to find the neighbors.'''
+    """Brute force implementation to find the neighbors."""
 
     def find_neighbors_by_coor(self, coor):
         return self._get_close_neighbor_dist(coor, self.active_idx)
 
 
 class BruteSphericalNeighborSearch(BaseSphericalNeighborSearch):
-    '''Brute force implementation to find the neighbors.'''
+    """Brute force implementation to find the neighbors."""
 
     def find_neighbors_by_coor(self, coor):
         return self._get_close_neighbor_dist(coor, self.active_idx)
diff --git a/parcels/interaction/neighborsearch/distanceutils.py b/parcels/interaction/neighborsearch/distanceutils.py
index 8059411c8..56a70ac7f 100644
--- a/parcels/interaction/neighborsearch/distanceutils.py
+++ b/parcels/interaction/neighborsearch/distanceutils.py
@@ -2,18 +2,18 @@
 
 
 def fast_distance(lat1, lon1, lat2, lon2):
-    '''Compute the arc distance assuming the earth is a sphere.
+    """Compute the arc distance assuming the earth is a sphere.
 
     This is not the only possible implementation. It was taken from:
     https://www.mkompf.com/gps/distcalc.html
-    '''
+    """
     g = np.sin(lat1)*np.sin(lat2)+np.cos(lat1)*np.cos(lat2)*np.cos(lon1-lon2)
     return np.arccos(np.minimum(1, g))
 
 
 def spherical_distance(depth1_m, lat1_deg, lon1_deg, depth2_m, lat2_deg,
                        lon2_deg):
-    "Compute the arc distance, uses degrees as input."
+    """Compute the arc distance, uses degrees as input."""
     R_earth = 6371000
     lat1 = np.pi*lat1_deg/180
     lon1 = np.pi*lon1_deg/180
diff --git a/parcels/interaction/neighborsearch/hashflat.py b/parcels/interaction/neighborsearch/hashflat.py
index 33d98d29a..66c8a7ffc 100644
--- a/parcels/interaction/neighborsearch/hashflat.py
+++ b/parcels/interaction/neighborsearch/hashflat.py
@@ -8,7 +8,8 @@
 
 
 class HashFlatNeighborSearch(BaseHashNeighborSearch, BaseFlatNeighborSearch):
-    '''Neighbor search using a hashtable (similar to octtrees).'''
+    """Neighbor search using a hashtable (similar to octtrees)."""
+
     _box = None
 
     def _find_neighbors(self, hash_id, coor):
@@ -32,9 +33,18 @@ def update_values(self, new_values, new_active_mask=None):
     def _check_box(self, new_values, new_active_mask):
         """Check whether particles have moved out of the overall box.
 
-        :param new_values: New particle coordinates (depth, lat, lon) to be checked.
-        :param new_active_mask: New active mask for the particles.
-        :returns True if box is still big enough, False if not.
+        Parameters
+        ----------
+        new_values :
+            New particle coordinates (depth, lat, lon) to be checked.
+        new_active_mask :
+            New active mask for the particles.
+
+        Returns
+        -------
+        type
+            True if box is still big enough, False if not.
+
         """
         if self._box is None:
             return False
@@ -110,9 +120,18 @@ def _values_to_hashes(self, values, active_idx=None):
 def hash_to_neighbors(hash_id, bits):
     """Compute neighboring cells from a hash.
 
-    :param hash_id: hash value of the current cell.
-    :param bits: key to compute the hashesh.
-    :returns neighbors: List of cells neighboring hash_id.
+    Parameters
+    ----------
+    hash_id :
+        hash value of the current cell.
+    bits :
+        key to compute the hashesh.
+
+    Returns
+    -------
+    type
+        neighbors: List of cells neighboring hash_id.
+
     """
     coor = np.zeros((len(bits),), dtype=np.int32)
     new_coor = np.zeros((len(bits),), dtype=np.int32)
diff --git a/parcels/interaction/neighborsearch/hashspherical.py b/parcels/interaction/neighborsearch/hashspherical.py
index 8821e9ec1..67d293689 100644
--- a/parcels/interaction/neighborsearch/hashspherical.py
+++ b/parcels/interaction/neighborsearch/hashspherical.py
@@ -11,22 +11,27 @@
 
 class HashSphericalNeighborSearch(BaseHashNeighborSearch,
                                   BaseSphericalNeighborSearch):
-    '''Neighbor search using a hashtable (similar to octtrees).'''
+    """Neighbor search using a hashtable (similar to octtrees).
+
+
+    Parameters
+    ----------
+    inter_dist_vert : float
+        Interaction distance (vertical) in m.
+    inter_dist_horiz : float
+        interaction distance (horizontal) in m
+    max_depth : float, optional
+        Maximum depth of the particles (default is 100000m).
+    """
+
     def __init__(self, inter_dist_vert, inter_dist_horiz,
                  max_depth=100000):
-        '''Initialize the neighbor data structure.
-
-        :param interaction_distance: maximum horizontal interaction distance.
-        :param interaction_depth: maximum depth of interaction.
-        :param values: depth, lat, lon values for particles.
-        :param max_depth: maximum depth of the ocean.
-        '''
         super().__init__(inter_dist_vert, inter_dist_horiz, max_depth)
 
         self._init_structure()
 
     def _find_neighbors(self, hash_id, coor):
-        '''Get neighbors from hash_id and location.'''
+        """Get neighbors from hash_id and location."""
         # Get the neighboring cells.
         neighbor_blocks = geo_hash_to_neighbors(
             hash_id, coor, self._bits, self.inter_arc_dist)
@@ -43,12 +48,22 @@ def _find_neighbors(self, hash_id, coor):
         return self._get_close_neighbor_dist(coor, potential_neighbors)
 
     def _values_to_hashes(self, values, active_idx=None):
-        '''Convert coordinates to cell ids.
-
-        :param values: array of positions of particles to convert
-                       ([depth, lat, lon], # of particles to convert).
-        :returns array of cell ids.
-        '''
+        """Convert coordinates to cell ids.
+
+        Parameters
+        ----------
+        values :
+            array of positions of particles to convert
+            ([depth, lat, lon], # of particles to convert).
+        active_idx :
+             (Default value = None)
+
+        Returns
+        -------
+        type
+            array of cell ids.
+
+        """
         if active_idx is None:
             active_idx = np.arange(values.shape[1], dtype=int)
         depth = values[0, active_idx]
@@ -78,10 +93,15 @@ def _values_to_hashes(self, values, active_idx=None):
         return point_array
 
     def rebuild(self, values, active_mask=-1):
-        '''Recreate the tree with new values.
-
-        :param values: positions of the particles.
-        '''
+        """Recreate the tree with new values.
+
+        Parameters
+        ----------
+        values :
+            positions of the particles.
+        active_mask :
+             (Default value = -1)
+        """
         super().rebuild(values, active_mask)
         active_idx = self.active_idx
 
@@ -100,7 +120,7 @@ def rebuild(self, values, active_mask=-1):
             self._hash_idx[idx_array] = np.arange(len(idx_array))
 
     def _init_structure(self):
-        '''Initialize the basic tree properties without building'''
+        """Initialize the basic tree properties without building"""
         epsilon = 1e-12
         R_earth = 6371000
 
@@ -117,7 +137,7 @@ def _init_structure(self):
 
 
 def i_3d_to_hash(i_depth, i_lat, i_lon, lat_sign, bits):
-    '''Convert longitude and lattitude id's to hash'''
+    """Convert longitude and lattitude id's to hash"""
     point_hash = lat_sign
     point_hash = np.bitwise_or(point_hash, np.left_shift(i_depth, 1))
     point_hash = np.bitwise_or(point_hash, np.left_shift(i_lat, 1+bits[0]))
@@ -126,7 +146,7 @@ def i_3d_to_hash(i_depth, i_lat, i_lon, lat_sign, bits):
 
 
 def geo_hash_to_neighbors(hash_id, coor, bits, inter_arc_dist):
-    '''Compute the hashes of all neighboring cells in a 3x3x3 neighborhood.'''
+    """Compute the hashes of all neighboring cells in a 3x3x3 neighborhood."""
     lat_sign = hash_id & 0x1
     i_depth = (hash_id >> 1) & ((1 << bits[0])-1)
     i_lat = (hash_id >> (1+bits[0])) & ((1 << bits[1])-1)
diff --git a/parcels/kernel/basekernel.py b/parcels/kernel/basekernel.py
index ec9912174..b5240e14e 100644
--- a/parcels/kernel/basekernel.py
+++ b/parcels/kernel/basekernel.py
@@ -43,17 +43,27 @@
 class BaseKernel:
     """Base super class for base Kernel objects that encapsulates auto-generated code.
 
-    :arg fieldset: FieldSet object providing the field information (possibly None)
-    :arg ptype: PType object for the kernel particle
-    :arg pyfunc: (aggregated) Kernel function
-    :arg funcname: function name
-    :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
-
-    Note: A Kernel is either created from a compiled <function ...> object
+    Parameters
+    ----------
+    fieldset : parcels.Fieldset
+        FieldSet object providing the field information (possibly None)
+    ptype :
+        PType object for the kernel particle
+    pyfunc :
+        (aggregated) Kernel function
+    funcname : str
+        function name
+    delete_cfiles : bool
+        Whether to delete the C-files after compilation in JIT mode (default is True)
+
+    Notes
+    -----
+    A Kernel is either created from a compiled <function ...> object
     or the necessary information (funcname, funccode, funcvars) is provided.
     The py_ast argument may be derived from the code string, but for
     concatenation, the merged AST plus the new header definition is required.
     """
+
     _pyfunc = None
     _fieldset = None
     _ptype = None
@@ -134,7 +144,7 @@ def _cache_key(self):
 
     @staticmethod
     def fix_indentation(string):
-        """Fix indentation to allow in-lined kernel definitions"""
+        """Fix indentation to allow in-lined kernel definitions."""
         lines = string.split('\n')
         indent = re_indent.match(lines[0])
         if indent:
@@ -143,7 +153,8 @@ def fix_indentation(string):
 
     def check_fieldsets_in_kernels(self, pyfunc):
         """
-        function checks the integrity of the fieldset with the kernels.
+        Checks the integrity of the fieldset with the kernels.
+
         This function is to be called from the derived class when setting up the 'pyfunc'.
         """
         if self.fieldset is not None:
@@ -168,9 +179,6 @@ def check_fieldsets_in_kernels(self, pyfunc):
                     raise NotImplementedError('Analytical Advection only works with Z-grids in the vertical')
 
     def check_kernel_signature_on_version(self):
-        """
-        returns numkernelargs
-        """
         numkernelargs = 0
         if self._pyfunc is not None:
             if version_info[0] < 3:
@@ -207,9 +215,7 @@ def remove_lib(self):
                 self.src_file = src_file_or_files
 
     def get_kernel_compile_files(self):
-        """
-        Returns the correct src_file, lib_file, log_file for this kernel
-        """
+        """Returns the correct src_file, lib_file, log_file for this kernel."""
         if MPI:
             mpi_comm = MPI.COMM_WORLD
             mpi_rank = mpi_comm.Get_rank()
@@ -236,7 +242,7 @@ def get_kernel_compile_files(self):
         return src_file_or_files, lib_file, log_file
 
     def compile(self, compiler):
-        """ Writes kernel code to file and compiles it."""
+        """Writes kernel code to file and compiles it."""
         all_files_array = []
         if self.src_file is None:
             if self.dyn_srcs is not None:
@@ -315,9 +321,7 @@ def remove_deleted(self, pset, output_file, endtime):
         pset.remove_indices(indices)
 
     def load_fieldset_jit(self, pset):
-        """
-        Updates the loaded fields of pset's fieldset according to the chunk information within their grids
-        """
+        """Updates the loaded fields of pset's fieldset according to the chunk information within their grids."""
         if pset.fieldset is not None:
             for g in pset.fieldset.gridset.grids:
                 g.cstruct = None  # This force to point newly the grids from Python to C
@@ -349,13 +353,22 @@ def load_fieldset_jit(self, pset):
                     g.lat = np.array(g.lat, order='C')
 
     def evaluate_particle(self, p, endtime, sign_dt, dt, analytical=False):
-        """
-        Execute the kernel evaluation of for an individual particle.
-        :arg p: object of (sub-)type (ScipyParticle, JITParticle) or (sub-)type of BaseParticleAccessor
-        :arg fieldset: fieldset of the containing ParticleSet (e.g. pset.fieldset)
-        :arg analytical: flag indicating the analytical advector or an iterative advection
-        :arg endtime: endtime of this overall kernel evaluation step
-        :arg dt: computational integration timestep
+        """Execute the kernel evaluation of for an individual particle.
+
+        Parameters
+        ----------
+        p :
+            object of (sub-)type (ScipyParticle, JITParticle) or (sub-)type of BaseParticleAccessor
+        fieldset :
+            fieldset of the containing ParticleSet (e.g. pset.fieldset)
+        analytical :
+            flag indicating the analytical advector or an iterative advection (Default value = False)
+        endtime :
+            endtime of this overall kernel evaluation step
+        dt :
+            computational integration timestep
+        sign_dt :
+
         """
         variables = self._ptype.variables
         # back up variables in case of OperationCode.Repeat
diff --git a/parcels/kernel/kernelaos.py b/parcels/kernel/kernelaos.py
index 7e1261459..6e8db57f4 100644
--- a/parcels/kernel/kernelaos.py
+++ b/parcels/kernel/kernelaos.py
@@ -28,11 +28,18 @@
 class KernelAOS(BaseKernel):
     """Kernel object that encapsulates auto-generated code.
 
-    :arg fieldset: FieldSet object providing the field information
-    :arg ptype: PType object for the kernel particle
-    :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
-
-    Note: A Kernel is either created from a compiled <function ...> object
+    Parameters
+    ----------
+    fieldset :
+        FieldSet object providing the field information
+    ptype :
+        PType object for the kernel particle
+    delete_cfiles : bool
+        Whether to delete the C-files after compilation in JIT mode (default is True)
+
+    Notes
+    -----
+    A Kernel is either created from a compiled <function ...> object
     or the necessary information (funcname, funccode, funcvars) is provided.
     The py_ast argument may be derived from the code string, but for
     concatenation, the merged AST plus the new header definition is required.
@@ -129,7 +136,7 @@ def __radd__(self, kernel):
         return kernel.merge(self, KernelAOS)
 
     def execute_jit(self, pset, endtime, dt):
-        """Invokes JIT engine to perform the core update loop"""
+        """Invokes JIT engine to perform the core update loop."""
         self.load_fieldset_jit(pset)
 
         fargs = []
@@ -145,7 +152,7 @@ def execute_jit(self, pset, endtime, dt):
             self._function(c_int(len(pset)), pdata, c_double(endtime), c_double(dt))
 
     def execute_python(self, pset, endtime, dt):
-        """Performs the core update loop via Python"""
+        """Performs the core update loop via Python."""
         # sign of dt: { [0, 1]: forward simulation; -1: backward simulation }
         sign_dt = np.sign(dt)
 
@@ -166,14 +173,14 @@ def execute_python(self, pset, endtime, dt):
             self.evaluate_particle(p, endtime, sign_dt, dt, analytical=analytical)
 
     def remove_deleted(self, pset, output_file, endtime):
-        """Utility to remove all particles that signalled deletion"""
+        """Utility to remove all particles that signalled deletion."""
         indices = [i for i, p in enumerate(pset) if p.state == OperationCode.Delete]
         if len(indices) > 0 and output_file is not None:
             output_file.write(pset, endtime, deleted_only=indices)
         pset.remove_indices(indices)
 
     def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_once=False):
-        """Execute this Kernel over a ParticleSet for several timesteps"""
+        """Execute this Kernel over a ParticleSet for several timesteps."""
         for p in pset:
             p.reset_state()
 
diff --git a/parcels/kernel/kernelsoa.py b/parcels/kernel/kernelsoa.py
index d0818e9d8..bfcddf096 100644
--- a/parcels/kernel/kernelsoa.py
+++ b/parcels/kernel/kernelsoa.py
@@ -28,11 +28,18 @@
 class KernelSOA(BaseKernel):
     """Kernel object that encapsulates auto-generated code.
 
-    :arg fieldset: FieldSet object providing the field information
-    :arg ptype: PType object for the kernel particle
-    :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
-
-    Note: A Kernel is either created from a compiled <function ...> object
+    Parameters
+    ----------
+    fieldset :
+        FieldSet object providing the field information
+    ptype :
+        PType object for the kernel particle
+    delete_cfiles : bool
+        Whether to delete the C-files after compilation in JIT mode (default is True)
+
+    Notes
+    -----
+    A Kernel is either created from a compiled <function ...> object
     or the necessary information (funcname, funccode, funcvars) is provided.
     The py_ast argument may be derived from the code string, but for
     concatenation, the merged AST plus the new header definition is required.
@@ -116,7 +123,7 @@ def __init__(self, fieldset, ptype, pyfunc=None, funcname=None,
                 self.src_file = src_file_or_files
 
     def execute_jit(self, pset, endtime, dt):
-        """Invokes JIT engine to perform the core update loop"""
+        """Invokes JIT engine to perform the core update loop."""
         self.load_fieldset_jit(pset)
 
         fargs = [byref(f.ctypes_struct) for f in self.field_args.values()]
@@ -126,7 +133,7 @@ def execute_jit(self, pset, endtime, dt):
                               c_double(endtime), c_double(dt), *fargs)
 
     def execute_python(self, pset, endtime, dt):
-        """Performs the core update loop via Python"""
+        """Performs the core update loop via Python."""
         # sign of dt: { [0, 1]: forward simulation; -1: backward simulation }
         sign_dt = np.sign(dt)
 
@@ -163,8 +170,7 @@ def __radd__(self, kernel):
         return kernel.merge(self, KernelSOA)
 
     def remove_deleted(self, pset, output_file, endtime):
-        """
-        Utility to remove all particles that signalled deletion
+        """Utility to remove all particles that signalled deletion.
 
         This deletion function is targetted to index-addressable, random-access array-collections.
         """
@@ -176,7 +182,7 @@ def remove_deleted(self, pset, output_file, endtime):
         pset.remove_indices(indices)
 
     def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_once=False):
-        """Execute this Kernel over a ParticleSet for several timesteps"""
+        """Execute this Kernel over a ParticleSet for several timesteps."""
         pset.collection.state[:] = StateCode.Evaluate
 
         if abs(dt) < 1e-6 and not execute_once:
diff --git a/parcels/particle.py b/parcels/particle.py
index 2d2aa07fb..cc4af961e 100644
--- a/parcels/particle.py
+++ b/parcels/particle.py
@@ -13,16 +13,22 @@
 
 
 class Variable:
-    """Descriptor class that delegates data access to particle data
-
-    :param name: Variable name as used within kernels
-    :param dtype: Data type (numpy.dtype) of the variable
-    :param initial: Initial value of the variable. Note that this can also be a Field object,
-             which will then be sampled at the location of the particle
-    :param to_write: Boolean or 'once'. Controls whether Variable is written to NetCDF file.
-             If to_write = 'once', the variable will be written as a time-independent 1D array
-    :type to_write: (bool, 'once', optional)
+    """Descriptor class that delegates data access to particle data.
+
+    Parameters
+    ----------
+    name : str
+        Variable name as used within kernels
+    dtype :
+        Data type (numpy.dtype) of the variable
+    initial :
+        Initial value of the variable. Note that this can also be a Field object,
+        which will then be sampled at the location of the particle
+    to_write : bool, 'once', optional
+        Boolean or 'once'. Controls whether Variable is written to NetCDF file.
+        If to_write = 'once', the variable will be written as a time-independent 1D array
     """
+
     def __init__(self, name, dtype=np.float32, initial=0, to_write=True):
         self.name = name
         self.dtype = dtype
@@ -47,14 +53,17 @@ def __repr__(self):
         return f"PVar<{self.name}|{self.dtype}>"
 
     def is64bit(self):
-        """Check whether variable is 64-bit"""
+        """Check whether variable is 64-bit."""
         return True if self.dtype in indicators_64bit else False
 
 
 class ParticleType:
-    """Class encapsulating the type information for custom particles
+    """Class encapsulating the type information for custom particles.
 
-    :param user_vars: Optional list of (name, dtype) tuples for custom variables
+    Parameters
+    ----------
+    user_vars :
+        Optional list of (name, dtype) tuples for custom variables
     """
 
     def __init__(self, pclass):
@@ -96,7 +105,7 @@ def _cache_key(self):
 
     @property
     def dtype(self):
-        """Numpy.dtype object that defines the C struct"""
+        """Numpy.dtype object that defines the C struct."""
         type_list = [(v.name, v.dtype) for v in self.variables]
         for v in self.variables:
             if v.dtype not in self.supported_dtypes:
@@ -108,13 +117,12 @@ def dtype(self):
 
     @property
     def size(self):
-        """Size of the underlying particle struct in bytes"""
+        """Size of the underlying particle struct in bytes."""
         return sum([8 if v.is64bit() else 4 for v in self.variables])
 
     @property
     def supported_dtypes(self):
-        """List of all supported numpy dtypes. All others are not supported"""
-
+        """List of all supported numpy dtypes. All others are not supported."""
         # Developer note: other dtypes (mostly 2-byte ones) are not supported now
         # because implementing and aligning them in cgen.GenerableStruct is a
         # major headache. Perhaps in a later stage
@@ -122,7 +130,8 @@ def supported_dtypes(self):
 
 
 class _Particle:
-    """Private base class for all particle types"""
+    """Private base class for all particle types."""
+
     lastID = 0  # class-level variable keeping track of last Particle ID used
 
     def __init__(self):
@@ -169,15 +178,24 @@ def setLastID(cls, offset):
 
 
 class ScipyParticle(_Particle):
-    """Class encapsulating the basic attributes of a particle,
-    to be executed in SciPy mode
-
-    :param lon: Initial longitude of particle
-    :param lat: Initial latitude of particle
-    :param depth: Initial depth of particle
-    :param fieldset: :mod:`parcels.fieldset.FieldSet` object to track this particle on
-    :param time: Current time of the particle
-
+    """Class encapsulating the basic attributes of a particle, to be executed in SciPy mode.
+
+    Parameters
+    ----------
+    lon : float
+        Initial longitude of particle
+    lat : float
+        Initial latitude of particle
+    depth : float
+        Initial depth of particle
+    fieldset : parcels.fieldset.FieldSet
+        mod:`parcels.fieldset.FieldSet` object to track this particle on
+    time : float
+        Current time of the particle
+
+
+    Notes
+    -----
     Additional Variables can be added via the :Class Variable: objects
     """
 
@@ -230,18 +248,27 @@ class ScipyInteractionParticle(ScipyParticle):
 
 
 class JITParticle(ScipyParticle):
-    """Particle class for JIT-based (Just-In-Time) Particle objects
-
-    :param lon: Initial longitude of particle
-    :param lat: Initial latitude of particle
-    :param fieldset: :mod:`parcels.fieldset.FieldSet` object to track this particle on
-    :param dt: Execution timestep for this particle
-    :param time: Current time of the particle
-
+    """Particle class for JIT-based (Just-In-Time) Particle objects.
+
+    Parameters
+    ----------
+    lon : float
+        Initial longitude of particle
+    lat : float
+        Initial latitude of particle
+    fieldset : parcels.fieldset.FieldSet
+        mod:`parcels.fieldset.FieldSet` object to track this particle on
+    dt :
+        Execution timestep for this particle
+    time :
+        Current time of the particle
+
+
+    Notes
+    -----
     Additional Variables can be added via the :Class Variable: objects
 
     Users should use JITParticles for faster advection computation.
-
     """
 
     def __init__(self, *args, **kwargs):
diff --git a/parcels/particlefile/__init__.py b/parcels/particlefile/__init__.py
index 9e5d618fc..a994ce0b1 100644
--- a/parcels/particlefile/__init__.py
+++ b/parcels/particlefile/__init__.py
@@ -1,4 +1,4 @@
-"""Module controlling the writing of ParticleSets to NetCDF file"""
+"""Module controlling the writing of ParticleSets to NetCDF file."""
 
 from .baseparticlefile import BaseParticleFile  # noqa: F401
 from .baseparticlefile import _set_calendar  # noqa: F401
diff --git a/parcels/particlefile/baseparticlefile.py b/parcels/particlefile/baseparticlefile.py
index 424b65945..755d2b1ce 100644
--- a/parcels/particlefile/baseparticlefile.py
+++ b/parcels/particlefile/baseparticlefile.py
@@ -1,4 +1,4 @@
-"""Module controlling the writing of ParticleSets to Zarr file"""
+"""Module controlling the writing of ParticleSets to Zarr file."""
 import os
 from abc import ABC, abstractmethod
 from datetime import timedelta as delta
@@ -33,15 +33,29 @@ def _set_calendar(origin_calendar):
 class BaseParticleFile(ABC):
     """Initialise trajectory output.
 
-    :param name: Basename of the output file. This can also be a Zarr store object.
-    :param particleset: ParticleSet to output
-    :param outputdt: Interval which dictates the update frequency of file output
-                     while ParticleFile is given as an argument of ParticleSet.execute()
-                     It is either a timedelta object or a positive double.
-    :param chunks: Tuple (trajs, obs) to control the size of chunks in the zarr output.
-    :param write_ondelete: Boolean to write particle data only when they are deleted. Default is False
-    :param create_new_zarrfile: Boolean to create a new file. Default is True
+    Parameters
+    ----------
+    name : str
+        Basename of the output file. This can also be a Zarr store object.
+    particleset :
+        ParticleSet to output
+    outputdt :
+        Interval which dictates the update frequency of file output
+        while ParticleFile is given as an argument of ParticleSet.execute()
+        It is either a timedelta object or a positive double.
+    chunks :
+        Tuple (trajs, obs) to control the size of chunks in the zarr output.
+    write_ondelete : bool
+        Whether to write particle data only when they are deleted. Default is False
+    create_new_zarrfile : bool
+        Whether to create a new file. Default is True
+
+    Returns
+    -------
+    BaseParticleFile
+        ParticleFile object that can be used to write particle data to file
     """
+
     write_ondelete = None
     outputdt = None
     lasttime_written = None
@@ -112,19 +126,16 @@ def __init__(self, name, particleset, outputdt=np.infty, chunks=None, write_onde
 
     @abstractmethod
     def _reserved_var_names(self):
-        """
-        returns the reserved dimension names not to be written just once.
-        """
+        """Returns the reserved dimension names not to be written just once."""
         pass
 
     def _create_variables_attribute_dict(self):
-        """
-        creates the dictionary with variable attributes.
+        """Creates the dictionary with variable attributes.
 
-        Attention:
+        Notes
+        -----
         For ParticleSet structures other than SoA, and structures where ID != index, this has to be overridden.
         """
-
         attrs = {'z': {"long_name": "",
                        "standard_name": "depth",
                        "units": "m",
@@ -166,10 +177,14 @@ def close(self, delete_tempfiles=True):
         pass
 
     def add_metadata(self, name, message):
-        """Add metadata to :class:`parcels.particleset.ParticleSet`
-
-        :param name: Name of the metadata variabale
-        :param message: message to be written
+        """Add metadata to :class:`parcels.particleset.ParticleSet`.
+
+        Parameters
+        ----------
+        name : str
+            Name of the metadata variabale
+        message : str
+            message to be written
         """
         self.metadata[name] = message
 
@@ -200,13 +215,17 @@ def _extend_zarr_dims(self, Z, store, dtype, axis):
         zarr.consolidate_metadata(store)
 
     def write(self, pset, time, deleted_only=False):
-        """Write all data from one time step to the zarr file
-
-        :param pset: ParticleSet object to write
-        :param time: Time at which to write ParticleSet
-        :param deleted_only: Flag to write only the deleted Particles
+        """Write all data from one time step to the zarr file.
+
+        Parameters
+        ----------
+        pset :
+            ParticleSet object to write
+        time :
+            Time at which to write ParticleSet
+        deleted_only :
+            Flag to write only the deleted Particles (Default value = False)
         """
-
         time = time.total_seconds() if isinstance(time, delta) else time
 
         if self.lasttime_written != time and (self.write_ondelete is False or deleted_only is not False):
diff --git a/parcels/particlefile/particlefileaos.py b/parcels/particlefile/particlefileaos.py
index 75f89c314..14d911020 100644
--- a/parcels/particlefile/particlefileaos.py
+++ b/parcels/particlefile/particlefileaos.py
@@ -9,13 +9,25 @@
 class ParticleFileAOS(BaseParticleFile):
     """Initialise trajectory output.
 
-    :param name: Basename of the output file. This can also be a Zarr store.
-    :param particleset: ParticleSet to output
-    :param outputdt: Interval which dictates the update frequency of file output
-                     while ParticleFile is given as an argument of ParticleSet.execute()
-                     It is either a timedelta object or a positive double.
-    :param chunks: Tuple (trajs, obs) to control the size of chunks in the zarr output.
-    :param write_ondelete: Boolean to write particle data only when they are deleted. Default is False
+    Parameters
+    ----------
+    name : str
+        Basename of the output file. This can also be a Zarr store.
+    particleset :
+        ParticleSet to output
+    outputdt :
+        Interval which dictates the update frequency of file output
+        while ParticleFile is given as an argument of ParticleSet.execute()
+        It is either a timedelta object or a positive double.
+    chunks :
+        Tuple (trajs, obs) to control the size of chunks in the zarr output.
+    write_ondelete :
+        Boolean to write particle data only when they are deleted. Default is False
+
+    Returns
+    -------
+    ParticleFileAOS
+        ParticleFile object that can be used to write particle data to file
     """
 
     def __init__(self, name, particleset, outputdt=np.infty, chunks=None, write_ondelete=False):
@@ -27,7 +39,5 @@ def __del__(self):
         super().__del__()
 
     def _reserved_var_names(self):
-        """
-        returns the reserved dimension names not to be written just once.
-        """
+        """Returns the reserved dimension names not to be written just once."""
         return ['time', 'lat', 'lon', 'depth', 'id']
diff --git a/parcels/particlefile/particlefilesoa.py b/parcels/particlefile/particlefilesoa.py
index c47abf885..aeb9ffc48 100644
--- a/parcels/particlefile/particlefilesoa.py
+++ b/parcels/particlefile/particlefilesoa.py
@@ -9,13 +9,26 @@
 class ParticleFileSOA(BaseParticleFile):
     """Initialise trajectory output.
 
-    :param name: Basename of the output file.  This can also be a Zarr store.
-    :param particleset: ParticleSet to output
-    :param outputdt: Interval which dictates the update frequency of file output
-                     while ParticleFile is given as an argument of ParticleSet.execute()
-                     It is either a timedelta object or a positive double.
-    :param chunks: Tuple (trajs, obs) to control the size of chunks in the zarr output.
-    :param write_ondelete: Boolean to write particle data only when they are deleted. Default is False
+    Parameters
+    ----------
+    name : str
+        Basename of the output file.  This can also be a Zarr store.
+    particleset :
+        ParticleSet to output
+    outputdt :
+        Interval which dictates the update frequency of file output
+        while ParticleFile is given as an argument of ParticleSet.execute()
+        It is either a timedelta object or a positive double.
+    chunks :
+        Tuple (trajs, obs) to control the size of chunks in the zarr output.
+    write_ondelete :
+        Whether to write particle data only when they are deleted. Default is False
+
+    Returns
+    -------
+    ParticleFileSOA
+        ParticleFile object that can be used to write particle data to file
+
     """
 
     def __init__(self, name, particleset, outputdt=np.infty, chunks=None, write_ondelete=False):
@@ -27,7 +40,5 @@ def __del__(self):
         super().__del__()
 
     def _reserved_var_names(self):
-        """
-        returns the reserved dimension names not to be written just once.
-        """
+        """Returns the reserved dimension names not to be written just once."""
         return ['time', 'lat', 'lon', 'depth', 'id']
diff --git a/parcels/particleset/baseparticleset.py b/parcels/particleset/baseparticleset.py
index fabdb5293..e40378608 100644
--- a/parcels/particleset/baseparticleset.py
+++ b/parcels/particleset/baseparticleset.py
@@ -25,6 +25,7 @@ class NDCluster(ABC):
 
 class BaseParticleSet(NDCluster):
     """Base ParticleSet."""
+
     _collection = None
     kernel = None
     interaction_kernel = None
@@ -60,16 +61,17 @@ def iterator(self):
         return self._collection.iterator()
 
     def __iter__(self):
-        """Allows for more intuitive iteration over a particleset, while
-        in reality iterating over the particles in the collection.
-        """
+        """Allows for more intuitive iteration over a particleset, while in reality iterating over the particles in the collection."""
         return self.iterator()
 
     def __getattr__(self, name):
         """
         Access a single property of all particles.
 
-        :param name: name of the property
+        Parameters
+        ----------
+        name : str
+            Name of the property
         """
         for v in self._collection.ptype.variables:
             if v.name == name:
@@ -109,43 +111,65 @@ def __create_progressbar(self, starttime, endtime):
 
     @classmethod
     def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None, **kwargs):
-        """Initialise the ParticleSet from lists of lon and lat
-
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param lon: List of initial longitude values for particles
-        :param lat: List of initial latitude values for particles
-        :param depth: Optional list of initial depth values for particles. Default is 0m
-        :param time: Optional list of start time values for particles. Default is fieldset.U.time[0]
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
-        Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
-       """
+        """Initialise the ParticleSet from lists of lon and lat.
+
+        Parameters
+        ----------
+        fieldset :
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        lon :
+            List of initial longitude values for particles
+        lat :
+            List of initial latitude values for particles
+        depth :
+            Optional list of initial depth values for particles. Default is 0m
+        time :
+            Optional list of start time values for particles. Default is fieldset.U.time[0]
+        repeatdt :
+            Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
+            Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
+        **kwargs :
+            Keyword arguments passed to the particleset constructor.
+        """
         return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt, lonlatdepth_dtype=lonlatdepth_dtype, **kwargs)
 
     @classmethod
     def from_line(cls, fieldset, pclass, start, finish, size, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None):
-        """Initialise the ParticleSet from start/finish coordinates with equidistant spacing
+        """Create a particleset in the shape of a line (according to a cartesian grid).
+
+        Initialise the ParticleSet from start/finish coordinates with equidistant spacing
         Note that this method uses simple numpy.linspace calls and does not take into account
         great circles, so may not be a exact on a globe
 
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param start: Starting point for initialisation of particles on a straight line.
-        :param finish: End point for initialisation of particles on a straight line.
-        :param size: Initial size of particle set
-        :param depth: Optional list of initial depth values for particles. Default is 0m
-        :param time: Optional start time value for particles. Default is fieldset.U.time[0]
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
+        Parameters
+        ----------
+        fieldset :
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        start :
+            Starting point for initialisation of particles on a straight line.
+        finish :
+            End point for initialisation of particles on a straight line.
+        size :
+            Initial size of particle set
+        depth :
+            Optional list of initial depth values for particles. Default is 0m
+        time :
+            Optional start time value for particles. Default is fieldset.U.time[0]
+        repeatdt :
+            Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
         """
-
         lon = np.linspace(start[0], finish[0], size)
         lat = np.linspace(start[1], finish[1], size)
         if type(depth) in [int, float]:
@@ -155,33 +179,53 @@ def from_line(cls, fieldset, pclass, start, finish, size, depth=None, time=None,
     @classmethod
     @abstractmethod
     def monte_carlo_sample(cls, start_field, size, mode='monte_carlo'):
-        """
-        Converts a starting field into a monte-carlo sample of lons and lats.
-
-        :param start_field: :mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
-
-        returns list(lon), list(lat)
+        """Converts a starting field into a monte-carlo sample of lons and lats.
+
+        Parameters
+        ----------
+        start_field : parcels.field.Field
+            mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
+        size :
+
+        mode :
+             (Default value = 'monte_carlo')
+
+        Returns
+        -------
+        list of float
+            A list of longitude values.
+        list of float
+            A list of latitude values.
         """
         pass
 
     @classmethod
     def from_field(cls, fieldset, pclass, start_field, size, mode='monte_carlo', depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None):
-        """Initialise the ParticleSet randomly drawn according to distribution from a field
-
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param start_field: Field for initialising particles stochastically (horizontally)  according to the presented density field.
-        :param size: Initial size of particle set
-        :param mode: Type of random sampling. Currently only 'monte_carlo' is implemented
-        :param depth: Optional list of initial depth values for particles. Default is 0m
-        :param time: Optional start time value for particles. Default is fieldset.U.time[0]
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
+        """Initialise the ParticleSet randomly drawn according to distribution from a field.
+
+        Parameters
+        ----------
+        fieldset : parcels.fieldset.FieldSet
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        start_field : parcels.field.Field
+            Field for initialising particles stochastically (horizontally)  according to the presented density field.
+        size :
+            Initial size of particle set
+        mode :
+            Type of random sampling. Currently only 'monte_carlo' is implemented (Default value = 'monte_carlo')
+        depth :
+            Optional list of initial depth values for particles. Default is 0m
+        time :
+            Optional start time value for particles. Default is fieldset.U.time[0]
+        repeatdt :
+            Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
         """
-
         lon, lat = cls.monte_carlo_sample(start_field, size, mode)
 
         return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, lonlatdepth_dtype=lonlatdepth_dtype, repeatdt=repeatdt)
@@ -193,43 +237,67 @@ def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime
         This creates a new ParticleSet based on locations of all particles written
         in a netcdf ParticleFile at a certain time. Particle IDs are preserved if restart=True
 
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param filename: Name of the particlefile from which to read initial conditions
-        :param restart: Boolean to signal if pset is used for a restart (default is True).
-               In that case, Particle IDs are preserved.
-        :param restarttime: time at which the Particles will be restarted. Default is the last time written.
-               Alternatively, restarttime could be a time value (including np.datetime64) or
-               a callable function such as np.nanmin. The last is useful when running with dt < 0.
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
+        Parameters
+        ----------
+        fieldset :
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        filename : str
+            Name of the particlefile from which to read initial conditions
+        restart : bool
+            Boolean to signal if pset is used for a restart (default is True).
+            In that case, Particle IDs are preserved.
+        restarttime :
+            time at which the Particles will be restarted. Default is the last time written.
+            Alternatively, restarttime could be a time value (including np.datetime64) or
+            a callable function such as np.nanmin. The last is useful when running with dt < 0.
+        repeatdt :
+            Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
+        **kwargs :
+            Keyword arguments passed to the particleset constructor.
         """
         pass
 
     def density(self, field_name=None, particle_val=None, relative=False, area_scale=False):
-        """Method to calculate the density of particles in a ParticleSet from their locations,
-        through a 2D histogram.
-
-        :param field: Optional :mod:`parcels.field.Field` object to calculate the histogram
-                      on. Default is `fieldset.U`
-        :param particle_val: Optional numpy-array of values to weigh each particle with,
-                             or string name of particle variable to use weigh particles with.
-                             Default is None, resulting in a value of 1 for each particle
-        :param relative: Boolean to control whether the density is scaled by the total
-                         weight of all particles. Default is False
-        :param area_scale: Boolean to control whether the density is scaled by the area
-                           (in m^2) of each grid cell. Default is False
+        """Calculate 2D particle density field from ParticleSet particle locations.
+
+        Parameters
+        ----------
+        field_name : str, optional
+            Name of the field from the fieldset to calculate the histogram on.
+            Defaults to using "U".
+        particle_val :
+            Optional numpy-array of values to weigh each particle with,
+            or string name of particle variable to use weigh particles with.
+            Default is None, resulting in a value of 1 for each particle
+        relative : bool
+            Whether the density is scaled by the total weight of all particles.
+            Default is False
+        area_scale : bool
+            Whether the density is scaled by the area (in m^2) of each grid cell.
+            Default is False
         """
         pass
 
     @abstractmethod
     def Kernel(self, pyfunc, c_include="", delete_cfiles=True):
-        """Wrapper method to convert a `pyfunc` into a :class:`parcels.kernel.Kernel` object
-        based on `fieldset` and `ptype` of the ParticleSet
-        :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
+        """Wrapper method to convert a `pyfunc` into a :class:`parcels.kernel.Kernel` object.
+
+        Conversion is based on `fieldset` and `ptype` of the ParticleSet.
+
+        Parameters
+        ----------
+        delete_cfiles : bool
+            Whether to delete the C-files after compilation in JIT mode (default is True)
+        pyfunc :
+
+        c_include :
+             (Default value = "")
         """
         pass
 
@@ -238,8 +306,7 @@ def InteractionKernel(self, pyfunc_inter):
 
     @abstractmethod
     def ParticleFile(self, *args, **kwargs):
-        """Wrapper method to initialise a :class:`parcels.particlefile.ParticleFile`
-        object from the ParticleSet"""
+        """Wrapper method to initialise a :class:`parcels.particlefile.ParticleFile` object from the ParticleSet."""
         pass
 
     @abstractmethod
@@ -248,8 +315,12 @@ def _set_particle_vector(self, name, value):
 
         This is a fallback implementation, it might be slow.
 
-        :param name: Name of the attribute (str).
-        :param value: New value to set the attribute of the particles to.
+        Parameters
+        ----------
+        name : str
+            Name of the attribute (str).
+        value :
+            New value to set the attribute of the particles to.
         """
         for p in self:
             setattr(p, name, value)
@@ -261,7 +332,12 @@ def error_particles(self):
 
         This is a fallback implementation, it might be slow.
 
-        :return: Collection iterator over error particles.
+
+        Returns
+        -------
+        iterator
+            Collection iterator over error particles.
+
         """
         error_indices = [
             i for i, p in enumerate(self)
@@ -279,8 +355,16 @@ def _impute_release_times(self, default):
 
         This is a fallback implementation, it might be slow.
 
-        :param default: Default release time.
-        :return: Minimum and maximum release times.
+        Parameters
+        ----------
+        default :
+            Default release time.
+
+        Returns
+        -------
+        type
+            Minimum and maximum release times.
+
         """
         max_rt = None
         min_rt = None
@@ -296,33 +380,49 @@ def _impute_release_times(self, default):
     def execute(self, pyfunc=AdvectionRK4, pyfunc_inter=None, endtime=None, runtime=None, dt=1.,
                 moviedt=None, recovery=None, output_file=None, movie_background_field=None,
                 verbose_progress=None, postIterationCallbacks=None, callbackdt=None):
-        """Execute a given kernel function over the particle set for
-        multiple timesteps. Optionally also provide sub-timestepping
+        """Execute a given kernel function over the particle set for multiple timesteps.
+
+        Optionally also provide sub-timestepping
         for particle output.
 
-        :param pyfunc: Kernel function to execute. This can be the name of a
-                       defined Python function or a :class:`parcels.kernel.Kernel` object.
-                       Kernels can be concatenated using the + operator
-        :param endtime: End time for the timestepping loop.
-                        It is either a datetime object or a positive double.
-        :param runtime: Length of the timestepping loop. Use instead of endtime.
-                        It is either a timedelta object or a positive double.
-        :param dt: Timestep interval to be passed to the kernel.
-                   It is either a timedelta object or a double.
-                   Use a negative value for a backward-in-time simulation.
-        :param moviedt:  Interval for inner sub-timestepping (leap), which dictates
-                         the update frequency of animation.
-                         It is either a timedelta object or a positive double.
-                         None value means no animation.
-        :param output_file: :mod:`parcels.particlefile.ParticleFile` object for particle output
-        :param recovery: Dictionary with additional `:mod:parcels.tools.error`
-                         recovery kernels to allow custom recovery behaviour in case of
-                         kernel errors.
-        :param movie_background_field: field plotted as background in the movie if moviedt is set.
-                                       'vector' shows the velocity as a vector field.
-        :param verbose_progress: Boolean for providing a progress bar for the kernel execution loop.
-        :param postIterationCallbacks: (Optional) Array of functions that are to be called after each iteration (post-process, non-Kernel)
-        :param callbackdt: (Optional, in conjecture with 'postIterationCallbacks) timestep inverval to (latestly) interrupt the running kernel and invoke post-iteration callbacks from 'postIterationCallbacks'
+        Parameters
+        ----------
+        pyfunc :
+            Kernel function to execute. This can be the name of a
+            defined Python function or a :class:`parcels.kernel.Kernel` object.
+            Kernels can be concatenated using the + operator (Default value = AdvectionRK4)
+        endtime :
+            End time for the timestepping loop.
+            It is either a datetime object or a positive double. (Default value = None)
+        runtime :
+            Length of the timestepping loop. Use instead of endtime.
+            It is either a timedelta object or a positive double. (Default value = None)
+        dt :
+            Timestep interval to be passed to the kernel.
+            It is either a timedelta object or a double.
+            Use a negative value for a backward-in-time simulation. (Default value = 1.)
+        moviedt :
+            Interval for inner sub-timestepping (leap), which dictates
+            the update frequency of animation.
+            It is either a timedelta object or a positive double.
+            None value means no animation. (Default value = None)
+        output_file :
+            mod:`parcels.particlefile.ParticleFile` object for particle output (Default value = None)
+        recovery :
+            Dictionary with additional `:mod:parcels.tools.error`
+            recovery kernels to allow custom recovery behaviour in case of
+            kernel errors. (Default value = None)
+        movie_background_field :
+            field plotted as background in the movie if moviedt is set.
+            'vector' shows the velocity as a vector field. (Default value = None)
+        verbose_progress : bool
+            Boolean for providing a progress bar for the kernel execution loop. (Default value = None)
+        postIterationCallbacks :
+            Optional) Array of functions that are to be called after each iteration (post-process, non-Kernel) (Default value = None)
+        callbackdt :
+            Optional, in conjecture with 'postIterationCallbacks) timestep inverval to (latestly) interrupt the running kernel and invoke post-iteration callbacks from 'postIterationCallbacks' (Default value = None)
+        pyfunc_inter :
+             (Default value = None)
         """
         # check if pyfunc has changed since last compile. If so, recompile
         if self.kernel is None or (self.kernel.pyfunc is not pyfunc and self.kernel is not pyfunc):
@@ -514,18 +614,33 @@ def execute(self, pyfunc=AdvectionRK4, pyfunc_inter=None, endtime=None, runtime=
 
     def show(self, with_particles=True, show_time=None, field=None, domain=None, projection='PlateCarree',
              land=True, vmin=None, vmax=None, savefile=None, animation=False, **kwargs):
-        """Method to 'show' a Parcels ParticleSet
-
-        :param with_particles: Boolean whether to show particles
-        :param show_time: Time at which to show the ParticleSet
-        :param field: Field to plot under particles (either None, a Field object, or 'vector')
-        :param domain: dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show
-        :param projection: type of cartopy projection to use (default PlateCarree)
-        :param land: Boolean whether to show land. This is ignored for flat meshes
-        :param vmin: minimum colour scale (only in single-plot mode)
-        :param vmax: maximum colour scale (only in single-plot mode)
-        :param savefile: Name of a file to save the plot to
-        :param animation: Boolean whether result is a single plot, or an animation
+        """Method to 'show' a Parcels ParticleSet.
+
+        Parameters
+        ----------
+        with_particles : bool
+            Whether to show particles (Default value = True)
+        show_time :
+            Time at which to show the ParticleSet (Default value = None)
+        field :
+            Field to plot under particles (either None, a Field object, or 'vector') (Default value = None)
+        domain :
+            dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show (Default value = None)
+        projection :
+            type of cartopy projection to use (default PlateCarree)
+        land : bool
+            Whether to show land. This is ignored for flat meshes (Default value = True)
+        vmin : float
+            minimum colour scale (only in single-plot mode) (Default value = None)
+        vmax : float
+            maximum colour scale (only in single-plot mode) (Default value = None)
+        savefile : str
+            Name of a file to save the plot to (Default value = None)
+        animation : bool
+            Whether result is a single plot, or an animation (Default value = False)
+        **kwargs :
+            Keyword arguments passed to the :func:`parcels.plotting.plotparticles`.
+
         """
         from parcels.plotting import plotparticles
         plotparticles(particles=self, with_particles=with_particles, show_time=show_time, field=field, domain=domain,
diff --git a/parcels/particleset/particlesetaos.py b/parcels/particleset/particlesetaos.py
index cd8106cba..802ce1f46 100644
--- a/parcels/particleset/particlesetaos.py
+++ b/parcels/particleset/particlesetaos.py
@@ -42,23 +42,34 @@ def _convert_to_reltime(time):
 class ParticleSetAOS(BaseParticleSet):
     """Container class for storing particle and executing kernel over them.
 
-    :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity.
-           While fieldset=None is supported, this will throw a warning as it breaks most Parcels functionality
-    :param pclass: Optional :mod:`parcels.particle.JITParticle` or
-                 :mod:`parcels.particle.ScipyParticle` object that defines custom particle
-    :param lon: List of initial longitude values for particles
-    :param lat: List of initial latitude values for particles
-    :param depth: Optional list of initial depth values for particles. Default is 0m
-    :param time: Optional list of initial time values for particles. Default is fieldset.U.grid.time[0]
-    :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-    :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-           It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-           and np.float64 if the interpolation method is 'cgrid_velocity'
-    :param pid_orig: Optional list of (offsets for) the particle IDs
-    :param partitions: List of cores on which to distribute the particles for MPI runs. Default: None, in which case particles
-           are distributed automatically on the processors
-
-    Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
+    Parameters
+    ----------
+    fieldset :
+        mod:`parcels.fieldset.FieldSet` object from which to sample velocity.
+        While fieldset=None is supported, this will throw a warning as it breaks most Parcels functionality
+    pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+        Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+    lon :
+        List of initial longitude values for particles
+    lat :
+        List of initial latitude values for particles
+    depth :
+        Optional list of initial depth values for particles. Default is 0m
+    time :
+        Optional list of initial time values for particles. Default is fieldset.U.grid.time[0]
+    repeatdt : datetime.timedelta or float, optional
+        Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
+    lonlatdepth_dtype :
+        Floating precision for lon, lat, depth particle coordinates.
+        It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+        and np.float64 if the interpolation method is 'cgrid_velocity'
+    pid_orig :
+        Optional list of (offsets for) the particle IDs
+    partitions :
+        List of cores on which to distribute the particles for MPI runs. Default: None, in which case particles
+        are distributed automatically on the processors
+
+        Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
     """
 
     def __init__(self, fieldset=None, pclass=JITParticle, lon=None, lat=None, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None, pid_orig=None, **kwargs):
@@ -273,8 +284,7 @@ def __del__(self):
         super().__del__()
 
     def delete(self, key):
-        """
-        This is the generic super-method to indicate obejct deletion of a specific object from this collection.
+        """This is the generic super-method to indicate obejct deletion of a specific object from this collection.
 
         Comment/Annotation:
         Functions for deleting multiple objects are more specialised than just a for-each loop of single-item deletion,
@@ -290,8 +300,7 @@ def delete(self, key):
             self.delete_by_ID(key)
 
     def delete_by_index(self, index):
-        """
-        This method deletes a particle from the  the collection based on its index. It does not return the deleted item.
+        """This method deletes a particle from the  the collection based on its index. It does not return the deleted item.
         Semantically, the function appears similar to the 'remove' operation. That said, the function in OceanParcels -
         instead of directly deleting the particle - just raises the 'deleted' status flag for the indexed particle.
         In result, the particle still remains in the collection. The functional interpretation of the 'deleted' status
@@ -300,8 +309,7 @@ def delete_by_index(self, index):
         self._collection[index].state = OperationCode.Delete
 
     def delete_by_ID(self, id):
-        """
-        This method deletes a particle from the  the collection based on its ID. It does not return the deleted item.
+        """This method deletes a particle from the  the collection based on its ID. It does not return the deleted item.
         Semantically, the function appears similar to the 'remove' operation. That said, the function in OceanParcels -
         instead of directly deleting the particle - just raises the 'deleted' status flag for the indexed particle.
         In result, the particle still remains in the collection. The functional interpretation of the 'deleted' status
@@ -313,16 +321,28 @@ def delete_by_ID(self, id):
     def _set_particle_vector(self, name, value):
         """Set attributes of all particles to new values.
 
-        :param name: Name of the attribute (str).
-        :param value: New value to set the attribute of the particles to.
+        Parameters
+        ----------
+        name : str
+            Name of the attribute.
+        value :
+            New value to set the attribute of the particles to.
         """
         [setattr(p, name, value) for p in self._collection.data]
 
     def _impute_release_times(self, default):
         """Set attribute 'time' to default if encountering NaN values.
 
-        :param default: Default release time.
-        :return: Minimum and maximum release times.
+        Parameters
+        ----------
+        default :
+            Default release time.
+
+        Returns
+        -------
+        type
+            Minimum and maximum release times.
+
         """
         max_rt = None
         min_rt = None
@@ -339,12 +359,21 @@ def data_indices(self, variable_name, compare_values, invert=False):
         """Get the indices of all particles where the value of
         `variable_name` equals (one of) `compare_values`.
 
-        :param variable_name: Name of the variable to check.
-        :param compare_values: Value or list of values to compare to.
-        :param invert: Whether to invert the selection. I.e., when True,
-                       return all indices that do not equal (one of)
-                       `compare_values`.
-        :return: Numpy array of indices that satisfy the test.
+        Parameters
+        ----------
+        variable_name : str
+            Name of the variable to check.
+        compare_values :
+            Value or list of values to compare to.
+        invert :
+            Whether to invert the selection. I.e., when True,
+            return all indices that do not equal (one of)
+            `compare_values`. (Default value = False)
+
+        Returns
+        -------
+        np.ndarray
+            Numpy array of indices that satisfy the test.
         """
         compare_values = np.array([compare_values, ]) if type(compare_values) not in [list, dict, np.ndarray] else compare_values
         result = []
@@ -373,7 +402,10 @@ def particle_data(self):
     def error_particles(self):
         """Get an iterator over all particles that are in an error state.
 
-        :return: Collection iterator over error particles.
+        Returns
+        -------
+        iterator
+            Collection iterator over error particles.
         """
         error_indices = [
             i for i, p in enumerate(self)
@@ -384,7 +416,10 @@ def error_particles(self):
     def num_error_particles(self):
         """Get the number of particles that are in an error state.
 
-        :return: The number of error particles.
+        Returns
+        -------
+        int
+            Number of error particles.
         """
         return np.sum([True for p in self._collection if p.state not in [StateCode.Success, StateCode.Evaluate]])
 
@@ -395,14 +430,17 @@ def iterator(self):
         return super().iterator()
 
     def __getitem__(self, index):
-        """Get a single particle by index"""
+        """Get a single particle by index."""
         return self._collection.get_single_by_index(index)
 
     def __getattr__(self, name):
         """
         Access a single property of all particles.
 
-        :param name: name of the property
+        Parameters
+        ----------
+        name : str
+            Name of the property to access.
         """
         for v in self._collection.ptype.variables:
             if v.name == name:
@@ -449,12 +487,25 @@ def lonlatdepth_dtype_from_field_interp_method(field):
 
     @classmethod
     def monte_carlo_sample(cls, start_field, size, mode='monte_carlo'):
-        """
-        Converts a starting field into a monte-carlo sample of lons and lats.
+        """Converts a starting field into a monte-carlo sample of lons and lats.
+
+        Parameters
+        ----------
+        start_field :
+            mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
 
-        :param start_field: :mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
+            returns list(lon), list(lat)
+        size :
 
-        returns list(lon), list(lat)
+        mode :
+             (Default value = 'monte_carlo')
+
+        Returns
+        -------
+        list of float
+            A list of longitude values.
+        list of float
+            A list of latitude values.
         """
         if mode == 'monte_carlo':
             data = start_field.data if isinstance(start_field.data, np.ndarray) else np.array(start_field.data)
@@ -500,19 +551,29 @@ def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime
         This creates a new ParticleSet based on locations of all particles written
         in a zarr ParticleFile at a certain time. Particle IDs are preserved if restart=True
 
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param filename: Name of the particlefile from which to read initial conditions
-        :param restart: Boolean to signal if pset is used for a restart (default is True).
-               In that case, Particle IDs are preserved.
-        :param restarttime: time at which the Particles will be restarted. Default is the last time written.
-               Alternatively, restarttime could be a time value (including np.datetime64) or
-               a callable function such as np.nanmin. The last is useful when running with dt < 0.
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
+        Parameters
+        ----------
+        fieldset :
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        filename : str
+            Name of the particlefile from which to read initial conditions
+        restart : bool
+            BSignal if pset is used for a restart (default is True).
+            In that case, Particle IDs are preserved.
+        restarttime :
+            time at which the Particles will be restarted. Default is the last time written.
+            Alternatively, restarttime could be a time value (including np.datetime64) or
+            a callable function such as np.nanmin. The last is useful when running with dt < 0.
+        repeatdt : datetime.timedelta or float, optional
+            Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
+        **kwargs :
+            Keyword arguments passed to the particleset constructor.
         """
         if repeatdt is not None:
             logger.warning(f'Note that the `repeatdt` argument is not retained from {filename}, and that '
@@ -563,13 +624,21 @@ def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime
                    lonlatdepth_dtype=lonlatdepth_dtype, repeatdt=repeatdt, **kwargs)
 
     def __iadd__(self, particles):
-        """Add particles to the ParticleSet. Note that this is an
-        incremental add, the particles will be added to the ParticleSet
+        """Add particles to the ParticleSet.
+
+        Note that this is an incremental add, the particles will be added to the ParticleSet
         on which this function is called.
 
-        :param particles: Another ParticleSet containing particles to add
-                          to this one.
-        :return: The current ParticleSet
+        Parameters
+        ----------
+        particles :
+            Another ParticleSet containing particles to add
+            to this one.
+
+        Returns
+        -------
+        type
+            The current ParticleSet
         """
         self.add(particles)
         return self
@@ -579,9 +648,17 @@ def add(self, particles):
         incremental add, the particles will be added to the ParticleSet
         on which this function is called.
 
-        :param particles: Another ParticleSet containing particles to add
-                          to this one.
-        :return: The current ParticleSet
+        Parameters
+        ----------
+        particles :
+            Another ParticleSet containing particles to add
+            to this one.
+
+        Returns
+        -------
+        type
+            The current ParticleSet
+
         """
         if isinstance(particles, BaseParticleSet):
             particles = particles.collection
@@ -589,33 +666,37 @@ def add(self, particles):
         return self
 
     def remove_indices(self, indices):
-        """Method to remove particles from the ParticleSet, based on their `indices`"""
+        """Method to remove particles from the ParticleSet, based on their `indices`."""
         if type(indices) in [int, np.int32, np.intp]:
             self._collection.remove_single_by_index(indices)
         else:
             self._collection.remove_multi_by_indices(indices)
 
     def remove_booleanvector(self, indices):
-        """Method to remove particles from the ParticleSet, based on an array of booleans"""
+        """Method to remove particles from the ParticleSet, based on an array of booleans."""
         # indices = np.where(indices)[0]
         indices = np.nonzero(indices)[0]
         self.remove_indices(indices)
 
     def density(self, field_name=None, particle_val=None, relative=False, area_scale=False):
-        """Method to calculate the density of particles in a ParticleSet from their locations,
-        through a 2D histogram.
-
-        :param field: Optional :mod:`parcels.field.Field` object to calculate the histogram
-                      on. Default is `fieldset.U`
-        :param particle_val: Optional numpy-array of values to weigh each particle with,
-                             or string name of particle variable to use weigh particles with.
-                             Default is None, resulting in a value of 1 for each particle
-        :param relative: Boolean to control whether the density is scaled by the total
-                         weight of all particles. Default is False
-        :param area_scale: Boolean to control whether the density is scaled by the area
-                           (in m^2) of each grid cell. Default is False
+        """Calculate 2D particle density field from ParticleSet particle locations.
+
+        Parameters
+        ----------
+        field_name : str, optional
+            Name of the field from the fieldset to calculate the histogram on.
+            Defaults to using "U".
+        particle_val :
+            Optional numpy-array of values to weigh each particle with,
+            or string name of particle variable to use weigh particles with.
+            Default is None, resulting in a value of 1 for each particle
+        relative : bool
+            Whether the density is scaled by the total weight of all particles.
+            Default is False
+        area_scale : bool
+            Whether the density is scaled by the area (in m^2) of each grid cell.
+            Default is False
         """
-
         field_name = field_name if field_name else "U"
         sampling_name = "UV" if field_name in ["U", "V"] else field_name
         field = getattr(self.fieldset, field_name)
@@ -658,21 +739,29 @@ def density(self, field_name=None, particle_val=None, relative=False, area_scale
 
     def Kernel(self, pyfunc, c_include="", delete_cfiles=True):
         """Wrapper method to convert a `pyfunc` into a :class:`parcels.kernel.Kernel` object
-        based on `fieldset` and `ptype` of the ParticleSet
+        based on `fieldset` and `ptype` of the ParticleSet.
 
-        :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
+        Parameters
+        ----------
+        delete_cfiles : bool
+            Whether to delete the C-files after compilation in JIT mode (default is True).
         """
         return KernelAOS(self.fieldset, self.collection.ptype, pyfunc=pyfunc, c_include=c_include, delete_cfiles=delete_cfiles)
 
     def ParticleFile(self, *args, **kwargs):
         """Wrapper method to initialise a :class:`parcels.particlefile.ParticleFile`
-        object from the ParticleSet"""
+        object from the ParticleSet.
+        """
         return ParticleFileAOS(*args, particleset=self, **kwargs)
 
     def set_variable_write_status(self, var, write_status):
-        """
-        Method to set the write status of a Variable
-        :param var: Name of the variable (string)
-        :param write_status: Write status of the variable (True, False or 'once')
+        """Method to set the write status of a Variable.
+
+        Parameters
+        ----------
+        var :
+            Name of the variable (string)
+        write_status :
+            Write status of the variable (True, False or 'once')
         """
         self._collection.set_variable_write_status(var, write_status)
diff --git a/parcels/particleset/particlesetsoa.py b/parcels/particleset/particlesetsoa.py
index 97e2d1c8c..2dab5120e 100644
--- a/parcels/particleset/particlesetsoa.py
+++ b/parcels/particleset/particlesetsoa.py
@@ -39,9 +39,7 @@
 
 
 def _convert_to_reltime(time):
-    """Check to determine if the value of the time parameter needs to be
-    converted to a relative value (relative to the time_origin).
-    """
+    """Check to determine if the value of the time parameter needs to be converted to a relative value (relative to the time_origin)."""
     if isinstance(time, np.datetime64) or (hasattr(time, 'calendar') and time.calendar in _get_cftime_calendars()):
         return True
     return False
@@ -55,25 +53,38 @@ class ParticleSetSOA(BaseParticleSet):
     and individual particles can only be deleted as a set procedually (i.e. by 'particle.delete()'-call during
     kernel execution).
 
-    :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity.
-           While fieldset=None is supported, this will throw a warning as it breaks most Parcels functionality
-    :param pclass: Optional :mod:`parcels.particle.JITParticle` or
-                 :mod:`parcels.particle.ScipyParticle` object that defines custom particle
-    :param lon: List of initial longitude values for particles
-    :param lat: List of initial latitude values for particles
-    :param depth: Optional list of initial depth values for particles. Default is 0m
-    :param time: Optional list of initial time values for particles. Default is fieldset.U.grid.time[0]
-    :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-    :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-           It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-           and np.float64 if the interpolation method is 'cgrid_velocity'
-    :param pid_orig: Optional list of (offsets for) the particle IDs
-    :param partitions: List of cores on which to distribute the particles for MPI runs. Default: None, in which case particles
-           are distributed automatically on the processors
-    :param periodic_domain_zonal: Zonal domain size, used to apply zonally periodic boundaries for particle-particle
-           interaction. If None, no zonally periodic boundaries are applied
-
-    Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
+    Parameters
+    ----------
+    fieldset :
+        mod:`parcels.fieldset.FieldSet` object from which to sample velocity.
+        While fieldset=None is supported, this will throw a warning as it breaks most Parcels functionality
+    pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+        Optional :mod:`parcels.particle.JITParticle` or
+        :mod:`parcels.particle.ScipyParticle` object that defines custom particle
+    lon :
+        List of initial longitude values for particles
+    lat :
+        List of initial latitude values for particles
+    depth :
+        Optional list of initial depth values for particles. Default is 0m
+    time :
+        Optional list of initial time values for particles. Default is fieldset.U.grid.time[0]
+    repeatdt : datetime.timedelta or float, optional
+        Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
+    lonlatdepth_dtype :
+        Floating precision for lon, lat, depth particle coordinates.
+        It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+        and np.float64 if the interpolation method is 'cgrid_velocity'
+    pid_orig :
+        Optional list of (offsets for) the particle IDs
+    partitions :
+        List of cores on which to distribute the particles for MPI runs. Default: None, in which case particles
+        are distributed automatically on the processors
+    periodic_domain_zonal :
+        Zonal domain size, used to apply zonally periodic boundaries for particle-particle
+        interaction. If None, no zonally periodic boundaries are applied
+
+        Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
     """
 
     def __init__(self, fieldset=None, pclass=JITParticle, lon=None, lat=None,
@@ -250,31 +261,52 @@ def __del__(self):
     def _set_particle_vector(self, name, value):
         """Set attributes of all particles to new values.
 
-        :param name: Name of the attribute (str).
-        :param value: New value to set the attribute of the particles to.
+        Parameters
+        ----------
+        name : str
+            Name of the attribute (str).
+        value : any
+            New value to set the attribute of the particles to.
         """
         self.collection._data[name][:] = value
 
     def _impute_release_times(self, default):
         """Set attribute 'time' to default if encountering NaN values.
 
-        :param default: Default release time.
-        :return: Minimum and maximum release times.
+        Parameters
+        ----------
+        default :
+            Default release time.
+
+        Returns
+        -------
+        type
+            Minimum and maximum release times.
+
         """
         if np.any(np.isnan(self._collection.data['time'])):
             self._collection.data['time'][np.isnan(self._collection.data['time'])] = default
         return np.min(self._collection.data['time']), np.max(self._collection.data['time'])
 
     def data_indices(self, variable_name, compare_values, invert=False):
-        """Get the indices of all particles where the value of
-        `variable_name` equals (one of) `compare_values`.
-
-        :param variable_name: Name of the variable to check.
-        :param compare_values: Value or list of values to compare to.
-        :param invert: Whether to invert the selection. I.e., when True,
-                       return all indices that do not equal (one of)
-                       `compare_values`.
-        :return: Numpy array of indices that satisfy the test.
+        """Get the indices of all particles where the value of `variable_name` equals (one of) `compare_values`.
+
+        Parameters
+        ----------
+        variable_name : str
+            Name of the variable to check.
+        compare_values :
+            Value or list of values to compare to.
+        invert :
+            Whether to invert the selection. I.e., when True,
+            return all indices that do not equal (one of)
+            `compare_values`. (Default value = False)
+
+        Returns
+        -------
+        np.ndarray
+            Numpy array of indices that satisfy the test.
+
         """
         compare_values = np.array([compare_values, ]) if type(compare_values) not in [list, dict, np.ndarray] else compare_values
         return np.where(np.isin(self._collection.data[variable_name], compare_values, invert=invert))[0]
@@ -288,7 +320,6 @@ def populate_indices(self):
         This is only intended for curvilinear grids, where the initial index search
         may be quite expensive.
         """
-
         if self.fieldset is None:
             # we need to be attached to a fieldset to have a valid
             # gridset to search for indices
@@ -316,7 +347,10 @@ def populate_indices(self):
     def error_particles(self):
         """Get an iterator over all particles that are in an error state.
 
-        :return: Collection iterator over error particles.
+        Returns
+        -------
+        iterator
+            Collection iterator over error particles.
         """
         error_indices = self.data_indices('state', [StateCode.Success, StateCode.Evaluate], invert=True)
         return ParticleCollectionIterableSOA(self._collection, subset=error_indices)
@@ -332,19 +366,21 @@ def active_particles_mask(self, time, dt):
     def num_error_particles(self):
         """Get the number of particles that are in an error state.
 
-        :return: The number of error particles.
+        Returns
+        -------
+        int
+            Number of error particles.
         """
         return np.sum(np.isin(
             self._collection.data['state'],
             [StateCode.Success, StateCode.Evaluate], invert=True))
 
     def __getitem__(self, index):
-        """Get a single particle by index"""
+        """Get a single particle by index."""
         return self._collection.get_single_by_index(index)
 
     def cstruct(self):
-        """
-        'cstruct' returns the ctypes mapping of the combined collections cstruct and the fieldset cstruct.
+        """'cstruct' returns the ctypes mapping of the combined collections cstruct and the fieldset cstruct.
         This depends on the specific structure in question.
         """
         cstruct = self._collection.cstruct()
@@ -356,12 +392,24 @@ def ctypes_struct(self):
 
     @classmethod
     def monte_carlo_sample(cls, start_field, size, mode='monte_carlo'):
-        """
-        Converts a starting field into a monte-carlo sample of lons and lats.
+        """Converts a starting field into a monte-carlo sample of lons and lats.
+
+        Parameters
+        ----------
+        start_field :
+            mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
+        size :
 
-        :param start_field: :mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally)  according to the presented density field.
+        mode :
+             (Default value = 'monte_carlo')
 
-        returns list(lon), list(lat)
+
+        Returns
+        -------
+        list of float
+            A list of longitude values.
+        list of float
+            A list of latitude values.
         """
         if mode == 'monte_carlo':
             data = start_field.data if isinstance(start_field.data, np.ndarray) else np.array(start_field.data)
@@ -407,21 +455,30 @@ def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime
         This creates a new ParticleSet based on locations of all particles written
         in a zarr ParticleFile at a certain time. Particle IDs are preserved if restart=True
 
-        :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
-        :param pclass: mod:`parcels.particle.JITParticle` or :mod:`parcels.particle.ScipyParticle`
-                 object that defines custom particle
-        :param filename: Name of the particlefile from which to read initial conditions
-        :param restart: Boolean to signal if pset is used for a restart (default is True).
-               In that case, Particle IDs are preserved.
-        :param restarttime: time at which the Particles will be restarted. Default is the last time written.
-               Alternatively, restarttime could be a time value (including np.datetime64) or
-               a callable function such as np.nanmin. The last is useful when running with dt < 0.
-        :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
-        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
-               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
-               and np.float64 if the interpolation method is 'cgrid_velocity'
+        Parameters
+        ----------
+        fieldset : parcels.fieldset.FieldSet
+            mod:`parcels.fieldset.FieldSet` object from which to sample velocity
+        pclass : parcels.particle.JITParticle or parcels.particle.ScipyParticle
+            Particle class. May be a particle class as defined in parcels, or a subclass defining a custom particle.
+        filename : str
+            Name of the particlefile from which to read initial conditions
+        restart : bool
+            BSignal if pset is used for a restart (default is True).
+            In that case, Particle IDs are preserved.
+        restarttime :
+            time at which the Particles will be restarted. Default is the last time written.
+            Alternatively, restarttime could be a time value (including np.datetime64) or
+            a callable function such as np.nanmin. The last is useful when running with dt < 0.
+        repeatdt : datetime.timedelta or float, optional
+            Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
+        lonlatdepth_dtype :
+            Floating precision for lon, lat, depth particle coordinates.
+            It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+            and np.float64 if the interpolation method is 'cgrid_velocity'
+        **kwargs :
+            Keyword arguments passed to the particleset constructor.
         """
-
         if repeatdt is not None:
             logger.warning(f'Note that the `repeatdt` argument is not retained from {filename}, and that '
                            'setting a new repeatdt will start particles from the _new_ particle '
@@ -515,13 +572,21 @@ def __sizeof__(self):
         return sys.getsizeof(self._collection)
 
     def __iadd__(self, particles):
-        """Add particles to the ParticleSet. Note that this is an
-        incremental add, the particles will be added to the ParticleSet
+        """Add particles to the ParticleSet.
+
+        Note that this is an incremental add, the particles will be added to the ParticleSet
         on which this function is called.
 
-        :param particles: Another ParticleSet containing particles to add
-                          to this one.
-        :return: The current ParticleSet
+        Parameters
+        ----------
+        particles :
+            Another ParticleSet containing particles to add
+            to this one.
+
+        Returns
+        -------
+        type
+            The current ParticleSet
         """
         self.add(particles)
         return self
@@ -537,8 +602,16 @@ def add(self, particles):
         incremental add, the particles will be added to the ParticleSet
         on which this function is called.
 
-        :param particles: Another ParticleSet containing particles to add to this one.
-        :return: The current ParticleSet
+        Parameters
+        ----------
+        particles :
+            Another ParticleSet containing particles to add to this one.
+
+        Returns
+        -------
+        type
+            The current ParticleSet
+
         """
         if isinstance(particles, BaseParticleSet):
             particles = particles.collection
@@ -548,7 +621,7 @@ def add(self, particles):
         return self
 
     def remove_indices(self, indices):
-        """Method to remove particles from the ParticleSet, based on their `indices`"""
+        """Method to remove particles from the ParticleSet, based on their `indices`."""
         # Removing particles invalidates the neighbor search structure.
         self._dirty_neighbor = True
         if type(indices) in [int, np.int32, np.intp]:
@@ -557,26 +630,30 @@ def remove_indices(self, indices):
             self._collection.remove_multi_by_indices(indices)
 
     def remove_booleanvector(self, indices):
-        """Method to remove particles from the ParticleSet, based on an array of booleans"""
+        """Method to remove particles from the ParticleSet, based on an array of booleans."""
         # Removing particles invalidates the neighbor search structure.
         self._dirty_neighbor = True
         self.remove_indices(np.where(indices)[0])
 
     def density(self, field_name=None, particle_val=None, relative=False, area_scale=False):
-        """Method to calculate the density of particles in a ParticleSet from their locations,
-        through a 2D histogram.
-
-        :param field: Optional :mod:`parcels.field.Field` object to calculate the histogram
-                      on. Default is `fieldset.U`
-        :param particle_val: Optional numpy-array of values to weigh each particle with,
-                             or string name of particle variable to use weigh particles with.
-                             Default is None, resulting in a value of 1 for each particle
-        :param relative: Boolean to control whether the density is scaled by the total
-                         weight of all particles. Default is False
-        :param area_scale: Boolean to control whether the density is scaled by the area
-                           (in m^2) of each grid cell. Default is False
+        """Calculate 2D particle density field from ParticleSet particle locations.
+
+        Parameters
+        ----------
+        field_name : str, optional
+            Name of the field from the fieldset to calculate the histogram on.
+            Defaults to using "U".
+        particle_val :
+            Optional numpy-array of values to weigh each particle with,
+            or string name of particle variable to use weigh particles with.
+            Default is None, resulting in a value of 1 for each particle
+        relative : bool
+            Whether the density is scaled by the total weight of all particles.
+            Default is False
+        area_scale : bool
+            Whether the density is scaled by the area (in m^2) of each grid cell.
+            Default is False
         """
-
         field_name = field_name if field_name else "U"
         sampling_name = "UV" if field_name in ["U", "V"] else field_name
         field = getattr(self.fieldset, field_name)
@@ -618,10 +695,18 @@ def density(self, field_name=None, particle_val=None, relative=False, area_scale
         return density
 
     def Kernel(self, pyfunc, c_include="", delete_cfiles=True):
-        """Wrapper method to convert a `pyfunc` into a :class:`parcels.kernel.Kernel` object
-        based on `fieldset` and `ptype` of the ParticleSet
+        """Wrapper method to convert a `pyfunc` into a :class:`parcels.kernel.Kernel` object.
+
+        Conversion is based on `fieldset` and `ptype` of the ParticleSet.
 
-        :param delete_cfiles: Boolean whether to delete the C-files after compilation in JIT mode (default is True)
+        Parameters
+        ----------
+        delete_cfiles : bool
+            Whether to delete the C-files after compilation in JIT mode (default is True)
+        pyfunc :
+
+        c_include :
+             (Default value = "")
         """
         return Kernel(self.fieldset, self.collection.ptype, pyfunc=pyfunc, c_include=c_include,
                       delete_cfiles=delete_cfiles)
@@ -632,14 +717,17 @@ def InteractionKernel(self, pyfunc_inter):
         return InteractionKernelSOA(self.fieldset, self.collection.ptype, pyfunc=pyfunc_inter)
 
     def ParticleFile(self, *args, **kwargs):
-        """Wrapper method to initialise a :class:`parcels.particlefile.ParticleFile`
-        object from the ParticleSet"""
+        """Wrapper method to initialise a :class:`parcels.particlefile.ParticleFile` object from the ParticleSet."""
         return ParticleFile(*args, particleset=self, **kwargs)
 
     def set_variable_write_status(self, var, write_status):
-        """
-        Method to set the write status of a Variable
-        :param var: Name of the variable (string)
-        :param write_status: Write status of the variable (True, False or 'once')
+        """Method to set the write status of a Variable.
+
+        Parameters
+        ----------
+        var :
+            Name of the variable (string)
+        write_status :
+            Write status of the variable (True, False or 'once')
         """
         self._collection.set_variable_write_status(var, write_status)
diff --git a/parcels/plotting.py b/parcels/plotting.py
index fe51ad279..3fba20c2a 100644
--- a/parcels/plotting.py
+++ b/parcels/plotting.py
@@ -13,20 +13,35 @@
 def plotparticles(particles, with_particles=True, show_time=None, field=None, domain=None,
                   projection='PlateCarree', land=True, vmin=None, vmax=None, savefile=None,
                   animation=False, **kwargs):
-    """Function to plot a Parcels ParticleSet
-
-    :param show_time: Time in seconds from start after which to show the ParticleSet
-    :param with_particles: Boolean whether particles are also plotted on Field
-    :param field: Field to plot under particles (either None, a Field object, or 'vector')
-    :param domain: dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show
-    :param projection: type of cartopy projection to use (default PlateCarree)
-    :param land: Boolean whether to show land. This is ignored for flat meshes
-    :param vmin: minimum colour scale (only in single-plot mode)
-    :param vmax: maximum colour scale (only in single-plot mode)
-    :param savefile: Name of a file to save the plot to
-    :param animation: Boolean whether result is a single plot, or an animation
+    """Function to plot a Parcels ParticleSet.
+
+    Parameters
+    ----------
+    show_time :
+        Time in seconds from start after which to show the ParticleSet (Default value = None)
+    with_particles : bool
+        Whether particles are also plotted on Field (Default value = True)
+    field : parcels.Field or str, optional
+        Field to plot under particles (either None, a Field object, or 'vector') (Default value = None)
+    domain :
+        dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show (Default value = None)
+    projection :
+        type of cartopy projection to use (default PlateCarree)
+    land : bool
+        Whether to show land. This is ignored for flat meshes (Default value = True)
+    vmin : float
+        minimum colour scale (only in single-plot mode) (Default value = None)
+    vmax : float
+        maximum colour scale (only in single-plot mode) (Default value = None)
+    savefile :
+        Name of a file to save the plot to (Default value = None)
+    animation : bool
+        Whether result is a single plot, or an animation (Default value = False)
+    particles :
+
+    **kwargs :
+        Keyword arguments passed to the :func:`plotfield` function.
     """
-
     show_time = particles[0].time if show_time is None else show_time
     if isinstance(show_time, datetime):
         show_time = np.datetime64(show_time)
@@ -100,19 +115,33 @@ def plotparticles(particles, with_particles=True, show_time=None, field=None, do
 
 def plotfield(field, show_time=None, domain=None, depth_level=0, projection='PlateCarree', land=True,
               vmin=None, vmax=None, savefile=None, **kwargs):
-    """Function to plot a Parcels Field
-
-    :param show_time: Time in seconds from start after which to show the Field
-    :param domain: dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show
-    :param depth_level: depth level to be plotted (default 0)
-    :param projection: type of cartopy projection to use (default PlateCarree)
-    :param land: Boolean whether to show land. This is ignored for flat meshes
-    :param vmin: minimum colour scale (only in single-plot mode)
-    :param vmax: maximum colour scale (only in single-plot mode)
-    :param savefile: Name of a file to save the plot to
-    :param animation: Boolean whether result is a single plot, or an animation
+    """Function to plot a Parcels Field.
+
+    Parameters
+    ----------
+    field : parcels.field.Field
+        Field to plot
+    show_time : float
+        Time in seconds from start after which to show the Field (Default value = None)
+    domain :
+        dictionary (with keys 'N', 'S', 'E', 'W') defining domain to show (Default value = None)
+    depth_level :
+        depth level to be plotted (default 0)
+    projection :
+        type of cartopy projection to use (default PlateCarree)
+    land : bool
+        Whether to show land. This is ignored for flat meshes (Default value = True)
+    vmin : float, optional
+        minimum colour scale (only in single-plot mode) (Default value = None)
+    vmax : float, optional
+        maximum colour scale (only in single-plot mode) (Default value = None)
+    savefile : str, optional
+        Name of a file to save the plot to (Default value = None)
+    animation : bool
+        Whether result is a single plot, or an animation
+    **kwargs :
+        Provide "titlestr" as the title of the plot, or "cartopy_features" to be used in :func:`create_parcelsfig_axis`.
     """
-
     if type(field) is VectorField:
         spherical = True if field.U.grid.mesh == 'spherical' else False
         field = [field.U, field.V]
diff --git a/parcels/rng.py b/parcels/rng.py
index 0f6585dca..b77405605 100644
--- a/parcels/rng.py
+++ b/parcels/rng.py
@@ -133,13 +133,13 @@ def _assign_parcels_random_ccodeconverter():
 
 
 def seed(seed):
-    """Sets the seed for parcels internal RNG"""
+    """Sets the seed for parcels internal RNG."""
     _assign_parcels_random_ccodeconverter()
     _parcels_random_ccodeconverter.lib.pcls_seed(c_int(seed))
 
 
 def random():
-    """Returns a random float between 0. and 1."""
+    """Returns a random float between 0.0 and 1.0."""
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_random
     rnd.argtype = []
@@ -148,7 +148,7 @@ def random():
 
 
 def uniform(low, high):
-    """Returns a random float between `low` and `high`"""
+    """Returns a random float between `low` and `high`."""
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_uniform
     rnd.argtype = [c_float, c_float]
@@ -157,7 +157,7 @@ def uniform(low, high):
 
 
 def randint(low, high):
-    """Returns a random int between `low` and `high`"""
+    """Returns a random int between `low` and `high`."""
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_randint
     rnd.argtype = [c_int, c_int]
@@ -166,7 +166,7 @@ def randint(low, high):
 
 
 def normalvariate(loc, scale):
-    """Returns a random float on normal distribution with mean `loc` and width `scale`"""
+    """Returns a random float on normal distribution with mean `loc` and width `scale`."""
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_normalvariate
     rnd.argtype = [c_float, c_float]
@@ -175,7 +175,7 @@ def normalvariate(loc, scale):
 
 
 def expovariate(lamb):
-    """Returns a randome float of an exponential distribution with parameter lamb"""
+    """Returns a randome float of an exponential distribution with parameter lamb."""
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_expovariate
     rnd.argtype = c_float
@@ -185,7 +185,8 @@ def expovariate(lamb):
 
 def vonmisesvariate(mu, kappa):
     """Returns a randome float of a Von Mises distribution
-    with mean angle mu and concentration parameter kappa"""
+    with mean angle mu and concentration parameter kappa.
+    """
     _assign_parcels_random_ccodeconverter()
     rnd = _parcels_random_ccodeconverter.lib.pcls_vonmisesvariate
     rnd.argtype = [c_float, c_float]
diff --git a/parcels/scripts/plottrajectoriesfile.py b/parcels/scripts/plottrajectoriesfile.py
index 0a1fa76d8..f79235721 100644
--- a/parcels/scripts/plottrajectoriesfile.py
+++ b/parcels/scripts/plottrajectoriesfile.py
@@ -17,24 +17,36 @@
 def plotTrajectoriesFile(filename, mode='2d', tracerfile=None, tracerfield='P',
                          tracerlon='x', tracerlat='y', recordedvar=None, movie_forward=True,
                          bins=20, show_plt=True, central_longitude=0):
-    """Quick and simple plotting of Parcels trajectories
-
-    :param filename: Name of Parcels-generated NetCDF file with particle positions
-    :param mode: Type of plot to show. Supported are '2d', '3d', 'hist2d',
-                'movie2d' and 'movie2d_notebook'. The latter two give animations,
-                with 'movie2d_notebook' specifically designed for jupyter notebooks
-    :param tracerfile: Name of NetCDF file to show as background
-    :param tracerfield: Name of variable to show as background
-    :param tracerlon: Name of longitude dimension of variable to show as background
-    :param tracerlat: Name of latitude dimension of variable to show as background
-    :param recordedvar: Name of variable used to color particles in scatter-plot.
-                Only works in 'movie2d' or 'movie2d_notebook' mode.
-    :param movie_forward: Boolean whether to show movie in forward or backward mode (default True)
-    :param bins: Number of bins to use in `hist2d` mode. See also https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist2d.html
-    :param show_plt: Boolean whether plot should directly be show (for py.test)
-    :param central_longitude: Degrees East at which to center the plot
+    """Quick and simple plotting of Parcels trajectories.
+
+    Parameters
+    ----------
+    filename : str
+        Name of Parcels-generated NetCDF file with particle positions
+    mode :
+        Type of plot to show. Supported are '2d', '3d', 'hist2d',
+        'movie2d' and 'movie2d_notebook'. The latter two give animations,
+        with 'movie2d_notebook' specifically designed for jupyter notebooks (Default value = '2d')
+    tracerfile :
+        Name of NetCDF file to show as background (Default value = None)
+    tracerfield :
+        Name of variable to show as background (Default value = 'P')
+    tracerlon :
+        Name of longitude dimension of variable to show as background (Default value = 'x')
+    tracerlat :
+        Name of latitude dimension of variable to show as background (Default value = 'y')
+    recordedvar :
+        Name of variable used to color particles in scatter-plot.
+        Only works in 'movie2d' or 'movie2d_notebook' mode. (Default value = None)
+    movie_forward : bool
+        Whether to show movie in forward or backward mode (default True)
+    bins :
+        Number of bins to use in `hist2d` mode. See also https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist2d.html (Default value = 20)
+    show_plt : bool
+        Whether plot should directly be shown (for py.test) (Default value = True)
+    central_longitude :
+        Degrees East at which to center the plot (Default value = 0)
     """
-
     environ["HDF5_USE_FILE_LOCKING"] = "FALSE"
     try:
         pfile = xr.open_zarr(str(filename), decode_cf=True)
diff --git a/parcels/tools/converters.py b/parcels/tools/converters.py
index c23b1b679..b9cee1581 100644
--- a/parcels/tools/converters.py
+++ b/parcels/tools/converters.py
@@ -15,7 +15,10 @@
 def convert_to_flat_array(var):
     """Convert lists and single integers/floats to one-dimensional numpy arrays
 
-    :param var: list or numeric to convert to a one-dimensional numpy array
+    Parameters
+    ----------
+    var : np.ndarray, float or array_like
+        list or numeric to convert to a one-dimensional numpy array
     """
     if isinstance(var, np.ndarray):
         return var.flatten()
@@ -37,10 +40,12 @@ def _get_cftime_calendars():
 
 
 class TimeConverter:
-    """ Converter class for dates with different calendars in FieldSets
+    """Converter class for dates with different calendars in FieldSets
 
-    :param: time_origin: time origin of the class. Currently supported formats are
-            float, integer, numpy.datetime64, and netcdftime.DatetimeNoLeap
+    Parameters
+    ----------
+    time_origin : float, integer, numpy.datetime64 or netcdftime.DatetimeNoLeap
+        time origin of the class.
     """
 
     def __init__(self, time_origin=0):
@@ -58,8 +63,16 @@ def reltime(self, time):
         """Method to compute the difference, in seconds, between a time and the time_origin
         of the TimeConverter
 
-        :param: time: input time
-        :return: time - self.time_origin
+        Parameters
+        ----------
+        time :
+
+
+        Returns
+        -------
+        type
+            time - self.time_origin
+
         """
         time = time.time_origin if isinstance(time, TimeConverter) else time
         if self.calendar in ['np_datetime64', 'np_timedelta64']:
@@ -85,8 +98,16 @@ def reltime(self, time):
     def fulltime(self, time):
         """Method to convert a time difference in seconds to a date, based on the time_origin
 
-        :param: time: input time
-        :return: self.time_origin + time
+        Parameters
+        ----------
+        time :
+
+
+        Returns
+        -------
+        type
+            self.time_origin + time
+
         """
         time = time.time_origin if isinstance(time, TimeConverter) else time
         if self.calendar in ['np_datetime64', 'np_timedelta64']:
@@ -132,9 +153,8 @@ def __le__(self, other):
 
 
 class UnitConverter:
-    """ Interface class for spatial unit conversion during field sampling
-        that performs no conversion.
-    """
+    """Interface class for spatial unit conversion during field sampling that performs no conversion."""
+
     source_unit = None
     target_unit = None
 
@@ -152,7 +172,8 @@ def ccode_to_source(self, x, y, z):
 
 
 class Geographic(UnitConverter):
-    """ Unit converter from geometric to geographic coordinates (m to degree) """
+    """Unit converter from geometric to geographic coordinates (m to degree)"""
+
     source_unit = 'm'
     target_unit = 'degree'
 
@@ -170,9 +191,10 @@ def ccode_to_source(self, x, y, z):
 
 
 class GeographicPolar(UnitConverter):
-    """ Unit converter from geometric to geographic coordinates (m to degree)
-        with a correction to account for narrower grid cells closer to the poles.
+    """Unit converter from geometric to geographic coordinates (m to degree)
+    with a correction to account for narrower grid cells closer to the poles.
     """
+
     source_unit = 'm'
     target_unit = 'degree'
 
@@ -190,7 +212,8 @@ def ccode_to_source(self, x, y, z):
 
 
 class GeographicSquare(UnitConverter):
-    """ Square distance converter from geometric to geographic coordinates (m2 to degree2) """
+    """Square distance converter from geometric to geographic coordinates (m2 to degree2)"""
+
     source_unit = 'm2'
     target_unit = 'degree2'
 
@@ -208,9 +231,10 @@ def ccode_to_source(self, x, y, z):
 
 
 class GeographicPolarSquare(UnitConverter):
-    """ Square distance converter from geometric to geographic coordinates (m2 to degree2)
-        with a correction to account for narrower grid cells closer to the poles.
+    """Square distance converter from geometric to geographic coordinates (m2 to degree2)
+    with a correction to account for narrower grid cells closer to the poles.
     """
+
     source_unit = 'm2'
     target_unit = 'degree2'
 
@@ -233,8 +257,7 @@ def ccode_to_source(self, x, y, z):
 
 
 def convert_xarray_time_units(ds, time):
-    """ Fixes DataArrays that have time.Unit instead of expected time.units
-    """
+    """Fixes DataArrays that have time.Unit instead of expected time.units"""
     da = ds[time] if isinstance(ds, xr.Dataset) else ds
     if 'units' not in da.attrs and 'Unit' in da.attrs:
         da.attrs['units'] = da.attrs['Unit']
diff --git a/parcels/tools/loggers.py b/parcels/tools/loggers.py
index c15b180e5..04bd233b2 100644
--- a/parcels/tools/loggers.py
+++ b/parcels/tools/loggers.py
@@ -1,4 +1,4 @@
-"""Script to create a `logger` for Parcels"""
+"""Script to create a `logger` for Parcels."""
 import logging
 
 __all__ = ['logger', 'XarrayDecodedFilter']
@@ -8,8 +8,8 @@
 
 
 class DuplicateFilter:
-    """Utility class to prevent warning_once warnings from being
-    displayed more than once"""
+    """Utility class to prevent warning_once warnings from being displayed more than once."""
+
     def __init__(self):
         self.msgs = set()
 
@@ -21,13 +21,13 @@ def filter(self, record):
 
 
 def warning_once(self, message, *args, **kws):
-    """Custom logging level for warnings that need to be displayed only once"""
+    """Custom logging level for warnings that need to be displayed only once."""
     if self.isEnabledFor(warning_once_level):
         self._log(warning_once_level, message, args, **kws)
 
 
 def info_once(self, message, *args, **kws):
-    """Custom logging level for info that need to be displayed only once"""
+    """Custom logging level for info that need to be displayed only once."""
     if self.isEnabledFor(info_once_level):
         self._log(info_once_level, message, args, **kws)
 
@@ -49,6 +49,7 @@ def info_once(self, message, *args, **kws):
 
 
 class XarrayDecodedFilter(logging.Filter):
-    """Filters the warning_once from fieldfilebuffer when cf_decoding fails"""
+    """Filters the warning_once from fieldfilebuffer when cf_decoding fails."""
+
     def filter(self, record):
         return 'Filling values might be wrongly parsed' not in record.getMessage()
diff --git a/parcels/tools/statuscodes.py b/parcels/tools/statuscodes.py
index 4c366cadb..5e07d6028 100644
--- a/parcels/tools/statuscodes.py
+++ b/parcels/tools/statuscodes.py
@@ -1,4 +1,4 @@
-"""Collection of pre-built recovery kernels"""
+"""Collection of pre-built recovery kernels."""
 
 
 __all__ = ['StateCode', 'OperationCode', 'ErrorCode',
@@ -27,9 +27,7 @@ class ErrorCode:
 
 
 class DaskChunkingError(RuntimeError):
-    """
-    Error indicating to the user that something with setting up Dask and chunked fieldsets went wrong.
-    """
+    """Error indicating to the user that something with setting up Dask and chunked fieldsets went wrong."""
 
     def __init__(self, src_class_type, message):
         msg = f"[{str(src_class_type)}]: {message}"
@@ -37,7 +35,7 @@ def __init__(self, src_class_type, message):
 
 
 class FieldSamplingError(RuntimeError):
-    """Utility error class to propagate erroneous field sampling in Scipy mode"""
+    """Utility error class to propagate erroneous field sampling in Scipy mode."""
 
     def __init__(self, x, y, z, field=None):
         self.field = field
@@ -49,7 +47,7 @@ def __init__(self, x, y, z, field=None):
 
 
 class FieldOutOfBoundError(RuntimeError):
-    """Utility error class to propagate out-of-bound field sampling in Scipy mode"""
+    """Utility error class to propagate out-of-bound field sampling in Scipy mode."""
 
     def __init__(self, x, y, z, field=None):
         self.field = field
@@ -62,7 +60,9 @@ def __init__(self, x, y, z, field=None):
 
 class FieldOutOfBoundSurfaceError(RuntimeError):
     """Utility error class to propagate out-of-bound field sampling at the surface in Scipy mode.
-       Note that if ErrorThroughSurface is not part of the recovery kernel, Parcels will use ErrorOutOfBounds."""
+
+    Note that if ErrorThroughSurface is not part of the recovery kernel, Parcels will use ErrorOutOfBounds.
+    """
 
     def __init__(self, x, y, z, field=None):
         self.field = field
@@ -74,7 +74,7 @@ def __init__(self, x, y, z, field=None):
 
 
 class TimeExtrapolationError(RuntimeError):
-    """Utility error class to propagate erroneous time extrapolation sampling in Scipy mode"""
+    """Utility error class to propagate erroneous time extrapolation sampling in Scipy mode."""
 
     def __init__(self, time, field=None, msg='allow_time_extrapoltion'):
         if field is not None and field.grid.time_origin and time is not None:
@@ -90,7 +90,7 @@ def __init__(self, time, field=None, msg='allow_time_extrapoltion'):
 
 
 class KernelError(RuntimeError):
-    """General particle kernel error with optional custom message"""
+    """General particle kernel error with optional custom message."""
 
     def __init__(self, particle, fieldset=None, msg=None):
         message = (f"{particle.state}\n"
@@ -103,7 +103,8 @@ def __init__(self, particle, fieldset=None, msg=None):
 
 
 class NotTestedError(Exception):
-    "Raised when the function is not tested. Code is commented"
+    """Raised when the function is not tested. Code is commented."""
+
     def __init__(self):
         super().__init__("Method has not been tested. Code has been commented out until unit tests are available.")
 
@@ -115,13 +116,13 @@ def parse_particletime(time, fieldset):
 
 
 def recovery_kernel_error(particle, fieldset, time):
-    """Default error kernel that throws exception"""
+    """Default error kernel that throws exception."""
     msg = f"Error: {particle.exception if particle.exception else None}"
     raise KernelError(particle, fieldset=fieldset, msg=msg)
 
 
 class InterpolationError(KernelError):
-    """Particle kernel error for interpolation error"""
+    """Particle kernel error for interpolation error."""
 
     def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
         if lon and lat:
@@ -132,7 +133,7 @@ def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
 
 
 class OutOfBoundsError(KernelError):
-    """Particle kernel error for out-of-bounds field sampling"""
+    """Particle kernel error for out-of-bounds field sampling."""
 
     def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
         if lon and lat:
@@ -143,7 +144,7 @@ def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
 
 
 class ThroughSurfaceError(KernelError):
-    """Particle kernel error for field sampling at surface"""
+    """Particle kernel error for field sampling at surface."""
 
     def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
         if lon and lat:
@@ -154,7 +155,7 @@ def __init__(self, particle, fieldset=None, lon=None, lat=None, depth=None):
 
 
 class OutOfTimeError(KernelError):
-    """Particle kernel error for time extrapolation field sampling"""
+    """Particle kernel error for time extrapolation field sampling."""
 
     def __init__(self, particle, fieldset):
         message = (f"Field sampled outside time domain at time {parse_particletime(particle.time, fieldset)}."
@@ -163,7 +164,7 @@ def __init__(self, particle, fieldset):
 
 
 def recovery_kernel_interpolation(particle, fieldset, time):
-    """Default sampling error kernel that throws InterpolationError"""
+    """Default sampling error kernel that throws InterpolationError."""
     if particle.exception is None:
         # TODO: JIT does not yet provide the context that created
         # the exception. We need to pass that info back from C.
@@ -174,7 +175,7 @@ def recovery_kernel_interpolation(particle, fieldset, time):
 
 
 def recovery_kernel_out_of_bounds(particle, fieldset, time):
-    """Default sampling error kernel that throws OutOfBoundsError"""
+    """Default sampling error kernel that throws OutOfBoundsError."""
     if particle.exception is None:
         # TODO: JIT does not yet provide the context that created
         # the exception. We need to pass that info back from C.
@@ -185,7 +186,7 @@ def recovery_kernel_out_of_bounds(particle, fieldset, time):
 
 
 def recovery_kernel_through_surface(particle, fieldset, time):
-    """Default sampling error kernel that throws OutOfBoundsError"""
+    """Default sampling error kernel that throws OutOfBoundsError."""
     if particle.exception is None:
         # TODO: JIT does not yet provide the context that created
         # the exception. We need to pass that info back from C.
@@ -196,7 +197,7 @@ def recovery_kernel_through_surface(particle, fieldset, time):
 
 
 def recovery_kernel_time_extrapolation(particle, fieldset, time):
-    """Default sampling error kernel that throws OutOfTimeError"""
+    """Default sampling error kernel that throws OutOfTimeError."""
     raise OutOfTimeError(particle, fieldset)
 
 
diff --git a/setup.cfg b/setup.cfg
index e180298eb..3c6c9a449 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -18,11 +18,50 @@ classifiers =
     Operating System :: OS Independent
 
 [flake8]
-ignore = E501,F403,E226,E722,W503
+ignore =
+    # missing whitespace around arithmetic operator
+    E226,
+    # do not use bare except, specify exception instead
+    E722,
+    # line break before binary operator
+    W503
+    # line too long (82 > 79 characters)
+    E501,
+    # ‘from module import *’ used; unable to detect undefined names
+    F403,
+
+[pydocstyle]
+ignore =
+    # Numpy docstring format http://www.pydocstyle.org/en/latest/error_codes.html#default-conventions
+    D107, D203, D212, D213, D402, D413, D415, D416, D417,
+
+    # TODO: once vvv is fixed, replace `ignore = ` section with `convention = numpy`
+    # IGNORE FOR NOW (requires more work)
+    # Missing docstring in public module
+    D100,
+    # Missing docstring in public class
+    D101,
+    # Missing docstring in public method
+    D102,
+    # Missing docstring in public function
+    D103,
+    # Missing docstring in public package
+    D104,
+    # Missing docstring in magic method
+    D105,
+    # Missing docstring in __init__
+    D400,
+    # First line should be in imperative mood (requires writing of summaries)
+    D401,
+    # First word of the docstring should not be `This`
+    D404,
+    # 1 blank line required between summary line and description (requires writing of summaries)
+    D205
 
 [tool:pytest]
 python_files = test_*.py example_*.py *tutorial*
 
+
 [isort]
 profile = black
 skip_gitignore = True


Test patch:
diff --git a/tests/test_advection.py b/tests/test_advection.py
index b73fbe578..35802b7e4 100644
--- a/tests/test_advection.py
+++ b/tests/test_advection.py
@@ -73,9 +73,7 @@ def depth_fixture(zdim=2):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_advection_zonal(lon, lat, depth, pset_mode, mode, npart=10):
-    """ Particles at high latitude move geographically faster due to
-        the pole correction in `GeographicPolar`.
-    """
+    """Particles at high latitude move geographically faster due to the pole correction in `GeographicPolar`."""
     data2D = {'U': np.ones((lon.size, lat.size), dtype=np.float32),
               'V': np.zeros((lon.size, lat.size), dtype=np.float32)}
     data3D = {'U': np.ones((lon.size, lat.size, depth.size), dtype=np.float32),
@@ -103,9 +101,7 @@ def test_advection_zonal(lon, lat, depth, pset_mode, mode, npart=10):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_advection_meridional(lon, lat, pset_mode, mode, npart=10):
-    """ Particles at high latitude move geographically faster due to
-        the pole correction in `GeographicPolar`.
-    """
+    """Particles at high latitude move geographically faster due to the pole correction in `GeographicPolar`."""
     data = {'U': np.zeros((lon.size, lat.size), dtype=np.float32),
             'V': np.ones((lon.size, lat.size), dtype=np.float32)}
     dimensions = {'lon': lon, 'lat': lat}
@@ -122,8 +118,7 @@ def test_advection_meridional(lon, lat, pset_mode, mode, npart=10):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['jit', 'scipy'])
 def test_advection_3D(pset_mode, mode, npart=11):
-    """ 'Flat' 2D zonal flow that increases linearly with depth from 0 m/s to 1 m/s
-    """
+    """Flat 2D zonal flow that increases linearly with depth from 0 m/s to 1 m/s."""
     xdim = ydim = zdim = 2
     dimensions = {'lon': np.linspace(0., 1e4, xdim, dtype=np.float32),
                   'lat': np.linspace(0., 1e4, ydim, dtype=np.float32),
diff --git a/tests/test_data/create_testfields.py b/tests/test_data/create_testfields.py
index 91896cbe4..f52c8d773 100644
--- a/tests/test_data/create_testfields.py
+++ b/tests/test_data/create_testfields.py
@@ -73,8 +73,15 @@ def generate_perlin_testfield():
 def write_simple_2Dt(field, filename, varname=None):
     """Write a :class:`Field` to a netcdf file
 
-    :param filename: Basename of the file
-    :param varname: Name of the field, to be appended to the filename"""
+    Parameters
+    ----------
+    field : parcels.field.Field
+        Field to write to file
+    filename : str
+        Base name of the file to write to
+    varname : str, optional
+        Name of the variable to write to file. If None, defaults to field.name
+    """
     filepath = str(f'{filename}{field.name}.nc')
     if varname is None:
         varname = field.name
diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py
index 907c7172c..ce8ab4536 100644
--- a/tests/test_diffusion.py
+++ b/tests/test_diffusion.py
@@ -30,7 +30,7 @@
 
 
 def zeros_fieldset(mesh='spherical', xdim=200, ydim=100, mesh_conversion=1):
-    """Generates a zero velocity field"""
+    """Generates a zero velocity field."""
     lon = np.linspace(-1e5*mesh_conversion, 1e5*mesh_conversion, xdim, dtype=np.float32)
     lat = np.linspace(-1e5*mesh_conversion, 1e5*mesh_conversion, ydim, dtype=np.float32)
 
@@ -76,8 +76,7 @@ def test_fieldKh_Brownian(mesh, mode, pset_mode, xdim=200, ydim=100, kh_zonal=10
 @pytest.mark.parametrize('kernel', [AdvectionDiffusionM1,
                                     AdvectionDiffusionEM])
 def test_fieldKh_SpatiallyVaryingDiffusion(mesh, mode, pset_mode, kernel, xdim=200, ydim=100):
-    """Test advection-diffusion kernels on a non-uniform diffusivity field
-    with a linear gradient in one direction"""
+    """Test advection-diffusion kernels on a non-uniform diffusivity field with a linear gradient in one direction."""
     mesh_conversion = 1/1852./60 if mesh == 'spherical' else 1
     fieldset = zeros_fieldset(mesh=mesh, xdim=xdim, ydim=ydim, mesh_conversion=mesh_conversion)
 
diff --git a/tests/test_fieldset.py b/tests/test_fieldset.py
index ba99cfb9a..c55c60be5 100644
--- a/tests/test_fieldset.py
+++ b/tests/test_fieldset.py
@@ -66,7 +66,7 @@ def generate_fieldset(xdim, ydim, zdim=1, tdim=1):
 @pytest.mark.parametrize('xdim', [100, 200])
 @pytest.mark.parametrize('ydim', [100, 200])
 def test_fieldset_from_data(xdim, ydim):
-    """ Simple test for fieldset initialisation from data. """
+    """Simple test for fieldset initialisation from data."""
     data, dimensions = generate_fieldset(xdim, ydim)
     fieldset = FieldSet.from_data(data, dimensions)
     assert len(fieldset.U.data.shape) == 3
@@ -76,7 +76,7 @@ def test_fieldset_from_data(xdim, ydim):
 
 
 def test_fieldset_extra_syntax():
-    """ Simple test for fieldset initialisation from data. """
+    """Simple test for fieldset initialisation from data."""
     data, dimensions = generate_fieldset(10, 10)
     failed = False
     try:
@@ -109,9 +109,7 @@ def test_fieldset_from_data_timedims(ttype, tdim):
 @pytest.mark.parametrize('xdim', [100, 200])
 @pytest.mark.parametrize('ydim', [100, 50])
 def test_fieldset_from_data_different_dimensions(xdim, ydim, zdim=4, tdim=2):
-    """ Test for fieldset initialisation from data using
-    dict-of-dict for dimensions. """
-
+    """Test for fieldset initialisation from data using dict-of-dict for dimensions."""
     lon = np.linspace(0., 1., xdim, dtype=np.float32)
     lat = np.linspace(0., 1., ydim, dtype=np.float32)
     depth = np.zeros(zdim, dtype=np.float32)
@@ -137,7 +135,7 @@ def test_fieldset_from_data_different_dimensions(xdim, ydim, zdim=4, tdim=2):
 @pytest.mark.parametrize('xdim', [100, 200])
 @pytest.mark.parametrize('ydim', [100, 200])
 def test_fieldset_from_parcels(xdim, ydim, tmpdir, filename='test_parcels'):
-    """ Simple test for fieldset initialisation from Parcels FieldSet file format. """
+    """Simple test for fieldset initialisation from Parcels FieldSet file format."""
     filepath = tmpdir.join(filename)
     data, dimensions = generate_fieldset(xdim, ydim)
     fieldset_out = FieldSet.from_data(data, dimensions)
@@ -262,7 +260,7 @@ def test_fieldset_float64(cast_data_dtype, mode, tmpdir, xdim=10, ydim=5):
 @pytest.mark.parametrize('indslon', [range(10, 20), [1]])
 @pytest.mark.parametrize('indslat', [range(30, 60), [22]])
 def test_fieldset_from_file_subsets(indslon, indslat, tmpdir, filename='test_subsets'):
-    """ Test for subsetting fieldset from file using indices dict. """
+    """Test for subsetting fieldset from file using indices dict."""
     data, dimensions = generate_fieldset(100, 100)
     filepath = tmpdir.join(filename)
     fieldsetfull = FieldSet.from_data(data, dimensions)
@@ -367,7 +365,7 @@ def test_add_field_after_pset(pset_mode, fieldtype):
 
 @pytest.mark.parametrize('chunksize', ['auto', None])
 def test_fieldset_samegrids_from_file(tmpdir, chunksize, filename='test_subsets'):
-    """ Test for subsetting fieldset from file using indices dict. """
+    """Test for subsetting fieldset from file using indices dict."""
     data, dimensions = generate_fieldset(100, 100)
     filepath1 = tmpdir.join(filename+'_1')
     fieldset1 = FieldSet.from_data(data, dimensions)
@@ -407,7 +405,7 @@ def test_fieldset_dimlength1_cgrid(gridtype):
 
 @pytest.mark.parametrize('chunksize', ['auto', None])
 def test_fieldset_diffgrids_from_file(tmpdir, chunksize, filename='test_subsets'):
-    """ Test for subsetting fieldset from file using indices dict. """
+    """Test for subsetting fieldset from file using indices dict."""
     data, dimensions = generate_fieldset(100, 100)
     filepath1 = tmpdir.join(filename+'_1')
     fieldset1 = FieldSet.from_data(data, dimensions)
@@ -432,7 +430,7 @@ def test_fieldset_diffgrids_from_file(tmpdir, chunksize, filename='test_subsets'
 
 @pytest.mark.parametrize('chunksize', ['auto', None])
 def test_fieldset_diffgrids_from_file_data(tmpdir, chunksize, filename='test_subsets'):
-    """ Test for subsetting fieldset from file using indices dict. """
+    """Test for subsetting fieldset from file using indices dict."""
     data, dimensions = generate_fieldset(100, 100)
     filepath = tmpdir.join(filename)
     fieldset_data = FieldSet.from_data(data, dimensions)
@@ -460,7 +458,7 @@ def test_fieldset_diffgrids_from_file_data(tmpdir, chunksize, filename='test_sub
 
 
 def test_fieldset_samegrids_from_data(tmpdir, filename='test_subsets'):
-    """ Test for subsetting fieldset from file using indices dict. """
+    """Test for subsetting fieldset from file using indices dict."""
     data, dimensions = generate_fieldset(100, 100)
     fieldset1 = FieldSet.from_data(data, dimensions)
     field_data = fieldset1.U
@@ -1020,7 +1018,7 @@ def test_fieldset_frompop(pset_mode, mode):
 
 @pytest.mark.parametrize('pset_mode', pset_modes)
 def test_fieldset_from_data_gridtypes(pset_mode, xdim=20, ydim=10, zdim=4):
-    """ Simple test for fieldset initialisation from data. """
+    """Simple test for fieldset initialisation from data."""
     lon = np.linspace(0., 10., xdim, dtype=np.float32)
     lat = np.linspace(0., 10., ydim, dtype=np.float32)
     depth = np.linspace(0., 1., zdim, dtype=np.float32)
diff --git a/tests/test_fieldset_sampling.py b/tests/test_fieldset_sampling.py
index d44f6aa31..5dd9083c9 100644
--- a/tests/test_fieldset_sampling.py
+++ b/tests/test_fieldset_sampling.py
@@ -71,9 +71,7 @@ def k_sample_P_fixture():
 
 
 def fieldset(xdim=200, ydim=100):
-    """ Standard fieldset spanning the earth's coordinates with U and V
-        equivalent to longitude and latitude in deg.
-    """
+    """Standard fieldset spanning the earth's coordinates with U and V equivalent to longitude and latitude in deg."""
     lon = np.linspace(-180, 180, xdim, dtype=np.float32)
     lat = np.linspace(-90, 90, ydim, dtype=np.float32)
     U, V = np.meshgrid(lat, lon)
@@ -89,7 +87,7 @@ def fieldset_fixture(xdim=200, ydim=100):
 
 
 def fieldset_geometric(xdim=200, ydim=100):
-    """ Standard earth fieldset with U and V equivalent to lon/lat in m. """
+    """Standard earth fieldset with U and V equivalent to lon/lat in m."""
     lon = np.linspace(-180, 180, xdim, dtype=np.float32)
     lat = np.linspace(-90, 90, ydim, dtype=np.float32)
     U, V = np.meshgrid(lat, lon)
@@ -109,8 +107,8 @@ def fieldset_geometric_fixture(xdim=200, ydim=100):
 
 
 def fieldset_geometric_polar(xdim=200, ydim=100):
-    """ Standard earth fieldset with U and V equivalent to lon/lat in m
-        and the inversion of the pole correction applied to U.
+    """Standard earth fieldset with U and V equivalent to lon/lat in m
+    and the inversion of the pole correction applied to U.
     """
     lon = np.linspace(-180, 180, xdim, dtype=np.float32)
     lat = np.linspace(-90, 90, ydim, dtype=np.float32)
@@ -131,7 +129,7 @@ def fieldset_geometric_polar_fixture(xdim=200, ydim=100):
 
 
 def test_fieldset_sample(fieldset, xdim=120, ydim=80):
-    """ Sample the fieldset using indexing notation. """
+    """Sample the fieldset using indexing notation."""
     lon = np.linspace(-170, 170, xdim, dtype=np.float32)
     lat = np.linspace(-80, 80, ydim, dtype=np.float32)
     v_s = np.array([fieldset.UV[0, 0., 70., x][1] for x in lon])
@@ -141,7 +139,7 @@ def test_fieldset_sample(fieldset, xdim=120, ydim=80):
 
 
 def test_fieldset_sample_eval(fieldset, xdim=60, ydim=60):
-    """ Sample the fieldset using the explicit eval function. """
+    """Sample the fieldset using the explicit eval function."""
     lon = np.linspace(-170, 170, xdim, dtype=np.float32)
     lat = np.linspace(-80, 80, ydim, dtype=np.float32)
     v_s = np.array([fieldset.UV.eval(0, 0., 70., x)[1] for x in lon])
@@ -431,13 +429,12 @@ def test_partialslip_nearland_vertical(pset_mode, mode, boundaryslip, npart=20):
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 @pytest.mark.parametrize('lat_flip', [False, True])
 def test_fieldset_sample_particle(pset_mode, mode, k_sample_uv, lat_flip, npart=120):
-    """ Sample the fieldset using an array of particles.
+    """Sample the fieldset using an array of particles.
 
     Note that the low tolerances (1.e-6) are due to the first-order
     interpolation in JIT mode and give an indication of the
     corresponding sampling error.
     """
-
     lon = np.linspace(-180, 180, 200, dtype=np.float32)
     if lat_flip:
         lat = np.linspace(90, -90, 100, dtype=np.float32)
@@ -463,7 +460,7 @@ def test_fieldset_sample_particle(pset_mode, mode, k_sample_uv, lat_flip, npart=
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_fieldset_sample_geographic(fieldset_geometric, pset_mode, mode, k_sample_uv, npart=120):
-    """ Sample a fieldset with conversion to geographic units (degrees). """
+    """Sample a fieldset with conversion to geographic units (degrees)."""
     fieldset = fieldset_geometric
     lon = np.linspace(-170, 170, npart)
     lat = np.linspace(-80, 80, npart)
@@ -480,7 +477,7 @@ def test_fieldset_sample_geographic(fieldset_geometric, pset_mode, mode, k_sampl
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_fieldset_sample_geographic_noconvert(fieldset_geometric, pset_mode, mode, k_sample_uv_noconvert, npart=120):
-    """ Sample a fieldset without conversion to geographic units. """
+    """Sample a fieldset without conversion to geographic units."""
     fieldset = fieldset_geometric
     lon = np.linspace(-170, 170, npart)
     lat = np.linspace(-80, 80, npart)
@@ -497,7 +494,7 @@ def test_fieldset_sample_geographic_noconvert(fieldset_geometric, pset_mode, mod
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_fieldset_sample_geographic_polar(fieldset_geometric_polar, pset_mode, mode, k_sample_uv, npart=120):
-    """ Sample a fieldset with conversion to geographic units and a pole correction. """
+    """Sample a fieldset with conversion to geographic units and a pole correction."""
     fieldset = fieldset_geometric_polar
     lon = np.linspace(-170, 170, npart)
     lat = np.linspace(-80, 80, npart)
@@ -516,11 +513,10 @@ def test_fieldset_sample_geographic_polar(fieldset_geometric_polar, pset_mode, m
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_meridionalflow_spherical(pset_mode, mode, xdim=100, ydim=200):
-    """ Create uniform NORTHWARD flow on spherical earth and advect particles
+    """Create uniform NORTHWARD flow on spherical earth and advect particles.
 
-    As flow is so simple, it can be directly compared to analytical solution
+    As flow is so simple, it can be directly compared to analytical solution.
     """
-
     maxvel = 1.
     dimensions = {'lon': np.linspace(-180, 180, xdim, dtype=np.float32),
                   'lat': np.linspace(-90, 90, ydim, dtype=np.float32)}
@@ -544,7 +540,7 @@ def test_meridionalflow_spherical(pset_mode, mode, xdim=100, ydim=200):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_zonalflow_spherical(pset_mode, mode, k_sample_p, xdim=100, ydim=200):
-    """ Create uniform EASTWARD flow on spherical earth and advect particles
+    """Create uniform EASTWARD flow on spherical earth and advect particles.
 
     As flow is so simple, it can be directly compared to analytical solution
     Note that in this case the cosine conversion is needed
@@ -579,9 +575,7 @@ def test_zonalflow_spherical(pset_mode, mode, k_sample_p, xdim=100, ydim=200):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_random_field(pset_mode, mode, k_sample_p, xdim=20, ydim=20, npart=100):
-    """Sampling test that tests for overshoots by sampling a field of
-    random numbers between 0 and 1.
-    """
+    """Sampling test that tests for overshoots by sampling a field of random numbers between 0 and 1."""
     np.random.seed(123456)
     dimensions = {'lon': np.linspace(0., 1., xdim, dtype=np.float32),
                   'lat': np.linspace(0., 1., ydim, dtype=np.float32)}
diff --git a/tests/test_interaction_kernel.py b/tests/test_interaction_kernel.py
index e7a998f97..ad6346fcf 100644
--- a/tests/test_interaction_kernel.py
+++ b/tests/test_interaction_kernel.py
@@ -14,9 +14,7 @@
 
 
 def DummyMoveNeighbor(particle, fieldset, time, neighbors, mutator):
-    """A particle boosts the movement of its nearest neighbor, by adding
-    0.1 to its lat position.
-    """
+    """A particle boosts the movement of its nearest neighbor, by adding 0.1 to its lat position."""
     if len(neighbors) == 0:
         return StateCode.Success
 
@@ -37,7 +35,7 @@ def DoNothing(particle, fieldset, time):
 
 
 def fieldset(xdim=20, ydim=20, mesh='spherical'):
-    """ Standard unit mesh fieldset """
+    """Standard unit mesh fieldset."""
     lon = np.linspace(0., 1., xdim, dtype=np.float32)
     lat = np.linspace(0., 1., ydim, dtype=np.float32)
     U, V = np.meshgrid(lat, lon)
diff --git a/tests/test_kernel_execution.py b/tests/test_kernel_execution.py
index 1aee70990..7a34105ee 100644
--- a/tests/test_kernel_execution.py
+++ b/tests/test_kernel_execution.py
@@ -33,7 +33,7 @@ def DoNothing(particle, fieldset, time):
 
 
 def fieldset(xdim=20, ydim=20):
-    """ Standard unit mesh fieldset """
+    """Standard unit mesh fieldset."""
     lon = np.linspace(0., 1., xdim, dtype=np.float32)
     lat = np.linspace(0., 1., ydim, dtype=np.float32)
     U, V = np.meshgrid(lat, lon)
diff --git a/tests/test_kernel_language.py b/tests/test_kernel_language.py
index 98b8b55e4..c19934fbc 100644
--- a/tests/test_kernel_language.py
+++ b/tests/test_kernel_language.py
@@ -41,7 +41,7 @@ def expr_kernel(name, pset, expr, pset_mode):
 
 
 def fieldset(xdim=20, ydim=20):
-    """ Standard unit mesh fieldset """
+    """Standard unit mesh fieldset."""
     lon = np.linspace(0., 1., xdim, dtype=np.float32)
     lat = np.linspace(0., 1., ydim, dtype=np.float32)
     U, V = np.meshgrid(lat, lon)
@@ -64,7 +64,7 @@ def fieldset_fixture(xdim=20, ydim=20):
     ('Div', '24 / 4', 6),
 ])
 def test_expression_int(pset_mode, mode, name, expr, result, npart=10):
-    """ Test basic arithmetic expressions """
+    """Test basic arithmetic expressions."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32)
     pset = pset_type[pset_mode]['pset'](None, pclass=TestParticle,
@@ -84,7 +84,7 @@ class TestParticle(ptype[mode]):
     ('Pow', '2 ** 3', 8),
 ])
 def test_expression_float(pset_mode, mode, name, expr, result, npart=10):
-    """ Test basic arithmetic expressions """
+    """Test basic arithmetic expressions."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32)
     pset = pset_type[pset_mode]['pset'](None, pclass=TestParticle,
@@ -110,7 +110,7 @@ class TestParticle(ptype[mode]):
     ('CheckNaN', 'math.nan != math.nan', True),
 ])
 def test_expression_bool(pset_mode, mode, name, expr, result, npart=10):
-    """ Test basic arithmetic expressions """
+    """Test basic arithmetic expressions."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32)
     pset = pset_type[pset_mode]['pset'](None, pclass=TestParticle,
@@ -126,7 +126,7 @@ class TestParticle(ptype[mode]):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_while_if_break(pset_mode, mode):
-    """Test while, if and break commands"""
+    """Test while, if and break commands."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32, initial=0.)
     pset = pset_type[pset_mode]['pset'](pclass=TestParticle, lon=[0], lat=[0])
@@ -145,7 +145,7 @@ def kernel(particle, fieldset, time):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_nested_if(pset_mode, mode):
-    """Test nested if commands"""
+    """Test nested if commands."""
     class TestParticle(ptype[mode]):
         p0 = Variable('p0', dtype=np.int32, initial=0)
         p1 = Variable('p1', dtype=np.int32, initial=1)
@@ -164,7 +164,7 @@ def kernel(particle, fieldset, time):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_pass(pset_mode, mode):
-    """Test pass commands"""
+    """Test pass commands."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.int32, initial=0)
     pset = pset_type[pset_mode]['pset'](pclass=TestParticle, lon=0, lat=0)
@@ -190,7 +190,7 @@ def kernel(particle, fieldset, time):
 
 @pytest.mark.parametrize('pset_mode', pset_modes)
 def test_parcels_tmpvar_in_kernel(pset_mode):
-    """Tests for error thrown if variable with 'tmp' defined in custom kernel"""
+    """Tests for error thrown if variable with 'tmp' defined in custom kernel."""
     error_thrown = False
     pset = pset_type[pset_mode]['pset'](pclass=JITParticle, lon=0, lat=0)
 
@@ -210,7 +210,7 @@ def kernel_pnum(particle, fieldset, time):
 
 @pytest.mark.parametrize('pset_mode', pset_modes)
 def test_abs(pset_mode):
-    """Tests for error thrown if using abs in kernel"""
+    """Tests for error thrown if using abs in kernel."""
     error_thrown = False
     pset = pset_type[pset_mode]['pset'](pclass=JITParticle, lon=0, lat=0)
 
@@ -227,7 +227,7 @@ def kernel_abs(particle, fieldset, time):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_if_withfield(fieldset, pset_mode, mode):
-    """Test combination of if and Field sampling commands"""
+    """Test combination of if and Field sampling commands."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32, initial=0.)
     pset = pset_type[pset_mode]['pset'](fieldset, pclass=TestParticle, lon=[0], lat=[0])
@@ -268,7 +268,7 @@ def kernel(particle, fieldset, time):
                       reason="py.test FD capturing does not work for jit on python3 or Win"))
      ])
 def test_print(fieldset, pset_mode, mode, capfd):
-    """Test print statements"""
+    """Test print statements."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32, initial=0.)
     pset = pset_type[pset_mode]['pset'](fieldset, pclass=TestParticle, lon=[0.5], lat=[0.5])
@@ -329,7 +329,7 @@ def random_series(npart, rngfunc, rngargs, mode):
     ('randint', [0, 20]),
 ])
 def test_random_float(pset_mode, mode, rngfunc, rngargs, npart=10):
-    """ Test basic random number generation """
+    """Test basic random number generation."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=np.float32 if rngfunc == 'randint' else np.float32)
     pset = pset_type[pset_mode]['pset'](pclass=TestParticle,
diff --git a/tests/test_particles.py b/tests/test_particles.py
index 48d55505a..afad5e1c4 100644
--- a/tests/test_particles.py
+++ b/tests/test_particles.py
@@ -48,7 +48,7 @@ class TestParticle(ptype[mode]):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_variable_init(fieldset, pset_mode, mode, npart=10):
-    """Test that checks correct initialisation of custom variables"""
+    """Test that checks correct initialisation of custom variables."""
     class TestParticle(ptype[mode]):
         p_float = Variable('p_float', dtype=np.float32, initial=10.)
         p_double = Variable('p_double', dtype=np.float64, initial=11.)
@@ -72,7 +72,7 @@ def addOne(particle, fieldset, time):
 @pytest.mark.parametrize('mode', ['jit'])
 @pytest.mark.parametrize('type', ['np.int8', 'mp.float', 'np.int16'])
 def test_variable_unsupported_dtypes(fieldset, pset_mode, mode, type):
-    """Test that checks errors thrown for unsupported dtypes in JIT mode"""
+    """Test that checks errors thrown for unsupported dtypes in JIT mode."""
     class TestParticle(ptype[mode]):
         p = Variable('p', dtype=type, initial=10.)
     error_thrown = False
@@ -86,7 +86,7 @@ class TestParticle(ptype[mode]):
 @pytest.mark.parametrize('pset_mode', pset_modes)
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 def test_variable_special_names(fieldset, pset_mode, mode):
-    """Test that checks errors thrown for special names"""
+    """Test that checks errors thrown for special names."""
     for vars in ['z', 'lon']:
         class TestParticle(ptype[mode]):
             tmp = Variable(vars, dtype=np.float32, initial=10.)
@@ -102,7 +102,7 @@ class TestParticle(ptype[mode]):
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
 @pytest.mark.parametrize('coord_type', [np.float32, np.float64])
 def test_variable_init_relative(fieldset, pset_mode, mode, coord_type, npart=10):
-    """Test that checks relative initialisation of custom variables"""
+    """Test that checks relative initialisation of custom variables."""
     lonlat_type = np.float64 if coord_type == 'double' else np.float32
 
     class TestParticle(ptype[mode]):