Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
2be42de
Roman changes from branch romanc:romanc/pyfms-monitor-ci
fmalatino May 5, 2026
544fc4a
Merge branch 'develop' into fix/dm_monitor
fmalatino May 5, 2026
0551484
Linting
fmalatino May 5, 2026
319320b
Fixing apt-get update in pyFMS workflow
fmalatino May 5, 2026
9e05a01
Using open_dataset instead of open_mfdataset in diag_manager monitor …
fmalatino May 5, 2026
c67041a
Matching romanc version of tests
fmalatino May 5, 2026
7a15106
Linting
fmalatino May 5, 2026
0521b8a
Looking at pip list in unit_tests
fmalatino May 5, 2026
fc4b13d
Checking non-pip installed netcdf version
fmalatino May 5, 2026
c410f22
Print statements to debug dm_monitor single test
fmalatino May 5, 2026
6cd2d28
Commenting out xarray Dataset accessing calls in test_dm_monitor_single
fmalatino May 5, 2026
0131b97
Adding back in assert of Path in test_dm_monitor_single
fmalatino May 5, 2026
7715c0c
Moving through dm_monitor_single
fmalatino May 7, 2026
98c4804
ALways install mpich and checking xarray call without time decode
fmalatino May 7, 2026
4238aae
Always installing pyfms dependencies
fmalatino May 7, 2026
c2a34c9
Verbose pip install
fmalatino May 7, 2026
2b83d84
Using dask scheduler to avoid race condition
fmalatino May 7, 2026
531828c
Removing debugging print statements
fmalatino May 7, 2026
26eeaad
Linting and removing commented sections
fmalatino May 7, 2026
31adac8
Merge branch 'develop' into fix/dm_monitor
fmalatino May 7, 2026
5186f80
Addressing comments from PR 459: removing use of dask scheduler
fmalatino May 8, 2026
0e2e124
Doing sudo apt-get update just for pyfms install
fmalatino May 8, 2026
b6933b0
Trying with h5netcdf engine in xarray open_dataset for single dm_moni…
fmalatino May 8, 2026
6681da9
Using threading.Lock to resolve issue in open_dataset loading
fmalatino May 8, 2026
b403498
Using pip list to check versions installed via pip in unit tests
fmalatino May 8, 2026
f546b28
Merge branch 'develop' into fix/dm_monitor
fmalatino May 8, 2026
ea986fc
Updating allowed version of netcdf4
fmalatino May 8, 2026
bd5a5b9
Removing chunks={} from open_dataset call
fmalatino May 8, 2026
c3a1baa
Checking if python 3.12 is causing breakage
fmalatino May 8, 2026
0cf5946
Linting
fmalatino May 8, 2026
d6cf6c0
Using netcdf4 directly over xarray
fmalatino May 8, 2026
ab22f58
Bring all asserts back into test_dm_monitor_single.py
fmalatino May 8, 2026
528f21f
Adding option for parallel pyfms tests vs non in unit_tests workflow
fmalatino May 8, 2026
877fd63
Using netcdf4 over xarray in test_dm_monitor_cubed.py
fmalatino May 8, 2026
e6c365f
Removing script mode for pip install in unit_tests workflow
fmalatino May 11, 2026
af1d2a5
Addressing PR 459 comments, removing -s flag, no apt-get update, sing…
fmalatino May 11, 2026
225ccbc
Merge branch 'develop' into fix/dm_monitor
fmalatino May 11, 2026
d18e647
Using --fix-missing to try to amend broken install for pyfms
fmalatino May 11, 2026
424760d
Using update for pyfms install to check that other changes are working
fmalatino May 11, 2026
62b21c0
Removing -y flag from pyfms dependency install
fmalatino May 11, 2026
ac125d1
Using script mode for pyfms dependency install
fmalatino May 11, 2026
9d85b34
Moving back to using separate parallel test runs in unit tests
fmalatino May 11, 2026
cb49a53
Always using openmpi in unit_tests workflow
fmalatino May 11, 2026
dae4094
Removing -s flag from serial cpu unit tests
fmalatino May 12, 2026
ae26ded
Trying with chunks set to None in xarray open_dataset to skip Dask
fmalatino May 14, 2026
08c5573
Checking decode_times use within xarray open_dataset failure
fmalatino May 14, 2026
8c5107b
Again checking decode_times in open_dataset and checking xarray version
fmalatino May 14, 2026
8a77760
Reverting changes back to netcdf direct access in test_dm_monitor_single
fmalatino May 14, 2026
098c3c6
Merge branch 'develop' into fix/dm_monitor
fmalatino May 20, 2026
b6631f8
Removing pip list debug command from unit_tests workflow
fmalatino May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions .github/workflows/unit_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ jobs:
strategy:
matrix:
python-version: ['3.11', '3.12', '3.13']
name: Python ${{ matrix.python-version }}
extra: ['test,zarr']
marker-serial: ['not parallel and not gpu and not pyfms']
marker-parallel: ['parallel and not gpu and not pyfms']
include:
# add pyfms tests for 3.12
- extra: 'test,pyfms'
marker-serial: 'pyfms and not parallel'
marker-parallel: 'pyfms and parallel'
python-version: '3.12'
# don't cancel other jobs if one fails
fail-fast: false
name: Python ${{ matrix.python-version }}${{ contains(matrix.extra, 'pyfms') && ' (pyFMS)' || '' }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -31,17 +42,24 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install mpi (MPICH flavor)
run: pip3 install mpich
- name: Install MPI
if: ${{!contains(matrix.extra, 'pyfms')}}
run: pip3 install openmpi

- name: Install pyFMS dependencies (includes system MPI)
if: contains(matrix.extra, 'pyfms')
run: |
sudo apt-get update
sudo apt-get install libopenmpi-dev netcdf-bin libnetcdf-dev libnetcdff-dev nco libyaml-dev diffutils

- name: Install Python packages
run: pip3 install .[test,zarr]
run: pip3 install .[${{matrix.extra}}]

- name: Run serial cpu tests
run: coverage run --rcfile=pyproject.toml -m pytest -m "not parallel and not gpu" tests
run: coverage run --rcfile=pyproject.toml -m pytest -m "${{matrix.marker-serial}}" tests

- name: Run parallel cpu tests
run: mpiexec -np 6 coverage run --rcfile=pyproject.toml -m mpi4py -m pytest -m "parallel and not gpu" tests
run: mpiexec -np 6 --oversubscribe coverage run --rcfile=pyproject.toml -m mpi4py -m pytest -m "${{matrix.marker-parallel}}" tests

- name: Output code coverage
run: |
Expand Down
3 changes: 3 additions & 0 deletions docs/docstrings/monitor/diag_manager_monitor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# diag_manager_monitor

::: monitor.diag_manager_monitor
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ nav:
- "subtile_grid_sizer": docstrings/initialization/subtile_grid_sizer.md
- monitor:
- "convert": docstrings/monitor/convert.md
- "diag_manager_monitor": docstrings/monitor/diag_manager_monitor.md
- "netcdf_monitor": docstrings/monitor/netcdf_monitor.md
- "protocol": docstrings/monitor/protocol.md
- "zarr_monitor": docstrings/monitor/zarr_monitor.md
Expand Down
5 changes: 5 additions & 0 deletions ndsl/optional_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def __call__(self, *args: Any, **kwargs: dict) -> None:
except ModuleNotFoundError as err:
zarr = RaiseWhenAccessed(err)

try:
import pyfms
except ModuleNotFoundError as err:
pyfms = RaiseWhenAccessed(err)

try:
import cupy
except ImportError:
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ module = [
markers = [
# tests running on a cpu (e.g. with cupy)
"gpu",
# tests relying on the optional pyFMS dependency
"pyfms",
# tests relying on at least two MPI processes
"parallel",
# tests relying on the optional zarr dependency
Expand Down
Empty file added tests/monitor/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import cftime
import numpy as np
import pytest
import xarray as xr
import yaml
from netCDF4 import Dataset, num2date

from ndsl import (
CubedSphereCommunicator,
Expand All @@ -21,9 +21,7 @@
)
from ndsl.config import Backend
from ndsl.initialization import SubtileGridSizer


pyfms = pytest.importorskip("pyfms")
from ndsl.optional_imports import pyfms


# init fms mpi and set up a simple domain
Expand Down Expand Up @@ -52,7 +50,7 @@ def fms_mpp_init():
return domain_id


def _create_input(reduction: str = "none"):
def _create_input(reduction: str = "none") -> None:
diag_config = {
"title": "ndsl_diag_manager_test",
"base_date": "1 1 1 0 0 0",
Expand Down Expand Up @@ -89,9 +87,9 @@ def _create_input(reduction: str = "none"):


# Simple test, uses a lat/lon grid and (1, npes) layout
@pytest.mark.pyfms
@pytest.mark.parallel
def test_dm_monitor():

def test_dm_monitor() -> None:
npes = MPIComm()._comm.Get_size()
if npes % 6 != 0:
raise RuntimeError("this test requires npes to be a multiple of 6 to run")
Expand Down Expand Up @@ -203,24 +201,28 @@ def test_dm_monitor():
pe = MPIComm()._comm.Get_rank() + 1
filename = "diag_manager_cubed_sphere.tile" + str(pe) + ".nc"
assert Path(filename).exists()
ds = xr.open_mfdataset(filename, decode_times=True)
assert "var1" in ds
np.testing.assert_array_equal(ds["var1"].shape, (ntimesteps, ny, nx))
assert "var2" in ds
np.testing.assert_array_equal(ds["var2"].shape, (ntimesteps, nz, ny, nx))
assert ds["var1"].dims == ("time", "y", "x")
assert ds["var2"].dims == ("time", "z", "y", "x")
assert ds["time"].shape == (ntimesteps,)
assert ds["time"].dims == ("time",)
assert ds["time"].values[0] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 15)
assert ds["time"].values[1] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 30)
assert ds["time"].values[2] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 45)
ds = Dataset(filename)
assert "var1" in ds.variables
var1_ds = ds.variables["var1"]
np.testing.assert_array_equal(var1_ds.shape, (ntimesteps, ny, nx))
assert "var2" in ds.variables
var2_ds = ds.variables["var2"]
np.testing.assert_array_equal(var2_ds.shape, (ntimesteps, nz, ny, nx))
assert var1_ds.dimensions == ("time", "y", "x")
assert var2_ds.dimensions == ("time", "z", "y", "x")
time_var = ds["time"]
dates = num2date(time_var[:], units=time_var.units, calendar=time_var.calendar)
assert time_var.shape == (ntimesteps,)
assert time_var.dimensions == ("time",)
assert dates[0] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 15)
assert dates[1] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 30)
assert dates[2] == cftime.DatetimeNoLeap(1, 1, 1, 0, 0, 45)
# data is just the timestep number
np.testing.assert_array_equal(ds["var1"].values[0, :, :], 1)
np.testing.assert_array_equal(ds["var1"].values[1, :, :], 2)
np.testing.assert_array_equal(ds["var1"].values[2, :, :], 3)
np.testing.assert_array_equal(ds["var2"].values[0, :, :, :], 2)
np.testing.assert_array_equal(ds["var2"].values[1, :, :, :], 4)
np.testing.assert_array_equal(ds["var2"].values[2, :, :, :], 6)
np.testing.assert_array_equal(var1_ds[0, :, :], 1)
np.testing.assert_array_equal(var1_ds[1, :, :], 2)
np.testing.assert_array_equal(var1_ds[2, :, :], 3)
np.testing.assert_array_equal(var2_ds[0, :, :, :], 2)
np.testing.assert_array_equal(var2_ds[1, :, :, :], 4)
np.testing.assert_array_equal(var2_ds[2, :, :, :], 6)

pyfms.fms.end()
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import cftime
import numpy as np
import pytest
import xarray as xr
import yaml
from netCDF4 import Dataset, num2date

from ndsl import (
DiagManagerMonitor,
Expand All @@ -22,12 +22,10 @@
)
from ndsl.config import Backend
from ndsl.initialization import SubtileGridSizer
from ndsl.optional_imports import pyfms


pyfms = pytest.importorskip("pyfms")


def _create_input(reduction: str = "none"):
def _create_input() -> None:
diag_config = {
"title": "ndsl_diag_manager_test",
"base_date": "2 1 1 1 1 1",
Expand Down Expand Up @@ -63,10 +61,10 @@ def _create_input(reduction: str = "none"):
f.write(text_content)


def test_dm_monitor_single_tile():
@pytest.mark.pyfms
def test_dm_monitor_single_tile() -> None:
# mpi info
npes = MPIComm()._comm.Get_size()
pe = MPIComm()._comm.Get_rank()
# tile parameters for quantities/domains
nx = 8
ny = 8
Expand Down Expand Up @@ -220,30 +218,30 @@ def test_dm_monitor_single_tile():

# check output!
assert Path("diag_manager_single_tile.nc").exists()
ds = xr.open_mfdataset("diag_manager_single_tile.nc", decode_times=True)
assert "var_2d" in ds
np.testing.assert_array_equal(ds["var_2d"].shape, (ntimesteps, nx, ny))
assert ds["var_2d"].dims == ("time", "y", "x")
assert ds["var_2d"].attrs["units"] == "muntin"
assert ds["var_3d"].dims == ("time", "z", "y", "x")
assert ds["var_3d"].attrs["units"] == "muntin"
assert ds["time"].shape == (ntimesteps,)
assert ds["time"].dims == ("time",)
assert ds["time"].values[0] == cftime.DatetimeNoLeap(2, 1, 1, 2, 1, 1)
assert ds["time"].values[1] == cftime.DatetimeNoLeap(2, 1, 1, 3, 1, 1)
assert ds["time"].values[2] == cftime.DatetimeNoLeap(2, 1, 1, 4, 1, 1)
np.testing.assert_array_equal(ds["var_2d"].values[0, :, :], var2_global.transpose())
np.testing.assert_array_equal(ds["var_2d"].values[1, :, :], var2_global.transpose())
np.testing.assert_array_equal(ds["var_2d"].values[2, :, :], var2_global.transpose())
ds = Dataset("diag_manager_single_tile.nc")
assert "var_2d" in ds.variables
assert "time" in ds.variables
assert "var_3d" in ds.variables
var2_ds = ds.variables["var_2d"]
time_var = ds.variables["time"]
var3_ds = ds.variables["var_3d"]
np.testing.assert_array_equal(var2_ds.shape, (ntimesteps, nx, ny))
assert var2_ds.dimensions == ("time", "y", "x")
assert var2_ds.units == "muntin"
assert var3_ds.dimensions == ("time", "z", "y", "x")
assert var3_ds.units == "muntin"
assert time_var.shape == (ntimesteps,)
assert time_var.dimensions == ("time",)
dates = num2date(time_var[:], units=time_var.units, calendar=time_var.calendar)
assert dates[0] == cftime.DatetimeNoLeap(2, 1, 1, 2, 1, 1)
assert dates[1] == cftime.DatetimeNoLeap(2, 1, 1, 3, 1, 1)
assert dates[2] == cftime.DatetimeNoLeap(2, 1, 1, 4, 1, 1)
np.testing.assert_array_equal(var2_ds[0, :, :], var2_global.transpose())
np.testing.assert_array_equal(var2_ds[1, :, :], var2_global.transpose())
np.testing.assert_array_equal(var2_ds[2, :, :], var2_global.transpose())
# data is transposed when passed into fortran
np.testing.assert_array_equal(
ds["var_3d"].values[0, :, :, :], var3_global.transpose()
)
np.testing.assert_array_equal(
ds["var_3d"].values[1, :, :, :], var3_global.transpose()
)
np.testing.assert_array_equal(
ds["var_3d"].values[2, :, :, :], var3_global.transpose()
)
np.testing.assert_array_equal(var3_ds[0, :, :, :], var3_global.transpose())
np.testing.assert_array_equal(var3_ds[1, :, :, :], var3_global.transpose())
np.testing.assert_array_equal(var3_ds[2, :, :, :], var3_global.transpose())

pyfms.fms.end()
File renamed without changes.
File renamed without changes.