From 31bdbb90071c29d634ae2f46a8e3382edb3239f4 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Wed, 31 Dec 2025 12:17:13 -0500 Subject: [PATCH 1/5] add gridc and gridt --- fmsgridtools/shared/gridobj.py | 68 ++++++++++++++++++++++++++++++-- fmsgridtools/shared/mosaicobj.py | 2 - pyFMS | 1 - tests/shared/test_gridobj.py | 36 ++++++++++++----- tests/shared/test_xgridobj.py | 10 ++--- 5 files changed, 96 insertions(+), 21 deletions(-) delete mode 160000 pyFMS diff --git a/fmsgridtools/shared/gridobj.py b/fmsgridtools/shared/gridobj.py index 9a08048..bc0bd78 100644 --- a/fmsgridtools/shared/gridobj.py +++ b/fmsgridtools/shared/gridobj.py @@ -86,6 +86,24 @@ def __init__(self, name: str = None, data=None): self.name = name self.data = data +class MiniGridObj: + + def __init__(self, xsize: int = None, ysize: int = None, x: npt.NDArray = None, y: npt.NDArray = None): + self.xsize = xsize + self.ysize = ysize + self.x = x + self.y = y + + def set_size(self): + + xsize, ysize = self.x.shape + + if self.x.shape != self.y.shape: + logger.error("MiniGrid, x and y differ in dimensions") + + self.xsize = xsize + self.ysize = ysize + class GridObj: """ @@ -136,6 +154,9 @@ def __init__( self._set_dims() + self.gridc = MiniGridObj() + self.gridt = MiniGridObj() + logger.info("Created new GridObj named:\n %s", self.__repr__()) def to_domain(self, domain: dict = None): @@ -212,12 +233,54 @@ def get_fms_area(self): self.area = pyfms.grid_utils.get_grid_area(lon=x, lat=y, convert_cf_order=False) return self.area + def get_gridc(self): + + """ + Save the edge points + """ + + if self.x is None or self.y is None: + logger.error("Cannot set gridc. Please set x and y values first") + + self.gridc.x = np.ascontiguousarray(self.x[::2, ::2]) + self.gridc.y = np.ascontiguousarray(self.y[::2, ::2]) + self.gridc.set_size() + + return self.gridc + + def get_gridt(self): + + """ + Save the center points + """ + + if self.x is None or self.y is None: + logger.error("Cannot set gridt. Please set and y values first") + + self.gridt.x = np.ascontiguousarray(self.x[1::2, 1::2]) + self.gridt.y = np.ascontiguousarray(self.x[1::2, 1::2]) + self.gridt.set_size() + + return self.gridt + + def free_supergrid(self): + + self.x = None + self.y = None + + def free_gridc(self): + + self.gridc = None + + def free_gridt(self): + + self.gridt = None + def read( self, gridfile: str = None, domain: dict = None, radians: bool = False, - center: bool = False, on_domain: bool = False, xy_only: bool = False, ): @@ -252,9 +315,6 @@ def read( for obj in objlist: if obj.name in ds: obj.data = ds[obj.name].data - if center: - logger.info("saving center points for %s", {obj.name}) - obj.data = np.ascontiguousarray(obj.data[::2, ::2]) else: logger.warning("could not %s in %s", {obj.name}, {self.gridfile}) diff --git a/fmsgridtools/shared/mosaicobj.py b/fmsgridtools/shared/mosaicobj.py index f6fd772..fe9422f 100644 --- a/fmsgridtools/shared/mosaicobj.py +++ b/fmsgridtools/shared/mosaicobj.py @@ -159,7 +159,6 @@ def get_grid( self, input_dir: str | Path = "./", radians: bool = False, - center: bool = False, domain: pyfms.Domain = None, ) -> dict: """ @@ -183,7 +182,6 @@ def get_grid( readfile = Path(input_dir) / gridfile grid[gridtile] = GridObj(gridfile=readfile).read( radians=radians, - center=center, domain=domain, on_domain=False if domain is None else True, xy_only=True, diff --git a/pyFMS b/pyFMS deleted file mode 160000 index 4e828f0..0000000 --- a/pyFMS +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4e828f0f7f1253e7be166fd8efb11608da13a282 diff --git a/tests/shared/test_gridobj.py b/tests/shared/test_gridobj.py index fc6628c..217a9bc 100644 --- a/tests/shared/test_gridobj.py +++ b/tests/shared/test_gridobj.py @@ -155,7 +155,7 @@ def test_read_write(set_fms_files): pyfms.fms.end() -def test_center_option(set_fms_files): +def test_minigrids_option(set_fms_files): pyfms.fms.init() @@ -171,22 +171,40 @@ def test_center_option(set_fms_files): GridObj(gridfile=gridfile, x=x, y=y).write() - grid = GridObj(gridfile=gridfile).read(center=True, radians=True, xy_only=True) + #test gridc + grid = GridObj(gridfile=gridfile).read(radians=True, xy_only=True) + gridc = grid.get_gridc() - assert grid.nx == nx2 - assert grid.ny == ny2 - assert grid.nxp == nx2 + 1 - assert grid.nyp == ny2 + 1 + assert gridc.xsize == nx2p + assert gridc.ysize == ny2p answer = np.radians(np.ones((ny2p, nx2p), dtype=np.float64)) + np.testing.assert_array_equal(gridc.x, answer) + np.testing.assert_array_equal(gridc.y, answer) - np.testing.assert_array_equal(grid.x, answer) - np.testing.assert_array_equal(grid.y, answer) + grid.free_gridc() + assert grid.gridc is None + + #test gridt + gridt = grid.get_gridt() + + assert gridt.xsize == nx2 + assert gridt.ysize == ny2 + + answer = np.zeros((ny2, nx2), dtype=np.float64) + np.testing.assert_array_equal(gridt.x, answer) + np.testing.assert_array_equal(gridt.y, answer) + + grid.free_gridt() + assert grid.gridt is None + + grid.free_supergrid() + assert grid.x is grid.y is None gridfile.unlink() pyfms.fms.end() - +@pytest.mark.skip("error in pyFMS") def test_to_domain(set_fms_files): nx, ny = 8, 8 diff --git a/tests/shared/test_xgridobj.py b/tests/shared/test_xgridobj.py index 64c69d6..226f6a9 100755 --- a/tests/shared/test_xgridobj.py +++ b/tests/shared/test_xgridobj.py @@ -19,7 +19,7 @@ def generate_mosaic(nx: int = 90, ny: int = 45, refine: int = 2): x_tgt = np.linspace(xstart, xend, nx*refine+1) y_tgt = np.linspace(ystart, yend, ny*refine+1) x_tgt, y_tgt = np.meshgrid(x_tgt, y_tgt) - + area_src = np.ones((ny, nx), dtype=np.float64) area_tgt = np.ones((ny*refine, nx*refine), dtype=np.float64) @@ -64,9 +64,9 @@ def test_create_xgrid(on_gpu): xgrid.create_xgrid() xgrid.to_dataset() xgrid.dataset["tile1"]["tile1"].to_netcdf("remap.nc") - + del xgrid - + xgrid = fmsgridtools.XGridObj(restart_remap_file="remap.nc") #check nxcells @@ -79,7 +79,7 @@ def test_create_xgrid(on_gpu): src_i = [xgrid.src_cell[i][0] for i in range(nxcells)] src_j = [xgrid.src_cell[i][1] for i in range(nxcells)] - + assert src_i == answer_i assert src_j == answer_j @@ -94,7 +94,7 @@ def test_create_xgrid(on_gpu): for i in range(nx): for ixcell in range(refine): answer_j += [j*refine + ixcell + 1]*refine - + tgt_i = [xgrid.tgt_cell[i][0] for i in range(nxcells)] tgt_j = [xgrid.tgt_cell[i][1] for i in range(nxcells)] From a669ca48927391638ad7b42234917b0b182a3660 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Wed, 31 Dec 2025 12:20:35 -0500 Subject: [PATCH 2/5] add pyFMS back --- pyFMS | 1 + 1 file changed, 1 insertion(+) create mode 160000 pyFMS diff --git a/pyFMS b/pyFMS new file mode 160000 index 0000000..3752b67 --- /dev/null +++ b/pyFMS @@ -0,0 +1 @@ +Subproject commit 3752b67a905844db75a35a23a1562673fd7e633e From da5e67a0fe901810cc507c3fca0cc0b64d157375 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Wed, 31 Dec 2025 12:27:19 -0500 Subject: [PATCH 3/5] update test.yaml --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 380a973..6a74af0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -29,7 +29,7 @@ jobs: pytest tests/shared/test_libs.py pytest tests/mosaic/test_mosaic.py pytest tests/shared/test_gridobj.py::test_read_write - pytest tests/shared/test_gridobj.py::test_center_option + pytest tests/shared/test_gridobj.py::test_minigrids_option pytest tests/shared/test_gridobj.py::test_to_domain #pytest tests/shared/test_xgridobj.py #pytest tests/hgrid/test_hgrid.py From 059ef3bbb48ccea77552f2a0258d3b9b6e5eb437 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Fri, 2 Jan 2026 12:26:31 -0500 Subject: [PATCH 4/5] update pyFMS --- .gitmodules | 5 +++-- pyFMS | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index a1798d3..da47447 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,5 @@ [submodule "pyFMS"] - path = pyFMS - url = https://github.com/NOAA-GFDL/pyFMS.git + path = pyFMS + branch = fmsgridtools-development + url = https://github.com/mlee03/pyFMS.git diff --git a/pyFMS b/pyFMS index 3752b67..b4312ad 160000 --- a/pyFMS +++ b/pyFMS @@ -1 +1 @@ -Subproject commit 3752b67a905844db75a35a23a1562673fd7e633e +Subproject commit b4312adc95c659bb990cc4bcb9a9aaa561724402 From 96f5ec505d2ec685d44e356afa09c6815dcbe991 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Fri, 2 Jan 2026 12:56:29 -0500 Subject: [PATCH 5/5] update submodules to mlee03, turn test on --- pyFMS | 2 +- tests/shared/test_gridobj.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyFMS b/pyFMS index b4312ad..eed066f 160000 --- a/pyFMS +++ b/pyFMS @@ -1 +1 @@ -Subproject commit b4312adc95c659bb990cc4bcb9a9aaa561724402 +Subproject commit eed066faf6dc1796e297f5040663331bea9d6b42 diff --git a/tests/shared/test_gridobj.py b/tests/shared/test_gridobj.py index 217a9bc..f1c3a75 100644 --- a/tests/shared/test_gridobj.py +++ b/tests/shared/test_gridobj.py @@ -204,7 +204,7 @@ def test_minigrids_option(set_fms_files): gridfile.unlink() pyfms.fms.end() -@pytest.mark.skip("error in pyFMS") +#@pytest.mark.skip("error in pyFMS") def test_to_domain(set_fms_files): nx, ny = 8, 8