Skip to content

Commit 90cebd3

Browse files
Merge branch 'bugfix/2568-output-fenceposting' of github.com:Parcels-Code/Parcels into bugfix/2568-output-fenceposting
2 parents 6f5981f + c0db495 commit 90cebd3

35 files changed

Lines changed: 717 additions & 425 deletions

.github/ISSUE_TEMPLATE/02_bug.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ body:
1717
- type: "textarea"
1818
attributes:
1919
label: "Code sample"
20-
description: "If relevant, please provide a code example where this bug is shown as well as any error message. A [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) is preffered as it makes it much easier for developers to identify the cause of the bug. This also allows them quickly determine whether the problem is with your code or with Parcels itself. If you want support on a specific dataset, please [follow our instructions on how to share dataset metadata](https://docs.parcels-code.org/en/main/development/posting-issues.html)"
20+
description: "If relevant, please provide a code example where this bug is shown as well as any error message. A [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) is preffered as it makes it much easier for developers to identify the cause of the bug. This also allows them quickly determine whether the problem is with your code or with Parcels itself. If you want support on a specific dataset, please [follow our instructions on how to share representative datasets](https://docs.parcels-code.org/en/main/development/posting-issues.html)"
2121
value: |
2222
```python
2323
# Paste your code within this block

.github/ci/recipe.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ requirements:
3535
- netcdf4 >=1.7.2
3636
- numpy >=2.1.0
3737
- tqdm >=4.50.0
38-
- xarray >=2024.5.0
38+
- xarray >=2025.8.0,<2026.4.0 # TODO: remove upper pin when https://github.com/UXARRAY/uxarray/issues/1490 is resolved
3939
- cf_xarray >=0.8.6
4040
- xgcm >=0.9.0
4141
- zarr >=2.15.0,!=2.18.0,<3

.github/workflows/ci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,17 @@ jobs:
243243
done
244244
env:
245245
PREFIX_API_KEY: ${{ secrets.PREFIX_API_KEY }} # zizmor: ignore[secrets-outside-env]
246+
247+
zizmor:
248+
name: GHA Security Analysis using Zizmor
249+
runs-on: ubuntu-latest
250+
permissions:
251+
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
252+
steps:
253+
- name: Checkout repository
254+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
255+
with:
256+
persist-credentials: false
257+
258+
- name: Run zizmor
259+
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ repos:
1313
rev: v1.23.1
1414
hooks:
1515
- id: zizmor
16+
args: ["--offline"]
1617
- repo: https://github.com/astral-sh/ruff-pre-commit
17-
rev: v0.15.8
18+
rev: v0.15.9
1819
hooks:
1920
- id: ruff
2021
name: ruff lint (.py)

docs/development/posting-issues.md

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,96 @@ Following these templates provides structure and ensures that we have all the ne
2020
Parcels is designed to work with a large range of input datasets.
2121

2222
When extending support for various input datasets, or trying to debug problems
23-
that only occur with specific datasets, having the dataset metadata is very valuable.
23+
that only occur with specific datasets, having access to your dataset (or a
24+
close representation of it) is very valuable.
2425

25-
This metadata could include information such as:
26+
This could include information such as:
2627

2728
- the nature of the array variables (e.g., via CF compliant metadata)
2829
- descriptions about the origin of the dataset, or additional comments
2930
- the shapes and data types of the arrays
31+
- the grid topology (coordinates and key variables)
3032

3133
This also allows us to see if your metadata is broken/non-compliant with standards - where we can then suggest fixes for you (and maybe we can tell the data provider!).
3234
Since version 4 of Parcels we rely much more on metadata to discover information about your input data.
3335

34-
Sharing this metadata often provides enough debugging information to solve your problem, instead of having to share a whole dataset.
36+
Sharing a compact representation of your dataset often provides enough information to solve your problem, without having to share the full dataset (which may be very large or contain sensitive data).
3537

36-
Sharing dataset metadata is made easy in Parcels.
38+
Parcels makes this easy by replacing irrelevant array data with zeros and saving the result as a compressed Zarr zip store, which is typically small enough to attach directly to a GitHub issue.
3739

3840
### Step 1. Users
3941

4042
As a user with access to your dataset, you would do:
4143

4244
```{code-cell}
43-
import json
45+
:tags: [hide-cell]
4446
47+
# Generate an example dataset to zip. The user would use their own.
4548
import xarray as xr
49+
from parcels._datasets.structured.generic import datasets
50+
datasets['ds_2d_left'].to_netcdf("my_dataset.nc")
51+
```
52+
53+
```{code-cell}
54+
import os
55+
56+
import xarray as xr
57+
import zarr
58+
59+
from parcels._datasets.utils import replace_arrays_with_zeros
60+
61+
# load your dataset
62+
ds = xr.open_dataset("my_dataset.nc") # or xr.open_zarr(...), etc.
63+
64+
# Replace all data arrays with zeros, keeping coordinate metadata.
65+
# This keeps array shapes and metadata while removing actual data.
66+
#
67+
# You can customise `except_for` to also retain actual values for specific variables:
68+
# except_for='coords' — keep coordinate arrays (useful for grid topology)
69+
# except_for=['lon', 'lat'] — keep a specific list of variables
70+
# except_for=None — remove all arrays (useful to know about dtypes, structure, and metadata). This is the default for the function.
71+
ds_trimmed = replace_arrays_with_zeros(ds, except_for = None)
4672
47-
# defining an example dataset to illustrate
48-
# (you would use `xr.open_dataset(...)` instead)
49-
ds = xr.Dataset(attrs={"description": "my dataset"})
73+
# Save to a zipped Zarr store - replace `my_dataset` with a more informative name
74+
with zarr.storage.ZipStore("my_dataset.zip", mode='w') as store:
75+
ds_trimmed.to_zarr(store)
5076
51-
output_file = "my_dataset.json"
52-
with open(output_file, "w") as f:
53-
json.dump(ds.to_dict(data=False), f) # write your dataset to a JSON excluding array data
77+
size_mb_original = os.path.getsize("my_dataset.nc") / 1e6
78+
print(f"Original size: {size_mb_original:.1f} MB")
79+
80+
# Check the file size (aim for < 25 MB so it can be attached to a GitHub issue)
81+
size_mb = os.path.getsize("my_dataset.zip") / 1e6
82+
print(f"Zip store size: {size_mb:.1f} MB")
5483
```
5584

56-
Then attach the JSON file written above alongside your issue
85+
Then attach the zip file written above alongside your issue.
86+
87+
If the file is larger than 25 MB, try passing `except_for=None` (the default)
88+
to ensure all arrays are zeroed out. If it is still too large, consider
89+
subsetting your dataset to a smaller spatial or temporal region before saving.
5790

5891
### Step 2. Maintainers and developers
5992

60-
As developers looking to inspect the metadata, we would do:
93+
As developers looking to inspect the dataset, we would do:
94+
95+
```{code-cell}
96+
import xarray as xr
97+
import zarr
98+
99+
ds = xr.open_zarr(zarr.storage.ZipStore("my_dataset.zip", mode="r"))
100+
ds
101+
```
61102

62103
```{code-cell}
63-
from parcels._datasets.utils import from_xarray_dataset_dict
104+
:tags: [hide-cell]
105+
106+
# Cleanup files in doc build process
107+
del ds
108+
from pathlib import Path
109+
Path("my_dataset.zip").unlink()
110+
Path("my_dataset.nc").unlink()
64111
65-
with open(output_file) as f:
66-
d = json.load(f)
67-
ds = from_xarray_dataset_dict(d)
68112
```
69113

70-
From there we can take a look the metadata of your dataset!
114+
From there we can take a look at the structure, metadata, and grid topology of your dataset!
115+
This also makes it straightforward for us to add this dataset to our test suite.

docs/getting_started/tutorial_output.ipynb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"import numpy as np\n",
3636
"import xarray as xr\n",
3737
"\n",
38-
"import parcels"
38+
"import parcels\n",
39+
"import parcels.tutorial"
3940
]
4041
},
4142
{
@@ -52,11 +53,9 @@
5253
"outputs": [],
5354
"source": [
5455
"# Load the CopernicusMarine data in the Agulhas region from the example_datasets\n",
55-
"example_dataset_folder = parcels.download_example_dataset(\n",
56-
" \"CopernicusMarine_data_for_Argo_tutorial\"\n",
56+
"ds_fields = parcels.tutorial.open_dataset(\n",
57+
" \"CopernicusMarine_data_for_Argo_tutorial/data\"\n",
5758
")\n",
58-
"\n",
59-
"ds_fields = xr.open_mfdataset(f\"{example_dataset_folder}/*.nc\", combine=\"by_coords\")\n",
6059
"ds_fields.load() # load the dataset into memory\n",
6160
"\n",
6261
"# Convert to SGRID-compliant dataset and create FieldSet\n",
@@ -558,7 +557,7 @@
558557
"metadata": {
559558
"celltoolbar": "Metagegevens bewerken",
560559
"kernelspec": {
561-
"display_name": "test-notebooks",
560+
"display_name": "default",
562561
"language": "python",
563562
"name": "python3"
564563
},
@@ -572,7 +571,7 @@
572571
"name": "python",
573572
"nbconvert_exporter": "python",
574573
"pygments_lexer": "ipython3",
575-
"version": "3.14.2"
574+
"version": "3.14.3"
576575
}
577576
},
578577
"nbformat": 4,

docs/getting_started/tutorial_quickstart.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and writing output files that can be read with xarray.
2020
import numpy as np
2121
import xarray as xr
2222
import parcels
23+
import parcels.tutorial
2324
```
2425

2526
## Input flow fields: `FieldSet`
@@ -29,11 +30,8 @@ hydrodynamics fields in which the particles are tracked. Here we provide an exam
2930
[Global Ocean Physics Reanalysis](https://doi.org/10.48670/moi-00021) from the Copernicus Marine Service.
3031

3132
```{code-cell}
32-
example_dataset_folder = parcels.download_example_dataset(
33-
"CopernicusMarine_data_for_Argo_tutorial"
34-
)
33+
ds_fields = parcels.tutorial.open_dataset("CopernicusMarine_data_for_Argo_tutorial/data")
3534
36-
ds_fields = xr.open_mfdataset(f"{example_dataset_folder}/*.nc", combine="by_coords")
3735
ds_fields.load() # load the dataset into memory
3836
ds_fields
3937
```

docs/user_guide/examples/explanation_kernelloop.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,10 @@ import numpy as np
5353
import xarray as xr
5454
5555
import parcels
56+
import parcels.tutorial
5657
5758
# Load the CopernicusMarine data in the Agulhas region from the example_datasets
58-
example_dataset_folder = parcels.download_example_dataset(
59-
"CopernicusMarine_data_for_Argo_tutorial"
60-
)
61-
62-
ds_fields = xr.open_mfdataset(f"{example_dataset_folder}/*.nc", combine="by_coords")
59+
ds_fields = parcels.tutorial.open_dataset("CopernicusMarine_data_for_Argo_tutorial/data")
6360
ds_fields.load() # load the dataset into memory
6461
6562
# Create an idealised wind field and add it to the dataset

docs/user_guide/examples/tutorial_Argofloats.ipynb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,13 @@
110110
"import xarray as xr\n",
111111
"\n",
112112
"import parcels\n",
113+
"import parcels.tutorial\n",
113114
"\n",
114115
"# Load the CopernicusMarine data in the Agulhas region from the example_datasets\n",
115-
"example_dataset_folder = parcels.download_example_dataset(\n",
116-
" \"CopernicusMarine_data_for_Argo_tutorial\"\n",
116+
"ds_fields = parcels.tutorial.open_dataset(\n",
117+
" \"CopernicusMarine_data_for_Argo_tutorial/data\"\n",
117118
")\n",
118119
"\n",
119-
"ds_fields = xr.open_mfdataset(f\"{example_dataset_folder}/*.nc\", combine=\"by_coords\")\n",
120-
"\n",
121120
"# TODO check how we can get good performance without loading full dataset in memory\n",
122121
"ds_fields.load() # load the dataset into memory\n",
123122
"\n",

docs/user_guide/examples/tutorial_croco_3D.ipynb

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,7 @@
3434
"metadata": {},
3535
"outputs": [],
3636
"source": [
37-
"import matplotlib.pyplot as plt\n",
38-
"import numpy as np\n",
39-
"import xarray as xr\n",
40-
"\n",
41-
"import parcels\n",
42-
"\n",
43-
"data_folder = parcels.download_example_dataset(\"CROCOidealized_data\")\n",
44-
"ds_fields = xr.open_dataset(data_folder / \"CROCO_idealized.nc\")\n",
45-
"\n",
46-
"ds_fields.load(); # Preload data to speed up access"
37+
"import matplotlib.pyplot as plt\nimport numpy as np\nimport xarray as xr\n\nimport parcels\nimport parcels.tutorial\n\nds_fields = parcels.tutorial.open_dataset(\"CROCOidealized_data/data\")\n\nds_fields.load(); # Preload data to speed up access"
4738
]
4839
},
4940
{

0 commit comments

Comments
 (0)