Skip to content

Commit 92cbd4f

Browse files
Run pre-commit hooks and enable in CI (#39)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 53f5d9d commit 92cbd4f

File tree

14 files changed

+164
-107
lines changed

14 files changed

+164
-107
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ build/
1313
parcels/
1414
.asv/
1515
html/
16-

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
results
2+
pixi.lock

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,39 @@ This repository houses performance benchmarks for [Parcels](https://github.com/O
1313
You can run the linting with `pixi run lint`
1414

1515
> [!IMPORTANT]
16-
> The default path for the benchmark data is set by [pooch.os_cache](https://www.fatiando.org/pooch/latest/api/generated/pooch.os_cache.html), which typically is a subdirectory of your home directory. Currently, you will need at least 50GB of disk space available to store the benchmark data.
17-
> To change the location of the benchmark data cache, you can set the environment variable `PARCELS_DATADIR` to a preferred location to store the benchmark data.
18-
16+
> The default path for the benchmark data is set by [pooch.os_cache](https://www.fatiando.org/pooch/latest/api/generated/pooch.os_cache.html), which typically is a subdirectory of your home directory. Currently, you will need at least 50GB of disk space available to store the benchmark data.
17+
> To change the location of the benchmark data cache, you can set the environment variable `PARCELS_DATADIR` to a preferred location to store the benchmark data.
1918
2019
To view the benchmark data
2120

2221
- `pixi run asv publish`
2322
- `pixi run asv preview`
2423

2524
## Contributing benchmark runs
25+
2626
We value seeing how Parcels benchmarks perform on a variety of systems. When you run the benchmarks, this adds data to the `results/` subdirectory in this repository. After running the benchmarks, you can commit the changes made to the `results/` subdirectory and open a pull request to contribute your benchmark results.
2727

2828
### Parcels Community Members
29+
2930
Members of the Parcels community can contribute benchmark data using the following steps
3031

3132
1. [Create a fork of this repository](https://github.com/Parcels-code/parcels-benchmarks/fork)
3233

3334
2. Clone your fork onto your system
35+
3436
```
3537
git clone git@github.com:<your-github-handle>/parcels-benchmarks.git ~/parcels-benchmarks
3638
```
3739

3840
3. Run the benchmarks
41+
3942
```
4043
cd ~/parcels-benchmarks
4144
pixi run asv run
4245
```
4346

4447
4. Commit your benchmark data and push the changes back to your fork, e.g.
48+
4549
```
4650
git add results
4751
git commit -m "Add benchmark data"
@@ -50,22 +54,23 @@ git push origin main
5054

5155
5. [Open a pull request from your fork](https://github.com/Parcels-code/parcels-benchmarks/compare)
5256

53-
54-
5557
## Adding benchmarks
56-
Adding benchmarks for parcels typically involves adding a dataset and defining the benchmarks you want to run.
5758

59+
Adding benchmarks for parcels typically involves adding a dataset and defining the benchmarks you want to run.
5860

5961
### Adding new data
62+
6063
Data is hosted remotely on a SurfDrive managed by the Parcels developers. You will need to open an issue on this repository to start the process of getting your data hosted in the shared SurfDrive.
6164
Once your data is hosted in the shared SurfDrive, you can easily add your dataset to the benchmark dataset manifest using
65+
6266
```
6367
pixi run benchmark-setup pixi add-dataset --name "Name for your dataset" --file "Path to ZIP archive in the SurfDrive"
6468
```
6569

6670
During this process, the dataset will be downloaded and a complete entry will be added to the [parcels_benchmarks/benchmarks.json](./parcels_benchmarks/benchmarks.json) manifest file. Once updated, this file can be committed to this repository and contributed via a pull request.
67-
71+
6872
### Writing the benchmarks
73+
6974
This repository uses [ASV](https://asv.readthedocs.io/) for running benchmarks. You can add benchmarks by including a python script in the `benchmarks/` subdirectory. Within each `benchmarks/*.py` file, we ask that you define a class for the set of benchmarks you plan to run for your dataset. You can use the existing benchmarks as a good starting point for writing your benchmarks.
7075

7176
To learn more about writing benchmarks compatible with ASV, see the [ASV "Writing Benchmarks" documentation](https://asv.readthedocs.io/en/latest/writing_benchmarks.html)

asv.conf.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
"repo": "https://github.com/Parcels-Code/parcels.git",
66
"branches": ["main"],
77
"environment_type": "rattler",
8-
"conda_channels": ["conda-forge", "defaults", "https://repo.prefix.dev/parcels"],
8+
"conda_channels": [
9+
"conda-forge",
10+
"defaults",
11+
"https://repo.prefix.dev/parcels"
12+
],
913
"default_benchmark_timeout": 1800,
1014
"env_dir": ".asv/env",
1115
"results_dir": "results",

benchmarks/fesom2.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import numpy as np
22
import uxarray as ux
33
from parcels import (
4-
convert,
5-
Field,
64
FieldSet,
75
Particle,
86
ParticleSet,
9-
UxGrid,
10-
VectorField,
7+
convert,
118
)
129
from parcels.kernels import AdvectionRK2_3D
13-
from parcels_benchmarks.benchmark_setup import download_example_dataset, PARCELS_DATADIR
1410

15-
runtime=np.timedelta64(1, "D")
16-
dt=np.timedelta64(2400, "s")
11+
from parcels_benchmarks.benchmark_setup import PARCELS_DATADIR, download_example_dataset
12+
13+
runtime = np.timedelta64(1, "D")
14+
dt = np.timedelta64(2400, "s")
15+
1716

1817
def _load_ds(datapath):
1918
"""Helper function to load uxarray dataset from datapath"""
@@ -24,38 +23,35 @@ def _load_ds(datapath):
2423

2524

2625
class FESOM2:
27-
params = (
28-
[10000],
29-
[AdvectionRK2_3D]
30-
)
31-
param_names = [
32-
"npart",
33-
"integrator"
34-
]
35-
def setup(self,npart,integrator):
26+
params = ([10000], [AdvectionRK2_3D])
27+
param_names = ["npart", "integrator"]
28+
29+
def setup(self, npart, integrator):
3630
# Ensure the dataset is downloaded in the desired data_home
3731
# and obtain the path to the dataset
38-
self.datapath = download_example_dataset("FESOM-baroclinic-gyre", data_home=PARCELS_DATADIR)
32+
self.datapath = download_example_dataset(
33+
"FESOM-baroclinic-gyre", data_home=PARCELS_DATADIR
34+
)
3935

40-
def time_load_data(self,npart,integrator):
36+
def time_load_data(self, npart, integrator):
4137
ds = _load_ds(self.datapath)
4238
for i in range(min(ds.coords["time"].size, 2)):
43-
u = ds["u"].isel(time=i).compute()
44-
v = ds["v"].isel(time=i).compute()
39+
_u = ds["u"].isel(time=i).compute()
40+
_v = ds["v"].isel(time=i).compute()
4541

46-
def pset_execute(self,npart,integrator):
42+
def pset_execute(self, npart, integrator):
4743
ds = _load_ds(self.datapath)
4844
ds = convert.fesom_to_ugrid(ds)
4945
fieldset = FieldSet.from_ugrid_conventions(ds)
5046

51-
lon = np.linspace(2.0,15.0,npart)
52-
lat = np.linspace(32.0,19.0,npart)
47+
lon = np.linspace(2.0, 15.0, npart)
48+
lat = np.linspace(32.0, 19.0, npart)
5349

5450
pset = ParticleSet(fieldset=fieldset, pclass=Particle, lon=lon, lat=lat)
5551
pset.execute(runtime=runtime, dt=dt, pyfunc=integrator)
5652

57-
def time_pset_execute(self,npart,integrator):
58-
self.pset_execute(npart,integrator)
53+
def time_pset_execute(self, npart, integrator):
54+
self.pset_execute(npart, integrator)
5955

60-
def peakmem_pset_execute(self,npart,integrator):
61-
self.pset_execute(npart,integrator)
56+
def peakmem_pset_execute(self, npart, integrator):
57+
self.pset_execute(npart, integrator)

benchmarks/moi_curvilinear.py

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,57 @@
1-
import xarray as xr
2-
import time
31
from glob import glob
2+
43
import numpy as np
54
import parcels
5+
import xarray as xr
66
import xgcm
77
from parcels.interpolators import XLinear
8-
from parcels_benchmarks.benchmark_setup import download_example_dataset, PARCELS_DATADIR
8+
9+
from parcels_benchmarks.benchmark_setup import PARCELS_DATADIR, download_example_dataset
910

1011
runtime = np.timedelta64(2, "D")
1112
dt = np.timedelta64(15, "m")
1213

14+
1315
def _load_ds(datapath, chunk):
1416
"""Helper function to load xarray dataset from datapath with or without chunking"""
1517

1618
fileU = f"{datapath}/psy4v3r1-daily_U_2025-01-0[1-3].nc"
17-
filenames = {"U": glob(fileU), "V": glob(fileU.replace("_U_", "_V_")), "W": glob(fileU.replace("_U_", "_W_"))}
19+
filenames = {
20+
"U": glob(fileU),
21+
"V": glob(fileU.replace("_U_", "_V_")),
22+
"W": glob(fileU.replace("_U_", "_W_")),
23+
}
1824
mesh_mask = f"{datapath}/PSY4V3R1_mesh_hgr.nc"
19-
fileargs = {"concat_dim": "time_counter",
20-
"combine": "nested",
21-
"data_vars": 'minimal',
22-
"coords": 'minimal',
23-
"compat": 'override',
25+
fileargs = {
26+
"concat_dim": "time_counter",
27+
"combine": "nested",
28+
"data_vars": "minimal",
29+
"coords": "minimal",
30+
"compat": "override",
2431
}
2532
if chunk:
26-
fileargs["chunks"] = {"time_counter": 1, "depth":2, "y": chunk, "x": chunk}
33+
fileargs["chunks"] = {"time_counter": 1, "depth": 2, "y": chunk, "x": chunk}
2734

28-
ds_u = xr.open_mfdataset(filenames["U"], **fileargs)[["vozocrtx"]].drop_vars(["nav_lon", "nav_lat"])
29-
ds_v = xr.open_mfdataset(filenames["V"], **fileargs)[["vomecrty"]].drop_vars(["nav_lon", "nav_lat"])
35+
ds_u = xr.open_mfdataset(filenames["U"], **fileargs)[["vozocrtx"]].drop_vars(
36+
["nav_lon", "nav_lat"]
37+
)
38+
ds_v = xr.open_mfdataset(filenames["V"], **fileargs)[["vomecrty"]].drop_vars(
39+
["nav_lon", "nav_lat"]
40+
)
3041
ds_depth = xr.open_mfdataset(filenames["W"], **fileargs)[["depthw"]]
3142
ds_mesh = xr.open_dataset(mesh_mask)[["glamf", "gphif"]].isel(t=0)
3243

3344
ds = xr.merge([ds_u, ds_v, ds_depth, ds_mesh], compat="identical")
34-
ds = ds.rename({"vozocrtx": "U", "vomecrty": "V", "glamf": "lon", "gphif": "lat", "time_counter": "time", "depthw": "depth"})
45+
ds = ds.rename(
46+
{
47+
"vozocrtx": "U",
48+
"vomecrty": "V",
49+
"glamf": "lon",
50+
"gphif": "lat",
51+
"time_counter": "time",
52+
"depthw": "depth",
53+
}
54+
)
3555
ds.deptht.attrs["c_grid_axis_shift"] = -0.5
3656

3757
return ds
@@ -40,41 +60,46 @@ def _load_ds(datapath, chunk):
4060
class MOICurvilinear:
4161
"""Mercator Ocean International model data based benchmark on a curvilinear grid."""
4262

43-
params = (
44-
["XLinear"],
45-
[256],
46-
[10000],
63+
params = (
64+
["XLinear"],
65+
[256],
66+
[10000],
4767
)
4868
param_names = [
49-
"interpolator",
50-
"chunk",
51-
"npart",
52-
]
53-
def setup(self,interpolator,chunk,npart):
54-
self.datapath = download_example_dataset("MOi-curvilinear", data_home=PARCELS_DATADIR)
55-
56-
def time_load_data_3d(self,interpolator,chunk,npart):
69+
"interpolator",
70+
"chunk",
71+
"npart",
72+
]
73+
74+
def setup(self, interpolator, chunk, npart):
75+
self.datapath = download_example_dataset(
76+
"MOi-curvilinear", data_home=PARCELS_DATADIR
77+
)
78+
79+
def time_load_data_3d(self, interpolator, chunk, npart):
5780
"""Benchmark that times loading the 'U' and 'V' data arrays only for 3-D"""
5881

5982
# To have a reasonable runtime, we only consider the time it takes to load two time levels
6083
# and two depth levels (at most)
61-
ds = _load_ds(self.datapath,chunk)
62-
for j in range(min(ds.coords["deptht"].size,2)):
84+
ds = _load_ds(self.datapath, chunk)
85+
for j in range(min(ds.coords["deptht"].size, 2)):
6386
for i in range(min(ds.coords["time"].size, 2)):
64-
u = ds["U"].isel(deptht=j,time=i).compute()
65-
v = ds["V"].isel(deptht=j,time=i).compute()
87+
_u = ds["U"].isel(deptht=j, time=i).compute()
88+
_v = ds["V"].isel(deptht=j, time=i).compute()
6689

67-
68-
def pset_execute_3d(self,interpolator,chunk,npart):
69-
ds = _load_ds(self.datapath,chunk)
70-
coords={
90+
def pset_execute_3d(self, interpolator, chunk, npart):
91+
ds = _load_ds(self.datapath, chunk)
92+
coords = {
7193
"X": {"left": "x"},
7294
"Y": {"left": "y"},
7395
"Z": {"center": "deptht", "left": "depth"},
7496
"T": {"center": "time"},
7597
}
7698

77-
grid = parcels._core.xgrid.XGrid(xgcm.Grid(ds, coords=coords, autoparse_metadata=False, periodic=False), mesh="spherical")
99+
grid = parcels._core.xgrid.XGrid(
100+
xgcm.Grid(ds, coords=coords, autoparse_metadata=False, periodic=False),
101+
mesh="spherical",
102+
)
78103

79104
if interpolator == "XLinear":
80105
interp_method = XLinear
@@ -86,21 +111,22 @@ def pset_execute_3d(self,interpolator,chunk,npart):
86111
U.units = parcels.GeographicPolar()
87112
V.units = parcels.Geographic()
88113
UV = parcels.VectorField("UV", U, V)
89-
114+
90115
fieldset = parcels.FieldSet([U, V, UV])
91-
116+
92117
pclass = parcels.Particle
93118

94119
lon = np.linspace(-10, 10, npart)
95120
lat = np.linspace(-30, -20, npart)
96121

97122
pset = parcels.ParticleSet(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat)
98123

99-
pset.execute(parcels.kernels.AdvectionEE, runtime=runtime, dt=dt, verbose_progress=False)
100-
101-
def time_pset_execute_3d(self,interpolator,chunk,npart):
102-
self.pset_execute_3d(interpolator,chunk,npart)
124+
pset.execute(
125+
parcels.kernels.AdvectionEE, runtime=runtime, dt=dt, verbose_progress=False
126+
)
103127

104-
def peakmem_pset_execute_3d(self,interpolator,chunk,npart):
105-
self.pset_execute_3d(interpolator,chunk,npart)
128+
def time_pset_execute_3d(self, interpolator, chunk, npart):
129+
self.pset_execute_3d(interpolator, chunk, npart)
106130

131+
def peakmem_pset_execute_3d(self, interpolator, chunk, npart):
132+
self.pset_execute_3d(interpolator, chunk, npart)

0 commit comments

Comments
 (0)