From 088e4686f958d53f6c2a1eef0b34f9f94960343c Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 22 Jan 2025 10:01:56 -0500 Subject: [PATCH 01/72] Staging GridObj changes --- gridtools/shared/gridobj.py | 142 ++++++++++++++++++++++++++- tests/shared/test_gridobj.py | 44 ++++++--- tests/shared/test_gridtools_utils.py | 4 +- 3 files changed, 170 insertions(+), 20 deletions(-) diff --git a/gridtools/shared/gridobj.py b/gridtools/shared/gridobj.py index 7b9f666..43312a9 100644 --- a/gridtools/shared/gridobj.py +++ b/gridtools/shared/gridobj.py @@ -1,20 +1,152 @@ import numpy as np import numpy.typing as npt import xarray as xr -from typing import List, Optional, Type +from typing import List, Optional import dataclasses +from gridtools.shared.gridtools_utils import check_file_is_there + @dataclasses.dataclass class GridObj: - grid: Optional[xr.Dataset] = None - gridfile: Optional[str] = None + grid_data: Optional[xr.Dataset] = None + grid_file: Optional[str] = None + x: Optional[npt.NDArray] = None + y: Optional[npt.NDArray] = None + dx: Optional[npt.NDArray] = None + dy: Optional[npt.NDArray] = None + area: Optional[npt.NDArray] = None + angle_dx: Optional[npt.NDArray] = None + angle_dy: Optional[npt.NDArray] = None + + def __post_init__(self): + if self.grid_data is not None: + self.x = self.grid_data.x.values + self.y = self.grid_data.y.values + self.dx = self.grid_data.dx.values + self.dy = self.grid_data.dy.values + self.area = self.grid_data.area.values + self.angle_dx = self.grid_data.angle_dx.values + self.angle_dy = self.grid_data.angle_dy.values + elif self.grid_file is not None: + self.from_file(self.grid_file) + else: + pass @classmethod def from_file(cls, filepath: str) -> "GridObj": + """ + This class method will return an instance of GridObj with attributes + matching the contents of the passed netcdf file containing the grid + data. + """ + _x = None + _y = None + _dx = None + _dy = None + _area = None + _angle_dx = None + _angle_dy = None + check_file_is_there(filepath) with xr.open_dataset(filepath) as ds: - return cls(grid=ds, gridfile=filepath) + return cls( + grid_data=ds, + grid_file=filepath, + x = ds.x.values, + y = ds.y.values, + dx = ds.dx.values, + dy = ds.dy.values, + area = ds.area.values, + angle_dx = ds.angle_dx.values, + angle_dy = ds.angle_dy.values, + ) def write_out_grid(self, filepath: str): - self.grid.to_netcdf(filepath) + """ + This method will generate a netcdf file containing the contents of the + grid_data attribute. + """ + if self.x is not None: + x = xr.DataArray( + data=self.x, + dims=["nyp", "nxp"], + attrs=dict( + units="degree_east", + standard_name="geographic_longitude", + ) + ) + if self.y is not None: + y = xr.DataArray( + data=self.y, + dims=["nyp", "nxp"], + attrs=dict( + units="degree_north", + standard_name="geographic_latitude", + ) + ) + if self.dx is not None: + dx = xr.DataArray( + data=self.dx, + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", + ) + ) + if self.dy is not None: + dy = xr.DataArray( + data=self.dy, + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", + ) + ) + if self.area is not None: + area = xr.DataArray( + data=self.area, + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", + ) + ) + if self.angle_dx is not None: + angle_dx = xr.DataArray( + data=self.angle_dx, + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", + ) + ) + if self.angle_dy is not None: + angle_dy = xr.DataArray( + data=self.angle_dy, + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", + ) + ) + + out_grid_dataset = xr.Dataset( + data_vars={ + "x": x, + "y": y, + "dx": dx, + "dy": dy, + "area": area, + "angle_dx": angle_dx, + "angle_dy": angle_dy, + } + ) + out_grid_dataset.to_netcdf(filepath) + + def get_variable_list(self) -> List: + """ + This method returns a list of variables contained within the grid_data + dataset. + """ + return list(self.grid_data.data_vars) #TODO: I/O method for passing to the host \ No newline at end of file diff --git a/tests/shared/test_gridobj.py b/tests/shared/test_gridobj.py index 3185e35..a3a76fd 100644 --- a/tests/shared/test_gridobj.py +++ b/tests/shared/test_gridobj.py @@ -7,6 +7,9 @@ from gridtools import GridObj def test_read_and_write_gridstruct(tmp_path): + """ + Creating data to generate xarray dataset from + """ nx = 3 ny = 3 nxp = nx + 1 @@ -103,23 +106,38 @@ def test_read_and_write_gridstruct(tmp_path): file_path = tmp_path / "test_grid.nc" - out_grid_obj = GridObj(grid=out_grid_dataset, gridfile=file_path) + empty_grid_obj = GridObj() - out_grid_obj.write_out_grid(filepath=file_path) + assert isinstance(empty_grid_obj, GridObj) + + from_dataset_grid_obj = GridObj(grid_data=out_grid_dataset) + assert from_dataset_grid_obj.grid_data is not None + assert from_dataset_grid_obj.grid_file is None + + from_dataset_grid_obj.write_out_grid(filepath=file_path) assert file_path.exists() - in_grid_obj = GridObj.from_file(filepath=file_path) - - assert in_grid_obj.grid.tile == out_grid_obj.grid.tile - np.testing.assert_array_equal(in_grid_obj.grid.x, out_grid_obj.grid.x) - np.testing.assert_array_equal(in_grid_obj.grid.y, out_grid_obj.grid.y) - np.testing.assert_array_equal(in_grid_obj.grid.dx, out_grid_obj.grid.dx) - np.testing.assert_array_equal(in_grid_obj.grid.dy, out_grid_obj.grid.dy) - np.testing.assert_array_equal(in_grid_obj.grid.area, out_grid_obj.grid.area) - np.testing.assert_array_equal(in_grid_obj.grid.angle_dx, out_grid_obj.grid.angle_dx) - np.testing.assert_array_equal(in_grid_obj.grid.angle_dy, out_grid_obj.grid.angle_dy) - assert in_grid_obj.grid.arcx == out_grid_obj.grid.arcx + from_file_grid_obj = GridObj(grid_file=file_path) + assert from_file_grid_obj.grid_data is None + assert from_file_grid_obj.grid_file is not None + + assert isinstance(from_file_grid_obj, GridObj) + + from_file_meth_grid_obj = GridObj.from_file(filepath=file_path) + + """ + Checking if from_file class method generates instance of GridObj, + and compares contents to file contents + """ + assert isinstance(from_file_meth_grid_obj, GridObj) + np.testing.assert_array_equal(from_file_meth_grid_obj.x, from_dataset_grid_obj.x) + np.testing.assert_array_equal(from_file_meth_grid_obj.y, from_dataset_grid_obj.y) + np.testing.assert_array_equal(from_file_meth_grid_obj.dx, from_dataset_grid_obj.dx) + np.testing.assert_array_equal(from_file_meth_grid_obj.dy, from_dataset_grid_obj.dy) + np.testing.assert_array_equal(from_file_meth_grid_obj.area, from_dataset_grid_obj.area) + np.testing.assert_array_equal(from_file_meth_grid_obj.angle_dx, from_dataset_grid_obj.angle_dx) + np.testing.assert_array_equal(from_file_meth_grid_obj.angle_dy, from_dataset_grid_obj.angle_dy) file_path.unlink() diff --git a/tests/shared/test_gridtools_utils.py b/tests/shared/test_gridtools_utils.py index 0c8b2a5..5b6ef68 100644 --- a/tests/shared/test_gridtools_utils.py +++ b/tests/shared/test_gridtools_utils.py @@ -7,13 +7,13 @@ def test_check_file_is_there() : testfile = 'file_is_here' with open(testfile, 'w') as myfile : pass - gridtools.check_file_is_there(testfile) + check_file_is_there(testfile) os.remove(testfile) @pytest.mark.xfail def test_check_file_is_not_there() : testfile = 'file_is_not_here' - gridtools.check_file_is_there(testfile) + check_file_is_there(testfile) From 8e23e5389b1209609db34f4d070d37aafc67fa17 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 22 Jan 2025 16:35:05 -0500 Subject: [PATCH 02/72] Changed method of access and added methods to GridObj --- gridtools/shared/gridobj.py | 218 ++++++++++++++++++++++------ tests/shared/test_gridobj.py | 267 ++++++++++++++++++++--------------- 2 files changed, 328 insertions(+), 157 deletions(-) diff --git a/gridtools/shared/gridobj.py b/gridtools/shared/gridobj.py index 43312a9..0ffb4b2 100644 --- a/gridtools/shared/gridobj.py +++ b/gridtools/shared/gridobj.py @@ -1,15 +1,22 @@ +import dataclasses +from typing import List, Optional + import numpy as np import numpy.typing as npt import xarray as xr -from typing import List, Optional -import dataclasses from gridtools.shared.gridtools_utils import check_file_is_there +""" +GridObj: + +Dataclass for containing basic grid data to be used by other grid objects +""" @dataclasses.dataclass class GridObj: grid_data: Optional[xr.Dataset] = None grid_file: Optional[str] = None + tile: Optional[str] = None x: Optional[npt.NDArray] = None y: Optional[npt.NDArray] = None dx: Optional[npt.NDArray] = None @@ -17,120 +24,210 @@ class GridObj: area: Optional[npt.NDArray] = None angle_dx: Optional[npt.NDArray] = None angle_dy: Optional[npt.NDArray] = None + arcx: Optional[str] = None def __post_init__(self): if self.grid_data is not None: - self.x = self.grid_data.x.values - self.y = self.grid_data.y.values - self.dx = self.grid_data.dx.values - self.dy = self.grid_data.dy.values - self.area = self.grid_data.area.values - self.angle_dx = self.grid_data.angle_dx.values - self.angle_dy = self.grid_data.angle_dy.values + varlist = list(self.grid_data.data_vars) + if "tile" in varlist: + self.tile = self.grid_data.tile.values.item().decode('ascii') + if "x" in varlist: + self.x = np.ascontiguousarray(self.grid_data.x.values) + if "y" in varlist: + self.y = np.ascontiguousarray(self.grid_data.y.values) + if "dx" in varlist: + self.dx = np.ascontiguousarray(self.grid_data.dx.values) + if "dy" in varlist: + self.dy = np.ascontiguousarray(self.grid_data.dy.values) + if "area" in varlist: + self.area = np.ascontiguousarray(self.grid_data.area.values) + if "angle_dx" in varlist: + self.angle_dx = np.ascontiguousarray(self.grid_data.angle_dx.values) + if "angle_dy" in varlist: + self.angle_dy = np.ascontiguousarray(self.grid_data.angle_dy.values) + if "arcx" in varlist: + self.arcx = self.grid_data.arcx.values.item().decode('ascii') elif self.grid_file is not None: - self.from_file(self.grid_file) + check_file_is_there(self.grid_file) + with xr.open_dataset(self.grid_file) as ds: + self.grid_data = ds + varlist = list(self.grid_data.data_vars) + if "tile" in varlist: + self.tile = self.grid_data.tile.values.item().decode('ascii') + if "x" in varlist: + self.x = np.ascontiguousarray(self.grid_data.x.values) + if "y" in varlist: + self.y = np.ascontiguousarray(self.grid_data.y.values) + if "dx" in varlist: + self.dx = np.ascontiguousarray(self.grid_data.dx.values) + if "dy" in varlist: + self.dy = np.ascontiguousarray(self.grid_data.dy.values) + if "area" in varlist: + self.area = np.ascontiguousarray(self.grid_data.area.values) + if "angle_dx" in varlist: + self.angle_dx = np.ascontiguousarray(self.grid_data.angle_dx.values) + if "angle_dy" in varlist: + self.angle_dy = np.ascontiguousarray(self.grid_data.angle_dy.values) + if "arcx" in varlist: + self.arcx = self.grid_data.arcx.values.item().decode('ascii') else: pass + """ + from_file: + + This class method will return an instance of GridObj with attributes + matching the contents of the passed netcdf file containing the grid + data. + """ @classmethod def from_file(cls, filepath: str) -> "GridObj": - """ - This class method will return an instance of GridObj with attributes - matching the contents of the passed netcdf file containing the grid - data. - """ - _x = None - _y = None - _dx = None - _dy = None - _area = None - _angle_dx = None - _angle_dy = None check_file_is_there(filepath) with xr.open_dataset(filepath) as ds: + varlist = list(ds.data_vars) + if "tile" in varlist: + _tile = ds.tile.values.item().decode('ascii') + if "x" in varlist: + _x = np.ascontiguousarray(ds.x.values) + if "y" in varlist: + _y = np.ascontiguousarray(ds.y.values) + if "dx" in varlist: + _dx = np.ascontiguousarray(ds.dx.values) + if "dy" in varlist: + _dy = np.ascontiguousarray(ds.dy.values) + if "area" in varlist: + _area = np.ascontiguousarray(ds.area.values) + if "angle_dx" in varlist: + _angle_dx = np.ascontiguousarray(ds.angle_dx.values) + if "angle_dy" in varlist: + _angle_dy = np.ascontiguousarray(ds.angle_dy.values) + if "arcx" in varlist: + _arcx = ds.arcx.values.item().decode('ascii') return cls( grid_data=ds, grid_file=filepath, - x = ds.x.values, - y = ds.y.values, - dx = ds.dx.values, - dy = ds.dy.values, - area = ds.area.values, - angle_dx = ds.angle_dx.values, - angle_dy = ds.angle_dy.values, + tile = _tile, + x = _x, + y = _y, + dx = _dx, + dy = _dy, + area = _area, + angle_dx = _angle_dx, + angle_dy = _angle_dy, + arcx = _arcx, ) + """ + write_out_grid: + + This method will generate a netcdf file containing the contents of the + grid_data attribute. + """ def write_out_grid(self, filepath: str): - """ - This method will generate a netcdf file containing the contents of the - grid_data attribute. - """ + if self.tile is not None: + tile = xr.DataArray( + [self.tile.encode("utf-8")], + attrs=dict( + standard_name = "grid_tile_spec", + geometry = "spherical", + north_pole = "0.0 90.0", + projection = "cube_gnomonic", + discretization = "logically_rectangular", + conformal = "FALSE", + ) + ) + else: + tile = None if self.x is not None: x = xr.DataArray( data=self.x, dims=["nyp", "nxp"], attrs=dict( - units="degree_east", + units="degree_east", standard_name="geographic_longitude", ) ) + else: + x = None if self.y is not None: y = xr.DataArray( data=self.y, dims=["nyp", "nxp"], attrs=dict( - units="degree_north", + units="degree_north", standard_name="geographic_latitude", ) ) + else: + y = None if self.dx is not None: dx = xr.DataArray( data=self.dx, dims=["nyp", "nx"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_x_distance", ) ) + else: + dx = None if self.dy is not None: dy = xr.DataArray( data=self.dy, dims=["ny", "nxp"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_y_distance", ) ) + else: + dy = None if self.area is not None: area = xr.DataArray( data=self.area, dims=["ny", "nx"], attrs=dict( - units="m2", + units="m2", standard_name="grid_cell_area", ) ) + else: + area = None if self.angle_dx is not None: angle_dx = xr.DataArray( data=self.angle_dx, dims=["nyp", "nxp"], attrs=dict( - units="degrees_east", + units="degrees_east", standard_name="grid_vertex_x_angle_WRT_geographic_east", ) ) + else: + angle_dx = None if self.angle_dy is not None: angle_dy = xr.DataArray( data=self.angle_dy, dims=["nyp", "nxp"], attrs=dict( - units="degrees_east", + units="degrees_east", standard_name="grid_vertex_x_angle_WRT_geographic_east", ) ) - + else: + angle_dy = None + if self.arcx is not None: + arcx = xr.DataArray( + [self.arcx.encode("utf-8")], + attrs=dict( + standard_name = "grid_edge_x_arc_type", + north_pole = "0.0 90.0", + ) + ) + else: + arcx = None out_grid_dataset = xr.Dataset( data_vars={ + "tile": tile, "x": x, "y": y, "dx": dx, @@ -138,15 +235,44 @@ def write_out_grid(self, filepath: str): "area": area, "angle_dx": angle_dx, "angle_dy": angle_dy, + "arcx": arcx, } ) out_grid_dataset.to_netcdf(filepath) + """ + get_agrid_lonlat: + + This method returns the lon and lat for the A-grid as calculated from the + x and y attributes of the GridObj. + """ + def get_agrid_lonlat(self)-> tuple[npt.NDArray, npt.NDArray]: + D2R = np.pi/180 + a_lon = None + a_lat = None + if self.x is not None and self.y is not None: + nx = (self.x.shape[1]-1)//2 + ny = (self.x.shape[0]-1)//2 + x_flat = self.x.flatten() + y_flat = self.y.flatten() + + a_lon = np.zeros(shape=nx) + a_lat = np.zeros(shape=ny) + + for i in range(nx): + a_lon[i] = x_flat[2*nx+1+2*i+1]*D2R + for j in range(ny): + a_lat[i] = y_flat[(2*j+1)*(2*nx+1)+1]*D2R + + return np.ascontiguousarray(a_lon), np.ascontiguousarray(a_lat) + + """ + get_variable_list: + + This method returns a list of variables contained within the grid_data + dataset. + """ def get_variable_list(self) -> List: - """ - This method returns a list of variables contained within the grid_data - dataset. - """ return list(self.grid_data.data_vars) -#TODO: I/O method for passing to the host \ No newline at end of file +#TODO: I/O method for passing to the host diff --git a/tests/shared/test_gridobj.py b/tests/shared/test_gridobj.py index a3a76fd..6cdfddf 100644 --- a/tests/shared/test_gridobj.py +++ b/tests/shared/test_gridobj.py @@ -1,144 +1,189 @@ import os -import pytest -import xarray as xr import numpy as np +import xarray as xr from gridtools import GridObj -def test_read_and_write_gridstruct(tmp_path): - """ - Creating data to generate xarray dataset from - """ - nx = 3 - ny = 3 - nxp = nx + 1 - nyp = ny + 1 - - tile = xr.DataArray( - ["tile1"], - attrs=dict( - standard_name="grid_tile_spec", - geometry="spherical", - north_pole="0.0 90.0", - projection="cube_gnomonic", - discretization="logically_rectangular", - ) + +""" +Creating data to generate xarray dataset from +""" + +nx = 3 +ny = 3 +nxp = nx + 1 +nyp = ny + 1 + +tile = xr.DataArray( + [b'tile1'], + attrs=dict( + standard_name="grid_tile_spec", + geometry="spherical", + north_pole="0.0 90.0", + projection="cube_gnomonic", + discretization="logically_rectangular", ) - x = xr.DataArray( - data=np.full(shape=(nyp,nxp), fill_value=1.0, dtype=np.float64), - dims=["nyp", "nxp"], - attrs=dict( - units="degree_east", - standard_name="geographic_longitude", - ) +) +x = xr.DataArray( + data=np.full(shape=(nyp,nxp), fill_value=1.0, dtype=np.float64), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_east", + standard_name="geographic_longitude", ) - y = xr.DataArray( - data=np.full(shape=(nyp,nxp), fill_value=2.0, dtype=np.float64), - dims=["nyp", "nxp"], - attrs=dict( - units="degree_north", - standard_name="geographic_latitude", - ) +) +y = xr.DataArray( + data=np.full(shape=(nyp,nxp), fill_value=2.0, dtype=np.float64), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_north", + standard_name="geographic_latitude", ) - dx = xr.DataArray( - data=np.full(shape=(nyp,nx), fill_value=1.5, dtype=np.float64), - dims=["nyp", "nx"], - attrs=dict( - units="meters", - standard_name="grid_edge_x_distance", - ) +) +dx = xr.DataArray( + data=np.full(shape=(nyp,nx), fill_value=1.5, dtype=np.float64), + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", ) - dy = xr.DataArray( - data=np.full(shape=(ny,nxp), fill_value=2.5, dtype=np.float64), - dims=["ny", "nxp"], - attrs=dict( - units="meters", - standard_name="grid_edge_y_distance", - ) +) +dy = xr.DataArray( + data=np.full(shape=(ny,nxp), fill_value=2.5, dtype=np.float64), + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", ) - area = xr.DataArray( - data=np.full(shape=(ny,nx), fill_value=4.0, dtype=np.float64), - dims=["ny", "nx"], - attrs=dict( - units="m2", - standard_name="grid_cell_area", - ) +) +area = xr.DataArray( + data=np.full(shape=(ny,nx), fill_value=4.0, dtype=np.float64), + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", ) - angle_dx = xr.DataArray( - data=np.full(shape=(nyp,nxp), fill_value=3.0, dtype=np.float64), - dims=["nyp", "nxp"], - attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", - ) +) +angle_dx = xr.DataArray( + data=np.full(shape=(nyp,nxp), fill_value=3.0, dtype=np.float64), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", ) - angle_dy = xr.DataArray( - data=np.full(shape=(nyp,nxp), fill_value=5.0, dtype=np.float64), - dims=["nyp", "nxp"], - attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", - ) +) +angle_dy = xr.DataArray( + data=np.full(shape=(nyp,nxp), fill_value=5.0, dtype=np.float64), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", ) - arcx = xr.DataArray( - ["arcx"], - attrs=dict( - standard_name="grid_edge_x_arc_type", - north_pole="0.0 90.0", - _FillValue=False, - ) +) +arcx = xr.DataArray( + [b'arcx'], + attrs=dict( + standard_name="grid_edge_x_arc_type", + north_pole="0.0 90.0", + _FillValue=False, ) - - out_grid_dataset = xr.Dataset( - data_vars={ - "tile": tile, - "x": x, - "y": y, - "dx": dx, - "dy": dy, - "area": area, - "angle_dx": angle_dx, - "angle_dy": angle_dy, - "arcx": arcx, - } - ) - - file_path = tmp_path / "test_grid.nc" +) + +out_grid_dataset = xr.Dataset( + data_vars={ + "tile": tile, + "x": x, + "y": y, + "dx": dx, + "dy": dy, + "area": area, + "angle_dx": angle_dx, + "angle_dy": angle_dy, + "arcx": arcx, + } +) + +def test_empty_grid_obj(): empty_grid_obj = GridObj() - assert isinstance(empty_grid_obj, GridObj) +def test_gridobj_from_dataset(): + from_dataset_grid_obj = GridObj(grid_data=out_grid_dataset) + assert isinstance(from_dataset_grid_obj, GridObj) assert from_dataset_grid_obj.grid_data is not None assert from_dataset_grid_obj.grid_file is None + np.testing.assert_array_equal(from_dataset_grid_obj.x, out_grid_dataset.x.values) + np.testing.assert_array_equal(from_dataset_grid_obj.y, out_grid_dataset.y.values) + np.testing.assert_array_equal(from_dataset_grid_obj.dx, out_grid_dataset.dx.values) + np.testing.assert_array_equal(from_dataset_grid_obj.dy, out_grid_dataset.dy.values) + np.testing.assert_array_equal(from_dataset_grid_obj.area, out_grid_dataset.area.values) + np.testing.assert_array_equal(from_dataset_grid_obj.angle_dx, out_grid_dataset.angle_dx.values) + np.testing.assert_array_equal(from_dataset_grid_obj.angle_dy, out_grid_dataset.angle_dy) + +def test_write_out_grid_griddata(tmp_path): + + from_dataset_grid_obj = GridObj(grid_data=out_grid_dataset) + + file_path = tmp_path / "test_grid.nc" + from_dataset_grid_obj.write_out_grid(filepath=file_path) assert file_path.exists() - from_file_grid_obj = GridObj(grid_file=file_path) - assert from_file_grid_obj.grid_data is None - assert from_file_grid_obj.grid_file is not None + file_path.unlink() - assert isinstance(from_file_grid_obj, GridObj) + assert not file_path.exists() + +def test_gridobj_from_gridfile_init(tmp_path): + + from_dataset_grid_obj = GridObj(grid_data=out_grid_dataset) + + file_path = tmp_path / "test_grid.nc" + + from_dataset_grid_obj.write_out_grid(filepath=file_path) + + from_file_init_grid_obj = GridObj(grid_file=file_path) + assert isinstance(from_file_init_grid_obj, GridObj) + assert from_file_init_grid_obj.grid_file is not None + + # print(from_file_init_grid_obj.x) + + np.testing.assert_array_equal(from_file_init_grid_obj.x, out_grid_dataset.x.values) + np.testing.assert_array_equal(from_file_init_grid_obj.y, out_grid_dataset.y.values) + np.testing.assert_array_equal(from_file_init_grid_obj.dx, out_grid_dataset.dx.values) + np.testing.assert_array_equal(from_file_init_grid_obj.dy, out_grid_dataset.dy.values) + np.testing.assert_array_equal(from_file_init_grid_obj.area, out_grid_dataset.area.values) + np.testing.assert_array_equal(from_file_init_grid_obj.angle_dx, out_grid_dataset.angle_dx.values) + np.testing.assert_array_equal(from_file_init_grid_obj.angle_dy, out_grid_dataset.angle_dy) + + file_path.unlink() + + assert not file_path.exists() + +def test_gridobj_from_file(tmp_path): + + from_dataset_grid_obj = GridObj(grid_data=out_grid_dataset) - from_file_meth_grid_obj = GridObj.from_file(filepath=file_path) - - """ - Checking if from_file class method generates instance of GridObj, - and compares contents to file contents - """ - assert isinstance(from_file_meth_grid_obj, GridObj) - np.testing.assert_array_equal(from_file_meth_grid_obj.x, from_dataset_grid_obj.x) - np.testing.assert_array_equal(from_file_meth_grid_obj.y, from_dataset_grid_obj.y) - np.testing.assert_array_equal(from_file_meth_grid_obj.dx, from_dataset_grid_obj.dx) - np.testing.assert_array_equal(from_file_meth_grid_obj.dy, from_dataset_grid_obj.dy) - np.testing.assert_array_equal(from_file_meth_grid_obj.area, from_dataset_grid_obj.area) - np.testing.assert_array_equal(from_file_meth_grid_obj.angle_dx, from_dataset_grid_obj.angle_dx) - np.testing.assert_array_equal(from_file_meth_grid_obj.angle_dy, from_dataset_grid_obj.angle_dy) + file_path = tmp_path / "test_grid.nc" + + from_dataset_grid_obj.write_out_grid(filepath=file_path) + + from_file_grid_obj = GridObj.from_file(filepath=file_path) + + assert isinstance(from_file_grid_obj, GridObj) file_path.unlink() assert not file_path.exists() + + np.testing.assert_array_equal(from_file_grid_obj.x, out_grid_dataset.x.values) + np.testing.assert_array_equal(from_file_grid_obj.y, out_grid_dataset.y.values) + np.testing.assert_array_equal(from_file_grid_obj.dx, out_grid_dataset.dx.values) + np.testing.assert_array_equal(from_file_grid_obj.dy, out_grid_dataset.dy.values) + np.testing.assert_array_equal(from_file_grid_obj.area, out_grid_dataset.area.values) + np.testing.assert_array_equal(from_file_grid_obj.angle_dx, out_grid_dataset.angle_dx.values) + np.testing.assert_array_equal(from_file_grid_obj.angle_dy, out_grid_dataset.angle_dy) From 563011fcb259a20d766630226bac0523a689ec7c Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 5 Feb 2025 12:18:39 -0500 Subject: [PATCH 03/72] Beginning changes to make_hgrid and change of entry point for make_topog --- FMSgridtools/make_hgrid/make_hgrid.py | 369 +++++++++++++++++++++++++- setup.py | 2 +- 2 files changed, 369 insertions(+), 2 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index a9a4e36..5a69bd9 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1 +1,368 @@ -# TODO: Add work from 'hold_hgrid' branch \ No newline at end of file +import xarray as xr +import numpy as np +import click +from typing import Optional + +from pyfms import pyFMS_mpp, pyFMS_mpp_domains +from FMSgridtools.shared.gridobj import GridObj + +MAXBOUNDS = 100 +REGULAR_LONLAT_GRID = 1 +TRIPOLAR_GRID = 2 +FROM_FILE = 3 +SIMPLE_CARTESIAN_GRID = 4 +SPECTRAL_GRID = 5 +CONFORMAL_CUBIC_GRID = 6 +GNOMONIC_ED = 7 +F_PLANE_GRID = 8 +BETA_PLANE_GRID = 9 +MISSING_VALUE = -9999. + +# TODO: Click stuff needed in here +@click.command() +@click.argument('args', nargs=-1) +@click.option("--grid_type", default="regular_lonlat_grid") +@click.option("--my_grid_file", default="") +@click.option("--nxbnds", default=2) +@click.option("--nybnds", default=2) +@click.option("--xbnds", type=str) +@click.option("--ybnds", type=str) +@click.option("--nlon", type=str) +@click.option("--nlat", type=str) +@click.option("--dlon", type=str) +@click.option("--dlat", type=str) +@click.option("--lat_join", default=65.) +@click.option("--nratio", default=1) +@click.option("--simple_dx", default=0.) +@click.option("--simple_dy", default=0.) +@click.option("--grid_name", default="horizontal_grid") +@click.option("--center", default="none") +@click.option("--shift_fac", default=18.0) +@click.option("--f_plane_latitude", default=100.) +@click.option("--do_schmidt", default=0) +@click.option("--do_cube_transform", default=0) +@click.option("--stretch_factor", type=float, default=0.0) +@click.option("--target_lon", type=float, default=0.0) +@click.option("--target_lat", type=float, default=0.0) +@click.option("--nest_grids", default=0) +@click.option("--parent_tile", type=str) +@click.option("--refine_ratio", type=str) +@click.option("--istart_nest", type=str) +@click.option("--iend_nest", type=str) +@click.option("--jstart_nest", type=str) +@click.option("--jend_nest", type=str) +@click.option("--halo", default=0) +@click.option("--great_circle_algorithm", default=False) +@click.option("--out_halo", default=0) +@click.option("--non_length_angle", default=False) +@click.option("--angular_midpoint", default=False) +@click.option("--rotate_poly", default=False) +@click.option("--verbose", default=False) +def main( + args: str, + grid_type: str, + my_grid_file: Optional[str], + nxbnds: int, + nybnds: int, + xbnds: str, + ybnds: str, + nlon: str, + nlat: str, + dlon: str, + dlat: str, + lat_join: float, + nratio: int, + simple_dx: float, + simple_dy: float, + grid_name: str, + center: str, + shift_fac: float, + f_plane_latitude: float, + do_schmidt: int, + do_cube_transform: int, + stretch_factor: float, + target_lon: float, + target_lat: float, + nest_grids: int, + parent_tile: str, + refine_ratio: str, + istart_nest: str, + iend_nest: str, + jstart_nest: str, + jend_nest: str, + halo: int, + great_circle_algorithm: bool, + out_halo: int, + no_length_angle: bool, + angular_midpoint: bool, + rotate_poly: bool, + verbose: bool, +): + + # start parallel + # TODO: need to link to location of pyFMS shared library + mpp = pyFMS_mpp(clib) + mpp_domains = pyFMS_mpp_domains(clib) + + # TODO: Find what to use for error_type + if(mpp.pyfms_npes() > 1): + mpp.pyfms_error(error_type, "make_hgrid: make_hgrid must be run one processor, contact developer") + + # grid_data = GridStruct( + # args=args, + # grid_type=grid_type, + # my_grid_file=my_grid_file, + # nxbnds=nxbnds, + # nybnds=nybnds, + # nlon=nlon, + # nlat=nlat, + # dlon=dlon, + # dlat=dlat, + # lat_join=lat_join, + # nratio=nratio, + # simple_dx=simple_dx, + # simple_dy=simple_dy, + # grid_name=grid_name, + # center=center, + # shift_fac=shift_fac, + # f_plane_latitude=f_plane_latitude, + # do_schmidt=do_schmidt, + # do_cube_transform=do_cube_transform, + # stretch_factor=stretch_factor, + # target_lon=target_lon, + # target_lat=target_lat, + # nest_grids=nest_grids, + # parent_tile=parent_tile, + # refine_ratio=refine_ratio, + # istart_nest=istart_nest, + # iend_nest=iend_nest, + # jstart_nest=jstart_nest, + # jend_nest=jend_nest, + # halo=halo, + # great_circle_algorithm=great_circle_algorithm, + # out_halo=out_halo, + # no_length_angle=no_length_angle, + # angular_midpoint=angular_midpoint, + # rotate_poly=rotate_poly, + # verbose=verbose, + # ) + + print(f"==>NOTE: the grid type is {grid_type}") + + # TODO: Find where ntiles went + if verbose: + print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}") + print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}") + + + # TODO: Methods to create types of grids to be passed instance of + # GridStruct class + + if(my_grid_type==REGULAR_LONLAT_GRID): + create_regular_lonlat_grid( + &nxbnds, + &nybnds, + xbnds, + ybnds, + nlon, + nlat, + dx_bnds, + dy_bnds, + use_legacy, + &isc, + &iec, + &jsc, + &jec, + x, + y, + dx, + dy, + area, + angle_dx, + center, + use_great_circle_algorithm, + ) + elif(my_grid_type==TRIPOLAR_GRID): + create_tripolar_grid( + &nxbnds, + &nybnds, + xbnds, + ybnds, + nlon, + nlat, + dx_bnds, + dy_bnds, + use_legacy, + &lat_join, + &isc, + &iec, + &jsc, + &jec, + x, + y, + dx, + dy, + area, + angle_dx, + center, + verbose, + use_great_circle_algorithm, + ) + elif(my_grid_type==FROM_FILE): + for n in range(ntiles): + n1 = n * nxp * nyp + n2 = n * nx * nyp + n3 = n * nxp * ny + n4 = n * nx * ny + create_grid_from_file( + my_grid_file[n], + &nx, + &ny, + x+n1, + y+n1, + dx+n2, + dy+n3, + area+n4, + angle_dx+n1, + use_great_circle_algorithm, + use_angular_midpoint, + ) + elif(my_grid_type==SIMPLE_CARTESIAN_GRID): + create_simple_cartesian_grid( + xbnds, + ybnds, + &nx, + &ny, + &simple_dx, + &simple_dy, + &isc, + &iec, + &jsc, + &jec, + x, + y, + dx, + dy, + area, + angle_dx, + ) + elif(my_grid_type==SPECTRAL_GRID): + create_spectral_grid( + &nx, + &ny, + &isc, + &iec, + &jsc, + &jec, + x, + y, + dx, + dy, + area, + angle_dx, + use_great_circle_algorithm, + ) + elif(my_grid_type==CONFORMAL_CUBIC_GRID): + create_conformal_cubic_grid( + &nx, + &nratio, + method, + orientation, + x, + y, + dx, + dy, + area, + angle_dx, + angle_dy, + ) + elif(my_grid_type==GNOMONIC_ED): + if(nest_grids == 1 and parent_tile_list[0] == 0): + create_gnomonic_cubic_grid_GR( + grid_type, + nxl, + nyl, + x, + y, + dx, + dy, + area, + angle_dx, + angle_dy, + shift_fac, + do_schmidt, + do_cube_transform, + stretch_factor, + target_lon, + target_lat, + nest_grids, + parent_tile[0], + refine_ratio[0], + istart_nest[0], + iend_nest[0], + jstart_nest[0], + jend_nest[0], + halo, + output_length_angle, + ) + else: + create_gnomonic_cubic_grid( + grid_type, + nxl, + nyl, + x, + y, + dx, + dy, + area, + angle_dx, + angle_dy, + shift_fac, + do_schmidt, + do_cube_transform, + stretch_factor, + target_lon, + target_lat, + nest_grids, + parent_tile, + refine_ratio, + istart_nest, + iend_nest, + jstart_nest, + jend_nest, + halo, + output_length_angle, + ) + elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): + create_f_plane_grid( + &nxbnds, + &nybnds, + xbnds, + ybnds, + nlon, + nlat, + dx_bnds, + dy_bnds, + use_legacy, + f_plane_latitude, + &isc, + &iec, + &jsc, + &jec, + x, + y, + dx, + dy, + area, + angle_dx, + center, + ) + + grid_data.write_data() + + if(mpp_pe() == mpp_root_pe() and verbose): + print("generate_grid is run successfully") + + mpp_end() + + # End of main \ No newline at end of file diff --git a/setup.py b/setup.py index e32a1e2..2d6e11b 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ def run(self): entry_points={ "console_scripts": [ "fmsgridtools make_hgrid = fmsgridtools.make_grid.hgrid.make_hgrid:main", - "make_topog = fmsgridtools.make_topog.make_topog:make_topog", + "fmsgridtools make_topog = fmsgridtools.make_topog.make_topog:make_topog", ] }, ) From 038a976e6e9f7ac1046ca39cb0f41411c8afae57 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 7 Feb 2025 13:26:44 -0500 Subject: [PATCH 04/72] Added todos to gridobj.py: remove metadata from write out, access to dimensions as attributes --- FMSgridtools/shared/gridobj.py | 106 +++++++++++++++++-------------- FMSgridtools/shared/mosaicobj.py | 4 +- setup.py | 1 + 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index ad702f7..d4b69a7 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -19,6 +19,10 @@ class GridObj: grid_data: Optional[xr.Dataset] = None grid_file: Optional[str] = None tile: Optional[str] = None + _nx: Optional[int] = None + _ny: Optional[int] = None + _nxp: Optional[int] = None + _nyp: Optional[int] = None x: Optional[npt.NDArray] = None y: Optional[npt.NDArray] = None dx: Optional[npt.NDArray] = None @@ -129,102 +133,62 @@ def write_out_grid(self, filepath: str): if self.tile is not None: tile = xr.DataArray( [self.tile], - attrs=dict( - standard_name = "grid_tile_spec", - geometry = "spherical", - north_pole = "0.0 90.0", - projection = "cube_gnomonic", - discretization = "logically_rectangular", - conformal = "FALSE", - ) - ).encode + ) else: tile = None if self.x is not None: x = xr.DataArray( data=self.x, dims=["nyp", "nxp"], - attrs=dict( - units="degree_east", - standard_name="geographic_longitude", - ) - ).encode + ) else: x = None if self.y is not None: y = xr.DataArray( data=self.y, dims=["nyp", "nxp"], - attrs=dict( - units="degree_north", - standard_name="geographic_latitude", - ) - ).encode + ) else: y = None if self.dx is not None: dx = xr.DataArray( data=self.dx, dims=["nyp", "nx"], - attrs=dict( - units="meters", - standard_name="grid_edge_x_distance", - ) - ).encode + ) else: dx = None if self.dy is not None: dy = xr.DataArray( data=self.dy, dims=["ny", "nxp"], - attrs=dict( - units="meters", - standard_name="grid_edge_y_distance", - ) - ).encode + ) else: dy = None if self.area is not None: area = xr.DataArray( data=self.area, dims=["ny", "nx"], - attrs=dict( - units="m2", - standard_name="grid_cell_area", - ) - ).encode + ) else: area = None if self.angle_dx is not None: angle_dx = xr.DataArray( data=self.angle_dx, dims=["nyp", "nxp"], - attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", - ) - ).encode + ) else: angle_dx = None if self.angle_dy is not None: angle_dy = xr.DataArray( data=self.angle_dy, dims=["nyp", "nxp"], - attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", - ) - ).encode + ) else: angle_dy = None if self.arcx is not None: arcx = xr.DataArray( [self.arcx], - attrs=dict( - standard_name = "grid_edge_x_arc_type", - north_pole = "0.0 90.0", - ) - ).encode + ) else: arcx = None out_grid_dataset = xr.Dataset( @@ -276,5 +240,49 @@ def get_agrid_lonlat(self)-> tuple[npt.NDArray, npt.NDArray]: """ def get_variable_list(self) -> List: return list(self.grid_data.data_vars) + + @property + def nx(self): + if self._nx is None: + if self.grid_data is not None: + self._nx = self.grid_data.sizes['nx'] + elif self.area is not None: + self._nx = self.area.shape[1] + else: + pass + return self._nx + + @property + def ny(self): + if self._ny is None: + if self.grid_data is not None: + self._ny = self.grid_data.sizes['ny'] + elif self.area is not None: + self._ny = self.area.shape[0] + else: + pass + return self._ny + + @property + def nxp(self): + if self._nxp is None: + if self.grid_data is not None: + self._nxp = self.grid_data.sizes['nxp'] + elif self.x is not None: + self._nxp = self.x.shape[1] + else: + pass + return self._nxp + + @property + def nyp(self): + if self._nyp is None: + if self.grid_data is not None: + self._nyp = self.grid_data.sizes['nyp'] + elif self.x is not None: + self._nyp = self.x.shape[0] + else: + pass + return self._nyp #TODO: I/O method for passing to the host diff --git a/FMSgridtools/shared/mosaicobj.py b/FMSgridtools/shared/mosaicobj.py index 24b2034..fa97a63 100755 --- a/FMSgridtools/shared/mosaicobj.py +++ b/FMSgridtools/shared/mosaicobj.py @@ -3,8 +3,8 @@ import xarray as xr import numpy as np import numpy.typing as npt -from gridtools.shared import GridObj -from gridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridobj import GridObj +from FMSgridtools.shared.gridtools_utils import check_file_is_there @dataclass class MosaicObj: diff --git a/setup.py b/setup.py index e32a1e2..fa12989 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ def run(self): requirements: List[str] = [ "click", + "gitpython", "h5netcdf", "h5py", "numpy", From cb87c5d3d10147bd575ee0544acf0fa59b2dea18 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 11 Feb 2025 10:51:54 -0500 Subject: [PATCH 05/72] Switching over to hold_hgrid branch --- FMSgridtools/make_hgrid/make_hgrid.py | 38 --------------------------- 1 file changed, 38 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 5a69bd9..94dd809 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -108,44 +108,6 @@ def main( if(mpp.pyfms_npes() > 1): mpp.pyfms_error(error_type, "make_hgrid: make_hgrid must be run one processor, contact developer") - # grid_data = GridStruct( - # args=args, - # grid_type=grid_type, - # my_grid_file=my_grid_file, - # nxbnds=nxbnds, - # nybnds=nybnds, - # nlon=nlon, - # nlat=nlat, - # dlon=dlon, - # dlat=dlat, - # lat_join=lat_join, - # nratio=nratio, - # simple_dx=simple_dx, - # simple_dy=simple_dy, - # grid_name=grid_name, - # center=center, - # shift_fac=shift_fac, - # f_plane_latitude=f_plane_latitude, - # do_schmidt=do_schmidt, - # do_cube_transform=do_cube_transform, - # stretch_factor=stretch_factor, - # target_lon=target_lon, - # target_lat=target_lat, - # nest_grids=nest_grids, - # parent_tile=parent_tile, - # refine_ratio=refine_ratio, - # istart_nest=istart_nest, - # iend_nest=iend_nest, - # jstart_nest=jstart_nest, - # jend_nest=jend_nest, - # halo=halo, - # great_circle_algorithm=great_circle_algorithm, - # out_halo=out_halo, - # no_length_angle=no_length_angle, - # angular_midpoint=angular_midpoint, - # rotate_poly=rotate_poly, - # verbose=verbose, - # ) print(f"==>NOTE: the grid type is {grid_type}") From e3ac3ce7298b429e670d739ac66c62db0a0e6e96 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 11 Feb 2025 16:02:12 -0500 Subject: [PATCH 06/72] Changes as of 16:01 11 Feb 2025 on feature/hgrid branch --- FMSgridtools/make_hgrid/make_hgrid.py | 302 +++++++++++++++++++++++--- 1 file changed, 271 insertions(+), 31 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 94dd809..8629054 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,5 +1,6 @@ import xarray as xr import numpy as np +import numpy.typing as npt import click from typing import Optional @@ -7,6 +8,7 @@ from FMSgridtools.shared.gridobj import GridObj MAXBOUNDS = 100 +MAX_NESTS = 128 REGULAR_LONLAT_GRID = 1 TRIPOLAR_GRID = 2 FROM_FILE = 3 @@ -18,42 +20,92 @@ BETA_PLANE_GRID = 9 MISSING_VALUE = -9999. -# TODO: Click stuff needed in here +def fill_cubic_grid_halo( + nx: int, + ny: int, + halo: int, + data: npt.NDArray[np.float64], + data1_all: npt.NDArray[np.float64], + data2_all: npt.NDArray[np.float64], + tile: int, + ioff: int, + joff: int, +): + nxp = nx + ioff + nyp = ny + joff + nxph = nx + ioff + 2*halo + nyph = ny + joff + 2*halo + + for i in range(nxph*nyph): + data[i] = MISSING_VALUE + + # first copy computing domain data + for j in range (nyp+1): + for i in range(nxp+1): + data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] + + ntiles = 6 + + if tile%2 == 1: + lw = (tile+ntiles-1)%ntiles + le = (tile+ntiles+2)%ntiles + ls = (tile+ntiles-2)%ntiles + ln = (tile+ntiles+1)%ntiles + for j in range(nyp+1): + data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo + data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo + + for i in range(nxp+1): + data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo + data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo + else: + lw = (tile+ntiles-2)%ntiles + le = (tile+ntiles+1)%ntiles + ls = (tile+ntiles-1)%ntiles + ln = (tile+ntiles+2)%ntiles + for j in range(nyp+1): + data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo + data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo + + for i in range(nxp+1): + data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo + data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo + @click.command() @click.argument('args', nargs=-1) -@click.option("--grid_type", default="regular_lonlat_grid") -@click.option("--my_grid_file", default="") -@click.option("--nxbnds", default=2) -@click.option("--nybnds", default=2) -@click.option("--xbnds", type=str) -@click.option("--ybnds", type=str) -@click.option("--nlon", type=str) -@click.option("--nlat", type=str) -@click.option("--dlon", type=str) -@click.option("--dlat", type=str) -@click.option("--lat_join", default=65.) -@click.option("--nratio", default=1) -@click.option("--simple_dx", default=0.) -@click.option("--simple_dy", default=0.) -@click.option("--grid_name", default="horizontal_grid") -@click.option("--center", default="none") -@click.option("--shift_fac", default=18.0) -@click.option("--f_plane_latitude", default=100.) -@click.option("--do_schmidt", default=0) -@click.option("--do_cube_transform", default=0) +@click.option("--grid_type", type=str, default="regular_lonlat_grid") +@click.option("--my_grid_file", type=str, default=None) +@click.option("--nxbnds", type=int, default=2) +@click.option("--nybnds", type=int, default=2) +@click.option("--xbnds", type=str, default=None) +@click.option("--ybnds", type=str, default=None) +@click.option("--nlon", type=str, default=None) +@click.option("--nlat", type=str, default=None) +@click.option("--dlon", type=str, default=None) +@click.option("--dlat", type=str, default=None) +@click.option("--lat_join", type=float, default=65.) +@click.option("--nratio", type=int, default=1) +@click.option("--simple_dx", type=float, default=0.) +@click.option("--simple_dy", type=float, default=0.) +@click.option("--grid_name", type=str, default="horizontal_grid") +@click.option("--center", type=str, default="none") +@click.option("--shift_fac", type=float, default=18.0) +@click.option("--f_plane_latitude", type=float, default=100.) +@click.option("--do_schmidt", type=int, default=0) +@click.option("--do_cube_transform", type=int, default=0) @click.option("--stretch_factor", type=float, default=0.0) @click.option("--target_lon", type=float, default=0.0) @click.option("--target_lat", type=float, default=0.0) -@click.option("--nest_grids", default=0) -@click.option("--parent_tile", type=str) -@click.option("--refine_ratio", type=str) -@click.option("--istart_nest", type=str) -@click.option("--iend_nest", type=str) -@click.option("--jstart_nest", type=str) -@click.option("--jend_nest", type=str) -@click.option("--halo", default=0) +@click.option("--nest_grids", type=int, default=0) +@click.option("--parent_tile", type=str, default=None) +@click.option("--refine_ratio", type=str, default=None) +@click.option("--istart_nest", type=str, default=None) +@click.option("--iend_nest", type=str, default=None) +@click.option("--jstart_nest", type=str, default=None) +@click.option("--jend_nest", type=str, default=None) +@click.option("--halo", type=int, default=0) @click.option("--great_circle_algorithm", default=False) -@click.option("--out_halo", default=0) +@click.option("--out_halo", type=int, default=0) @click.option("--non_length_angle", default=False) @click.option("--angular_midpoint", default=False) @click.option("--rotate_poly", default=False) @@ -98,6 +150,82 @@ def main( rotate_poly: bool, verbose: bool, ): + nratio = 1 + method = "conformal" + orientation = "center_pole" + nxbnds0 = nxbnds + nybnds0 = nybnds + nxbnds1 = 0 + nybnds1 = 0 + nxbnds2 = 0 + nybnds2 = 0 + nxbnds3 = 0 + nybnds3 = 0 + num_nest_args = 0 + nn = 0 + present_stretch_factor = 0 + present_target_lon = 0 + present_target_lat = 0 + use_great_circle_algorithm = 0 + use_angular_midpoint = 0 + output_length_angle = 1 + ntiles = 1 + ntiles_global = 1 + grid_obj = GridObj() + gridname = "horizontal_grid" + center = "none" + arcx = "small_circle" + north_pole_tile = "0.0 90.0" + north_pole_arcx = "0.0 90.0" + discretization = "logically_rectangular" + conformal = "true" + + if xbnds is not None: + xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') + nxbnds1 = xbnds.size + if ybnds is not None: + ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') + nybnds1 = ybnds.size + if nlon is not None: + nlon = np.fromstring(nlon, dtype=int, sep=',') + nxbnds2 = nlon.size + if nlat is not None: + nlat = np.fromstring(nlat, dtype=int, sep=',') + nybnds2 = nlat.size + if dlon is not None: + dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') + nxbnds3 = dx_bnds.size + if dlat is not None: + dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') + nybnds3 = dy_bnds.size + if refine_ratio is not None: + refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') + num_nest_args = refine_ratio.size + if parent_tile is not None: + parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') + num_nest_args = parent_tile.size + if istart_nest is not None: + istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') + num_nest_args = istart_nest.size + if iend_nest is not None: + iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') + num_nest_args = iend_nest.size + if jstart_nest is not None: + jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') + num_nest_args = jstart_nest.size + if jend_nest is not None: + jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') + num_nest_args = jend_nest.size + if great_circle_algorithm: + use_great_circle_algorithm = 1 + if no_length_angle: + output_length_angle = 0 + if angular_midpoint: + use_angular_midpoint = 1 + if my_grid_file is not None: + my_grid_file = np.array(my_grid_file.split(',')) + ntiles_file = my_grid_file.size + # start parallel # TODO: need to link to location of pyFMS shared library @@ -108,10 +236,122 @@ def main( if(mpp.pyfms_npes() > 1): mpp.pyfms_error(error_type, "make_hgrid: make_hgrid must be run one processor, contact developer") - print(f"==>NOTE: the grid type is {grid_type}") + if grid_type == "regular_lonlat_grid": + my_grid_type = REGULAR_LONLAT_GRID + elif grid_type == "tripolar_grid": + my_grid_type = TRIPOLAR_GRID + elif grid_type == "from_file": + my_grid_type = FROM_FILE + elif grid_type == "simple_cartesian_grid": + my_grid_type = SIMPLE_CARTESIAN_GRID + elif grid_type == "spectral_grid": + my_grid_type = SPECTRAL_GRID + elif grid_type == "conformal_cubic_grid": + my_grid_type = CONFORMAL_CUBIC_GRID + elif grid_type == "gnomonic_ed": + my_grid_type = GNOMONIC_ED + elif grid_type == "f_plane_grid": + my_grid_type = F_PLANE_GRID + elif grid_type == "beta_plane_grid": + my_grid_type = BETA_PLANE_GRID + else: + mpp.pyfms_error("make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', " + "'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', " + "'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") + + if my_grid_type != GNOMONIC_ED and out_halo != 0: + mpp.pyfms_error("make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") + if out_halo != 0 and out_halo != 1: + mpp.pyfms_error("make_hgrid: out_halo should be 0 or 1") + if my_grid_type != GNOMONIC_ED and do_schmidt: + mpp.pyfms_error("make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") + if my_grid_type != GNOMONIC_ED and do_cube_transform: + mpp.pyfms_error("make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") + if do_cube_transform and do_schmidt: + mpp.pyfms_error("make_hgrid: both --do_cube_transform and --do_schmidt are set") + + use_legacy = 0 + + """ + Command line argument check + """ + if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + nxbnds = nxbnds0 + nybnds = nybnds0 + if nxbnds < 2 or nybnds < 2: + mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") + if nxbnds != nxbnds1: + mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") + if nybnds != nybnds1: + mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") + + num_specify = 0 + + if nxbnds2 > 0 and nybnds2 > 0: + num_specify += 1 + if nxbnds3 > 0 and nybnds3 > 0: + num_specify += 1 + use_legacy = 1 + + if num_specify == 0: + mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") + if num_specify == 2: + mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") + if use_legacy: + if nxbnds != nxbnds3: + mpp.pfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") + if nybnds != nybnds3: + mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") + else: + if nxbnds != nxbnds2+1: + mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") + if nybnds != nybnds2+1: + mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") + + if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: + ntiles = 6 + ntiles_global = 6 + + if my_grid_type != GNOMONIC_ED and nest_grids: + mpp.pyfms_error("make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") + + if my_grid_type == TRIPOLAR_GRID: + projection = "tripolar" + if nxbnds != 2: + mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") + elif my_grid_type == FROM_FILE: + if ntiles_file == 0: + mpp.pyfms_error("make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") + ntiles = ntiles_file + ntiles_global = ntiles_file + for n in range(ntiles): + # look at fms_gridtools for variable check + elif my_grid_type == SIMPLE_CARTESIAN_GRID: + geometry = "planar" + north_pole_tile = "none" + if nxbnds1 != 2 or nybnds1 != 2: + mpp.pyfms_error("make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") + if nxbnds2 != 1 or nybnds2 != 1: + mpp.pyfms_error("make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") + if simple_dx == 0 or simple_dy == 0: + mpp.pyfms_error("make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") + elif my_grid_type == SPECTRAL_GRID: + if nxbnds2 != 1 or nybnds2 != 1: + mpp.pyfms_error("make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") + elif my_grid_type == CONFORMAL_CUBIC_GRID: + projection = "cube_gnomonic" + conformal = "FALSE" + if nxbnds2 != 1: + mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") + if nratio < 1: + mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") + + + # TODO: Find where ntiles went + # line 1002 in make_hgrid.c if verbose: print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}") print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}") From a227658111abdaf72c4706327f6b7e6f63686be8 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 12 Feb 2025 12:16:21 -0500 Subject: [PATCH 07/72] Added in main functionality for make_hgrid --- FMSgridtools/make_hgrid/make_hgrid.py | 130 +++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 8629054..37a7d16 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,3 +1,4 @@ +import sys import xarray as xr import numpy as np import numpy.typing as npt @@ -347,14 +348,133 @@ def main( mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") if nratio < 1: mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") - + elif my_grid_type == GNOMONIC_ED: + projection = "cube_gnomonic" + conformal = "FALSE" + if do_schmidt or do_cube_transform: + if present_stretch_factor == 0 or present_target_lon == 0 or present_target_lat == 0: + mpp.pyfms_error("make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") + for n in range(nest_grids): + if refine_ratio[n] == 0: + mpp.pyfms_error("make_hgrid: --refine_ratio must be set when --nest_grids is set") + else: + if istart_nest[n] == 0: + mpp.pyfms_error("make_hgrid: --istart_nest must be set when --nest_grids is set") + if iend_nest[n] == 0: + mpp.pyfms_error("make_hgrid: --iend_nest must be set when --nest_grids is set") + if jstart_nest[n] == 0: + mpp.pyfms_error("make_hgrid: --jstart_nest must be set when --nest_grids is set") + if jend_nest[n] == 0: + mpp.pyfms_error("make_hgrid: --jend_nest must be set when --nest_grids is set") + if halo == 0: + mpp.pyfms_error("make_hgrid: --halo must be set when --nest_grids is set") + ntiles += 1 + if verbose: + print(f"Configuration for nest {ntiles} validated.", file=sys.stderr) + if verbose: + print(f"Updated number of tiles, including nests (ntiles): {ntiles}", file=sys.stderr) + if nxbnds2 != 1: + mpp.pyfms_error("make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") + elif my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + if f_plane_latitude > 90 or f_plane_latitude < -90: + mpp.pyfms_error("make_hgrid: f_plane_latitude should be between -90 and 90.") + if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: + print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) + if mpp.pe() == 0: + print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) + else: + mpp.pyfms_error("make_hgrid: passed grid type is not implemented") + + if verbose: + print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}", file=sys.stderr) + print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) + + nxl = np.empty(shape=ntiles, dtype=np.int32) + nyl = np.empty(shape=ntiles, dtype=np.int32) + + """ + Get super grid size + """ + if use_legacy: + nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) # in tool_util.c + nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) # in tool_util.c + elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: + for n in range(ntiles_global): + nxl[n] = nlon[n] + nyl[n] = nxl[n] + if nest_grids and parent_tile[0] == 0: + nxl[n] *= refine_ratio[0] + nyl[n] *= refine_ratio[0] + + for n in range(ntiles_global, ntiles): + nn = n - ntiles_global + nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] + nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + elif my_grid_type == FROM_FILE: + for n in range(ntiles_global): + nxl[n] = nlon[n] + nyl[n] = nlat[n] + else: + nxl[0] = 0 + nyl[0] = 0 + for n in range(nxbnds-1): + nxl[0] += nlon[n] + for n in range(nybnds - 1): + nyl[0] += nlat[n] + + nx = nxl[0] + ny = nyl[0] + nxp = nx + 1 + nyp = ny + 1 + + if center == "none" and center == "c_cell" and center == "t_cell": + mpp.pyfms_error("make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") + if not output_length_angle and my_grid_type != GNOMONIC_ED: + mpp.pyfms_error("make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") + + """ + Create grid information + """ + + for n_nest in range(ntiles): + print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) + + if my_grid_type == FROM_FILE: + size1 = 0 + size2 = 0 + size3 = 0 + size4 = 0 + for n in range(ntiles_global): + size1 += (nlon[n] + 1) * (nlat[n] + 1) + size2 += (nlon[n] + 1) * (nlat[n] + 1 + 1) + size3 += (nlon[n] + 1 +1) * (nlat[n] + 1) + size4 += (nlon[n] + 1) * (nlat[n] + 1) + else: + size1 = nxp * nyp * ntiles_global + size2 = nxp * (nyp + 1) * ntiles_global + size3 = (nxp + 1) * nyp * ntiles_global + size4 = nxp * nyp * ntiles_global + if nest_grids == 1 and parent_tile[0] == 0: + for n_nest in range(ntiles_global, ntiles_global+nest_grids): + if verbose: + print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) + size1 += (nxl[n_nest]+1) * (nyl[n_nest]+1) + size2 += (nxl[n_nest]+1) * (nyl[n_nest]+2) + size3 += (nxl[n_nest]+2) * (nyl[n_nest]+1) + size4 += (nxl[n_nest]+1) * (nyl[n_nest]+1) - # TODO: Find where ntiles went - # line 1002 in make_hgrid.c if verbose: - print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}") - print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}") + print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) + grid_obj.x = np.empty(shape=size1, dtype=np.float64) + grid_obj.y = np.empty(shape=size1, dtype=np.float64) + grid_obj.area = np.empty(shape=size4, dtype=np.float64) + if output_length_angle: + grid_obj.dx = np.empty(shape=size2, dtype=np.float64) + grid_obj.dy = np.empty(shape=size3, dtype=np.float64) + grid_obj.angle_dx = np.empty(shape=size1, dtype=np.float64) + if conformal != "true": + grid_obj.angle_dy = np.empty(shape=size1, dtype=np.float64) # TODO: Methods to create types of grids to be passed instance of From 787b4497304103569eefa97bdba40823f6acbb4b Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 12 Feb 2025 14:43:51 -0500 Subject: [PATCH 08/72] Added to make_hgrid_utils create_regular_lonlat_grid and create_tripolar_grid --- FMSgridtools/make_hgrid/make_hgrid.py | 44 +++- FMSgridtools/shared/gridobj.py | 2 +- FMSgridtools/shared/mosaicobj.py | 4 +- .../pyfrenctools/make_hgrid/empty.py | 1 - .../make_hgrid/make_hgrid_util.py | 232 ++++++++++++++++++ 5 files changed, 277 insertions(+), 6 deletions(-) delete mode 100644 FRENCTools_lib/pyfrenctools/make_hgrid/empty.py create mode 100644 FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 37a7d16..9daf679 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -7,6 +7,7 @@ from pyfms import pyFMS_mpp, pyFMS_mpp_domains from FMSgridtools.shared.gridobj import GridObj +from FMSgridtools.shared.gridtools_utils import check_file_is_there MAXBOUNDS = 100 MAX_NESTS = 128 @@ -328,7 +329,43 @@ def main( ntiles = ntiles_file ntiles_global = ntiles_file for n in range(ntiles): - # look at fms_gridtools for variable check + if ".nc" in my_grid_file[n]: + file_path = my_grid_file[n] + ".nc" + check_file_is_there(file_path) + with xr.open_dataset(file_path) as ds: + if "grid_xt" in ds.sizes: + if "grid_yt" not in ds.sizes: + mpp.pyfms_error("make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") + nlon[n] = ds.sizes["grid_xt"]*2 + nlat[n] = ds.sizes["grid_yt"]*2 + elif "rlon" in ds.sizes: + if "rlat" not in ds.sizes: + mpp.pyfms_error("make_hgrid: rlat should be a dimension when rlon is a dimension") + nlon[n] = ds.sizes["rlon"]*2 + nlat[n] = ds.sizes["rlat"]*2 + elif "lon" in ds.sizes: + if "lat" not in ds.sizes: + mpp.pyfms_error("make_hgrid: lat should be a dimension when lon is a dimension") + nlon[n] = ds.sizes["lon"]*2 + nlat[n] = ds.sizes["lat"]*2 + elif "i" in ds.sizes: + if "j" not in ds.sizes: + mpp.pyfms_error("make_hgrid: j should be a dimension when i is a dimension") + nlon[n] = ds.sizes["i"]*2 + nlat[n] = ds.sizes["j"]*2 + elif "x" in ds.sizes: + if "y" not in ds.sizes: + mpp.pyfms_error("make_hgrid: y should be a dimension when x is a dimension") + nlon[n] = ds.sizes["x"]*2 + nlat[n] = ds.sizes["y"]*2 + else: + mpp.pyfms_error("make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") + else: + if nxbnds2 != ntiles or nybnds2 != ntiles: + mpp.pyfms_error("make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") + for n in range(1, ntiles): + if nlon[n] != nlon[0] or nlat[n] != nlat[0]: + mpp.pyfms_error("make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") elif my_grid_type == SIMPLE_CARTESIAN_GRID: geometry = "planar" north_pole_tile = "none" @@ -476,7 +513,10 @@ def main( if conformal != "true": grid_obj.angle_dy = np.empty(shape=size1, dtype=np.float64) - + isc = 0 + iec = nx - 1 + jsc = 0 + jec = ny - 1 # TODO: Methods to create types of grids to be passed instance of # GridStruct class diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 0ffb4b2..8e34750 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -5,7 +5,7 @@ import numpy.typing as npt import xarray as xr -from gridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridtools_utils import check_file_is_there """ GridObj: diff --git a/FMSgridtools/shared/mosaicobj.py b/FMSgridtools/shared/mosaicobj.py index 24b2034..fa97a63 100755 --- a/FMSgridtools/shared/mosaicobj.py +++ b/FMSgridtools/shared/mosaicobj.py @@ -3,8 +3,8 @@ import xarray as xr import numpy as np import numpy.typing as npt -from gridtools.shared import GridObj -from gridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridobj import GridObj +from FMSgridtools.shared.gridtools_utils import check_file_is_there @dataclass class MosaicObj: diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/empty.py b/FRENCTools_lib/pyfrenctools/make_hgrid/empty.py deleted file mode 100644 index e517126..0000000 --- a/FRENCTools_lib/pyfrenctools/make_hgrid/empty.py +++ /dev/null @@ -1 +0,0 @@ -# For git tracking, to be removed \ No newline at end of file diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py new file mode 100644 index 0000000..f43fd6e --- /dev/null +++ b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -0,0 +1,232 @@ +import numpy as np +import numpy.typing as npt +import ctypes + +from pyfms.data_handling import ( + setscalar_Cint32, + setscalar_Cdouble, + setarray_Cdouble, + setarray_Cint32, + set_Cchar, +) + +lib = ctypes.CDLL("../../FRENCTools_lib/cfrenctools/c_build/clib.so") + +def create_regular_lonlat_grid( + nxbnds: int, + nybnds: int, + xbnds: npt.NDArray[np.float64], + ybnds: npt.NDArray[np.float64], + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + dlon: npt.NDArray[np.float64], + dlat: npt.NDArray[np.float64], + use_legacy: int, + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + center: str, + use_great_circle_algorithm: int +): + _create_regular_lonlat_grid = lib.create_regular_lonlat_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + dlon_p, dlon_t = setarray_Cdouble(dlon) + dlat_p, dlat_t = setarray_Cdouble(dlat) + use_legacy_c = ctypes.c_int(use_legacy) + use_legacy_t = ctypes.POINTER(ctypes.c_int) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) + use_great_circle_algorithm_t = ctypes.POINTER(ctypes.c_int) + + _create_regular_lonlat_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + use_great_circle_algorithm_t, + ] + _create_regular_lonlat_grid.restype = None + + _create_regular_lonlat_grid( + nxbnds_c, + nybnds_c, + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + dlon_p, + dlat_p, + use_legacy_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + center_c, + use_great_circle_algorithm_c, + ) + +def create_tripolar_grid( + nxbnds: int, + nybnds: int, + xbnds: npt.NDArray[np.float64], + ybnds: npt.NDArray[np.float64], + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + dlon: npt.NDArray[np.float64], + dlat: npt.NDArray[np.float64], + use_legacy: int, + lat_join_in: float, + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + center: str, + verbose: int, + use_great_circle_algorithm: int +): + _create_tripolar_grid = lib.create_tripolar_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + dlon_p, dlon_t = setarray_Cdouble(dlon) + dlat_p, dlat_t = setarray_Cdouble(dlat) + use_legacy_c = ctypes.c_int(use_legacy) + use_legacy_t = ctypes.POINTER(ctypes.c_int) + lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + verbose_c = ctypes.c_int(verbose) + verbose_t = ctypes.POINTER(ctypes.c_int) + use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) + use_great_circle_algorithm_t = ctypes.POINTER(ctypes.c_int) + + _create_tripolar_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + lat_join_in_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + verbose_t, + use_great_circle_algorithm_t, + ] + _create_tripolar_grid.restype = None + + _create_tripolar_grid( + nxbnds_c, + nybnds_c, + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + dlon_p, + dlat_p, + use_legacy_c, + lat_join_in_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + center_c, + verbose_c, + use_great_circle_algorithm_c, + ) + +def create_grid_from_file(): + +def create_simple_cartesian_grid(): + +def create_spectral_grid(): + +def create_conformal_cubic_grid(): + +def create_gnomonic_cubic_grid_GR(): + +def create_gnomonic_cubic_grid(): + +def create_f_plane_grid(): \ No newline at end of file From 9dcab22769ff55411e6f925438f39f7237fec451 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 12 Feb 2025 15:43:35 -0500 Subject: [PATCH 09/72] Added in wrappers for create_regular_lonlat_grid, create_tripolar_grid, create_grid_from_file, create_simple_cartesian_grid, create_spectral_grid, create_conformal_cubic_grid --- .../make_hgrid/make_hgrid_util.py | 257 +++++++++++++++++- 1 file changed, 253 insertions(+), 4 deletions(-) diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index f43fd6e..e29b777 100644 --- a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -217,13 +217,262 @@ def create_tripolar_grid( use_great_circle_algorithm_c, ) -def create_grid_from_file(): +def create_grid_from_file( + file: str, + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + use_great_circle_algorithm: int, + use_angular_midpoint: int +): + _create_grid_from_file = lib.create_grid_from_file + + file_c, file_t = set_Cchar(file) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) + use_great_circle_algorithm_t = ctypes.c_int + use_angular_midpoint_c = ctypes.c_int(use_angular_midpoint) + use_angular_midpoint_t = ctypes.c_int + + _create_grid_from_file.argtypes = [ + file_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + use_great_circle_algorithm_t, + use_angular_midpoint_t, + ] + _create_grid_from_file.restype = None + + _create_grid_from_file( + file_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + use_great_circle_algorithm_c, + use_angular_midpoint_c + ) + +def create_simple_cartesian_grid( + xbnds: npt.NDArray[np.float64], + ybnds: npt.NDArray[np.float64], + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + simple_dx: float, + simple_dy: float, + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], +): + _create_simple_cartesian_grid = lib.create_simple_cartesian_grid + + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + simple_dx_c, simple_dx_t = setscalar_Cdouble(simple_dx) + simple_dy_c, simple_dy_t = setarray_Cdouble(simple_dy) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + + _create_simple_cartesian_grid.argtypes = [ + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + simple_dx_t, + simple_dy_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + ] + _create_simple_cartesian_grid.restype = None + + _create_simple_cartesian_grid( + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + simple_dx_c, + simple_dy_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + ) + + +def create_spectral_grid( + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + use_great_circle_algorithm: int, +): + _create_spectral_grid = lib.create_spectral_grid + + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) + use_great_circle_algorithm_t = ctypes.c_int + + _create_spectral_grid.argtypes = [ + nlon_t, + nlat_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + use_great_circle_algorithm_t, + ] + _create_spectral_grid.restype = None + + _create_spectral_grid( + nlon_p, + nlat_p, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dx_p, + use_great_circle_algorithm_c, + ) + +def create_conformal_cubic_grid( + npts: int, + nratio: int, + method: str, + orientation: str, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + angle_dy: npt.NDArray[np.float64], +): + _create_conformal_cubic_grid = lib.create_conformal_cubic_grid -def create_simple_cartesian_grid(): + npts_c, npts_t = setscalar_Cint32(npts) + nratio_c, nratio_t = setscalar_Cint32(nratio) + method_c, method_t = set_Cchar(method) + orientation_c, orientation_t = set_Cchar(orientation) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) -def create_spectral_grid(): + _create_conformal_cubic_grid.argtypes = [ + npts_t, + nratio_t, + method_t, + orientation_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + ] + _create_conformal_cubic_grid.restype = None -def create_conformal_cubic_grid(): + _create_conformal_cubic_grid( + npts_c, + nratio_c, + method_c, + orientation_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + ) def create_gnomonic_cubic_grid_GR(): From a9435c341d288bfc15b0754404aa83a051bbce98 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 13 Feb 2025 14:00:07 -0500 Subject: [PATCH 10/72] Switching over to fix gridobj branch --- FMSgridtools/make_hgrid/make_hgrid.py | 254 +++++++------- .../make_hgrid/make_hgrid_util.py | 320 +++++++++++++++++- 2 files changed, 452 insertions(+), 122 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 9daf679..d28d266 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -5,9 +5,22 @@ import click from typing import Optional -from pyfms import pyFMS_mpp, pyFMS_mpp_domains +from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains + from FMSgridtools.shared.gridobj import GridObj from FMSgridtools.shared.gridtools_utils import check_file_is_there +from FRENCTools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( + create_regular_lonlat_grid, + create_tripolar_grid, + create_grid_from_file, + create_simple_cartesian_grid, + create_spectral_grid, + create_conformal_cubic_grid, + create_gnomonic_cubic_grid_GR, + create_gnomonic_cubic_grid, + create_f_plane_grid, +) +from FRENCTools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size MAXBOUNDS = 100 MAX_NESTS = 128 @@ -163,8 +176,10 @@ def main( nybnds2 = 0 nxbnds3 = 0 nybnds3 = 0 + num_nest_args = 0 nn = 0 + present_stretch_factor = 0 present_target_lon = 0 present_target_lat = 0 @@ -174,14 +189,25 @@ def main( ntiles = 1 ntiles_global = 1 grid_obj = GridObj() + gridname = "horizontal_grid" center = "none" + geometry = "spherical" + projection = "none" arcx = "small_circle" north_pole_tile = "0.0 90.0" north_pole_arcx = "0.0 90.0" discretization = "logically_rectangular" conformal = "true" + pyfms = pyFMS(clibFMS_path="") + mpp = pyFMS_mpp(clibFMS=pyfms.clibFMS) + mpp_domains = pyFMS_mpp_domains(clibFMS=pyfms.clibFMS) + + # TODO: Find what to use for error_type + if(mpp.npes() > 1): + mpp.pyfms_error("make_hgrid: make_hgrid must be run one processor, contact developer") + if xbnds is not None: xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') nxbnds1 = xbnds.size @@ -227,18 +253,9 @@ def main( if my_grid_file is not None: my_grid_file = np.array(my_grid_file.split(',')) ntiles_file = my_grid_file.size - - # start parallel - # TODO: need to link to location of pyFMS shared library - mpp = pyFMS_mpp(clib) - mpp_domains = pyFMS_mpp_domains(clib) - - # TODO: Find what to use for error_type - if(mpp.pyfms_npes() > 1): - mpp.pyfms_error(error_type, "make_hgrid: make_hgrid must be run one processor, contact developer") - - print(f"==>NOTE: the grid type is {grid_type}") + if mpp.pe() == 0 and verbose: + print(f"==>NOTE: the grid type is {grid_type}") if grid_type == "regular_lonlat_grid": my_grid_type = REGULAR_LONLAT_GRID @@ -259,18 +276,19 @@ def main( elif grid_type == "beta_plane_grid": my_grid_type = BETA_PLANE_GRID else: - mpp.pyfms_error("make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', " - "'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', " - "'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") + mpp.pyfms_error("make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") if my_grid_type != GNOMONIC_ED and out_halo != 0: mpp.pyfms_error("make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") if out_halo != 0 and out_halo != 1: mpp.pyfms_error("make_hgrid: out_halo should be 0 or 1") + if my_grid_type != GNOMONIC_ED and do_schmidt: mpp.pyfms_error("make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") + if my_grid_type != GNOMONIC_ED and do_cube_transform: mpp.pyfms_error("make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") + if do_cube_transform and do_schmidt: mpp.pyfms_error("make_hgrid: both --do_cube_transform and --do_schmidt are set") @@ -290,7 +308,6 @@ def main( mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") num_specify = 0 - if nxbnds2 > 0 and nybnds2 > 0: num_specify += 1 if nxbnds3 > 0 and nybnds3 > 0: @@ -433,8 +450,8 @@ def main( Get super grid size """ if use_legacy: - nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) # in tool_util.c - nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) # in tool_util.c + nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) + nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: for n in range(ntiles_global): nxl[n] = nlon[n] @@ -454,7 +471,7 @@ def main( else: nxl[0] = 0 nyl[0] = 0 - for n in range(nxbnds-1): + for n in range(nxbnds - 1): nxl[0] += nlon[n] for n in range(nybnds - 1): nyl[0] += nlat[n] @@ -517,13 +534,11 @@ def main( iec = nx - 1 jsc = 0 jec = ny - 1 - # TODO: Methods to create types of grids to be passed instance of - # GridStruct class if(my_grid_type==REGULAR_LONLAT_GRID): create_regular_lonlat_grid( - &nxbnds, - &nybnds, + nxbnds, + nybnds, xbnds, ybnds, nlon, @@ -531,23 +546,23 @@ def main( dx_bnds, dy_bnds, use_legacy, - &isc, - &iec, - &jsc, - &jec, - x, - y, - dx, - dy, - area, - angle_dx, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, center, use_great_circle_algorithm, ) elif(my_grid_type==TRIPOLAR_GRID): create_tripolar_grid( - &nxbnds, - &nybnds, + nxbnds, + nybnds, xbnds, ybnds, nlon, @@ -555,17 +570,17 @@ def main( dx_bnds, dy_bnds, use_legacy, - &lat_join, - &isc, - &iec, - &jsc, - &jec, - x, - y, - dx, - dy, - area, - angle_dx, + lat_join, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, center, verbose, use_great_circle_algorithm, @@ -578,14 +593,14 @@ def main( n4 = n * nx * ny create_grid_from_file( my_grid_file[n], - &nx, - &ny, - x+n1, - y+n1, - dx+n2, - dy+n3, - area+n4, - angle_dx+n1, + nx, + ny, + grid_obj.x[n1], + grid_obj.y[n1], + grid_obj.dx[n2], + grid_obj.dy[n3], + grid_obj.area[n4], + grid_obj.angle_dx[n1], use_great_circle_algorithm, use_angular_midpoint, ) @@ -593,64 +608,64 @@ def main( create_simple_cartesian_grid( xbnds, ybnds, - &nx, - &ny, - &simple_dx, - &simple_dy, - &isc, - &iec, - &jsc, - &jec, - x, - y, - dx, - dy, - area, - angle_dx, + nx, + ny, + simple_dx, + simple_dy, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, ) elif(my_grid_type==SPECTRAL_GRID): create_spectral_grid( - &nx, - &ny, - &isc, - &iec, - &jsc, - &jec, - x, - y, - dx, - dy, - area, - angle_dx, + nx, + ny, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, use_great_circle_algorithm, ) elif(my_grid_type==CONFORMAL_CUBIC_GRID): create_conformal_cubic_grid( - &nx, - &nratio, + nx, + nratio, method, orientation, - x, - y, - dx, - dy, - area, - angle_dx, - angle_dy, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, + grid_obj.angle_dy, ) elif(my_grid_type==GNOMONIC_ED): - if(nest_grids == 1 and parent_tile_list[0] == 0): + if(nest_grids == 1 and parent_tile[0] == 0): create_gnomonic_cubic_grid_GR( grid_type, nxl, nyl, - x, - y, - dx, - dy, - area, - angle_dx, - angle_dy, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, + grid_obj.angle_dy, shift_fac, do_schmidt, do_cube_transform, @@ -672,13 +687,13 @@ def main( grid_type, nxl, nyl, - x, - y, - dx, - dy, - area, - angle_dx, - angle_dy, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, + grid_obj.angle_dy, shift_fac, do_schmidt, do_cube_transform, @@ -697,8 +712,8 @@ def main( ) elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): create_f_plane_grid( - &nxbnds, - &nybnds, + nxbnds, + nybnds, xbnds, ybnds, nlon, @@ -707,24 +722,25 @@ def main( dy_bnds, use_legacy, f_plane_latitude, - &isc, - &iec, - &jsc, - &jec, - x, - y, - dx, - dy, - area, - angle_dx, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, center, ) - grid_data.write_data() + grid_obj.write_out_grid(filepath="") - if(mpp_pe() == mpp_root_pe() and verbose): + if(mpp.pe() == 0 and verbose): print("generate_grid is run successfully") + + pyfms.pyfms_end() - mpp_end() # End of main \ No newline at end of file diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index e29b777..f0c67a4 100644 --- a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -474,8 +474,322 @@ def create_conformal_cubic_grid( angle_dy_p, ) -def create_gnomonic_cubic_grid_GR(): +def create_gnomonic_cubic_grid_GR( + grid_type: str, + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + angle_dy: npt.NDArray[np.float64], + shift_fac: float, + do_schmidt: int, + do_cube_transform: int, + stretch_factor: float, + target_lon: float, + target_lat: float, + nest_grid: int, + parent_tile: int, + refine_ratio: int, + istart_nest: int, + iend_nest: int, + jstart_nest: int, + jend_nest: int, + halo: int, + output_length_angle: int, +): + _create_gnomonic_cubic_grid_GR = lib.create_gnomonic_cubic_gridGR + + grid_type_c, grid_type_t = set_Cchar(grid_type) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) + shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) + do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) + do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) + stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) + target_lon_c, target_lon_t = setscalar_Cint32(target_lon) + target_lat_c, target_lat_t = setscalar_Cint32(target_lat) + nest_grid_c, nest_grid_t = setscalar_Cint32(nest_grid) + parent_tile_c, parent_tile_t = setscalar_Cint32(parent_tile) + refine_ratio_c, refine_ratio_t = setscalar_Cint32(refine_ratio) + istart_nest_c, istart_nest_t = setscalar_Cint32(istart_nest) + iend_nest_c, iend_nest_t = setscalar_Cint32(iend_nest) + jstart_nest_c, jstart_nest_t = setscalar_Cint32(jstart_nest) + jend_nest_c, jend_nest_t = setscalar_Cint32(jend_nest) + halo_c, halo_t = setscalar_Cint32(halo) + output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) + + _create_gnomonic_cubic_grid_GR.argtypes = [ + grid_type_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + shift_fac_t, + do_schmidt_t, + do_cube_transform_t, + stretch_factor_t, + target_lon_t, + target_lat_t, + nest_grid_t, + parent_tile_t, + refine_ratio_t, + istart_nest_t, + iend_nest_t, + jstart_nest_t, + jend_nest_t, + halo_t, + output_length_angle_t, + ] + _create_gnomonic_cubic_grid_GR.restype = None + + _create_gnomonic_cubic_grid_GR( + grid_type_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + shift_fac_c, + do_schmidt_c, + do_cube_transform_c, + stretch_factor_c, + target_lon_c, + target_lat_c, + nest_grid_c, + parent_tile_c, + refine_ratio_c, + istart_nest_c, + iend_nest_c, + jstart_nest_c, + jend_nest_c, + halo_c, + output_length_angle_c, + ) -def create_gnomonic_cubic_grid(): +def create_gnomonic_cubic_grid( + grid_type: str, + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + angle_dy: npt.NDArray[np.float64], + shift_fac: float, + do_schmidt: int, + do_cube_transform: int, + stretch_factor: float, + target_lon: float, + target_lat: float, + num_nest_grids: int, + parent_tile: npt.NDArray[np.int32], + refine_ratio: npt.NDArray[np.int32], + istart_nest: npt.NDArray[np.int32], + iend_nest: npt.NDArray[np.int32], + jstart_nest: npt.NDArray[np.int32], + jend_nest: npt.NDArray[np.int32], + halo: int, + output_length_angle: int, +): + _create_gnomonic_cubic_grid = lib.create_gnomonic_cubic_grid + + grid_type_c, grid_type_t = set_Cchar(grid_type) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) + shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) + do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) + do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) + stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) + target_lon_c, target_lon_t = setscalar_Cdouble(target_lon) + target_lat_c, target_lat_t = setscalar_Cdouble(target_lat) + num_nest_grids_c, num_nest_grids_t = setscalar_Cint32(num_nest_grids) + parent_tile_p, parent_tile_t = setarray_Cint32(parent_tile) + refine_ratio_p, refine_ratio_t = setarray_Cint32(refine_ratio) + istart_nest_p, istart_nest_t = setarray_Cint32(istart_nest) + iend_nest_p, iend_nest_t = setarray_Cint32(iend_nest) + jstart_nest_p, jstart_nest_t = setarray_Cint32(jstart_nest) + jend_nest_p, jend_nest_t = setarray_Cint32(jend_nest) + halo_c, halo_t = setscalar_Cint32(halo) + output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) + + _create_gnomonic_cubic_grid.argtypes = [ + grid_type_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + shift_fac_t, + do_schmidt_t, + do_cube_transform_t, + stretch_factor_t, + target_lon_t, + target_lat_t, + num_nest_grids_t, + parent_tile_t, + refine_ratio_t, + istart_nest_t, + iend_nest_t, + jstart_nest_t, + jend_nest_t, + halo_t, + output_length_angle_t, + ] + _create_gnomonic_cubic_grid.restype = None + + _create_gnomonic_cubic_grid( + grid_type_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + shift_fac_c, + do_schmidt_c, + do_cube_transform_c, + stretch_factor_c, + target_lon_c, + target_lat_c, + num_nest_grids_c, + parent_tile_p, + refine_ratio_p, + istart_nest_p, + iend_nest_p, + jstart_nest_p, + jend_nest_p, + halo_c, + output_length_angle_c, + ) -def create_f_plane_grid(): \ No newline at end of file +def create_f_plane_grid( + nxbnds: int, + nybnds: int, + xbnds: npt.NDArray[np.float64], + ybnds: npt.NDArray[np.float64], + nlon: npt.NDArray[np.int32], + nlat: npt.NDArray[np.int32], + dlon: npt.NDArray[np.float64], + dlat: npt.NDArray[np.float64], + use_legacy: int, + f_plane_latitude: float, + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + dx: npt.NDArray[np.float64], + dy: npt.NDArray[np.float64], + area: npt.NDArray[np.float64], + angle_dx: npt.NDArray[np.float64], + center: str +): + _create_f_plane_grid = lib.create_f_plane_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + dlon_p, dlon_t = setarray_Cdouble(dlon) + dlat_p, dlat_t = setarray_Cdouble(dlat) + use_legacy_c, use_legacy_t = setscalar_Cint32(use_legacy) + f_plane_latitude_c, f_plane_latitude_t = setscalar_Cdouble(f_plane_latitude) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + + _create_f_plane_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + f_plane_latitude_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + ] + _create_f_plane_grid.restype = None + + _create_f_plane_grid( + nxbnds_c, + nybnds_c, + xbnds_p, + ybnds_p, + nlon_p, + nlat_t, + dlon_p, + dlat_p, + use_legacy_c, + f_plane_latitude_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + center_c, + ) \ No newline at end of file From df1e9b7da305b366865039df585397be3154101a Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 13 Feb 2025 14:03:27 -0500 Subject: [PATCH 11/72] Adding None initialization to from_file GridObj method --- FMSgridtools/shared/gridobj.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index d4b69a7..6a16087 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -91,6 +91,15 @@ def from_file(cls, filepath: str) -> "GridObj": check_file_is_there(filepath) with xr.open_dataset(filepath) as ds: varlist = list(ds.data_vars) + _tile = None + _x = None + _y = None + _dx = None + _dy = None + _area = None + _angle_dx = None + _angle_dy = None + _arcx = None if "tile" in varlist: _tile = ds.tile.values.item().decode('ascii') if "x" in varlist: From d516331787553aa8a417d516a03000ce567a3c8f Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 13 Feb 2025 14:13:05 -0500 Subject: [PATCH 12/72] Merged in fix/grid_obj branch --- FMSgridtools/shared/gridobj.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 72baffa..e2150a8 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -7,11 +7,6 @@ from FMSgridtools.shared.gridtools_utils import check_file_is_there -<<<<<<< HEAD -======= -# TODO: Remove direct attributes, use property decorators instead - ->>>>>>> fix/grid_obj """ GridObj: @@ -22,13 +17,10 @@ class GridObj: grid_data: Optional[xr.Dataset] = None grid_file: Optional[str] = None tile: Optional[str] = None -<<<<<<< HEAD -======= _nx: Optional[int] = None _ny: Optional[int] = None _nxp: Optional[int] = None _nyp: Optional[int] = None ->>>>>>> fix/grid_obj x: Optional[npt.NDArray] = None y: Optional[npt.NDArray] = None dx: Optional[npt.NDArray] = None From f669851fd836dd1a4e4dda77a2de8106f8cf8fd8 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 18 Feb 2025 15:04:41 -0500 Subject: [PATCH 13/72] Addition of h-grid obj prelim --- FMSgridtools/make_hgrid/hgridobj.py | 134 ++++++++++++++++++ FMSgridtools/make_hgrid/make_hgrid.py | 129 +++++++++-------- .../make_hgrid/make_hgrid_util.py | 51 +++++++ .../pyfrenctools/shared/tool_util.py | 34 +++++ 4 files changed, 289 insertions(+), 59 deletions(-) create mode 100644 FMSgridtools/make_hgrid/hgridobj.py create mode 100644 FRENCTools_lib/pyfrenctools/shared/tool_util.py diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py new file mode 100644 index 0000000..0596406 --- /dev/null +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -0,0 +1,134 @@ +import dataclasses +from typing import List, Optional +import numpy as np +import numpy.typing as npt +import xarray as xr + +from FMSgridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridobj import GridObj + +@dataclasses.dataclass +class HGridObj(GridObj): + + def write_out_hgrid( + self, + tilename, + outfile, + north_pole_tile: Optional[str]="none", + north_pole_arcx: Optional[str]="none", + projection: Optional[str]="none", + geometry: Optional[str]="none", + discretization: Optional[str]="none", + conformal: Optional[str]="none", + out_halo: Optional[int]=0, + output_length_angle: Optional[int]=0 + ): + tile = None + x = None + y = None + if north_pole_tile == "none": + tile = xr.DataArray( + ["tile"], + attrs=dict( + standard_name="grid_tile_spec", + geometry=geometry, + discretization=discretization, + conformal=conformal, + ) + ) + elif projection == "none": + tile = xr.DataArray( + ["tile"], + attrs=dict( + standard_name="grid_tile_spec", + geometry=geometry, + north_pole=north_pole_tile, + discretization=discretization, + conformal=conformal, + ) + ) + else: + tile = xr.DataArray( + ["tile"], + attrs=dict( + standard_name="grid_tile_spec", + geometry=geometry, + north_pole=north_pole_tile, + projection=projection, + discretization=discretization, + conformal=conformal, + ) + ) + + x = xr.DataArray( + data=self.x, + dims=["nyp", "nxp"], + attrs=dict( + units="degree_east", + standard_name="geographic_longitude", + ) + ) + if out_halo > 0: + x.attrs["_FillValue"] = -9999. + + y = xr.DataArray( + data=self.y, + dims=["nyp", "nxp"], + attrs=dict( + units="degree_north", + standard_name="geographic_latitude", + ) + ) + if out_halo > 0: + y.attrs["_FillValue"] = -9999. + + if output_length_angle: + dx = xr.DataArray( + data=self.dx, + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", + ) + ) + if out_halo > 0: + dx.attrs["_FillValue"] = -9999. + dy = xr.DataArray( + data=self.dy, + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", + ) + ) + if out_halo > 0: + dy.attrs["_FillValue"] = -9999. + angle_dx = xr.DataArray( + data=self.angle_dx, + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", + ) + ) + if conformal == "true": + angle_dy = xr.DataArray( + data=self.angle_dy, + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_north", + standard_name="grid_vertex_y_angle_WRT_geographic_north", + ) + ) + area = xr.DataArray( + data=self.area, + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", + ) + ) + if out_halo > 0: + area.attrs["_FillValue"] = -9999. + arcx = xr. + diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index d28d266..5755305 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -7,7 +7,7 @@ from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains -from FMSgridtools.shared.gridobj import GridObj +from FMSgridtools.make_hgrid.hgridobj import HGridObj from FMSgridtools.shared.gridtools_utils import check_file_is_there from FRENCTools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( create_regular_lonlat_grid, @@ -19,6 +19,7 @@ create_gnomonic_cubic_grid_GR, create_gnomonic_cubic_grid, create_f_plane_grid, + fill_cubic_grid_halo, ) from FRENCTools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size @@ -35,56 +36,6 @@ BETA_PLANE_GRID = 9 MISSING_VALUE = -9999. -def fill_cubic_grid_halo( - nx: int, - ny: int, - halo: int, - data: npt.NDArray[np.float64], - data1_all: npt.NDArray[np.float64], - data2_all: npt.NDArray[np.float64], - tile: int, - ioff: int, - joff: int, -): - nxp = nx + ioff - nyp = ny + joff - nxph = nx + ioff + 2*halo - nyph = ny + joff + 2*halo - - for i in range(nxph*nyph): - data[i] = MISSING_VALUE - - # first copy computing domain data - for j in range (nyp+1): - for i in range(nxp+1): - data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] - - ntiles = 6 - - if tile%2 == 1: - lw = (tile+ntiles-1)%ntiles - le = (tile+ntiles+2)%ntiles - ls = (tile+ntiles-2)%ntiles - ln = (tile+ntiles+1)%ntiles - for j in range(nyp+1): - data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo - data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo - - for i in range(nxp+1): - data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo - data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo - else: - lw = (tile+ntiles-2)%ntiles - le = (tile+ntiles+1)%ntiles - ls = (tile+ntiles-1)%ntiles - ln = (tile+ntiles+2)%ntiles - for j in range(nyp+1): - data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo - data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo - - for i in range(nxp+1): - data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo - data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo @click.command() @click.argument('args', nargs=-1) @@ -188,7 +139,7 @@ def main( output_length_angle = 1 ntiles = 1 ntiles_global = 1 - grid_obj = GridObj() + grid_obj = HGridObj() gridname = "horizontal_grid" center = "none" @@ -433,7 +384,8 @@ def main( if f_plane_latitude > 90 or f_plane_latitude < -90: mpp.pyfms_error("make_hgrid: f_plane_latitude should be between -90 and 90.") if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: - print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) + if mpp.pe() == 0: + print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) if mpp.pe() == 0: print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) else: @@ -595,12 +547,12 @@ def main( my_grid_file[n], nx, ny, - grid_obj.x[n1], - grid_obj.y[n1], - grid_obj.dx[n2], - grid_obj.dy[n3], - grid_obj.area[n4], - grid_obj.angle_dx[n1], + grid_obj.x[n1:], + grid_obj.y[n1:], + grid_obj.dx[n2:], + grid_obj.dy[n3:], + grid_obj.area[n4:], + grid_obj.angle_dx[n1:], use_great_circle_algorithm, use_angular_midpoint, ) @@ -735,6 +687,65 @@ def main( center, ) + pos_c = 0 + pos_e = 0 + pos_t = 0 + pos_n = 0 + for n in range(ntiles): + tilename = "tile" + str(n+1) + if ntiles > 1: + outfile = grid_name + ".tile" + ".nc" + str(n+1) + else: + outfile = grid_name + ".nc" + + if verbose: + print(f"Writing out {outfile}", file=sys.stderr) + + nx = nxl[n] + ny = nyl[n] + if verbose: + print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) + nxp = nx + 1 + nyp = nx + 1 + + if out_halo == 0: + if verbose: + print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) + print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) + if n > 0: + print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) + grid_obj.x = grid_obj.x[pos_c:] + grid_obj.y = grid_obj.y[pos_c:] + if output_length_angle: + grid_obj.dx = grid_obj.dx[pos_n:] + grid_obj.dy = grid_obj.dy[pos_e:] + grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] + if conformal == "true": + grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] + grid_obj.area = grid_obj.area[pos_t:] + + else: + tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + if verbose: + print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) + grid_obj.x = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) + grid_obj.y = tmp.copy() + if output_length_angle: + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) + grid_obj.angle_dx = tmp.copy() + if conformal == "true": + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) + grid_obj.angle_dy = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) + grid_obj.dx = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) + grid_obj.dy = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) + grid_obj.area = tmp.copy() + + grid_obj.write_out_grid(filepath="") if(mpp.pe() == 0 and verbose): diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index f0c67a4..eac55f4 100644 --- a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -12,6 +12,57 @@ lib = ctypes.CDLL("../../FRENCTools_lib/cfrenctools/c_build/clib.so") +def fill_cubic_grid_halo( + nx: int, + ny: int, + halo: int, + data: npt.NDArray[np.float64], + data1_all: npt.NDArray[np.float64], + data2_all: npt.NDArray[np.float64], + tile: int, + ioff: int, + joff: int, +): + nxp = nx + ioff + nyp = ny + joff + nxph = nx + ioff + 2*halo + nyph = ny + joff + 2*halo + + for i in range(nxph*nyph): + data[i] = MISSING_VALUE + + # first copy computing domain data + for j in range (nyp+1): + for i in range(nxp+1): + data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] + + ntiles = 6 + + if tile%2 == 1: + lw = (tile+ntiles-1)%ntiles + le = (tile+ntiles+2)%ntiles + ls = (tile+ntiles-2)%ntiles + ln = (tile+ntiles+1)%ntiles + for j in range(nyp+1): + data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo + data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo + + for i in range(nxp+1): + data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo + data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo + else: + lw = (tile+ntiles-2)%ntiles + le = (tile+ntiles+1)%ntiles + ls = (tile+ntiles-1)%ntiles + ln = (tile+ntiles+2)%ntiles + for j in range(nyp+1): + data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo + data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo + + for i in range(nxp+1): + data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo + data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo + def create_regular_lonlat_grid( nxbnds: int, nybnds: int, diff --git a/FRENCTools_lib/pyfrenctools/shared/tool_util.py b/FRENCTools_lib/pyfrenctools/shared/tool_util.py new file mode 100644 index 0000000..13c02cb --- /dev/null +++ b/FRENCTools_lib/pyfrenctools/shared/tool_util.py @@ -0,0 +1,34 @@ +import numpy as np +import numpy.typing as npt +import ctypes + +from pyfms.data_handling import ( + setscalar_Cint32, + setarray_Cdouble, +) + +lib = ctypes.CDLL("../../FRENCTools_lib/cfrenctools/c_build/clib.so") + +def get_legacy_grid_size( + nb: int, + bnds: npt.NDArray[np.float64], + dbnds: npt.NDArray[np.float64], +): + _get_legacy_grid_size = lib.get_legacy_grid_size + + nb_c, nb_t = setscalar_Cint32(nb) + bnds_p, bnds_t = setarray_Cdouble(bnds) + dbnds_p, dbnds_t = setarray_Cdouble(dbnds) + + _get_legacy_grid_size.argtypes = [ + nb_t, + bnds_t, + dbnds_t, + ] + _get_legacy_grid_size.restype = ctypes.c_int + + _get_legacy_grid_size( + nb_c, + bnds_p, + dbnds_p, + ) \ No newline at end of file From a0f4a3f4fc0bcd7b948245e3741ba03416cd01b6 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 18 Feb 2025 15:18:36 -0500 Subject: [PATCH 14/72] Removed empty attributes from GridObj, left access only from gridfile/dataset --- FMSgridtools/shared/gridobj.py | 104 +-------------------------------- 1 file changed, 2 insertions(+), 102 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 6a16087..8b58c1b 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -7,8 +7,6 @@ from FMSgridtools.shared.gridtools_utils import check_file_is_there -# TODO: Remove direct attributes, use property decorators instead - """ GridObj: @@ -18,19 +16,10 @@ class GridObj: grid_data: Optional[xr.Dataset] = None grid_file: Optional[str] = None - tile: Optional[str] = None _nx: Optional[int] = None _ny: Optional[int] = None _nxp: Optional[int] = None _nyp: Optional[int] = None - x: Optional[npt.NDArray] = None - y: Optional[npt.NDArray] = None - dx: Optional[npt.NDArray] = None - dy: Optional[npt.NDArray] = None - area: Optional[npt.NDArray] = None - angle_dx: Optional[npt.NDArray] = None - angle_dy: Optional[npt.NDArray] = None - arcx: Optional[str] = None def __post_init__(self): if self.grid_data is not None: @@ -139,81 +128,8 @@ def from_file(cls, filepath: str) -> "GridObj": grid_data attribute. """ def write_out_grid(self, filepath: str): - if self.tile is not None: - tile = xr.DataArray( - [self.tile], - ) - else: - tile = None - if self.x is not None: - x = xr.DataArray( - data=self.x, - dims=["nyp", "nxp"], - ) - else: - x = None - if self.y is not None: - y = xr.DataArray( - data=self.y, - dims=["nyp", "nxp"], - ) - else: - y = None - if self.dx is not None: - dx = xr.DataArray( - data=self.dx, - dims=["nyp", "nx"], - ) - else: - dx = None - if self.dy is not None: - dy = xr.DataArray( - data=self.dy, - dims=["ny", "nxp"], - ) - else: - dy = None - if self.area is not None: - area = xr.DataArray( - data=self.area, - dims=["ny", "nx"], - ) - else: - area = None - if self.angle_dx is not None: - angle_dx = xr.DataArray( - data=self.angle_dx, - dims=["nyp", "nxp"], - ) - else: - angle_dx = None - if self.angle_dy is not None: - angle_dy = xr.DataArray( - data=self.angle_dy, - dims=["nyp", "nxp"], - ) - else: - angle_dy = None - if self.arcx is not None: - arcx = xr.DataArray( - [self.arcx], - ) - else: - arcx = None - out_grid_dataset = xr.Dataset( - data_vars={ - "tile": tile, - "x": x, - "y": y, - "dx": dx, - "dy": dy, - "area": area, - "angle_dx": angle_dx, - "angle_dy": angle_dy, - "arcx": arcx, - } - ) - out_grid_dataset.to_netcdf(filepath) + if self.grid_data is not None: + self.grid_data.to_netcdf(filepath) """ get_agrid_lonlat: @@ -255,10 +171,6 @@ def nx(self): if self._nx is None: if self.grid_data is not None: self._nx = self.grid_data.sizes['nx'] - elif self.area is not None: - self._nx = self.area.shape[1] - else: - pass return self._nx @property @@ -266,10 +178,6 @@ def ny(self): if self._ny is None: if self.grid_data is not None: self._ny = self.grid_data.sizes['ny'] - elif self.area is not None: - self._ny = self.area.shape[0] - else: - pass return self._ny @property @@ -277,10 +185,6 @@ def nxp(self): if self._nxp is None: if self.grid_data is not None: self._nxp = self.grid_data.sizes['nxp'] - elif self.x is not None: - self._nxp = self.x.shape[1] - else: - pass return self._nxp @property @@ -288,10 +192,6 @@ def nyp(self): if self._nyp is None: if self.grid_data is not None: self._nyp = self.grid_data.sizes['nyp'] - elif self.x is not None: - self._nyp = self.x.shape[0] - else: - pass return self._nyp #TODO: I/O method for passing to the host From fd8af1548283e8a315c4ae83e32fcc0104313da0 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 18 Feb 2025 15:48:59 -0500 Subject: [PATCH 15/72] Amended GridObj from_file method --- FMSgridtools/shared/gridobj.py | 73 ++++++++-------------------------- 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 8b58c1b..616863d 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -16,10 +16,6 @@ class GridObj: grid_data: Optional[xr.Dataset] = None grid_file: Optional[str] = None - _nx: Optional[int] = None - _ny: Optional[int] = None - _nxp: Optional[int] = None - _nyp: Optional[int] = None def __post_init__(self): if self.grid_data is not None: @@ -79,46 +75,9 @@ def __post_init__(self): def from_file(cls, filepath: str) -> "GridObj": check_file_is_there(filepath) with xr.open_dataset(filepath) as ds: - varlist = list(ds.data_vars) - _tile = None - _x = None - _y = None - _dx = None - _dy = None - _area = None - _angle_dx = None - _angle_dy = None - _arcx = None - if "tile" in varlist: - _tile = ds.tile.values.item().decode('ascii') - if "x" in varlist: - _x = np.ascontiguousarray(ds.x.values) - if "y" in varlist: - _y = np.ascontiguousarray(ds.y.values) - if "dx" in varlist: - _dx = np.ascontiguousarray(ds.dx.values) - if "dy" in varlist: - _dy = np.ascontiguousarray(ds.dy.values) - if "area" in varlist: - _area = np.ascontiguousarray(ds.area.values) - if "angle_dx" in varlist: - _angle_dx = np.ascontiguousarray(ds.angle_dx.values) - if "angle_dy" in varlist: - _angle_dy = np.ascontiguousarray(ds.angle_dy.values) - if "arcx" in varlist: - _arcx = ds.arcx.values.item().decode('ascii') return cls( grid_data=ds, grid_file=filepath, - tile = _tile, - x = _x, - y = _y, - dx = _dx, - dy = _dy, - area = _area, - angle_dx = _angle_dx, - angle_dy = _angle_dy, - arcx = _arcx, ) """ @@ -168,30 +127,30 @@ def get_variable_list(self) -> List: @property def nx(self): - if self._nx is None: - if self.grid_data is not None: - self._nx = self.grid_data.sizes['nx'] - return self._nx + _nx = None + if self.grid_data is not None: + _nx = self.grid_data.sizes['nx'] + return _nx @property def ny(self): - if self._ny is None: - if self.grid_data is not None: - self._ny = self.grid_data.sizes['ny'] - return self._ny + _ny = None + if self.grid_data is not None: + _ny = self.grid_data.sizes['ny'] + return _ny @property def nxp(self): - if self._nxp is None: - if self.grid_data is not None: - self._nxp = self.grid_data.sizes['nxp'] - return self._nxp + _nxp = None + if self.grid_data is not None: + _nxp = self.grid_data.sizes['nxp'] + return _nxp @property def nyp(self): - if self._nyp is None: - if self.grid_data is not None: - self._nyp = self.grid_data.sizes['nyp'] - return self._nyp + _nyp = None + if self.grid_data is not None: + _nyp = self.grid_data.sizes['nyp'] + return _nyp #TODO: I/O method for passing to the host From 7bffc352ea40a7575373428c16404493716b069d Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 19 Feb 2025 10:31:59 -0500 Subject: [PATCH 16/72] Switching over to fix/grid_obj branch --- FMSgridtools/make_hgrid/hgridobj.py | 45 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 0596406..4fe57c5 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -8,7 +8,16 @@ from FMSgridtools.shared.gridobj import GridObj @dataclasses.dataclass -class HGridObj(GridObj): +class HGridObj(): + tile: Optional[str] = None + x: Optional[npt.NDArray] = None + y: Optional[npt.NDArray] = None + dx: Optional[npt.NDArray] = None + dy: Optional[npt.NDArray] = None + area: Optional[npt.NDArray] = None + angle_dx: Optional[npt.NDArray] = None + angle_dy: Optional[npt.NDArray] = None + arcx: Optional[str] = None def write_out_hgrid( self, @@ -23,9 +32,6 @@ def write_out_hgrid( out_halo: Optional[int]=0, output_length_angle: Optional[int]=0 ): - tile = None - x = None - y = None if north_pole_tile == "none": tile = xr.DataArray( ["tile"], @@ -68,8 +74,6 @@ def write_out_hgrid( standard_name="geographic_longitude", ) ) - if out_halo > 0: - x.attrs["_FillValue"] = -9999. y = xr.DataArray( data=self.y, @@ -79,8 +83,6 @@ def write_out_hgrid( standard_name="geographic_latitude", ) ) - if out_halo > 0: - y.attrs["_FillValue"] = -9999. if output_length_angle: dx = xr.DataArray( @@ -91,8 +93,7 @@ def write_out_hgrid( standard_name="grid_edge_x_distance", ) ) - if out_halo > 0: - dx.attrs["_FillValue"] = -9999. + dy = xr.DataArray( data=self.dy, dims=["ny", "nxp"], @@ -101,8 +102,7 @@ def write_out_hgrid( standard_name="grid_edge_y_distance", ) ) - if out_halo > 0: - dy.attrs["_FillValue"] = -9999. + angle_dx = xr.DataArray( data=self.angle_dx, dims=["nyp", "nxp"], @@ -128,7 +128,26 @@ def write_out_hgrid( standard_name="grid_cell_area", ) ) + + if north_pole_arcx == "none": + arcx = xr.DataArray( + ["arcx"], + attrs=dict( + standard_name="grid_edge_x_arc_type", + ) + ) + else: + arcx = xr.DataArray( + ["arcx"], + attrs=dict( + standard_name="grid_edge_x_arc_type", + north_pole=north_pole_arcx, + ) + ) if out_halo > 0: + x.attrs["_FillValue"] = -9999. + y.attrs["_FillValue"] = -9999. + dx.attrs["_FillValue"] = -9999. + dy.attrs["_FillValue"] = -9999. area.attrs["_FillValue"] = -9999. - arcx = xr. From b198f92a722e035eebcbaa455107f787b49b4bb2 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 19 Feb 2025 10:49:05 -0500 Subject: [PATCH 17/72] Made properties of GridObj all default to None when there is no dataset --- FMSgridtools/shared/gridobj.py | 130 +++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 616863d..53b1d33 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -18,51 +18,10 @@ class GridObj: grid_file: Optional[str] = None def __post_init__(self): - if self.grid_data is not None: - varlist = list(self.grid_data.data_vars) - if "tile" in varlist: - self.tile = self.grid_data.tile.values.item().decode('ascii') - if "x" in varlist: - self.x = np.ascontiguousarray(self.grid_data.x.values) - if "y" in varlist: - self.y = np.ascontiguousarray(self.grid_data.y.values) - if "dx" in varlist: - self.dx = np.ascontiguousarray(self.grid_data.dx.values) - if "dy" in varlist: - self.dy = np.ascontiguousarray(self.grid_data.dy.values) - if "area" in varlist: - self.area = np.ascontiguousarray(self.grid_data.area.values) - if "angle_dx" in varlist: - self.angle_dx = np.ascontiguousarray(self.grid_data.angle_dx.values) - if "angle_dy" in varlist: - self.angle_dy = np.ascontiguousarray(self.grid_data.angle_dy.values) - if "arcx" in varlist: - self.arcx = self.grid_data.arcx.values.item().decode('ascii') - elif self.grid_file is not None: + if self.grid_file is not None: check_file_is_there(self.grid_file) with xr.open_dataset(self.grid_file) as ds: self.grid_data = ds - varlist = list(self.grid_data.data_vars) - if "tile" in varlist: - self.tile = self.grid_data.tile.values.item().decode('ascii') - if "x" in varlist: - self.x = np.ascontiguousarray(self.grid_data.x.values) - if "y" in varlist: - self.y = np.ascontiguousarray(self.grid_data.y.values) - if "dx" in varlist: - self.dx = np.ascontiguousarray(self.grid_data.dx.values) - if "dy" in varlist: - self.dy = np.ascontiguousarray(self.grid_data.dy.values) - if "area" in varlist: - self.area = np.ascontiguousarray(self.grid_data.area.values) - if "angle_dx" in varlist: - self.angle_dx = np.ascontiguousarray(self.grid_data.angle_dx.values) - if "angle_dy" in varlist: - self.angle_dy = np.ascontiguousarray(self.grid_data.angle_dy.values) - if "arcx" in varlist: - self.arcx = self.grid_data.arcx.values.item().decode('ascii') - else: - pass """ from_file: @@ -125,32 +84,95 @@ def get_agrid_lonlat(self)-> tuple[npt.NDArray, npt.NDArray]: def get_variable_list(self) -> List: return list(self.grid_data.data_vars) + @property + def tile(self): + if self.grid_data is not None: + return self.grid_data.tile.values.item().decode('ascii') + else: + return None + + @property + def x(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.x.values) + else: + return None + + @property + def y(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.y.values) + else: + return None + + @property + def dx(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.dx.values) + else: + return None + + @property + def dy(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.dy.values) + else: + return None + + @property + def area(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.area.values) + else: + return None + + @property + def angle_dx(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.angle_dx.values) + else: + return None + + @property + def angle_dy(self): + if self.grid_data is not None: + return np.ascontiguousarray(self.grid_data.angle_dy.values) + else: + return None + + @property + def arcx(self): + if self.grid_data is not None: + return self.grid_data.arcx.values.item().decode('ascii') + else: + return None + @property def nx(self): - _nx = None if self.grid_data is not None: - _nx = self.grid_data.sizes['nx'] - return _nx + return self.grid_data.sizes['nx'] + else: + return None @property def ny(self): - _ny = None if self.grid_data is not None: - _ny = self.grid_data.sizes['ny'] - return _ny + return self.grid_data.sizes['ny'] + else: + return None @property def nxp(self): - _nxp = None if self.grid_data is not None: - _nxp = self.grid_data.sizes['nxp'] - return _nxp + return self.grid_data.sizes['nxp'] + else: + return None @property def nyp(self): - _nyp = None if self.grid_data is not None: - _nyp = self.grid_data.sizes['nyp'] - return _nyp + return self.grid_data.sizes['nyp'] + else: + return None #TODO: I/O method for passing to the host From 983ae1d78ad829358aea6aa6d70539d39247fbba Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 19 Feb 2025 13:06:21 -0500 Subject: [PATCH 18/72] Switching over to fix/grid_obj branch --- FMSgridtools/make_hgrid/hgridobj.py | 70 +++++++++++++++++++ .../make_hgrid/make_hgrid_util.py | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 4fe57c5..35d3848 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -151,3 +151,73 @@ def write_out_hgrid( dy.attrs["_FillValue"] = -9999. area.attrs["_FillValue"] = -9999. + def make_gridobj(self) -> "GridObj": + tile = None + x = None + y = None + dx = None + dy = None + angle_dx = None + angle_dy = None + area = None + arcx = None + if self.tile is not None: + tile = xr.DataArray( + [self.tile] + ) + if self.x is not None: + x = xr.DataArray( + data=self.x, + dims=["nyp", "nxp"], + ) + if self.y is not None: + y = xr.DataArray( + data=self.y, + dims=["nyp", "nxp"], + ) + if self.dx is not None: + dx = xr.DataArray( + data=self.dx, + dims=["nyp", "nx"], + ) + if self.dy is not None: + dy = xr.DataArray( + data=self.dy, + dims=["ny", "nxp"], + ) + if self.angle_dx is not None: + angle_dx = xr.DataArray( + data=self.angle_dx, + dims=["nyp", "nxp"], + ) + if self.angle_dy is not None: + angle_dy = xr.DataArray( + data=self.angle_dy, + dims=["nyp", "nxp"], + ) + if self.area is not None: + area = xr.DataArray( + data=self.area, + dims=["ny", "nx"], + ) + if self.arcx is not None: + arcx = xr.DataArray( + [self.arcx], + ) + dataset = xr.Dataset( + data_vars = { + "tile": tile, + "x": x, + "y": y, + "dx": dx, + "dy": dy, + "angle_dx": angle_dx, + "angle_dy": angle_dy, + "area": area, + "arcx": arcx + } + ) + + return GridObj(grid_data=dataset) + + diff --git a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index eac55f4..995eba7 100644 --- a/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FRENCTools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -29,7 +29,7 @@ def fill_cubic_grid_halo( nyph = ny + joff + 2*halo for i in range(nxph*nyph): - data[i] = MISSING_VALUE + data[i] = -9999. # first copy computing domain data for j in range (nyp+1): From b9213956c4cc68d759bf39235920170c4b278cc7 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 19 Feb 2025 13:16:10 -0500 Subject: [PATCH 19/72] Changed GridObj attribute grid_data to dataset --- FMSgridtools/shared/gridobj.py | 69 +++++++++++++++++----------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 53b1d33..eb24e24 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -14,14 +14,14 @@ """ @dataclasses.dataclass class GridObj: - grid_data: Optional[xr.Dataset] = None + dataset: Optional[xr.Dataset] = None grid_file: Optional[str] = None def __post_init__(self): if self.grid_file is not None: check_file_is_there(self.grid_file) with xr.open_dataset(self.grid_file) as ds: - self.grid_data = ds + self.dataset = ds """ from_file: @@ -35,7 +35,7 @@ def from_file(cls, filepath: str) -> "GridObj": check_file_is_there(filepath) with xr.open_dataset(filepath) as ds: return cls( - grid_data=ds, + dataset=ds, grid_file=filepath, ) @@ -43,11 +43,11 @@ def from_file(cls, filepath: str) -> "GridObj": write_out_grid: This method will generate a netcdf file containing the contents of the - grid_data attribute. + dataset attribute. """ def write_out_grid(self, filepath: str): - if self.grid_data is not None: - self.grid_data.to_netcdf(filepath) + if self.dataset is not None: + self.dataset.to_netcdf(filepath) """ get_agrid_lonlat: @@ -78,100 +78,99 @@ def get_agrid_lonlat(self)-> tuple[npt.NDArray, npt.NDArray]: """ get_variable_list: - This method returns a list of variables contained within the grid_data - dataset. + This method returns a list of variables contained within the dataset. """ def get_variable_list(self) -> List: - return list(self.grid_data.data_vars) + return list(self.dataset.data_vars) @property def tile(self): - if self.grid_data is not None: - return self.grid_data.tile.values.item().decode('ascii') + if self.dataset is not None: + return self.dataset.tile.values.item().decode('ascii') else: return None @property def x(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.x.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.x.values) else: return None @property def y(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.y.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.y.values) else: return None @property def dx(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.dx.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.dx.values) else: return None @property def dy(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.dy.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.dy.values) else: return None @property def area(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.area.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.area.values) else: return None @property def angle_dx(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.angle_dx.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.angle_dx.values) else: return None @property def angle_dy(self): - if self.grid_data is not None: - return np.ascontiguousarray(self.grid_data.angle_dy.values) + if self.dataset is not None: + return np.ascontiguousarray(self.dataset.angle_dy.values) else: return None @property def arcx(self): - if self.grid_data is not None: - return self.grid_data.arcx.values.item().decode('ascii') + if self.dataset is not None: + return self.dataset.arcx.values.item().decode('ascii') else: return None @property def nx(self): - if self.grid_data is not None: - return self.grid_data.sizes['nx'] + if self.dataset is not None: + return self.dataset.sizes['nx'] else: return None @property def ny(self): - if self.grid_data is not None: - return self.grid_data.sizes['ny'] + if self.dataset is not None: + return self.dataset.sizes['ny'] else: return None @property def nxp(self): - if self.grid_data is not None: - return self.grid_data.sizes['nxp'] + if self.dataset is not None: + return self.dataset.sizes['nxp'] else: return None @property def nyp(self): - if self.grid_data is not None: - return self.grid_data.sizes['nyp'] + if self.dataset is not None: + return self.dataset.sizes['nyp'] else: return None From b28821df4749eb50fcb0ccb1dc5cd8fcbb797bc5 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 20 Feb 2025 14:15:19 -0500 Subject: [PATCH 20/72] Main functionality for make_hgrid added --- FMSgridtools/make_hgrid/hgridobj.py | 183 +++++++++++++---------- FMSgridtools/make_hgrid/make_hgrid.py | 199 ++++++++++++++++---------- 2 files changed, 230 insertions(+), 152 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 35d3848..26e900b 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -23,18 +23,27 @@ def write_out_hgrid( self, tilename, outfile, - north_pole_tile: Optional[str]="none", - north_pole_arcx: Optional[str]="none", - projection: Optional[str]="none", - geometry: Optional[str]="none", - discretization: Optional[str]="none", - conformal: Optional[str]="none", - out_halo: Optional[int]=0, - output_length_angle: Optional[int]=0 + north_pole_tile="none", + north_pole_arcx="none", + projection="none", + geometry="none", + discretization="none", + conformal="none", + out_halo=0, + output_length_angle=0 ): + tile = None + x = None + y = None + dx = None + dy = None + area = None + angle_dx = None + angle_dy = None + arcx = None if north_pole_tile == "none": tile = xr.DataArray( - ["tile"], + [tilename], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, @@ -44,7 +53,7 @@ def write_out_hgrid( ) elif projection == "none": tile = xr.DataArray( - ["tile"], + [tilename], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, @@ -55,7 +64,7 @@ def write_out_hgrid( ) else: tile = xr.DataArray( - ["tile"], + [tilename], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, @@ -74,7 +83,7 @@ def write_out_hgrid( standard_name="geographic_longitude", ) ) - + y = xr.DataArray( data=self.y, dims=["nyp", "nxp"], @@ -83,7 +92,7 @@ def write_out_hgrid( standard_name="geographic_latitude", ) ) - + if output_length_angle: dx = xr.DataArray( data=self.dx, @@ -101,8 +110,7 @@ def write_out_hgrid( units="meters", standard_name="grid_edge_y_distance", ) - ) - + ) angle_dx = xr.DataArray( data=self.angle_dx, dims=["nyp", "nxp"], @@ -111,6 +119,10 @@ def write_out_hgrid( standard_name="grid_vertex_x_angle_WRT_geographic_east", ) ) + if out_halo > 0: + dx.attrs["_FillValue"] = -9999. + dy.attrs["_FillValue"] = -9999. + angle_dx.attrs["_FillValue"] = -9999. if conformal == "true": angle_dy = xr.DataArray( data=self.angle_dy, @@ -120,6 +132,9 @@ def write_out_hgrid( standard_name="grid_vertex_y_angle_WRT_geographic_north", ) ) + if out_halo > 0: + angle_dy.attrs["_FillValue"] = -9999. + area = xr.DataArray( data=self.area, dims=["ny", "nx"], @@ -131,14 +146,14 @@ def write_out_hgrid( if north_pole_arcx == "none": arcx = xr.DataArray( - ["arcx"], + [self.arcx], attrs=dict( standard_name="grid_edge_x_arc_type", ) ) else: arcx = xr.DataArray( - ["arcx"], + [self.arcx], attrs=dict( standard_name="grid_edge_x_arc_type", north_pole=north_pole_arcx, @@ -147,77 +162,93 @@ def write_out_hgrid( if out_halo > 0: x.attrs["_FillValue"] = -9999. y.attrs["_FillValue"] = -9999. - dx.attrs["_FillValue"] = -9999. - dy.attrs["_FillValue"] = -9999. area.attrs["_FillValue"] = -9999. - def make_gridobj(self) -> "GridObj": - tile = None - x = None - y = None - dx = None - dy = None - angle_dx = None - angle_dy = None - area = None - arcx = None - if self.tile is not None: - tile = xr.DataArray( - [self.tile] - ) - if self.x is not None: - x = xr.DataArray( - data=self.x, - dims=["nyp", "nxp"], - ) - if self.y is not None: - y = xr.DataArray( - data=self.y, - dims=["nyp", "nxp"], - ) - if self.dx is not None: - dx = xr.DataArray( - data=self.dx, - dims=["nyp", "nx"], - ) - if self.dy is not None: - dy = xr.DataArray( - data=self.dy, - dims=["ny", "nxp"], - ) - if self.angle_dx is not None: - angle_dx = xr.DataArray( - data=self.angle_dx, - dims=["nyp", "nxp"], - ) - if self.angle_dy is not None: - angle_dy = xr.DataArray( - data=self.angle_dy, - dims=["nyp", "nxp"], - ) - if self.area is not None: - area = xr.DataArray( - data=self.area, - dims=["ny", "nx"], - ) - if self.arcx is not None: - arcx = xr.DataArray( - [self.arcx], - ) dataset = xr.Dataset( - data_vars = { + data_vars={ "tile": tile, "x": x, "y": y, "dx": dx, "dy": dy, + "area": area, "angle_dx": angle_dx, "angle_dy": angle_dy, - "area": area, - "arcx": arcx + "arcx": arcx, } ) + self.dataset = dataset + dataset.to_netcdf(outfile) - return GridObj(grid_data=dataset) + def make_gridobj(self) -> "GridObj": + if self.dataset is None: + tile = None + x = None + y = None + dx = None + dy = None + angle_dx = None + angle_dy = None + area = None + arcx = None + if self.tile is not None: + tile = xr.DataArray( + [self.tile] + ) + if self.x is not None: + x = xr.DataArray( + data=self.x, + dims=["nyp", "nxp"], + ) + if self.y is not None: + y = xr.DataArray( + data=self.y, + dims=["nyp", "nxp"], + ) + if self.dx is not None: + dx = xr.DataArray( + data=self.dx, + dims=["nyp", "nx"], + ) + if self.dy is not None: + dy = xr.DataArray( + data=self.dy, + dims=["ny", "nxp"], + ) + if self.angle_dx is not None: + angle_dx = xr.DataArray( + data=self.angle_dx, + dims=["nyp", "nxp"], + ) + if self.angle_dy is not None: + angle_dy = xr.DataArray( + data=self.angle_dy, + dims=["nyp", "nxp"], + ) + if self.area is not None: + area = xr.DataArray( + data=self.area, + dims=["ny", "nx"], + ) + if self.arcx is not None: + arcx = xr.DataArray( + [self.arcx], + ) + dataset = xr.Dataset( + data_vars = { + "tile": tile, + "x": x, + "y": y, + "dx": dx, + "dy": dy, + "angle_dx": angle_dx, + "angle_dy": angle_dy, + "area": area, + "arcx": arcx + } + ) + else: + dataset=self.dataset + return GridObj(dataset=dataset) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 5755305..d672289 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,5 +1,6 @@ import sys import xarray as xr +import ctypes import numpy as np import numpy.typing as npt import click @@ -77,7 +78,6 @@ @click.option("--rotate_poly", default=False) @click.option("--verbose", default=False) def main( - args: str, grid_type: str, my_grid_file: Optional[str], nxbnds: int, @@ -111,7 +111,7 @@ def main( halo: int, great_circle_algorithm: bool, out_halo: int, - no_length_angle: bool, + non_length_angle: bool, angular_midpoint: bool, rotate_poly: bool, verbose: bool, @@ -139,9 +139,9 @@ def main( output_length_angle = 1 ntiles = 1 ntiles_global = 1 + ntiles_file = 0 grid_obj = HGridObj() - gridname = "horizontal_grid" center = "none" geometry = "spherical" projection = "none" @@ -155,9 +155,8 @@ def main( mpp = pyFMS_mpp(clibFMS=pyfms.clibFMS) mpp_domains = pyFMS_mpp_domains(clibFMS=pyfms.clibFMS) - # TODO: Find what to use for error_type if(mpp.npes() > 1): - mpp.pyfms_error("make_hgrid: make_hgrid must be run one processor, contact developer") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: make_hgrid must be run one processor, contact developer") if xbnds is not None: xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') @@ -177,6 +176,12 @@ def main( if dlat is not None: dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') nybnds3 = dy_bnds.size + if stretch_factor != 0.0: + present_stretch_factor = 1 + if target_lon != 0.0: + present_target_lon = 1 + if target_lat != 0.0: + present_target_lat = 1 if refine_ratio is not None: refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') num_nest_args = refine_ratio.size @@ -197,7 +202,7 @@ def main( num_nest_args = jend_nest.size if great_circle_algorithm: use_great_circle_algorithm = 1 - if no_length_angle: + if non_length_angle: output_length_angle = 0 if angular_midpoint: use_angular_midpoint = 1 @@ -205,6 +210,8 @@ def main( my_grid_file = np.array(my_grid_file.split(',')) ntiles_file = my_grid_file.size + # TODO: rotate_poly? + if mpp.pe() == 0 and verbose: print(f"==>NOTE: the grid type is {grid_type}") @@ -227,21 +234,21 @@ def main( elif grid_type == "beta_plane_grid": my_grid_type = BETA_PLANE_GRID else: - mpp.pyfms_error("make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") + mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") if my_grid_type != GNOMONIC_ED and out_halo != 0: - mpp.pyfms_error("make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") if out_halo != 0 and out_halo != 1: - mpp.pyfms_error("make_hgrid: out_halo should be 0 or 1") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") if my_grid_type != GNOMONIC_ED and do_schmidt: - mpp.pyfms_error("make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") if my_grid_type != GNOMONIC_ED and do_cube_transform: - mpp.pyfms_error("make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") if do_cube_transform and do_schmidt: - mpp.pyfms_error("make_hgrid: both --do_cube_transform and --do_schmidt are set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") use_legacy = 0 @@ -252,11 +259,11 @@ def main( nxbnds = nxbnds0 nybnds = nybnds0 if nxbnds < 2 or nybnds < 2: - mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") if nxbnds != nxbnds1: - mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") if nybnds != nybnds1: - mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") num_specify = 0 if nxbnds2 > 0 and nybnds2 > 0: @@ -266,34 +273,34 @@ def main( use_legacy = 1 if num_specify == 0: - mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") if num_specify == 2: - mpp.pyfms_error("make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") if use_legacy: if nxbnds != nxbnds3: - mpp.pfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") + mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") if nybnds != nybnds3: - mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") else: if nxbnds != nxbnds2+1: - mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") if nybnds != nybnds2+1: - mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: ntiles = 6 ntiles_global = 6 if my_grid_type != GNOMONIC_ED and nest_grids: - mpp.pyfms_error("make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") if my_grid_type == TRIPOLAR_GRID: projection = "tripolar" if nxbnds != 2: - mpp.pyfms_error("make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") elif my_grid_type == FROM_FILE: if ntiles_file == 0: - mpp.pyfms_error("make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") ntiles = ntiles_file ntiles_global = ntiles_file for n in range(ntiles): @@ -303,93 +310,98 @@ def main( with xr.open_dataset(file_path) as ds: if "grid_xt" in ds.sizes: if "grid_yt" not in ds.sizes: - mpp.pyfms_error("make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") nlon[n] = ds.sizes["grid_xt"]*2 nlat[n] = ds.sizes["grid_yt"]*2 elif "rlon" in ds.sizes: if "rlat" not in ds.sizes: - mpp.pyfms_error("make_hgrid: rlat should be a dimension when rlon is a dimension") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: rlat should be a dimension when rlon is a dimension") nlon[n] = ds.sizes["rlon"]*2 nlat[n] = ds.sizes["rlat"]*2 elif "lon" in ds.sizes: if "lat" not in ds.sizes: - mpp.pyfms_error("make_hgrid: lat should be a dimension when lon is a dimension") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: lat should be a dimension when lon is a dimension") nlon[n] = ds.sizes["lon"]*2 nlat[n] = ds.sizes["lat"]*2 elif "i" in ds.sizes: if "j" not in ds.sizes: - mpp.pyfms_error("make_hgrid: j should be a dimension when i is a dimension") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: j should be a dimension when i is a dimension") nlon[n] = ds.sizes["i"]*2 nlat[n] = ds.sizes["j"]*2 elif "x" in ds.sizes: if "y" not in ds.sizes: - mpp.pyfms_error("make_hgrid: y should be a dimension when x is a dimension") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: y should be a dimension when x is a dimension") nlon[n] = ds.sizes["x"]*2 nlat[n] = ds.sizes["y"]*2 else: - mpp.pyfms_error("make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") else: if nxbnds2 != ntiles or nybnds2 != ntiles: - mpp.pyfms_error("make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") + """ + For simplification purposes, it is assumed at this point that all tiles will have the same grid size + """ for n in range(1, ntiles): if nlon[n] != nlon[0] or nlat[n] != nlat[0]: - mpp.pyfms_error("make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") elif my_grid_type == SIMPLE_CARTESIAN_GRID: geometry = "planar" north_pole_tile = "none" if nxbnds1 != 2 or nybnds1 != 2: - mpp.pyfms_error("make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") if nxbnds2 != 1 or nybnds2 != 1: - mpp.pyfms_error("make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") if simple_dx == 0 or simple_dy == 0: - mpp.pyfms_error("make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") elif my_grid_type == SPECTRAL_GRID: if nxbnds2 != 1 or nybnds2 != 1: - mpp.pyfms_error("make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") elif my_grid_type == CONFORMAL_CUBIC_GRID: projection = "cube_gnomonic" conformal = "FALSE" if nxbnds2 != 1: - mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") if nratio < 1: - mpp.pyfms_error("make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") elif my_grid_type == GNOMONIC_ED: projection = "cube_gnomonic" conformal = "FALSE" if do_schmidt or do_cube_transform: if present_stretch_factor == 0 or present_target_lon == 0 or present_target_lat == 0: - mpp.pyfms_error("make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") for n in range(nest_grids): if refine_ratio[n] == 0: - mpp.pyfms_error("make_hgrid: --refine_ratio must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --refine_ratio must be set when --nest_grids is set") + if parent_tile[n] == 0 and mpp.pe() == 0: + print("NOTE from make_hgrid: parent_tile is 0, the output grid will have resolution refine_ration*nlon", file=sys.stderr) else: if istart_nest[n] == 0: - mpp.pyfms_error("make_hgrid: --istart_nest must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --istart_nest must be set when --nest_grids is set") if iend_nest[n] == 0: - mpp.pyfms_error("make_hgrid: --iend_nest must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --iend_nest must be set when --nest_grids is set") if jstart_nest[n] == 0: - mpp.pyfms_error("make_hgrid: --jstart_nest must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jstart_nest must be set when --nest_grids is set") if jend_nest[n] == 0: - mpp.pyfms_error("make_hgrid: --jend_nest must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jend_nest must be set when --nest_grids is set") if halo == 0: - mpp.pyfms_error("make_hgrid: --halo must be set when --nest_grids is set") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --halo must be set when --nest_grids is set") ntiles += 1 if verbose: print(f"Configuration for nest {ntiles} validated.", file=sys.stderr) if verbose: print(f"Updated number of tiles, including nests (ntiles): {ntiles}", file=sys.stderr) if nxbnds2 != 1: - mpp.pyfms_error("make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") elif my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: if f_plane_latitude > 90 or f_plane_latitude < -90: - mpp.pyfms_error("make_hgrid: f_plane_latitude should be between -90 and 90.") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: f_plane_latitude should be between -90 and 90.") if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: if mpp.pe() == 0: print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) if mpp.pe() == 0: print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) else: - mpp.pyfms_error("make_hgrid: passed grid type is not implemented") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") if verbose: print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}", file=sys.stderr) @@ -406,7 +418,7 @@ def main( nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: for n in range(ntiles_global): - nxl[n] = nlon[n] + nxl[n] = nlon[0] nyl[n] = nxl[n] if nest_grids and parent_tile[0] == 0: nxl[n] *= refine_ratio[0] @@ -434,9 +446,11 @@ def main( nyp = ny + 1 if center == "none" and center == "c_cell" and center == "t_cell": - mpp.pyfms_error("make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") + + # --non_length_angle should only be set when grid_type == GNOMONIC_ED if not output_length_angle and my_grid_type != GNOMONIC_ED: - mpp.pyfms_error("make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") """ Create grid information @@ -445,42 +459,44 @@ def main( for n_nest in range(ntiles): print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) + size1 = ctypes.c_ulong(0) + size2 = ctypes.c_ulong(0) + size3 = ctypes.c_ulong(0) + size4 = ctypes.c_long(0) + if my_grid_type == FROM_FILE: - size1 = 0 - size2 = 0 - size3 = 0 - size4 = 0 for n in range(ntiles_global): - size1 += (nlon[n] + 1) * (nlat[n] + 1) - size2 += (nlon[n] + 1) * (nlat[n] + 1 + 1) - size3 += (nlon[n] + 1 +1) * (nlat[n] + 1) - size4 += (nlon[n] + 1) * (nlat[n] + 1) + size1.value += (nlon[n] + 1) * (nlat[n] + 1) + size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) + size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + size4.value += (nlon[n] + 1) * (nlat[n] + 1) else: - size1 = nxp * nyp * ntiles_global - size2 = nxp * (nyp + 1) * ntiles_global - size3 = (nxp + 1) * nyp * ntiles_global - size4 = nxp * nyp * ntiles_global + size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) + size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) + size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) + size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - if nest_grids == 1 and parent_tile[0] == 0: + if not (nest_grids == 1 and parent_tile[0] == 0): for n_nest in range(ntiles_global, ntiles_global+nest_grids): if verbose: print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) - size1 += (nxl[n_nest]+1) * (nyl[n_nest]+1) - size2 += (nxl[n_nest]+1) * (nyl[n_nest]+2) - size3 += (nxl[n_nest]+2) * (nyl[n_nest]+1) - size4 += (nxl[n_nest]+1) * (nyl[n_nest]+1) + size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) + size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) + size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) if verbose: print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) - grid_obj.x = np.empty(shape=size1, dtype=np.float64) - grid_obj.y = np.empty(shape=size1, dtype=np.float64) - grid_obj.area = np.empty(shape=size4, dtype=np.float64) + grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) + grid_obj.arcx = arcx if output_length_angle: - grid_obj.dx = np.empty(shape=size2, dtype=np.float64) - grid_obj.dy = np.empty(shape=size3, dtype=np.float64) - grid_obj.angle_dx = np.empty(shape=size1, dtype=np.float64) + grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) + grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) + grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) if conformal != "true": - grid_obj.angle_dy = np.empty(shape=size1, dtype=np.float64) + grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) isc = 0 iec = nx - 1 @@ -687,6 +703,9 @@ def main( center, ) + """ + Write out data + """ pos_c = 0 pos_e = 0 pos_t = 0 @@ -745,8 +764,36 @@ def main( fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) grid_obj.area = tmp.copy() + if verbose: + print(f"About to close {outfile}") - grid_obj.write_out_grid(filepath="") + nx = nxl[n] + ny = nyl[n] + nxp = nx + 1 + nyp = ny + 1 + + if verbose: + print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) + pos_c += nxp*nyp + if verbose: + print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) + pos_e += nxp*ny + pos_n += nx*nyp + pos_t += nx*ny + + + grid_obj.write_out_hgrid( + tilename=tilename, + outfile=outfile, + north_pole_tile=north_pole_tile, + north_pole_arcx=north_pole_arcx, + projection=projection, + geometry=geometry, + discretization=discretization, + conformal=conformal, + out_halo=out_halo, + output_length_angle=output_length_angle, + ) if(mpp.pe() == 0 and verbose): print("generate_grid is run successfully") From d3c475bce41fbacdd0ccdb03967d04a37152ee8d Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 24 Feb 2025 16:23:12 -0500 Subject: [PATCH 21/72] Added doc strings to make_hgrid --- FMSgridtools/make_hgrid/make_hgrid.py | 558 ++++++++++++++++-- .../make_hgrid/make_hgrid_util.py | 23 +- setup.py | 2 +- 3 files changed, 515 insertions(+), 68 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index d672289..f1715d2 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -24,6 +24,236 @@ ) from FRENCTools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size +""" +Usage of make_hgrid + +fmsgridtools make_hgrid --grid_type (see types supported below) (string) + --my_grid_file file_name (string) + --nxbnds # + --nybnds # + --xbnds x(1),...,x(nxbnds) + --ybnds y(1),...,y(nybnds) + --nlon nlon(1),...nlon(nxbnds-1) + --nlat nlat(1),...nlat(nybnds-1) + --dlon dlon(1),...dlon(nxbnds) + --dlat dlat(1),...dlat(nybnds) + --lat_join # + --num_lon # + --nratio # + --simple_dx # + --simple_dy # + --grid_name (string) + --center (string) + --verbose (bool) + --shift_fac # + --do_schmidt (bool) + --stretch_fac # + --target_lon # + --target_lat # + --do_cube_transform (bool) + --nest_grids # + --parent_tile parent_tile(1),...parent_tile(nests-1) + --refine_ratio refine_ratio(1),...refine_ratio(nests-1) + --halo # + --istart_nest istart_nest(1),...istart_nest(nests-1) + --iend_nest iend_nest(1),...iend_nest(nests-1) + --jstart_nest jstart_nest(1),...jstart_nest(nests-1) + --jend_nest jend_nest(1),...jend_nest(nests-1) + --use_great_circle_algorithm (bool) + --out_halo # + --output_length_angle (bool) + +The available options for grid_type are: + 1. 'from_file': + --my_grid_file must be specified. The grid + specified in my_grid_file should be super grid + vertex. + 2. 'spectral_grid' + 3. 'regular_lonlat_grid': + --nxbnds, --nybnds --xbnds, --ybnds, must be + specified to define the grid bounds. + 4. 'tripolar_grid': + --nxbnds, --nybnds, --xbnds, --ybnds, must be + specified to define the grid bounds. --lat_join + is optional with default value 65. + 5 'conformal_cubic_grid' + 6 'gnomonic_ed' + 7. 'simple_cartesian_grid': + --xbnds, --ybnds must be specified to define + the grid bounds location and grid size. number + of bounds must be 2 in both and x and y-direction. + --simple_dx and --simple_dy must be specified to + specify uniform cell length. + 8 . 'f_plane_grid': + For setting geometric fractors according + to f-plane. f_plane_latitude need to be specified. + 9. 'beta_plane_grid': + For setting geometric fractors according + to beta plane. f_plane_latitude need to be + specified + +Example use: + + 1. generating regular lon-lat grid (supergrid size 60x20) + fmsgridtools make_hgrid --grid_type regular_lonlat_grid + --nxbnd 2 + --nybnd 2 + --xbnd 0,30 + --ybnd 50,60 + --nlon 60 + --nlat 20 + + 2. generating tripolar grid with various grid resolution and C-cell + centered using monotonic bi-cub spline interpolation. + fmsgridtools make_hgrid --grid_type tripolar_grid + --nxbnd 2 + --nybnd 7 + --xbnd -280,80 + --ybnd -82,-30,-10,0,10,30,90 + --nlon 720 + --nlat 104,48,40,40,48,120 + --grid_name om3_grid + --center c_cell + + 3. generating tripolar grid with various grid resolution and C-cell + centered using legacy algorithm (create GFDL CM2/ocean-like grid) + fmsgridtools make_hgrid --grid_type tripolar_grid + --nxbnd 2 + --nybnd 7 + --xbnd -280,80 + --ybnd -82,-30,-10,0,10,30,90 + --dlon 1.0,1.0 + --dlat 1.0,1.0,0.6666667,0.3333333,0.6666667,1.0,1.0 + --grid_name om3_grid + --center c_cell + + 4. generating simple cartesian grid(supergrid size 20x20) + fmsgridtools make_hgrid --grid_type simple_cartesian_grid + --xbnd 0,30 + --ybnd 50,60 + --nlon 20 + --nlat 20 + --simple_dx 1000 + --simple_dy 1000 + + 5. generating conformal cubic grid. (supergrid size 60x60 for each tile) + fmsgridtools make_hgrid --grid_type conformal_cubic_grid + --nlon 60 + --nratio 2 + + 6. generating gnomonic cubic grid with equal_dist_face_edge(C48 grid) + fmsgridtools make_hgrid --grid_type gnomonic_ed + --nlon 96 + + 7. generating gnomonic cubic stretched grid. + fmsgridtools make_hgrid --grid_type gnomonic_ed + --nlon 180 + --do_schmidt + --stretch_factor 3 + --target_lat 40. + --target_lon 20. + + 8. generating gnomonic cubic stretched grid with two nests on tile 6. + fmsgridtools make_hgrid --grid_type gnomonic_ed + --nlon 192 + --do_schmidt + --stretch_factor 3 + --target_lat 10. + --target_lon 20. + --nest_grids 2 + --parent_tile 6,6 + --refine_ratio 2,2 + --istart_nest 11,51 + --jstart_nest 11,51 + --iend_nest 42,82 + --jend_nest 42,82 + --halo 3 + + 9. generating spectral grid. (supergrid size 128x64) + fmsgridtools make_hgrid --grid_type spectral_grid + --nlon 128 + --nlat 64 + + 10. Through user-defined grids + fmsgridtools make_hgrid --grid_type from_file + --my_grid_file my_grid_file + --nlon 4 + --nlat 4 + + Contents of a sample my_grid_file: + The first line of my_grid_file will be text ( will be ignored) + followed by nlon+1 lines of real value of x-direction supergrid bound + location. Then another line of text ( will be ignored), followed by + nlat+1 lines of real value of y-direction supergrid bound location. + + For example: + + x-grid + 0.0 + 5.0 + 10.0 + 15.0 + 20.0 + y-grid + -10 + 10 + 20 + 30 + 40 + + 11. generating f_plane_grids + fmsgridtools make_hgrid --grid_type f_plane_grid + --f_plane_latitude 55 + --nxbnd 2 + --nybnd 2 + --xbnd 0,30 + --ybnd 50,60 + --nlon 60 + --nlat 20 + +A note on generating cyclic regular lon-lat grids when center = 'c_cell':- +It is possible to have an improperly centered boundary unless care is taken to +ensure local symmetry at the join. +A correctly formed grid is only guaranteed if the first three values of the +--xbnd argument mirror the last 3 and the first two 'nlon' arguments mirror the +last 2. + +For example for a global grid make_hgrid should be invoked as + fmsgridtools make_hgrid --grid_type regular_lonlat_grid ... + --xbnd 0,X1,X2,...,360-X2,360-X1,360 + --nlon N1,N2,...,N2,N1 + --center c_cell + +As an example + + fmsgridtools make_hgrid --grid_type regular_lonlat_grid + --nxbnd 7 + --nybnd 2 + --xbnd 0,15,30,300,330,345,360 + --ybnd 50,60 + --nlon 4,2,6,4,2,4 + --nlat 2 + --center c_cell + + +results in a valid cyclic grid whereas (note the second last value of nlon) + + fmsgridtools make_hgrid --grid_type regular_lonlat_grid + --nxbnd 7 + --nybnd 2 + --xbnd 0,15,30,300,330,345,360 + --ybnd 50,60 + --nlon 4,2,6,4,4,4 + --nlat 2 + --center c_cell + + +is not properly centered across 0,360 + +An informational message is issued if the leftmost and rightmost resolutions +differ by more than 1 part in 10E6 +""" + MAXBOUNDS = 100 MAX_NESTS = 128 REGULAR_LONLAT_GRID = 1 @@ -39,44 +269,272 @@ @click.command() -@click.argument('args', nargs=-1) -@click.option("--grid_type", type=str, default="regular_lonlat_grid") -@click.option("--my_grid_file", type=str, default=None) -@click.option("--nxbnds", type=int, default=2) -@click.option("--nybnds", type=int, default=2) -@click.option("--xbnds", type=str, default=None) -@click.option("--ybnds", type=str, default=None) -@click.option("--nlon", type=str, default=None) -@click.option("--nlat", type=str, default=None) -@click.option("--dlon", type=str, default=None) -@click.option("--dlat", type=str, default=None) -@click.option("--lat_join", type=float, default=65.) -@click.option("--nratio", type=int, default=1) -@click.option("--simple_dx", type=float, default=0.) -@click.option("--simple_dy", type=float, default=0.) -@click.option("--grid_name", type=str, default="horizontal_grid") -@click.option("--center", type=str, default="none") -@click.option("--shift_fac", type=float, default=18.0) -@click.option("--f_plane_latitude", type=float, default=100.) -@click.option("--do_schmidt", type=int, default=0) -@click.option("--do_cube_transform", type=int, default=0) -@click.option("--stretch_factor", type=float, default=0.0) -@click.option("--target_lon", type=float, default=0.0) -@click.option("--target_lat", type=float, default=0.0) -@click.option("--nest_grids", type=int, default=0) -@click.option("--parent_tile", type=str, default=None) -@click.option("--refine_ratio", type=str, default=None) -@click.option("--istart_nest", type=str, default=None) -@click.option("--iend_nest", type=str, default=None) -@click.option("--jstart_nest", type=str, default=None) -@click.option("--jend_nest", type=str, default=None) -@click.option("--halo", type=int, default=0) -@click.option("--great_circle_algorithm", default=False) -@click.option("--out_halo", type=int, default=0) -@click.option("--non_length_angle", default=False) -@click.option("--angular_midpoint", default=False) -@click.option("--rotate_poly", default=False) -@click.option("--verbose", default=False) +@click.option( + "--grid_type", + type=str, + default="regular_lonlat_grid", + help="specify type of topography. See above for grid type option.", +) +@click.option( + "--my_grid_file", + type=str, + default=None, + help="when this flag is present, the program will read grid information\ + from 'my_grid_file'. The file format can be ascii file or netcdf\ + file. Multiple file entry are allowed but the number should be\ + less than MAXBOUNDS.", +) +@click.option( + "--nxbnds", + type=int, + default=2, + help="Specify number of zonal regions for varying resolution.", +) +@click.option( + "--nybnds", + type=int, + default=2, + help="Specify number of meridinal regions for varying resolution.", +) +@click.option( + "--xbnds", + type=str, + default=None, + help="Specify boundaries for defining zonal regions of varying resolution.\ + When --tripolar is present, x also defines the longitude of the two\ + new poles. nxbnds must be 2 and lon_start = x(1), lon_end = x(nxbnds)\ + are longitude of the two new poles.", +) +@click.option( + "--ybnds", + type=str, + default=None, + help="Specify boundaries for defining meridional regions of varying\ + resolution", +) +@click.option( + "--nlon", + type=str, + default=None, + help="Number of model grid points(supergrid) for each zonal regions of\ + varying resolution.", +) +@click.option( + "--nlat", + type=str, + default=None, + help="Number of model grid points(supergid) for each meridinal regions of\ + varying resolution.", +) +@click.option( + "--dlon", + type=str, + default=None, + help="nominal resolution of zonal regions", +) +@click.option( + "--dlat", + type=str, + default=None, + help="nominal resolution of meridional regions", +) +@click.option( + "--lat_join", + type=float, + default=65., + help="Specify latitude for joining spherical and rotated bipolar grid.\ + Default value is 65 degree.", +) +@click.option( + "--nratio", + type=int, + default=1, + help="Speicify the refinement ratio when calculating cell length and area\ + of supergrid.", +) +@click.option( + "--simple_dx", + type=float, + default=0., + help="Specify the uniform cell length in x-direction for simple cartesian\ + grid.", +) +@click.option( + "--simple_dy", + type=float, + default=0., + help="Specify the uniform cell length in y-direction for simple cartesian\ + grid.", +) +@click.option( + "--grid_name", + type=str, + default="horizontal_grid", + help=("Specify the grid name. The output grid file name will be" + "grid_name.nc if there is one tile and grid_name.tile#.nc if there is" + "more than one tile. The default value will be horizontal_grid."), +) +@click.option( + "--center", + type=str, + default="none", + help=("Specify the center location of grid. Valid entries will be 'none'" + ", 't_cell' or 'c_cell' with default value 'none'. The grid " + "refinement is assumed to be 2 in x and y-direction when center is " + "not 'none'. 'c_cell' should be used for the grid used in MOM."), +) +@click.option( + "--shift_fac", + type=float, + default=18.0, + help="shift west by 180/shift_fac. Default value is 18.", +) +@click.option( + "--f_plane_latitude", + type=float, + default=100., + help="" +) +@click.option( + "--do_schmidt", + is_flag=True, + default=False, + help=("Set to do Schmidt transformation to create stretched grid. When " + "do_schmidt is set, the following must be set: --stretch_factor, " + " --target_lon and --target_lat."), +) +@click.option( + "--do_cube_transform", + is_flag=True, + default=False, + help=("re-orient the rotated cubed sphere so that tile 6 has 'north' " + "facing upward, which would make analysis and explaining nest " + "placement much easier. When do_cube_transform is set, the " + "following must be set: --stretch_factor, --latget_lon, and " + " --target_lat."), +) +@click.option( + "--stretch_factor", + type=float, + default=0.0, + help="Stretching factor for the grid", +) +@click.option( + "--target_lon", + type=float, + default=0.0, + help="center longitude of the highest resolution tile", +) +@click.option( + "--target_lat", + type=float, + default=0.0, + help="center latitude of the highest resolution tile", +) +@click.option( + "--nest_grids", + type=int, + default=0, + help=("set to create this # nested grids as well as the global grid. This " + "replaces the option --nest_grid. This option could only be set when " + "grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid ", + "files created, there are # more nest grids with " + " file name = $grid_name.tile${parent_tile}.nest.nc"), +) +@click.option( + "--parent_tile", + type=str, + default=None, + help="Specify the comma-separated list of the parent tile number(s) of \ + nest grid(s).", +) +@click.option( + "--refine_ratio", + type=str, + default=None, + help="Specify the comma-separated list of refinement ratio(s) for nest\ + grid(s).", +) +@click.option( + "--istart_nest", + type=str, + default=None, + help="Specify the comma-separated list of starting i-direction index(es)\ + of nest grid(s) in parent tile supergrid(Fortran index).", +) +@click.option( + "--iend_nest", + type=str, + default=None, + help="Specify the comma-separated list of ending i-direction index(es) of \ + nest grids in parent tile supergrid( Fortran index).", +) +@click.option( + "--jstart_nest", + type=str, + default=None, + help="Specify the comma-separated list of starting j-direction index(es) of \ + nest grids in parent tile supergrid(Fortran index).", +) +@click.option( + "--jend_nest", + type=str, + default=None, + help="Specify the comma-separated list of ending j-direction index(es) of \ + nest grids in parent tile supergrid (Fortran index).", +) +@click.option( + "--halo", + type=int, + default=0, + help=("halo size is used in the atmosphere cubic sphere model. Its purpose " + "is to make sure the nest, including the halo region, is fully " + "contained within a single parent (coarse) tile. The option may " + "be obsolete and removed in future development. It only needs to " + "be specified when --nest_grid(s) is set."), +) +@click.option( + "--use_great_circle_algorithm", + is_flag=True, + default=False, + help="When specified, great_circle_algorithm will be used to compute grid \ + cell area.", +) +@click.option( + "--out_halo", + type=int, + default=0, + help="extra halo size data to be written out. This is only works for \ + gnomonic_ed.", +) +@click.option( + "--output_length_angle", + is_flag=True, + default=False, + help="When specified, will not output length(dx,dy) and angle \ + (angle_dx, angle_dy)" +) +@click.option( + "--angular_midpoint", + is_flag=True, + default=False, + help="" +) +@click.option( + "--rotate_poly", + is_flag=True, + default=False, + help=("Set to calculate polar polygon areas by calculating the area of a " + "copy of the polygon, with the copy being rotated far away from the" + "pole.") +) +@click.option( + "--verbose", + is_flag=True, + default=False, + help=("Will print out running time message when this option is set. " + "Otherwise the run will be silent when there is no error.") +) def main( grid_type: str, my_grid_file: Optional[str], @@ -96,8 +554,8 @@ def main( center: str, shift_fac: float, f_plane_latitude: float, - do_schmidt: int, - do_cube_transform: int, + do_schmidt: bool, + do_cube_transform: bool, stretch_factor: float, target_lon: float, target_lat: float, @@ -109,9 +567,9 @@ def main( jstart_nest: str, jend_nest: str, halo: int, - great_circle_algorithm: bool, + use_great_circle_algorithm: bool, out_halo: int, - non_length_angle: bool, + output_length_angle: bool, angular_midpoint: bool, rotate_poly: bool, verbose: bool, @@ -134,9 +592,6 @@ def main( present_stretch_factor = 0 present_target_lon = 0 present_target_lat = 0 - use_great_circle_algorithm = 0 - use_angular_midpoint = 0 - output_length_angle = 1 ntiles = 1 ntiles_global = 1 ntiles_file = 0 @@ -200,10 +655,6 @@ def main( if jend_nest is not None: jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') num_nest_args = jend_nest.size - if great_circle_algorithm: - use_great_circle_algorithm = 1 - if non_length_angle: - output_length_angle = 0 if angular_midpoint: use_angular_midpoint = 1 if my_grid_file is not None: @@ -250,7 +701,7 @@ def main( if do_cube_transform and do_schmidt: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") - use_legacy = 0 + use_legacy = False """ Command line argument check @@ -270,7 +721,7 @@ def main( num_specify += 1 if nxbnds3 > 0 and nybnds3 > 0: num_specify += 1 - use_legacy = 1 + use_legacy = True if num_specify == 0: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") @@ -801,4 +1252,7 @@ def main( pyfms.pyfms_end() - # End of main \ No newline at end of file + # End of main + + if __name__ == "__main__": + main() \ No newline at end of file diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index 1f643d4..c1107c3 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -96,8 +96,7 @@ def create_regular_lonlat_grid( nlat_p, nlat_t = setarray_Cint32(nlat) dlon_p, dlon_t = setarray_Cdouble(dlon) dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c = ctypes.c_int(use_legacy) - use_legacy_t = ctypes.POINTER(ctypes.c_int) + use_legacy_c, use_legacy_t = setscalar_Cint32(use_legacy) isc_c, isc_t = setscalar_Cint32(isc) iec_c, iec_t = setscalar_Cint32(iec) jsc_c, jsc_t = setscalar_Cint32(jsc) @@ -109,8 +108,7 @@ def create_regular_lonlat_grid( area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) center_c, center_t = set_Cchar(center) - use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) - use_great_circle_algorithm_t = ctypes.POINTER(ctypes.c_int) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) _create_regular_lonlat_grid.argtypes = [ nxbnds_t, @@ -196,8 +194,7 @@ def create_tripolar_grid( nlat_p, nlat_t = setarray_Cint32(nlat) dlon_p, dlon_t = setarray_Cdouble(dlon) dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c = ctypes.c_int(use_legacy) - use_legacy_t = ctypes.POINTER(ctypes.c_int) + use_legacy_c, use_legacy_t = setscalar_Cint32(use_legacy) lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) isc_c, isc_t = setscalar_Cint32(isc) iec_c, iec_t = setscalar_Cint32(iec) @@ -210,10 +207,8 @@ def create_tripolar_grid( area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) center_c, center_t = set_Cchar(center) - verbose_c = ctypes.c_int(verbose) - verbose_t = ctypes.POINTER(ctypes.c_int) - use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) - use_great_circle_algorithm_t = ctypes.POINTER(ctypes.c_int) + verbose_c, verbose_t = setscalar_Cint32(verbose) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) _create_tripolar_grid.argtypes = [ nxbnds_t, @@ -292,8 +287,7 @@ def create_grid_from_file( dy_p, dy_t = setarray_Cdouble(dy) area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) - use_great_circle_algorithm_t = ctypes.c_int + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) use_angular_midpoint_c = ctypes.c_int(use_angular_midpoint) use_angular_midpoint_t = ctypes.c_int @@ -432,8 +426,7 @@ def create_spectral_grid( dy_p, dy_t = setarray_Cdouble(dy) area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c = ctypes.c_int(use_great_circle_algorithm) - use_great_circle_algorithm_t = ctypes.c_int + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) _create_spectral_grid.argtypes = [ nlon_t, @@ -537,7 +530,7 @@ def create_gnomonic_cubic_grid_GR( angle_dx: npt.NDArray[np.float64], angle_dy: npt.NDArray[np.float64], shift_fac: float, - do_schmidt: int, + do_schmidt: bool, do_cube_transform: int, stretch_factor: float, target_lon: float, diff --git a/setup.py b/setup.py index cf6185d..efb6fc6 100644 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ def run(self): cmdclass={'install': CustomInstall}, entry_points={ "console_scripts": [ - "fmsgridtools make_hgrid = fmsgridtools.make_grid.hgrid.make_hgrid:main", + "fmsgridtools make_hgrid = FMSgridtools.make_hgrid.make_hgrid:main", "fmsgridtools make_topog = fmsgridtools.make_topog.make_topog:make_topog", ] }, From 7ca91d9775072ddce4644f80caab1042283f0c17 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 27 Feb 2025 13:41:45 -0500 Subject: [PATCH 22/72] Changing over to fix/grid_obj --- FMSgridtools/__init__.py | 1 + FMSgridtools/make_hgrid/make_hgrid.py | 4 ++-- setup.py | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/FMSgridtools/__init__.py b/FMSgridtools/__init__.py index e573646..c9ca1b1 100644 --- a/FMSgridtools/__init__.py +++ b/FMSgridtools/__init__.py @@ -1,4 +1,5 @@ from .shared.gridobj import GridObj +from .make_hgrid.make_hgrid import make_hgrid from .make_topog.topogobj import TopogObj from .shared.gridtools_utils import check_file_is_there from .shared.gridtools_utils import get_provenance_attrs diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index f1715d2..09b2f8e 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -535,7 +535,7 @@ help=("Will print out running time message when this option is set. " "Otherwise the run will be silent when there is no error.") ) -def main( +def make_hgrid( grid_type: str, my_grid_file: Optional[str], nxbnds: int, @@ -1255,4 +1255,4 @@ def main( # End of main if __name__ == "__main__": - main() \ No newline at end of file + make_hgrid() \ No newline at end of file diff --git a/setup.py b/setup.py index efb6fc6..aa0f835 100644 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ def run(self): "numpy", "xarray", "netCDF4", + "pyfms @ git+https://github.com/fmalatino/pyFMS.git" ] setup( @@ -58,7 +59,7 @@ def run(self): cmdclass={'install': CustomInstall}, entry_points={ "console_scripts": [ - "fmsgridtools make_hgrid = FMSgridtools.make_hgrid.make_hgrid:main", + "make_hgrid = FMSgridtools.make_hgrid.make_hgrid:make_hgrid", "fmsgridtools make_topog = fmsgridtools.make_topog.make_topog:make_topog", ] }, From b890c6270fe5f712c64acad2f9a12ad95a476992 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 5 Mar 2025 14:52:47 -0500 Subject: [PATCH 23/72] Switching to main --- FMSgridtools/make_hgrid/make_hgrid.py | 1183 +++++++++-------- FMSgridtools/shared/gridobj.py | 27 +- .../make_hgrid/make_hgrid_util.py | 4 +- pyFMS | 2 +- setup.py | 9 +- 5 files changed, 616 insertions(+), 609 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 09b2f8e..946756e 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -10,7 +10,7 @@ from FMSgridtools.make_hgrid.hgridobj import HGridObj from FMSgridtools.shared.gridtools_utils import check_file_is_there -from FRENCTools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( +from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( create_regular_lonlat_grid, create_tripolar_grid, create_grid_from_file, @@ -22,7 +22,7 @@ create_f_plane_grid, fill_cubic_grid_halo, ) -from FRENCTools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size +# from FREnctools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size """ Usage of make_hgrid @@ -378,10 +378,10 @@ "--center", type=str, default="none", - help=("Specify the center location of grid. Valid entries will be 'none'" + help="""Specify the center location of grid. Valid entries will be 'none'" ", 't_cell' or 'c_cell' with default value 'none'. The grid " "refinement is assumed to be 2 in x and y-direction when center is " - "not 'none'. 'c_cell' should be used for the grid used in MOM."), + "not 'none'. 'c_cell' should be used for the grid used in MOM.""", ) @click.option( "--shift_fac", @@ -435,11 +435,11 @@ "--nest_grids", type=int, default=0, - help=("set to create this # nested grids as well as the global grid. This " - "replaces the option --nest_grid. This option could only be set when " - "grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid ", - "files created, there are # more nest grids with " - " file name = $grid_name.tile${parent_tile}.nest.nc"), + help="""set to create this # nested grids as well as the global grid. This + replaces the option --nest_grid. This option could only be set when + grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid , + files created, there are # more nest grids with + file name = grid_name.tile.nest.nc""", ) @click.option( "--parent_tile", @@ -613,641 +613,642 @@ def make_hgrid( if(mpp.npes() > 1): mpp.pyfms_error(errortype=2, errormsg="make_hgrid: make_hgrid must be run one processor, contact developer") - if xbnds is not None: - xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') - nxbnds1 = xbnds.size - if ybnds is not None: - ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') - nybnds1 = ybnds.size - if nlon is not None: - nlon = np.fromstring(nlon, dtype=int, sep=',') - nxbnds2 = nlon.size - if nlat is not None: - nlat = np.fromstring(nlat, dtype=int, sep=',') - nybnds2 = nlat.size - if dlon is not None: - dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') - nxbnds3 = dx_bnds.size - if dlat is not None: - dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') - nybnds3 = dy_bnds.size - if stretch_factor != 0.0: - present_stretch_factor = 1 - if target_lon != 0.0: - present_target_lon = 1 - if target_lat != 0.0: - present_target_lat = 1 - if refine_ratio is not None: - refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') - num_nest_args = refine_ratio.size - if parent_tile is not None: - parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') - num_nest_args = parent_tile.size - if istart_nest is not None: - istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') - num_nest_args = istart_nest.size - if iend_nest is not None: - iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') - num_nest_args = iend_nest.size - if jstart_nest is not None: - jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') - num_nest_args = jstart_nest.size - if jend_nest is not None: - jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') - num_nest_args = jend_nest.size - if angular_midpoint: - use_angular_midpoint = 1 - if my_grid_file is not None: - my_grid_file = np.array(my_grid_file.split(',')) - ntiles_file = my_grid_file.size + # if xbnds is not None: + # xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') + # nxbnds1 = xbnds.size + # if ybnds is not None: + # ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') + # nybnds1 = ybnds.size + # if nlon is not None: + # nlon = np.fromstring(nlon, dtype=int, sep=',') + # nxbnds2 = nlon.size + # if nlat is not None: + # nlat = np.fromstring(nlat, dtype=int, sep=',') + # nybnds2 = nlat.size + # if dlon is not None: + # dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') + # nxbnds3 = dx_bnds.size + # if dlat is not None: + # dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') + # nybnds3 = dy_bnds.size + # if stretch_factor != 0.0: + # present_stretch_factor = 1 + # if target_lon != 0.0: + # present_target_lon = 1 + # if target_lat != 0.0: + # present_target_lat = 1 + # if refine_ratio is not None: + # refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') + # num_nest_args = refine_ratio.size + # if parent_tile is not None: + # parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') + # num_nest_args = parent_tile.size + # if istart_nest is not None: + # istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') + # num_nest_args = istart_nest.size + # if iend_nest is not None: + # iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') + # num_nest_args = iend_nest.size + # if jstart_nest is not None: + # jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') + # num_nest_args = jstart_nest.size + # if jend_nest is not None: + # jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') + # num_nest_args = jend_nest.size + # if angular_midpoint: + # use_angular_midpoint = 1 + # if my_grid_file is not None: + # my_grid_file = np.array(my_grid_file.split(',')) + # ntiles_file = my_grid_file.size # TODO: rotate_poly? - if mpp.pe() == 0 and verbose: - print(f"==>NOTE: the grid type is {grid_type}") + # if mpp.pe() == 0 and verbose: + # print(f"==>NOTE: the grid type is {grid_type}") - if grid_type == "regular_lonlat_grid": - my_grid_type = REGULAR_LONLAT_GRID - elif grid_type == "tripolar_grid": - my_grid_type = TRIPOLAR_GRID - elif grid_type == "from_file": - my_grid_type = FROM_FILE - elif grid_type == "simple_cartesian_grid": - my_grid_type = SIMPLE_CARTESIAN_GRID - elif grid_type == "spectral_grid": - my_grid_type = SPECTRAL_GRID - elif grid_type == "conformal_cubic_grid": - my_grid_type = CONFORMAL_CUBIC_GRID - elif grid_type == "gnomonic_ed": - my_grid_type = GNOMONIC_ED - elif grid_type == "f_plane_grid": - my_grid_type = F_PLANE_GRID - elif grid_type == "beta_plane_grid": - my_grid_type = BETA_PLANE_GRID - else: - mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") + # if grid_type == "regular_lonlat_grid": + # my_grid_type = REGULAR_LONLAT_GRID + # elif grid_type == "tripolar_grid": + # my_grid_type = TRIPOLAR_GRID + # elif grid_type == "from_file": + # my_grid_type = FROM_FILE + # elif grid_type == "simple_cartesian_grid": + # my_grid_type = SIMPLE_CARTESIAN_GRID + # elif grid_type == "spectral_grid": + # my_grid_type = SPECTRAL_GRID + # elif grid_type == "conformal_cubic_grid": + # my_grid_type = CONFORMAL_CUBIC_GRID + # elif grid_type == "gnomonic_ed": + # my_grid_type = GNOMONIC_ED + # elif grid_type == "f_plane_grid": + # my_grid_type = F_PLANE_GRID + # elif grid_type == "beta_plane_grid": + # my_grid_type = BETA_PLANE_GRID + # else: + # mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") - if my_grid_type != GNOMONIC_ED and out_halo != 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") - if out_halo != 0 and out_halo != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") + # if my_grid_type != GNOMONIC_ED and out_halo != 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") + # if out_halo != 0 and out_halo != 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") - if my_grid_type != GNOMONIC_ED and do_schmidt: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") + # if my_grid_type != GNOMONIC_ED and do_schmidt: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") - if my_grid_type != GNOMONIC_ED and do_cube_transform: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") + # if my_grid_type != GNOMONIC_ED and do_cube_transform: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") - if do_cube_transform and do_schmidt: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") + # if do_cube_transform and do_schmidt: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") - use_legacy = False + # use_legacy = False """ Command line argument check """ - if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: - nxbnds = nxbnds0 - nybnds = nybnds0 - if nxbnds < 2 or nybnds < 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") - if nxbnds != nxbnds1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") - if nybnds != nybnds1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") + + # if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + # nxbnds = nxbnds0 + # nybnds = nybnds0 + # if nxbnds < 2 or nybnds < 2: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") + # if nxbnds != nxbnds1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") + # if nybnds != nybnds1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") - num_specify = 0 - if nxbnds2 > 0 and nybnds2 > 0: - num_specify += 1 - if nxbnds3 > 0 and nybnds3 > 0: - num_specify += 1 - use_legacy = True + # num_specify = 0 + # if nxbnds2 > 0 and nybnds2 > 0: + # num_specify += 1 + # if nxbnds3 > 0 and nybnds3 > 0: + # num_specify += 1 + # use_legacy = True - if num_specify == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") - if num_specify == 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") - if use_legacy: - if nxbnds != nxbnds3: - mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") - if nybnds != nybnds3: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") - else: - if nxbnds != nxbnds2+1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") - if nybnds != nybnds2+1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") + # if num_specify == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") + # if num_specify == 2: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") + # if use_legacy: + # if nxbnds != nxbnds3: + # mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") + # if nybnds != nybnds3: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") + # else: + # if nxbnds != nxbnds2+1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") + # if nybnds != nybnds2+1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") - if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: - ntiles = 6 - ntiles_global = 6 + # if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: + # ntiles = 6 + # ntiles_global = 6 - if my_grid_type != GNOMONIC_ED and nest_grids: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") + # if my_grid_type != GNOMONIC_ED and nest_grids: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") - if my_grid_type == TRIPOLAR_GRID: - projection = "tripolar" - if nxbnds != 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") - elif my_grid_type == FROM_FILE: - if ntiles_file == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") - ntiles = ntiles_file - ntiles_global = ntiles_file - for n in range(ntiles): - if ".nc" in my_grid_file[n]: - file_path = my_grid_file[n] + ".nc" - check_file_is_there(file_path) - with xr.open_dataset(file_path) as ds: - if "grid_xt" in ds.sizes: - if "grid_yt" not in ds.sizes: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") - nlon[n] = ds.sizes["grid_xt"]*2 - nlat[n] = ds.sizes["grid_yt"]*2 - elif "rlon" in ds.sizes: - if "rlat" not in ds.sizes: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: rlat should be a dimension when rlon is a dimension") - nlon[n] = ds.sizes["rlon"]*2 - nlat[n] = ds.sizes["rlat"]*2 - elif "lon" in ds.sizes: - if "lat" not in ds.sizes: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: lat should be a dimension when lon is a dimension") - nlon[n] = ds.sizes["lon"]*2 - nlat[n] = ds.sizes["lat"]*2 - elif "i" in ds.sizes: - if "j" not in ds.sizes: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: j should be a dimension when i is a dimension") - nlon[n] = ds.sizes["i"]*2 - nlat[n] = ds.sizes["j"]*2 - elif "x" in ds.sizes: - if "y" not in ds.sizes: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: y should be a dimension when x is a dimension") - nlon[n] = ds.sizes["x"]*2 - nlat[n] = ds.sizes["y"]*2 - else: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") - else: - if nxbnds2 != ntiles or nybnds2 != ntiles: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") - """ - For simplification purposes, it is assumed at this point that all tiles will have the same grid size - """ - for n in range(1, ntiles): - if nlon[n] != nlon[0] or nlat[n] != nlat[0]: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") - elif my_grid_type == SIMPLE_CARTESIAN_GRID: - geometry = "planar" - north_pole_tile = "none" - if nxbnds1 != 2 or nybnds1 != 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") - if nxbnds2 != 1 or nybnds2 != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") - if simple_dx == 0 or simple_dy == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") - elif my_grid_type == SPECTRAL_GRID: - if nxbnds2 != 1 or nybnds2 != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") - elif my_grid_type == CONFORMAL_CUBIC_GRID: - projection = "cube_gnomonic" - conformal = "FALSE" - if nxbnds2 != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") - if nratio < 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") - elif my_grid_type == GNOMONIC_ED: - projection = "cube_gnomonic" - conformal = "FALSE" - if do_schmidt or do_cube_transform: - if present_stretch_factor == 0 or present_target_lon == 0 or present_target_lat == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") - for n in range(nest_grids): - if refine_ratio[n] == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --refine_ratio must be set when --nest_grids is set") - if parent_tile[n] == 0 and mpp.pe() == 0: - print("NOTE from make_hgrid: parent_tile is 0, the output grid will have resolution refine_ration*nlon", file=sys.stderr) - else: - if istart_nest[n] == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --istart_nest must be set when --nest_grids is set") - if iend_nest[n] == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --iend_nest must be set when --nest_grids is set") - if jstart_nest[n] == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jstart_nest must be set when --nest_grids is set") - if jend_nest[n] == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jend_nest must be set when --nest_grids is set") - if halo == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --halo must be set when --nest_grids is set") - ntiles += 1 - if verbose: - print(f"Configuration for nest {ntiles} validated.", file=sys.stderr) - if verbose: - print(f"Updated number of tiles, including nests (ntiles): {ntiles}", file=sys.stderr) - if nxbnds2 != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") - elif my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: - if f_plane_latitude > 90 or f_plane_latitude < -90: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: f_plane_latitude should be between -90 and 90.") - if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: - if mpp.pe() == 0: - print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) - if mpp.pe() == 0: - print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) - else: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") + # if my_grid_type == TRIPOLAR_GRID: + # projection = "tripolar" + # if nxbnds != 2: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") + # elif my_grid_type == FROM_FILE: + # if ntiles_file == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") + # ntiles = ntiles_file + # ntiles_global = ntiles_file + # for n in range(ntiles): + # if ".nc" in my_grid_file[n]: + # file_path = my_grid_file[n] + ".nc" + # check_file_is_there(file_path) + # with xr.open_dataset(file_path) as ds: + # if "grid_xt" in ds.sizes: + # if "grid_yt" not in ds.sizes: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") + # nlon[n] = ds.sizes["grid_xt"]*2 + # nlat[n] = ds.sizes["grid_yt"]*2 + # elif "rlon" in ds.sizes: + # if "rlat" not in ds.sizes: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: rlat should be a dimension when rlon is a dimension") + # nlon[n] = ds.sizes["rlon"]*2 + # nlat[n] = ds.sizes["rlat"]*2 + # elif "lon" in ds.sizes: + # if "lat" not in ds.sizes: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: lat should be a dimension when lon is a dimension") + # nlon[n] = ds.sizes["lon"]*2 + # nlat[n] = ds.sizes["lat"]*2 + # elif "i" in ds.sizes: + # if "j" not in ds.sizes: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: j should be a dimension when i is a dimension") + # nlon[n] = ds.sizes["i"]*2 + # nlat[n] = ds.sizes["j"]*2 + # elif "x" in ds.sizes: + # if "y" not in ds.sizes: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: y should be a dimension when x is a dimension") + # nlon[n] = ds.sizes["x"]*2 + # nlat[n] = ds.sizes["y"]*2 + # else: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") + # else: + # if nxbnds2 != ntiles or nybnds2 != ntiles: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") + # """ + # For simplification purposes, it is assumed at this point that all tiles will have the same grid size + # """ + # for n in range(1, ntiles): + # if nlon[n] != nlon[0] or nlat[n] != nlat[0]: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") + # elif my_grid_type == SIMPLE_CARTESIAN_GRID: + # geometry = "planar" + # north_pole_tile = "none" + # if nxbnds1 != 2 or nybnds1 != 2: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") + # if nxbnds2 != 1 or nybnds2 != 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") + # if simple_dx == 0 or simple_dy == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") + # elif my_grid_type == SPECTRAL_GRID: + # if nxbnds2 != 1 or nybnds2 != 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") + # elif my_grid_type == CONFORMAL_CUBIC_GRID: + # projection = "cube_gnomonic" + # conformal = "FALSE" + # if nxbnds2 != 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") + # if nratio < 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") + # elif my_grid_type == GNOMONIC_ED: + # projection = "cube_gnomonic" + # conformal = "FALSE" + # if do_schmidt or do_cube_transform: + # if present_stretch_factor == 0 or present_target_lon == 0 or present_target_lat == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") + # for n in range(nest_grids): + # if refine_ratio[n] == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --refine_ratio must be set when --nest_grids is set") + # if parent_tile[n] == 0 and mpp.pe() == 0: + # print("NOTE from make_hgrid: parent_tile is 0, the output grid will have resolution refine_ration*nlon", file=sys.stderr) + # else: + # if istart_nest[n] == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --istart_nest must be set when --nest_grids is set") + # if iend_nest[n] == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --iend_nest must be set when --nest_grids is set") + # if jstart_nest[n] == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jstart_nest must be set when --nest_grids is set") + # if jend_nest[n] == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jend_nest must be set when --nest_grids is set") + # if halo == 0: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --halo must be set when --nest_grids is set") + # ntiles += 1 + # if verbose: + # print(f"Configuration for nest {ntiles} validated.", file=sys.stderr) + # if verbose: + # print(f"Updated number of tiles, including nests (ntiles): {ntiles}", file=sys.stderr) + # if nxbnds2 != 1: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") + # elif my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + # if f_plane_latitude > 90 or f_plane_latitude < -90: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: f_plane_latitude should be between -90 and 90.") + # if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: + # if mpp.pe() == 0: + # print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) + # if mpp.pe() == 0: + # print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) + # else: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") - if verbose: - print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}", file=sys.stderr) - print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) + # if verbose: + # print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}", file=sys.stderr) + # print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) - nxl = np.empty(shape=ntiles, dtype=np.int32) - nyl = np.empty(shape=ntiles, dtype=np.int32) + # nxl = np.empty(shape=ntiles, dtype=np.int32) + # nyl = np.empty(shape=ntiles, dtype=np.int32) """ Get super grid size """ - if use_legacy: - nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) - nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) - elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: - for n in range(ntiles_global): - nxl[n] = nlon[0] - nyl[n] = nxl[n] - if nest_grids and parent_tile[0] == 0: - nxl[n] *= refine_ratio[0] - nyl[n] *= refine_ratio[0] + # if use_legacy: + # nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) + # nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) + # elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: + # for n in range(ntiles_global): + # nxl[n] = nlon[0] + # nyl[n] = nxl[n] + # if nest_grids and parent_tile[0] == 0: + # nxl[n] *= refine_ratio[0] + # nyl[n] *= refine_ratio[0] - for n in range(ntiles_global, ntiles): - nn = n - ntiles_global - nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] - nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] - elif my_grid_type == FROM_FILE: - for n in range(ntiles_global): - nxl[n] = nlon[n] - nyl[n] = nlat[n] - else: - nxl[0] = 0 - nyl[0] = 0 - for n in range(nxbnds - 1): - nxl[0] += nlon[n] - for n in range(nybnds - 1): - nyl[0] += nlat[n] + # for n in range(ntiles_global, ntiles): + # nn = n - ntiles_global + # nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] + # nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + # elif my_grid_type == FROM_FILE: + # for n in range(ntiles_global): + # nxl[n] = nlon[n] + # nyl[n] = nlat[n] + # else: + # nxl[0] = 0 + # nyl[0] = 0 + # for n in range(nxbnds - 1): + # nxl[0] += nlon[n] + # for n in range(nybnds - 1): + # nyl[0] += nlat[n] - nx = nxl[0] - ny = nyl[0] - nxp = nx + 1 - nyp = ny + 1 + # nx = nxl[0] + # ny = nyl[0] + # nxp = nx + 1 + # nyp = ny + 1 - if center == "none" and center == "c_cell" and center == "t_cell": - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") + # if center == "none" and center == "c_cell" and center == "t_cell": + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") - # --non_length_angle should only be set when grid_type == GNOMONIC_ED - if not output_length_angle and my_grid_type != GNOMONIC_ED: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") + # # --non_length_angle should only be set when grid_type == GNOMONIC_ED + # if not output_length_angle and my_grid_type != GNOMONIC_ED: + # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") """ Create grid information """ - for n_nest in range(ntiles): - print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) + # for n_nest in range(ntiles): + # print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) - size1 = ctypes.c_ulong(0) - size2 = ctypes.c_ulong(0) - size3 = ctypes.c_ulong(0) - size4 = ctypes.c_long(0) + # size1 = ctypes.c_ulong(0) + # size2 = ctypes.c_ulong(0) + # size3 = ctypes.c_ulong(0) + # size4 = ctypes.c_long(0) - if my_grid_type == FROM_FILE: - for n in range(ntiles_global): - size1.value += (nlon[n] + 1) * (nlat[n] + 1) - size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) - size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) - size4.value += (nlon[n] + 1) * (nlat[n] + 1) - else: - size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) - size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) - size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) - size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) + # if my_grid_type == FROM_FILE: + # for n in range(ntiles_global): + # size1.value += (nlon[n] + 1) * (nlat[n] + 1) + # size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) + # size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + # size4.value += (nlon[n] + 1) * (nlat[n] + 1) + # else: + # size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) + # size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) + # size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) + # size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - if not (nest_grids == 1 and parent_tile[0] == 0): - for n_nest in range(ntiles_global, ntiles_global+nest_grids): - if verbose: - print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) - size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) - size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) - size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + # if not (nest_grids == 1 and parent_tile[0] == 0): + # for n_nest in range(ntiles_global, ntiles_global+nest_grids): + # if verbose: + # print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) + # size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + # size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) + # size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) + # size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - if verbose: - print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) - grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) - grid_obj.arcx = arcx - if output_length_angle: - grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) - grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) - grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - if conformal != "true": - grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + # if verbose: + # print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) + # grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) + # grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) + # grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) + # grid_obj.arcx = arcx + # if output_length_angle: + # grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) + # grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) + # grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) + # if conformal != "true": + # grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) - isc = 0 - iec = nx - 1 - jsc = 0 - jec = ny - 1 + # isc = 0 + # iec = nx - 1 + # jsc = 0 + # jec = ny - 1 - if(my_grid_type==REGULAR_LONLAT_GRID): - create_regular_lonlat_grid( - nxbnds, - nybnds, - xbnds, - ybnds, - nlon, - nlat, - dx_bnds, - dy_bnds, - use_legacy, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - center, - use_great_circle_algorithm, - ) - elif(my_grid_type==TRIPOLAR_GRID): - create_tripolar_grid( - nxbnds, - nybnds, - xbnds, - ybnds, - nlon, - nlat, - dx_bnds, - dy_bnds, - use_legacy, - lat_join, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - center, - verbose, - use_great_circle_algorithm, - ) - elif(my_grid_type==FROM_FILE): - for n in range(ntiles): - n1 = n * nxp * nyp - n2 = n * nx * nyp - n3 = n * nxp * ny - n4 = n * nx * ny - create_grid_from_file( - my_grid_file[n], - nx, - ny, - grid_obj.x[n1:], - grid_obj.y[n1:], - grid_obj.dx[n2:], - grid_obj.dy[n3:], - grid_obj.area[n4:], - grid_obj.angle_dx[n1:], - use_great_circle_algorithm, - use_angular_midpoint, - ) - elif(my_grid_type==SIMPLE_CARTESIAN_GRID): - create_simple_cartesian_grid( - xbnds, - ybnds, - nx, - ny, - simple_dx, - simple_dy, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - ) - elif(my_grid_type==SPECTRAL_GRID): - create_spectral_grid( - nx, - ny, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - use_great_circle_algorithm, - ) - elif(my_grid_type==CONFORMAL_CUBIC_GRID): - create_conformal_cubic_grid( - nx, - nratio, - method, - orientation, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - grid_obj.angle_dy, - ) - elif(my_grid_type==GNOMONIC_ED): - if(nest_grids == 1 and parent_tile[0] == 0): - create_gnomonic_cubic_grid_GR( - grid_type, - nxl, - nyl, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - grid_obj.angle_dy, - shift_fac, - do_schmidt, - do_cube_transform, - stretch_factor, - target_lon, - target_lat, - nest_grids, - parent_tile[0], - refine_ratio[0], - istart_nest[0], - iend_nest[0], - jstart_nest[0], - jend_nest[0], - halo, - output_length_angle, - ) - else: - create_gnomonic_cubic_grid( - grid_type, - nxl, - nyl, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - grid_obj.angle_dy, - shift_fac, - do_schmidt, - do_cube_transform, - stretch_factor, - target_lon, - target_lat, - nest_grids, - parent_tile, - refine_ratio, - istart_nest, - iend_nest, - jstart_nest, - jend_nest, - halo, - output_length_angle, - ) - elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): - create_f_plane_grid( - nxbnds, - nybnds, - xbnds, - ybnds, - nlon, - nlat, - dx_bnds, - dy_bnds, - use_legacy, - f_plane_latitude, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - center, - ) + # if(my_grid_type==REGULAR_LONLAT_GRID): + # create_regular_lonlat_grid( + # nxbnds, + # nybnds, + # xbnds, + # ybnds, + # nlon, + # nlat, + # dx_bnds, + # dy_bnds, + # use_legacy, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # center, + # use_great_circle_algorithm, + # ) + # elif(my_grid_type==TRIPOLAR_GRID): + # create_tripolar_grid( + # nxbnds, + # nybnds, + # xbnds, + # ybnds, + # nlon, + # nlat, + # dx_bnds, + # dy_bnds, + # use_legacy, + # lat_join, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # center, + # verbose, + # use_great_circle_algorithm, + # ) + # elif(my_grid_type==FROM_FILE): + # for n in range(ntiles): + # n1 = n * nxp * nyp + # n2 = n * nx * nyp + # n3 = n * nxp * ny + # n4 = n * nx * ny + # create_grid_from_file( + # my_grid_file[n], + # nx, + # ny, + # grid_obj.x[n1:], + # grid_obj.y[n1:], + # grid_obj.dx[n2:], + # grid_obj.dy[n3:], + # grid_obj.area[n4:], + # grid_obj.angle_dx[n1:], + # use_great_circle_algorithm, + # use_angular_midpoint, + # ) + # elif(my_grid_type==SIMPLE_CARTESIAN_GRID): + # create_simple_cartesian_grid( + # xbnds, + # ybnds, + # nx, + # ny, + # simple_dx, + # simple_dy, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # ) + # elif(my_grid_type==SPECTRAL_GRID): + # create_spectral_grid( + # nx, + # ny, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # use_great_circle_algorithm, + # ) + # elif(my_grid_type==CONFORMAL_CUBIC_GRID): + # create_conformal_cubic_grid( + # nx, + # nratio, + # method, + # orientation, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # grid_obj.angle_dy, + # ) + # elif(my_grid_type==GNOMONIC_ED): + # if(nest_grids == 1 and parent_tile[0] == 0): + # create_gnomonic_cubic_grid_GR( + # grid_type, + # nxl, + # nyl, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # grid_obj.angle_dy, + # shift_fac, + # do_schmidt, + # do_cube_transform, + # stretch_factor, + # target_lon, + # target_lat, + # nest_grids, + # parent_tile[0], + # refine_ratio[0], + # istart_nest[0], + # iend_nest[0], + # jstart_nest[0], + # jend_nest[0], + # halo, + # output_length_angle, + # ) + # else: + # create_gnomonic_cubic_grid( + # grid_type, + # nxl, + # nyl, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # grid_obj.angle_dy, + # shift_fac, + # do_schmidt, + # do_cube_transform, + # stretch_factor, + # target_lon, + # target_lat, + # nest_grids, + # parent_tile, + # refine_ratio, + # istart_nest, + # iend_nest, + # jstart_nest, + # jend_nest, + # halo, + # output_length_angle, + # ) + # elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): + # create_f_plane_grid( + # nxbnds, + # nybnds, + # xbnds, + # ybnds, + # nlon, + # nlat, + # dx_bnds, + # dy_bnds, + # use_legacy, + # f_plane_latitude, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # center, + # ) """ Write out data """ - pos_c = 0 - pos_e = 0 - pos_t = 0 - pos_n = 0 - for n in range(ntiles): - tilename = "tile" + str(n+1) - if ntiles > 1: - outfile = grid_name + ".tile" + ".nc" + str(n+1) - else: - outfile = grid_name + ".nc" + # pos_c = 0 + # pos_e = 0 + # pos_t = 0 + # pos_n = 0 + # for n in range(ntiles): + # tilename = "tile" + str(n+1) + # if ntiles > 1: + # outfile = grid_name + ".tile" + ".nc" + str(n+1) + # else: + # outfile = grid_name + ".nc" - if verbose: - print(f"Writing out {outfile}", file=sys.stderr) + # if verbose: + # print(f"Writing out {outfile}", file=sys.stderr) - nx = nxl[n] - ny = nyl[n] - if verbose: - print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) - nxp = nx + 1 - nyp = nx + 1 + # nx = nxl[n] + # ny = nyl[n] + # if verbose: + # print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) + # nxp = nx + 1 + # nyp = nx + 1 - if out_halo == 0: - if verbose: - print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) - print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) - if n > 0: - print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) - grid_obj.x = grid_obj.x[pos_c:] - grid_obj.y = grid_obj.y[pos_c:] - if output_length_angle: - grid_obj.dx = grid_obj.dx[pos_n:] - grid_obj.dy = grid_obj.dy[pos_e:] - grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] - if conformal == "true": - grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] - grid_obj.area = grid_obj.area[pos_t:] + # if out_halo == 0: + # if verbose: + # print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) + # print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) + # if n > 0: + # print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) + # grid_obj.x = grid_obj.x[pos_c:] + # grid_obj.y = grid_obj.y[pos_c:] + # if output_length_angle: + # grid_obj.dx = grid_obj.dx[pos_n:] + # grid_obj.dy = grid_obj.dy[pos_e:] + # grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] + # if conformal == "true": + # grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] + # grid_obj.area = grid_obj.area[pos_t:] - else: - tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) - if verbose: - print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) - grid_obj.x = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) - grid_obj.y = tmp.copy() - if output_length_angle: - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) - grid_obj.angle_dx = tmp.copy() - if conformal == "true": - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) - grid_obj.angle_dy = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) - grid_obj.dx = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) - grid_obj.dy = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) - grid_obj.area = tmp.copy() + # else: + # tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + # if verbose: + # print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) + # grid_obj.x = tmp.copy() + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) + # grid_obj.y = tmp.copy() + # if output_length_angle: + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) + # grid_obj.angle_dx = tmp.copy() + # if conformal == "true": + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) + # grid_obj.angle_dy = tmp.copy() + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) + # grid_obj.dx = tmp.copy() + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) + # grid_obj.dy = tmp.copy() + # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) + # grid_obj.area = tmp.copy() - if verbose: - print(f"About to close {outfile}") + # if verbose: + # print(f"About to close {outfile}") - nx = nxl[n] - ny = nyl[n] - nxp = nx + 1 - nyp = ny + 1 + # nx = nxl[n] + # ny = nyl[n] + # nxp = nx + 1 + # nyp = ny + 1 - if verbose: - print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) - pos_c += nxp*nyp - if verbose: - print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) - pos_e += nxp*ny - pos_n += nx*nyp - pos_t += nx*ny + # if verbose: + # print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) + # pos_c += nxp*nyp + # if verbose: + # print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) + # pos_e += nxp*ny + # pos_n += nx*nyp + # pos_t += nx*ny - grid_obj.write_out_hgrid( - tilename=tilename, - outfile=outfile, - north_pole_tile=north_pole_tile, - north_pole_arcx=north_pole_arcx, - projection=projection, - geometry=geometry, - discretization=discretization, - conformal=conformal, - out_halo=out_halo, - output_length_angle=output_length_angle, - ) + # grid_obj.write_out_hgrid( + # tilename=tilename, + # outfile=outfile, + # north_pole_tile=north_pole_tile, + # north_pole_arcx=north_pole_arcx, + # projection=projection, + # geometry=geometry, + # discretization=discretization, + # conformal=conformal, + # out_halo=out_halo, + # output_length_angle=output_length_angle, + # ) - if(mpp.pe() == 0 and verbose): - print("generate_grid is run successfully") + # if(mpp.pe() == 0 and verbose): + # print("generate_grid is run successfully") pyfms.pyfms_end() diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 58dc225..dddef5a 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -10,18 +10,20 @@ """ GridObj: -Dataclass for containing basic grid data to be used by other grid objects +Class for containing basic grid data to be used by other grid objects """ -@dataclasses.dataclass + class GridObj: - dataset: Optional[xr.Dataset] = None - grid_file: Optional[str] = None - def __post_init__(self): - if self.grid_file is not None: + def __init__( + self, + dataset: Optional[xr.Dataset] = None, + grid_file: Optional[str] = None + ): + if grid_file is not None: check_file_is_there(self.grid_file) - with xr.open_dataset(self.grid_file) as ds: - self.dataset = ds + self.grid_file = grid_file + self.dataset = xr.open_dataset(self.grid_file) """ from_file: @@ -33,11 +35,10 @@ def __post_init__(self): @classmethod def from_file(cls, filepath: str) -> "GridObj": check_file_is_there(filepath) - with xr.open_dataset(filepath) as ds: - return cls( - dataset=ds, - grid_file=filepath, - ) + return cls( + dataset=xr.open_dataset(filepath), + grid_file=filepath, + ) """ write_out_grid: diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index c1107c3..bf58f7d 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -2,7 +2,7 @@ import numpy.typing as npt import ctypes -from pyfms.data_handling import ( +from pyfms.pyfms_data_handling import ( setscalar_Cint32, setscalar_Cdouble, setarray_Cdouble, @@ -10,7 +10,7 @@ set_Cchar, ) -lib = ctypes.CDLL("../../FRENCTools_lib/cfrenctools/c_build/clib.so") +lib = ctypes.CDLL("./FREnctools_lib/cfrenctools/c_build/clib.so") def fill_cubic_grid_halo( nx: int, diff --git a/pyFMS b/pyFMS index a2026fd..d3f2c1f 160000 --- a/pyFMS +++ b/pyFMS @@ -1 +1 @@ -Subproject commit a2026fd1ef63d23b2307654b64a3e755c2ddba8c +Subproject commit d3f2c1f7ac1e421fea66c30d34582f512a74b065 diff --git a/setup.py b/setup.py index aa0f835..42650a7 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,11 @@ from setuptools import setup, find_namespace_packages from setuptools.command.install import install +def local_pkg(name: str, relative_path: str) -> str: + """Returns an absolute path to a local package.""" + path = f"{name} @ file://{Path(os.path.abspath(__file__)).parent / relative_path}" + return path + class CustomInstall(install): def run(self): with open("compile_log.txt", "w") as f: @@ -41,7 +46,7 @@ def run(self): "numpy", "xarray", "netCDF4", - "pyfms @ git+https://github.com/fmalatino/pyFMS.git" + local_pkg("pyfms", "pyFMS") ] setup( @@ -52,7 +57,7 @@ def run(self): extras_require=extras_requires, name="fmsgridtools", license="", - packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.pyfrenctools.*"]), + packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.*" ]), include_package_data=True, version="0.0.1", zip_safe=False, From e2f06bb9df4a0b01baf828166b1127e58d6cb554 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 5 Mar 2025 15:51:22 -0500 Subject: [PATCH 24/72] Beginning stages of testing make_hgrid --- FMSgridtools/make_hgrid/make_hgrid.py | 169 ++++++++++++++------------ FMSgridtools/shared/gridobj.py | 1 - FMSgridtools/shared/xgridobj.py | 4 +- 3 files changed, 90 insertions(+), 84 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 946756e..fa87a9d 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,4 +1,5 @@ import sys +import os import xarray as xr import ctypes import numpy as np @@ -606,102 +607,106 @@ def make_hgrid( discretization = "logically_rectangular" conformal = "true" - pyfms = pyFMS(clibFMS_path="") + fms_file = "input.nml" + with open(fms_file, "x") as file: + file.write("") + + pyfms = pyFMS(clibFMS_path="./pyFMS/cFMS/libcFMS/.libs/libcFMS.so") mpp = pyFMS_mpp(clibFMS=pyfms.clibFMS) mpp_domains = pyFMS_mpp_domains(clibFMS=pyfms.clibFMS) if(mpp.npes() > 1): mpp.pyfms_error(errortype=2, errormsg="make_hgrid: make_hgrid must be run one processor, contact developer") - # if xbnds is not None: - # xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') - # nxbnds1 = xbnds.size - # if ybnds is not None: - # ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') - # nybnds1 = ybnds.size - # if nlon is not None: - # nlon = np.fromstring(nlon, dtype=int, sep=',') - # nxbnds2 = nlon.size - # if nlat is not None: - # nlat = np.fromstring(nlat, dtype=int, sep=',') - # nybnds2 = nlat.size - # if dlon is not None: - # dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') - # nxbnds3 = dx_bnds.size - # if dlat is not None: - # dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') - # nybnds3 = dy_bnds.size - # if stretch_factor != 0.0: - # present_stretch_factor = 1 - # if target_lon != 0.0: - # present_target_lon = 1 - # if target_lat != 0.0: - # present_target_lat = 1 - # if refine_ratio is not None: - # refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') - # num_nest_args = refine_ratio.size - # if parent_tile is not None: - # parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') - # num_nest_args = parent_tile.size - # if istart_nest is not None: - # istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') - # num_nest_args = istart_nest.size - # if iend_nest is not None: - # iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') - # num_nest_args = iend_nest.size - # if jstart_nest is not None: - # jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') - # num_nest_args = jstart_nest.size - # if jend_nest is not None: - # jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') - # num_nest_args = jend_nest.size - # if angular_midpoint: - # use_angular_midpoint = 1 - # if my_grid_file is not None: - # my_grid_file = np.array(my_grid_file.split(',')) - # ntiles_file = my_grid_file.size + if xbnds is not None: + xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') + nxbnds1 = xbnds.size + if ybnds is not None: + ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') + nybnds1 = ybnds.size + if nlon is not None: + nlon = np.fromstring(nlon, dtype=int, sep=',') + nxbnds2 = nlon.size + if nlat is not None: + nlat = np.fromstring(nlat, dtype=int, sep=',') + nybnds2 = nlat.size + if dlon is not None: + dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') + nxbnds3 = dx_bnds.size + if dlat is not None: + dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') + nybnds3 = dy_bnds.size + if stretch_factor != 0.0: + present_stretch_factor = 1 + if target_lon != 0.0: + present_target_lon = 1 + if target_lat != 0.0: + present_target_lat = 1 + if refine_ratio is not None: + refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') + num_nest_args = refine_ratio.size + if parent_tile is not None: + parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') + num_nest_args = parent_tile.size + if istart_nest is not None: + istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') + num_nest_args = istart_nest.size + if iend_nest is not None: + iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') + num_nest_args = iend_nest.size + if jstart_nest is not None: + jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') + num_nest_args = jstart_nest.size + if jend_nest is not None: + jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') + num_nest_args = jend_nest.size + if angular_midpoint: + use_angular_midpoint = 1 + if my_grid_file is not None: + my_grid_file = np.array(my_grid_file.split(',')) + ntiles_file = my_grid_file.size # TODO: rotate_poly? - # if mpp.pe() == 0 and verbose: - # print(f"==>NOTE: the grid type is {grid_type}") + if mpp.pe() == 0 and verbose: + print(f"==>NOTE: the grid type is {grid_type}") - # if grid_type == "regular_lonlat_grid": - # my_grid_type = REGULAR_LONLAT_GRID - # elif grid_type == "tripolar_grid": - # my_grid_type = TRIPOLAR_GRID - # elif grid_type == "from_file": - # my_grid_type = FROM_FILE - # elif grid_type == "simple_cartesian_grid": - # my_grid_type = SIMPLE_CARTESIAN_GRID - # elif grid_type == "spectral_grid": - # my_grid_type = SPECTRAL_GRID - # elif grid_type == "conformal_cubic_grid": - # my_grid_type = CONFORMAL_CUBIC_GRID - # elif grid_type == "gnomonic_ed": - # my_grid_type = GNOMONIC_ED - # elif grid_type == "f_plane_grid": - # my_grid_type = F_PLANE_GRID - # elif grid_type == "beta_plane_grid": - # my_grid_type = BETA_PLANE_GRID - # else: - # mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") + if grid_type == "regular_lonlat_grid": + my_grid_type = REGULAR_LONLAT_GRID + elif grid_type == "tripolar_grid": + my_grid_type = TRIPOLAR_GRID + elif grid_type == "from_file": + my_grid_type = FROM_FILE + elif grid_type == "simple_cartesian_grid": + my_grid_type = SIMPLE_CARTESIAN_GRID + elif grid_type == "spectral_grid": + my_grid_type = SPECTRAL_GRID + elif grid_type == "conformal_cubic_grid": + my_grid_type = CONFORMAL_CUBIC_GRID + elif grid_type == "gnomonic_ed": + my_grid_type = GNOMONIC_ED + elif grid_type == "f_plane_grid": + my_grid_type = F_PLANE_GRID + elif grid_type == "beta_plane_grid": + my_grid_type = BETA_PLANE_GRID + else: + mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") - # if my_grid_type != GNOMONIC_ED and out_halo != 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") - # if out_halo != 0 and out_halo != 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") + if my_grid_type != GNOMONIC_ED and out_halo != 0: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") + if out_halo != 0 and out_halo != 1: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") - # if my_grid_type != GNOMONIC_ED and do_schmidt: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") + if my_grid_type != GNOMONIC_ED and do_schmidt: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") - # if my_grid_type != GNOMONIC_ED and do_cube_transform: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") + if my_grid_type != GNOMONIC_ED and do_cube_transform: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") - # if do_cube_transform and do_schmidt: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") + if do_cube_transform and do_schmidt: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") - # use_legacy = False + use_legacy = False """ Command line argument check @@ -1251,6 +1256,8 @@ def make_hgrid( # print("generate_grid is run successfully") pyfms.pyfms_end() + + os.remove(fms_file) # End of main diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index dddef5a..b911b9e 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -1,4 +1,3 @@ -import dataclasses from typing import List, Optional import numpy as np diff --git a/FMSgridtools/shared/xgridobj.py b/FMSgridtools/shared/xgridobj.py index 1a4a476..42c579f 100755 --- a/FMSgridtools/shared/xgridobj.py +++ b/FMSgridtools/shared/xgridobj.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Optional import xarray as xr -from gridtools.shared.gridtools_utils import check_file_is_there -from gridtools.shared.gridobj import GridObj +from FMSgridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridobj import GridObj @dataclass class XGridObj() : From 5014c5d523e57b52554d004cf8a6ea67cb1a4e7a Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 7 Mar 2025 21:50:04 -0500 Subject: [PATCH 25/72] Testing make_hgrid up to write out for regular_lonlat_grid --- FMSgridtools/make_hgrid/hgridobj.py | 20 +- FMSgridtools/make_hgrid/make_hgrid.py | 471 ++++++++++-------- .../make_hgrid/create_lonlat_grid.c | 7 + .../make_hgrid/make_hgrid_util.py | 141 ++++-- 4 files changed, 363 insertions(+), 276 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 26e900b..866a866 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -7,17 +7,17 @@ from FMSgridtools.shared.gridtools_utils import check_file_is_there from FMSgridtools.shared.gridobj import GridObj -@dataclasses.dataclass class HGridObj(): - tile: Optional[str] = None - x: Optional[npt.NDArray] = None - y: Optional[npt.NDArray] = None - dx: Optional[npt.NDArray] = None - dy: Optional[npt.NDArray] = None - area: Optional[npt.NDArray] = None - angle_dx: Optional[npt.NDArray] = None - angle_dy: Optional[npt.NDArray] = None - arcx: Optional[str] = None + def __init__(self): + self.tile = "" + self.x = None + self.y = None + self.dx = None + self.dy = None + self.area = None + self.angle_dx = None + self.angle_dy = None + self.arcx = "" def write_out_hgrid( self, diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index fa87a9d..89a0db8 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -62,7 +62,7 @@ --jend_nest jend_nest(1),...jend_nest(nests-1) --use_great_circle_algorithm (bool) --out_halo # - --output_length_angle (bool) + --no_output_length_angle (bool) The available options for grid_type are: 1. 'from_file': @@ -509,7 +509,7 @@ gnomonic_ed.", ) @click.option( - "--output_length_angle", + "--no_output_length_angle", is_flag=True, default=False, help="When specified, will not output length(dx,dy) and angle \ @@ -570,7 +570,7 @@ def make_hgrid( halo: int, use_great_circle_algorithm: bool, out_halo: int, - output_length_angle: bool, + no_output_length_angle: bool, angular_midpoint: bool, rotate_poly: bool, verbose: bool, @@ -593,6 +593,7 @@ def make_hgrid( present_stretch_factor = 0 present_target_lon = 0 present_target_lat = 0 + output_length_angle = 1 ntiles = 1 ntiles_global = 1 ntiles_file = 0 @@ -621,47 +622,74 @@ def make_hgrid( if xbnds is not None: xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') nxbnds1 = xbnds.size + else: + xbnds = np.empty(shape=100, dtype=np.float64, order="C") + if ybnds is not None: ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') nybnds1 = ybnds.size + else: + ybnds = np.empty(shape=100, dtype=np.float64, order="C") + if nlon is not None: - nlon = np.fromstring(nlon, dtype=int, sep=',') + nlon = np.fromstring(nlon, dtype=np.int32, sep=',') nxbnds2 = nlon.size + if nlat is not None: - nlat = np.fromstring(nlat, dtype=int, sep=',') + nlat = np.fromstring(nlat, dtype=np.int32, sep=',') nybnds2 = nlat.size + if dlon is not None: dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') nxbnds3 = dx_bnds.size + else: + dx_bnds = np.zeros(shape=100, dtype=np.float64, order="C") + if dlat is not None: dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') nybnds3 = dy_bnds.size + else: + dy_bnds = np.zeros(shape=100, dtype=np.float64, order="C") + if stretch_factor != 0.0: present_stretch_factor = 1 + if target_lon != 0.0: present_target_lon = 1 + if target_lat != 0.0: present_target_lat = 1 + if refine_ratio is not None: - refine_ratio = np.fromstring(refine_ratio, dtype=int, sep=',') + refine_ratio = np.fromstring(refine_ratio, dtype=np.int32, sep=',') num_nest_args = refine_ratio.size + if parent_tile is not None: - parent_tile = np.fromstring(refine_ratio, dtype=int, sep=',') + parent_tile = np.fromstring(refine_ratio, dtype=np.int32, sep=',') num_nest_args = parent_tile.size + if istart_nest is not None: - istart_nest = np.fromstring(istart_nest, dtype=int, sep=',') - num_nest_args = istart_nest.size + istart_nest = np.fromstring(istart_nest, dtype=np.int32, sep=',') + num_nest_args = istart_nest.size + if iend_nest is not None: - iend_nest = np.fromstring(iend_nest, dtype=int, sep=',') + iend_nest = np.fromstring(iend_nest, dtype=np.int32, sep=',') num_nest_args = iend_nest.size + if jstart_nest is not None: - jstart_nest = np.fromstring(jstart_nest, dtype=int, sep=',') + jstart_nest = np.fromstring(jstart_nest, dtype=np.int32, sep=',') num_nest_args = jstart_nest.size + if jend_nest is not None: - jend_nest = np.fromstring(jend_nest, dtype=int, sep=',') + jend_nest = np.fromstring(jend_nest, dtype=np.int32, sep=',') num_nest_args = jend_nest.size + + if no_output_length_angle: + output_length_angle = 0 + if angular_midpoint: use_angular_midpoint = 1 + if my_grid_file is not None: my_grid_file = np.array(my_grid_file.split(',')) ntiles_file = my_grid_file.size @@ -706,43 +734,44 @@ def make_hgrid( if do_cube_transform and do_schmidt: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") - use_legacy = False + use_legacy = 0 """ Command line argument check """ - # if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: - # nxbnds = nxbnds0 - # nybnds = nybnds0 - # if nxbnds < 2 or nybnds < 2: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") - # if nxbnds != nxbnds1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") - # if nybnds != nybnds1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") + if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + nxbnds = nxbnds0 + nybnds = nybnds0 + if nxbnds < 2 or nybnds < 2: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") + if nxbnds != nxbnds1: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") + if nybnds != nybnds1: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") - # num_specify = 0 - # if nxbnds2 > 0 and nybnds2 > 0: - # num_specify += 1 - # if nxbnds3 > 0 and nybnds3 > 0: - # num_specify += 1 - # use_legacy = True + num_specify = 0 + if nxbnds2 > 0 and nybnds2 > 0: + num_specify += 1 + if nxbnds3 > 0 and nybnds3 > 0: + num_specify += 1 + use_legacy = 1 + print(f"use_legacy = {use_legacy}") - # if num_specify == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") - # if num_specify == 2: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") - # if use_legacy: - # if nxbnds != nxbnds3: - # mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") - # if nybnds != nybnds3: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") - # else: - # if nxbnds != nxbnds2+1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") - # if nybnds != nybnds2+1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") + if num_specify == 0: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") + if num_specify == 2: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") + if use_legacy: + if nxbnds != nxbnds3: + mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") + if nybnds != nybnds3: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") + else: + if nxbnds != nxbnds2+1: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") + if nybnds != nybnds2+1: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") # if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: # ntiles = 6 @@ -860,130 +889,131 @@ def make_hgrid( # else: # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") - # if verbose: - # print(f"[INFO] make_hgrid.c Number of tiles (ntiles): {ntiles}", file=sys.stderr) - # print(f"[INFO] make_hgrid.c Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) + if verbose: + print(f"[INFO] make_hgrid: Number of tiles (ntiles): {ntiles}", file=sys.stderr) + print(f"[INFO] make_hgrid: Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) - # nxl = np.empty(shape=ntiles, dtype=np.int32) - # nyl = np.empty(shape=ntiles, dtype=np.int32) + nxl = np.empty(shape=ntiles, dtype=np.int32) + nyl = np.empty(shape=ntiles, dtype=np.int32) """ Get super grid size """ - # if use_legacy: - # nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) - # nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) - # elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: - # for n in range(ntiles_global): - # nxl[n] = nlon[0] - # nyl[n] = nxl[n] - # if nest_grids and parent_tile[0] == 0: - # nxl[n] *= refine_ratio[0] - # nyl[n] *= refine_ratio[0] - - # for n in range(ntiles_global, ntiles): - # nn = n - ntiles_global - # nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] - # nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] - # elif my_grid_type == FROM_FILE: - # for n in range(ntiles_global): - # nxl[n] = nlon[n] - # nyl[n] = nlat[n] - # else: - # nxl[0] = 0 - # nyl[0] = 0 - # for n in range(nxbnds - 1): - # nxl[0] += nlon[n] - # for n in range(nybnds - 1): - # nyl[0] += nlat[n] + if use_legacy: + nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) + nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) + elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: + for n in range(ntiles_global): + nxl[n] = nlon[0] + nyl[n] = nxl[n] + if nest_grids and parent_tile[0] == 0: + nxl[n] *= refine_ratio[0] + nyl[n] *= refine_ratio[0] + + for n in range(ntiles_global, ntiles): + nn = n - ntiles_global + nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] + nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + elif my_grid_type == FROM_FILE: + for n in range(ntiles_global): + nxl[n] = nlon[n] + nyl[n] = nlat[n] + else: + nxl[0] = 0 + nyl[0] = 0 + for n in range(nxbnds - 1): + nxl[0] += nlon[n] + for n in range(nybnds - 1): + nyl[0] += nlat[n] - # nx = nxl[0] - # ny = nyl[0] - # nxp = nx + 1 - # nyp = ny + 1 + nx = nxl[0] + ny = nyl[0] + nxp = nx + 1 + nyp = ny + 1 - # if center == "none" and center == "c_cell" and center == "t_cell": - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") + if center == "none" and center == "c_cell" and center == "t_cell": + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") - # # --non_length_angle should only be set when grid_type == GNOMONIC_ED - # if not output_length_angle and my_grid_type != GNOMONIC_ED: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") + # --non_length_angle should only be set when grid_type == GNOMONIC_ED + if not output_length_angle and my_grid_type != GNOMONIC_ED: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") """ Create grid information """ - # for n_nest in range(ntiles): - # print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) + for n_nest in range(ntiles): + print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) - # size1 = ctypes.c_ulong(0) - # size2 = ctypes.c_ulong(0) - # size3 = ctypes.c_ulong(0) - # size4 = ctypes.c_long(0) + size1 = ctypes.c_ulong(0) + size2 = ctypes.c_ulong(0) + size3 = ctypes.c_ulong(0) + size4 = ctypes.c_long(0) - # if my_grid_type == FROM_FILE: - # for n in range(ntiles_global): - # size1.value += (nlon[n] + 1) * (nlat[n] + 1) - # size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) - # size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) - # size4.value += (nlon[n] + 1) * (nlat[n] + 1) - # else: - # size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) - # size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) - # size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) - # size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - - # if not (nest_grids == 1 and parent_tile[0] == 0): - # for n_nest in range(ntiles_global, ntiles_global+nest_grids): - # if verbose: - # print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) - # size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - # size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) - # size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) - # size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - - # if verbose: - # print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) - # grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) - # grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) - # grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) - # grid_obj.arcx = arcx - # if output_length_angle: - # grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) - # grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) - # grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - # if conformal != "true": - # grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) - - # isc = 0 - # iec = nx - 1 - # jsc = 0 - # jec = ny - 1 - - # if(my_grid_type==REGULAR_LONLAT_GRID): - # create_regular_lonlat_grid( - # nxbnds, - # nybnds, - # xbnds, - # ybnds, - # nlon, - # nlat, - # dx_bnds, - # dy_bnds, - # use_legacy, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # center, - # use_great_circle_algorithm, - # ) + if my_grid_type == FROM_FILE: + for n in range(ntiles_global): + size1.value += (nlon[n] + 1) * (nlat[n] + 1) + size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) + size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + size4.value += (nlon[n] + 1) * (nlat[n] + 1) + else: + size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) + size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) + size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) + size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) + + if not (nest_grids == 1 and parent_tile[0] == 0): + for n_nest in range(ntiles_global, ntiles_global+nest_grids): + if verbose: + print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) + size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) + size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) + size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + + if verbose: + print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) + grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) + grid_obj.arcx = arcx + if output_length_angle: + grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) + grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) + grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) + if conformal != "true": + grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + + isc = 0 + iec = nx - 1 + jsc = 0 + jec = ny - 1 + + if(my_grid_type==REGULAR_LONLAT_GRID): + print(f"use_legacy py = {use_legacy}") + create_regular_lonlat_grid( + nxbnds, + nybnds, + xbnds, + ybnds, + nlon, + nlat, + dx_bnds, + dy_bnds, + use_legacy, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, + center, + use_great_circle_algorithm, + ) # elif(my_grid_type==TRIPOLAR_GRID): # create_tripolar_grid( # nxbnds, @@ -1163,80 +1193,79 @@ def make_hgrid( """ Write out data """ - # pos_c = 0 - # pos_e = 0 - # pos_t = 0 - # pos_n = 0 - # for n in range(ntiles): - # tilename = "tile" + str(n+1) - # if ntiles > 1: - # outfile = grid_name + ".tile" + ".nc" + str(n+1) - # else: - # outfile = grid_name + ".nc" + pos_c = 0 + pos_e = 0 + pos_t = 0 + pos_n = 0 + for n in range(ntiles): + tilename = "tile" + str(n+1) + if ntiles > 1: + outfile = grid_name + ".tile" + ".nc" + str(n+1) + else: + outfile = grid_name + ".nc" - # if verbose: - # print(f"Writing out {outfile}", file=sys.stderr) + if verbose: + print(f"Writing out {outfile}", file=sys.stderr) - # nx = nxl[n] - # ny = nyl[n] - # if verbose: - # print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) - # nxp = nx + 1 - # nyp = nx + 1 - - # if out_halo == 0: - # if verbose: - # print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) - # print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) - # if n > 0: - # print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) - # grid_obj.x = grid_obj.x[pos_c:] - # grid_obj.y = grid_obj.y[pos_c:] - # if output_length_angle: - # grid_obj.dx = grid_obj.dx[pos_n:] - # grid_obj.dy = grid_obj.dy[pos_e:] - # grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] - # if conformal == "true": - # grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] - # grid_obj.area = grid_obj.area[pos_t:] + nx = nxl[n] + ny = nyl[n] + if verbose: + print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) + nxp = nx + 1 + nyp = nx + 1 - # else: - # tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) - # if verbose: - # print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) - # grid_obj.x = tmp.copy() - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) - # grid_obj.y = tmp.copy() - # if output_length_angle: - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) - # grid_obj.angle_dx = tmp.copy() - # if conformal == "true": - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) - # grid_obj.angle_dy = tmp.copy() - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) - # grid_obj.dx = tmp.copy() - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) - # grid_obj.dy = tmp.copy() - # fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) - # grid_obj.area = tmp.copy() + if out_halo == 0: + if verbose: + print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) + print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) + if n > 0: + print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) + grid_obj.x = grid_obj.x[pos_c:] + grid_obj.y = grid_obj.y[pos_c:] + if output_length_angle: + grid_obj.dx = grid_obj.dx[pos_n:] + grid_obj.dy = grid_obj.dy[pos_e:] + grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] + if conformal != "true": + grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] + grid_obj.area = grid_obj.area[pos_t:] + else: + tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + if verbose: + print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) + grid_obj.x = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) + grid_obj.y = tmp.copy() + if output_length_angle: + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) + grid_obj.angle_dx = tmp.copy() + if conformal != "true": + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) + grid_obj.angle_dy = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) + grid_obj.dx = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) + grid_obj.dy = tmp.copy() + fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) + grid_obj.area = tmp.copy() - # if verbose: - # print(f"About to close {outfile}") + if verbose: + print(f"About to close {outfile}") - # nx = nxl[n] - # ny = nyl[n] - # nxp = nx + 1 - # nyp = ny + 1 + nx = nxl[n] + ny = nyl[n] + nxp = nx + 1 + nyp = ny + 1 - # if verbose: - # print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) - # pos_c += nxp*nyp - # if verbose: - # print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) - # pos_e += nxp*ny - # pos_n += nx*nyp - # pos_t += nx*ny + if verbose: + print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) + pos_c += nxp*nyp + if verbose: + print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) + pos_e += nxp*ny + pos_n += nx*nyp + pos_t += nx*ny # grid_obj.write_out_hgrid( @@ -1252,8 +1281,8 @@ def make_hgrid( # output_length_angle=output_length_angle, # ) - # if(mpp.pe() == 0 and verbose): - # print("generate_grid is run successfully") + if(mpp.pe() == 0 and verbose): + print("generate_grid is run successfully") pyfms.pyfms_end() diff --git a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c index ebdec7b..ca05651 100644 --- a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c +++ b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c @@ -289,6 +289,8 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j { long n, i, j; double lon[4], lat[4]; + + double test; n = 0; for(j=0; j Date: Thu, 13 Mar 2025 15:28:00 -0400 Subject: [PATCH 26/72] Passing make_hgrid example 1 --- FMSgridtools/make_hgrid/hgridobj.py | 129 ++++++++++-------- FMSgridtools/make_hgrid/make_hgrid.py | 65 ++++----- .../make_hgrid/create_lonlat_grid.c | 5 - 3 files changed, 106 insertions(+), 93 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 866a866..d62a83a 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -23,6 +23,10 @@ def write_out_hgrid( self, tilename, outfile, + nx: int, + ny: int, + nxp: int, + nyp: int, north_pole_tile="none", north_pole_arcx="none", projection="none", @@ -75,74 +79,84 @@ def write_out_hgrid( ) ) - x = xr.DataArray( - data=self.x, - dims=["nyp", "nxp"], - attrs=dict( - units="degree_east", - standard_name="geographic_longitude", - ) - ) - - y = xr.DataArray( - data=self.y, - dims=["nyp", "nxp"], - attrs=dict( - units="degree_north", - standard_name="geographic_latitude", - ) - ) - - if output_length_angle: - dx = xr.DataArray( - data=self.dx, - dims=["nyp", "nx"], + if self.x is not None: + x = xr.DataArray( + data=self.x[:(nyp*nxp)].reshape((nyp,nxp)), + dims=["nyp", "nxp"], attrs=dict( - units="meters", - standard_name="grid_edge_x_distance", + units="degree_east", + standard_name="geographic_longitude", ) ) - dy = xr.DataArray( - data=self.dy, - dims=["ny", "nxp"], - attrs=dict( - units="meters", - standard_name="grid_edge_y_distance", - ) - ) - angle_dx = xr.DataArray( - data=self.angle_dx, + if self.y is not None: + y = xr.DataArray( + data=self.y[:(nyp*nxp)].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", + units="degree_north", + standard_name="geographic_latitude", ) ) - if out_halo > 0: - dx.attrs["_FillValue"] = -9999. - dy.attrs["_FillValue"] = -9999. - angle_dx.attrs["_FillValue"] = -9999. - if conformal == "true": - angle_dy = xr.DataArray( - data=self.angle_dy, + + if output_length_angle: + if self.dx is not None: + dx = xr.DataArray( + data=self.dx[:(nyp*nx)].reshape((nyp, nx)), + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", + ) + ) + if self.dy is not None: + dy = xr.DataArray( + data=self.dy[:(ny*nxp)].reshape((ny, nxp)), + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", + ) + ) + if self.angle_dx is not None: + angle_dx = xr.DataArray( + data=self.angle_dx[:(nyp*nxp)].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( - units="degrees_north", - standard_name="grid_vertex_y_angle_WRT_geographic_north", + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", ) ) + if out_halo > 0: + if dx is not None: + dx.attrs["_FillValue"] = -9999. + if dy is not None: + dy.attrs["_FillValue"] = -9999. + if angle_dx is not None: + angle_dx.attrs["_FillValue"] = -9999. + if conformal != "true": + if self.angle_dy is not None: + angle_dy = xr.DataArray( + data=self.angle_dy.reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_north", + standard_name="grid_vertex_y_angle_WRT_geographic_north", + ) + ) if out_halo > 0: - angle_dy.attrs["_FillValue"] = -9999. + if angle_dy is not None: + angle_dy.attrs["_FillValue"] = -9999. - area = xr.DataArray( - data=self.area, - dims=["ny", "nx"], - attrs=dict( - units="m2", - standard_name="grid_cell_area", + if self.area is not None: + area = xr.DataArray( + data=self.area[:(ny*nx)].reshape((ny, nx)), + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", + ) ) - ) if north_pole_arcx == "none": arcx = xr.DataArray( @@ -160,9 +174,12 @@ def write_out_hgrid( ) ) if out_halo > 0: - x.attrs["_FillValue"] = -9999. - y.attrs["_FillValue"] = -9999. - area.attrs["_FillValue"] = -9999. + if x is not None: + x.attrs["_FillValue"] = -9999. + if y is not None: + y.attrs["_FillValue"] = -9999. + if area is not None: + area.attrs["_FillValue"] = -9999. dataset = xr.Dataset( data_vars={ diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 89a0db8..7784125 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -97,20 +97,20 @@ 1. generating regular lon-lat grid (supergrid size 60x20) fmsgridtools make_hgrid --grid_type regular_lonlat_grid - --nxbnd 2 - --nybnd 2 - --xbnd 0,30 - --ybnd 50,60 + --nxbnds 2 + --nybnds 2 + --xbnds 0,30 + --ybnds 50,60 --nlon 60 --nlat 20 2. generating tripolar grid with various grid resolution and C-cell centered using monotonic bi-cub spline interpolation. fmsgridtools make_hgrid --grid_type tripolar_grid - --nxbnd 2 - --nybnd 7 - --xbnd -280,80 - --ybnd -82,-30,-10,0,10,30,90 + --nxbnds 2 + --nybnds 7 + --xbnds -280,80 + --ybnds -82,-30,-10,0,10,30,90 --nlon 720 --nlat 104,48,40,40,48,120 --grid_name om3_grid @@ -119,10 +119,10 @@ 3. generating tripolar grid with various grid resolution and C-cell centered using legacy algorithm (create GFDL CM2/ocean-like grid) fmsgridtools make_hgrid --grid_type tripolar_grid - --nxbnd 2 - --nybnd 7 - --xbnd -280,80 - --ybnd -82,-30,-10,0,10,30,90 + --nxbnds 2 + --nybnds 7 + --xbnds -280,80 + --ybnds -82,-30,-10,0,10,30,90 --dlon 1.0,1.0 --dlat 1.0,1.0,0.6666667,0.3333333,0.6666667,1.0,1.0 --grid_name om3_grid @@ -130,8 +130,8 @@ 4. generating simple cartesian grid(supergrid size 20x20) fmsgridtools make_hgrid --grid_type simple_cartesian_grid - --xbnd 0,30 - --ybnd 50,60 + --xbnds 0,30 + --ybnds 50,60 --nlon 20 --nlat 20 --simple_dx 1000 @@ -756,7 +756,6 @@ def make_hgrid( if nxbnds3 > 0 and nybnds3 > 0: num_specify += 1 use_legacy = 1 - print(f"use_legacy = {use_legacy}") if num_specify == 0: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") @@ -943,7 +942,7 @@ def make_hgrid( """ for n_nest in range(ntiles): - print(f"[INFO] tile: {n_nest}, {nxl[n_nest]}, {nyl[n_nest]}, ntiles: {ntiles}", file=sys.stderr) + print(f"[INFO] tile: {n_nest}, nxl[{nxl[n_nest]}], nyl[{nyl[n_nest]}], ntiles: {ntiles}", file=sys.stderr) size1 = ctypes.c_ulong(0) size2 = ctypes.c_ulong(0) @@ -972,7 +971,7 @@ def make_hgrid( size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) if verbose: - print(f"[INFO] Allocating arrays of size {size1} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) + print(f"[INFO] Allocating arrays of size {size1.value} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) @@ -990,7 +989,6 @@ def make_hgrid( jec = ny - 1 if(my_grid_type==REGULAR_LONLAT_GRID): - print(f"use_legacy py = {use_legacy}") create_regular_lonlat_grid( nxbnds, nybnds, @@ -1212,7 +1210,7 @@ def make_hgrid( if verbose: print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) nxp = nx + 1 - nyp = nx + 1 + nyp = ny + 1 if out_halo == 0: if verbose: @@ -1267,19 +1265,22 @@ def make_hgrid( pos_n += nx*nyp pos_t += nx*ny - - # grid_obj.write_out_hgrid( - # tilename=tilename, - # outfile=outfile, - # north_pole_tile=north_pole_tile, - # north_pole_arcx=north_pole_arcx, - # projection=projection, - # geometry=geometry, - # discretization=discretization, - # conformal=conformal, - # out_halo=out_halo, - # output_length_angle=output_length_angle, - # ) + grid_obj.write_out_hgrid( + tilename=tilename, + outfile=outfile, + nx=nx, + ny=ny, + nxp=nxp, + nyp=nyp, + north_pole_tile=north_pole_tile, + north_pole_arcx=north_pole_arcx, + projection=projection, + geometry=geometry, + discretization=discretization, + conformal=conformal, + out_halo=out_halo, + output_length_angle=output_length_angle, + ) if(mpp.pe() == 0 and verbose): print("generate_grid is run successfully") diff --git a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c index ca05651..8fd27d4 100644 --- a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c +++ b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c @@ -300,7 +300,6 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j } } /* zonal length */ - printf("at zonal length\n"); n = 0; for(j=jsc; j<=jec+1; j++) { for(i=isc; i<=iec; i++ ) { @@ -309,7 +308,6 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j } /* meridinal length */ - printf("at meridinal length\n"); n = 0; for(j=jsc; j<=jec; j++) { for(i=isc; i<=iec+1; i++ ) { @@ -318,7 +316,6 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j } /* cell area */ - printf("at cell area\n"); if(use_great_circle_algorithm) { double *x_rad=NULL, *y_rad=NULL; int nx, ny; @@ -327,7 +324,6 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j ny = nyp-1; /* since make_hgrid is limited to be run on 1 processor, we could assume nx = iec-isc+1 and ny=jec-jsc+1 */ - printf("at setup of x_rad, y_rad"); x_rad = (double *)malloc(nxp*nyp*sizeof(double)); y_rad = (double *)malloc(nxp*nyp*sizeof(double)); for(i=0; i Date: Wed, 2 Apr 2025 12:02:17 -0400 Subject: [PATCH 27/72] Using data_handling module until replaced - comments --- FMSgridtools/make_hgrid/make_hgrid.py | 63 ++++---- .../pyfrenctools/shared/tool_util.py | 34 ---- .../make_hgrid/make_hgrid_util.py | 148 ++++++++++-------- 3 files changed, 120 insertions(+), 125 deletions(-) delete mode 100644 FRENCTools_lib/pyfrenctools/shared/tool_util.py diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 7784125..7f9fa1c 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -779,10 +779,10 @@ def make_hgrid( # if my_grid_type != GNOMONIC_ED and nest_grids: # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") - # if my_grid_type == TRIPOLAR_GRID: - # projection = "tripolar" - # if nxbnds != 2: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") + if my_grid_type == TRIPOLAR_GRID: + projection = "tripolar" + if nxbnds != 2: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") # elif my_grid_type == FROM_FILE: # if ntiles_file == 0: # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") @@ -1012,32 +1012,32 @@ def make_hgrid( center, use_great_circle_algorithm, ) - # elif(my_grid_type==TRIPOLAR_GRID): - # create_tripolar_grid( - # nxbnds, - # nybnds, - # xbnds, - # ybnds, - # nlon, - # nlat, - # dx_bnds, - # dy_bnds, - # use_legacy, - # lat_join, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # center, - # verbose, - # use_great_circle_algorithm, - # ) + elif(my_grid_type==TRIPOLAR_GRID): + create_tripolar_grid( + nxbnds, + nybnds, + xbnds, + ybnds, + nlon, + nlat, + dx_bnds, + dy_bnds, + use_legacy, + lat_join, + isc, + iec, + jsc, + jec, + grid_obj.x, + grid_obj.y, + grid_obj.dx, + grid_obj.dy, + grid_obj.area, + grid_obj.angle_dx, + center, + verbose, + use_great_circle_algorithm, + ) # elif(my_grid_type==FROM_FILE): # for n in range(ntiles): # n1 = n * nxp * nyp @@ -1187,6 +1187,9 @@ def make_hgrid( # grid_obj.angle_dx, # center, # ) + else: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") + """ Write out data diff --git a/FRENCTools_lib/pyfrenctools/shared/tool_util.py b/FRENCTools_lib/pyfrenctools/shared/tool_util.py deleted file mode 100644 index 13c02cb..0000000 --- a/FRENCTools_lib/pyfrenctools/shared/tool_util.py +++ /dev/null @@ -1,34 +0,0 @@ -import numpy as np -import numpy.typing as npt -import ctypes - -from pyfms.data_handling import ( - setscalar_Cint32, - setarray_Cdouble, -) - -lib = ctypes.CDLL("../../FRENCTools_lib/cfrenctools/c_build/clib.so") - -def get_legacy_grid_size( - nb: int, - bnds: npt.NDArray[np.float64], - dbnds: npt.NDArray[np.float64], -): - _get_legacy_grid_size = lib.get_legacy_grid_size - - nb_c, nb_t = setscalar_Cint32(nb) - bnds_p, bnds_t = setarray_Cdouble(bnds) - dbnds_p, dbnds_t = setarray_Cdouble(dbnds) - - _get_legacy_grid_size.argtypes = [ - nb_t, - bnds_t, - dbnds_t, - ] - _get_legacy_grid_size.restype = ctypes.c_int - - _get_legacy_grid_size( - nb_c, - bnds_p, - dbnds_p, - ) \ No newline at end of file diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index 040e303..cb8fda4 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -91,74 +91,101 @@ def create_regular_lonlat_grid( nxbnds_c, nxbnds_t = ctypes.c_int(nxbnds), ctypes.POINTER(ctypes.c_int) nybnds_c, nybnds_t = ctypes.c_int(nybnds), ctypes.POINTER(ctypes.c_int) - if xbnds is not None: - xbnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=xbnds.shape, flags="C_CONTIGUOUS") - else: - xbnds_t = ctypes.POINTER(ctypes.c_double) + # if xbnds is not None: + # xbnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=xbnds.shape, flags="C_CONTIGUOUS") + # else: + # xbnds_t = ctypes.POINTER(ctypes.c_double) - if ybnds is not None: - ybnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=ybnds.shape) - else: - ybnds_t = ctypes.POINTER(ctypes.c_double) + xbnds, xbnds_t = setarray_Cdouble(xbnds) - if nlon is not None: - nlon_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlon.shape, flags="C_CONTIGUOUS") - else: - nlon_t = ctypes.POINTER(ctypes.c_int) + # if ybnds is not None: + # ybnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=ybnds.shape) + # else: + # ybnds_t = ctypes.POINTER(ctypes.c_double) - if nlat is not None: - nlat_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlat.shape, flags="C_CONTIGUOUS") - else: - nlat_t = ctypes.POINTER(ctypes.c_int) + ybnds, ybnds_t = setarray_Cdouble(ybnds) - if dlon is not None: - dlon_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlon.shape, flags="C_CONTIGUOUS") - else: - dlon_t = ctypes.POINTER(ctypes.c_double) + # if nlon is not None: + # nlon_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlon.shape, flags="C_CONTIGUOUS") + # else: + # nlon_t = ctypes.POINTER(ctypes.c_int) - if dlat is not None: - dlat_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlat.shape, flags="C_CONTIGUOUS") - else: - dlat_t = ctypes.POINTER(ctypes.c_double) + nlon, nlon_t = setarray_Cint32(nlon) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + # if nlat is not None: + # nlat_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlat.shape, flags="C_CONTIGUOUS") + # else: + # nlat_t = ctypes.POINTER(ctypes.c_int) - isc_c, isc_t = ctypes.c_int(isc), ctypes.POINTER(ctypes.c_int) - iec_c, iec_t = ctypes.c_int(iec), ctypes.POINTER(ctypes.c_int) - jsc_c, jsc_t = ctypes.c_int(jsc), ctypes.POINTER(ctypes.c_int) - jec_c, jec_t = ctypes.c_int(jec), ctypes.POINTER(ctypes.c_int) + nlat, nlat_t = setarray_Cint32(nlat) - if x is not None: - x_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=x.shape, flags="C_CONTIGUOUS") - else: - x_t = ctypes.POINTER(ctypes.c_double) + # if dlon is not None: + # dlon_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlon.shape, flags="C_CONTIGUOUS") + # else: + # dlon_t = ctypes.POINTER(ctypes.c_double) - if y is not None: - y_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=y.shape, flags="C_CONTIGUOUS") - else: - y_t = ctypes.POINTER(ctypes.c_double) + dlon, dlon_t = setarray_Cdouble(dlon) - if dx is not None: - dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dx.shape, flags="C_CONTIGUOUS") - else: - dx_t = ctypes.POINTER(ctypes.c_double) + # if dlat is not None: + # dlat_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlat.shape, flags="C_CONTIGUOUS") + # else: + # dlat_t = ctypes.POINTER(ctypes.c_double) - if dy is not None: - dy_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dy.shape, flags="C_CONTIGUOUS") - else: - dy_t = ctypes.POINTER(ctypes.c_double) + dlat, dlat_t = setarray_Cdouble(dlat) - if area is not None: - area_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=area.shape, flags="C_CONTIGUOUS") - else: - area_t = ctypes.POINTER(ctypes.c_double) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - if angle_dx is not None: - angle_dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=angle_dx.shape, flags="C_CONTIGUOUS") - else: - angle_dx_t = ctypes.POINTER(ctypes.c_double) + # isc_c, isc_t = ctypes.c_int(isc), ctypes.POINTER(ctypes.c_int) + # iec_c, iec_t = ctypes.c_int(iec), ctypes.POINTER(ctypes.c_int) + # jsc_c, jsc_t = ctypes.c_int(jsc), ctypes.POINTER(ctypes.c_int) + # jec_c, jec_t = ctypes.c_int(jec), ctypes.POINTER(ctypes.c_int) + + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) - center_c, center_t = ctypes.c_char_p(center.encode("utf-8")), ctypes.c_char_p + # if x is not None: + # x_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=x.shape, flags="C_CONTIGUOUS") + # else: + # x_t = ctypes.POINTER(ctypes.c_double) + x, x_t = setarray_Cdouble(x) + + # if y is not None: + # y_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=y.shape, flags="C_CONTIGUOUS") + # else: + # y_t = ctypes.POINTER(ctypes.c_double) + y, y_t = setarray_Cdouble(y) + + # if dx is not None: + # dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dx.shape, flags="C_CONTIGUOUS") + # else: + # dx_t = ctypes.POINTER(ctypes.c_double) + dx, dx_t = setarray_Cdouble(dx) + + # if dy is not None: + # dy_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dy.shape, flags="C_CONTIGUOUS") + # else: + # dy_t = ctypes.POINTER(ctypes.c_double) + dy, dy_t = setarray_Cdouble(dy) + + # if area is not None: + # area_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=area.shape, flags="C_CONTIGUOUS") + # else: + # area_t = ctypes.POINTER(ctypes.c_double) + + area, area_t = setarray_Cdouble(area) + + # if angle_dx is not None: + # angle_dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=angle_dx.shape, flags="C_CONTIGUOUS") + # else: + # angle_dx_t = ctypes.POINTER(ctypes.c_double) + + angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) + + # center_c, center_t = ctypes.c_char_p(center.encode("utf-8")), ctypes.c_char_p + center_c, center_t = set_Cchar(center) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int _create_regular_lonlat_grid.argtypes = [ @@ -245,7 +272,7 @@ def create_tripolar_grid( nlat_p, nlat_t = setarray_Cint32(nlat) dlon_p, dlon_t = setarray_Cdouble(dlon) dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = setscalar_Cint32(use_legacy) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) isc_c, isc_t = setscalar_Cint32(isc) iec_c, iec_t = setscalar_Cint32(iec) @@ -258,8 +285,8 @@ def create_tripolar_grid( area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) center_c, center_t = set_Cchar(center) - verbose_c, verbose_t = setscalar_Cint32(verbose) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) + verbose_c, verbose_t = ctypes.c_int(verbose), ctypes.c_int + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int _create_tripolar_grid.argtypes = [ nxbnds_t, @@ -339,8 +366,7 @@ def create_grid_from_file( area_p, area_t = setarray_Cdouble(area) angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) - use_angular_midpoint_c = ctypes.c_int(use_angular_midpoint) - use_angular_midpoint_t = ctypes.c_int + use_angular_midpoint_c, use_angular_midpoint_t = ctypes.c_int(use_angular_midpoint), ctypes.c_int _create_grid_from_file.argtypes = [ file_t, @@ -826,8 +852,8 @@ def create_f_plane_grid( nlat_p, nlat_t = setarray_Cint32(nlat) dlon_p, dlon_t = setarray_Cdouble(dlon) dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = setscalar_Cint32(use_legacy) - f_plane_latitude_c, f_plane_latitude_t = setscalar_Cdouble(f_plane_latitude) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + f_plane_latitude_c, f_plane_latitude_t = ctypes.c_double(f_plane_latitude), ctypes.c_double isc_c, isc_t = setscalar_Cint32(isc) iec_c, iec_t = setscalar_Cint32(iec) jsc_c, jsc_t = setscalar_Cint32(jsc) From e8b3b94b10c2d17bc0509d8d7f001be28f4a2868 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 2 Apr 2025 12:26:55 -0400 Subject: [PATCH 28/72] Adding in access to provenance data in make_hgrid --- FMSgridtools/make_hgrid/hgridobj.py | 4 +- FMSgridtools/make_hgrid/make_hgrid.py | 4 +- FMSgridtools/shared/gridtools_utils.py | 2 +- .../make_hgrid/make_hgrid_util.py | 79 +------------------ 4 files changed, 8 insertions(+), 81 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index d62a83a..ed0bc23 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -27,6 +27,7 @@ def write_out_hgrid( ny: int, nxp: int, nyp: int, + global_attrs: dict, north_pole_tile="none", north_pole_arcx="none", projection="none", @@ -34,7 +35,7 @@ def write_out_hgrid( discretization="none", conformal="none", out_halo=0, - output_length_angle=0 + output_length_angle=0, ): tile = None x = None @@ -194,6 +195,7 @@ def write_out_hgrid( "arcx": arcx, } ) + dataset.attrs = global_attrs self.dataset = dataset dataset.to_netcdf(outfile) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 7f9fa1c..5282eb1 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -10,7 +10,7 @@ from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains from FMSgridtools.make_hgrid.hgridobj import HGridObj -from FMSgridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( create_regular_lonlat_grid, create_tripolar_grid, @@ -1268,6 +1268,7 @@ def make_hgrid( pos_n += nx*nyp pos_t += nx*ny + prov_attrs = get_provenance_attrs(great_circle_algorithm=use_great_circle_algorithm) grid_obj.write_out_hgrid( tilename=tilename, outfile=outfile, @@ -1275,6 +1276,7 @@ def make_hgrid( ny=ny, nxp=nxp, nyp=nyp, + global_attrs=prov_attrs, north_pole_tile=north_pole_tile, north_pole_arcx=north_pole_arcx, projection=projection, diff --git a/FMSgridtools/shared/gridtools_utils.py b/FMSgridtools/shared/gridtools_utils.py index 4c56925..89247ea 100755 --- a/FMSgridtools/shared/gridtools_utils.py +++ b/FMSgridtools/shared/gridtools_utils.py @@ -20,7 +20,7 @@ def get_provenance_attrs( # as global attributes for output netcdf files repo = Repo(search_parent_directories=True) git_hash = repo.head.object.hexsha - package_version = get_distribution("gridtools").version + package_version = get_distribution("fmsgridtools").version history = " ".join(sys.argv) hostname = run(["hostname"],capture_output=True,text=True).stdout g_attrs = { diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index cb8fda4..7949e40 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -90,102 +90,25 @@ def create_regular_lonlat_grid( nxbnds_c, nxbnds_t = ctypes.c_int(nxbnds), ctypes.POINTER(ctypes.c_int) nybnds_c, nybnds_t = ctypes.c_int(nybnds), ctypes.POINTER(ctypes.c_int) - - # if xbnds is not None: - # xbnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=xbnds.shape, flags="C_CONTIGUOUS") - # else: - # xbnds_t = ctypes.POINTER(ctypes.c_double) - xbnds, xbnds_t = setarray_Cdouble(xbnds) - - # if ybnds is not None: - # ybnds_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=ybnds.shape) - # else: - # ybnds_t = ctypes.POINTER(ctypes.c_double) - ybnds, ybnds_t = setarray_Cdouble(ybnds) - - # if nlon is not None: - # nlon_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlon.shape, flags="C_CONTIGUOUS") - # else: - # nlon_t = ctypes.POINTER(ctypes.c_int) - nlon, nlon_t = setarray_Cint32(nlon) - - # if nlat is not None: - # nlat_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=nlat.shape, flags="C_CONTIGUOUS") - # else: - # nlat_t = ctypes.POINTER(ctypes.c_int) - nlat, nlat_t = setarray_Cint32(nlat) - - # if dlon is not None: - # dlon_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlon.shape, flags="C_CONTIGUOUS") - # else: - # dlon_t = ctypes.POINTER(ctypes.c_double) - dlon, dlon_t = setarray_Cdouble(dlon) - - # if dlat is not None: - # dlat_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dlat.shape, flags="C_CONTIGUOUS") - # else: - # dlat_t = ctypes.POINTER(ctypes.c_double) - dlat, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - - # isc_c, isc_t = ctypes.c_int(isc), ctypes.POINTER(ctypes.c_int) - # iec_c, iec_t = ctypes.c_int(iec), ctypes.POINTER(ctypes.c_int) - # jsc_c, jsc_t = ctypes.c_int(jsc), ctypes.POINTER(ctypes.c_int) - # jec_c, jec_t = ctypes.c_int(jec), ctypes.POINTER(ctypes.c_int) - isc_c, isc_t = setscalar_Cint32(isc) iec_c, iec_t = setscalar_Cint32(iec) jsc_c, jsc_t = setscalar_Cint32(jsc) jec_c, jec_t = setscalar_Cint32(jec) - - # if x is not None: - # x_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=x.shape, flags="C_CONTIGUOUS") - # else: - # x_t = ctypes.POINTER(ctypes.c_double) x, x_t = setarray_Cdouble(x) - - # if y is not None: - # y_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=y.shape, flags="C_CONTIGUOUS") - # else: - # y_t = ctypes.POINTER(ctypes.c_double) y, y_t = setarray_Cdouble(y) - - # if dx is not None: - # dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dx.shape, flags="C_CONTIGUOUS") - # else: - # dx_t = ctypes.POINTER(ctypes.c_double) dx, dx_t = setarray_Cdouble(dx) - - # if dy is not None: - # dy_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=dy.shape, flags="C_CONTIGUOUS") - # else: - # dy_t = ctypes.POINTER(ctypes.c_double) dy, dy_t = setarray_Cdouble(dy) - - # if area is not None: - # area_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=area.shape, flags="C_CONTIGUOUS") - # else: - # area_t = ctypes.POINTER(ctypes.c_double) - area, area_t = setarray_Cdouble(area) - - # if angle_dx is not None: - # angle_dx_t = np.ctypeslib.ndpointer(dtype=np.float64, shape=angle_dx.shape, flags="C_CONTIGUOUS") - # else: - # angle_dx_t = ctypes.POINTER(ctypes.c_double) - angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) - - # center_c, center_t = ctypes.c_char_p(center.encode("utf-8")), ctypes.c_char_p center_c, center_t = set_Cchar(center) - + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int _create_regular_lonlat_grid.argtypes = [ From c3ee653d22a99da20407031791801bfde7a75d9c Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 2 Apr 2025 12:33:37 -0400 Subject: [PATCH 29/72] Adding TODO for access to make_hgrid through fmsgridtools --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c2ae734..9d9932d 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ def run(self): cmdclass={'install': CustomInstall}, entry_points={ "console_scripts": [ - "fmsgridtools make_hgrid = fmsgridtools.make_grid.hgrid.make_hgrid:main", + "make_hgrid = FMSgridtools.make_hgrid.make_hgrid:make_hgrid", # TODO fmsggridtools entrypoint "make_topog = FMSgridtools.make_topog.make_topog:make_topog", # TODO fmsgridtools entrypoint ] }, From 9cdd612411ca727225bac91e05f24c7d98c16bd2 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 2 Apr 2025 13:39:24 -0400 Subject: [PATCH 30/72] Removing test variable from create_lonlat_grid.c --- FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c index 8fd27d4..ebdec7b 100644 --- a/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c +++ b/FREnctools_lib/cfrenctools/make_hgrid/create_lonlat_grid.c @@ -289,8 +289,6 @@ void set_regular_lonlat_grid( int nxp, int nyp, int isc, int iec, int jsc, int j { long n, i, j; double lon[4], lat[4]; - - double test; n = 0; for(j=0; j Date: Wed, 2 Apr 2025 14:00:34 -0400 Subject: [PATCH 31/72] Updating pyFMS --- FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py | 4 ++-- pyFMS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index 7949e40..dce5235 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -2,7 +2,7 @@ import numpy.typing as npt import ctypes -from pyfms.pyfms_data_handling import ( +from pyfms.data_handling import ( setscalar_Cint32, setscalar_Cdouble, setarray_Cdouble, @@ -836,4 +836,4 @@ def create_f_plane_grid( area_p, angle_dx_p, center_c, - ) \ No newline at end of file + ) diff --git a/pyFMS b/pyFMS index d3f2c1f..6a28647 160000 --- a/pyFMS +++ b/pyFMS @@ -1 +1 @@ -Subproject commit d3f2c1f7ac1e421fea66c30d34582f512a74b065 +Subproject commit 6a28647f5f1d3d86ae70f4bfd997460fd382b9dd From b99c80b394d419311b97c839a69b1862e8aec6ba Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 2 Apr 2025 14:12:24 -0400 Subject: [PATCH 32/72] Changes needed for updates to pyFMS --- FMSgridtools/make_hgrid/make_hgrid.py | 7 ++++--- FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 5282eb1..8435535 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -612,9 +612,10 @@ def make_hgrid( with open(fms_file, "x") as file: file.write("") - pyfms = pyFMS(clibFMS_path="./pyFMS/cFMS/libcFMS/.libs/libcFMS.so") - mpp = pyFMS_mpp(clibFMS=pyfms.clibFMS) - mpp_domains = pyFMS_mpp_domains(clibFMS=pyfms.clibFMS) + #TODO: Will change after pyFMS refactor + pyfms = pyFMS(cFMS_path="./pyFMS/cFMS/libcFMS/.libs/libcFMS.so") + mpp = pyFMS_mpp(cFMS=pyfms.cFMS) + mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) if(mpp.npes() > 1): mpp.pyfms_error(errortype=2, errormsg="make_hgrid: make_hgrid must be run one processor, contact developer") diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index dce5235..0fb69ee 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -2,7 +2,7 @@ import numpy.typing as npt import ctypes -from pyfms.data_handling import ( +from pyfms.pyfms_utils.data_handling import ( setscalar_Cint32, setscalar_Cdouble, setarray_Cdouble, From 262062ae13da58e5b0f9fd387d6522e60dad8100 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 10 Apr 2025 13:12:15 -0400 Subject: [PATCH 33/72] Edits to checking of variables to write to file in hgridobj.py --- FMSgridtools/make_hgrid/hgridobj.py | 67 ++++++++++++++++++----------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index ed0bc23..4f8e08f 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -46,6 +46,7 @@ def write_out_hgrid( angle_dx = None angle_dy = None arcx = None + var_dict={} if north_pole_tile == "none": tile = xr.DataArray( [tilename], @@ -79,6 +80,7 @@ def write_out_hgrid( conformal=conformal, ) ) + var_dict['tile'] = tile if self.x is not None: x = xr.DataArray( @@ -89,6 +91,11 @@ def write_out_hgrid( standard_name="geographic_longitude", ) ) + + if out_halo > 0: + x.attrs["_FillValue"] = -9999. + + var_dict['x'] = x if self.y is not None: y = xr.DataArray( @@ -99,6 +106,11 @@ def write_out_hgrid( standard_name="geographic_latitude", ) ) + + if out_halo > 0: + y.attrs["_FillValue"] = -9999. + + var_dict['y'] = y if output_length_angle: if self.dx is not None: @@ -110,6 +122,12 @@ def write_out_hgrid( standard_name="grid_edge_x_distance", ) ) + + if out_halo > 0: + dx.attrs["_FillValue"] = -9999. + + var_dict['dx'] = dx + if self.dy is not None: dy = xr.DataArray( data=self.dy[:(ny*nxp)].reshape((ny, nxp)), @@ -119,6 +137,12 @@ def write_out_hgrid( standard_name="grid_edge_y_distance", ) ) + + if out_halo > 0: + dy.attrs["_FillValue"] = -9999. + + var_dict['dy'] = dy + if self.angle_dx is not None: angle_dx = xr.DataArray( data=self.angle_dx[:(nyp*nxp)].reshape((nyp, nxp)), @@ -128,13 +152,12 @@ def write_out_hgrid( standard_name="grid_vertex_x_angle_WRT_geographic_east", ) ) - if out_halo > 0: - if dx is not None: - dx.attrs["_FillValue"] = -9999. - if dy is not None: - dy.attrs["_FillValue"] = -9999. - if angle_dx is not None: + + if out_halo > 0: angle_dx.attrs["_FillValue"] = -9999. + + var_dict['angle_dx'] = angle_dx + if conformal != "true": if self.angle_dy is not None: angle_dy = xr.DataArray( @@ -145,10 +168,12 @@ def write_out_hgrid( standard_name="grid_vertex_y_angle_WRT_geographic_north", ) ) - if out_halo > 0: - if angle_dy is not None: + + if out_halo > 0: angle_dy.attrs["_FillValue"] = -9999. + var_dict['angle_dy'] = angle_dy + if self.area is not None: area = xr.DataArray( data=self.area[:(ny*nx)].reshape((ny, nx)), @@ -159,6 +184,11 @@ def write_out_hgrid( ) ) + if out_halo > 0: + area.attrs["_FillValue"] = -9999. + + var_dict['area'] = area + if north_pole_arcx == "none": arcx = xr.DataArray( [self.arcx], @@ -174,26 +204,11 @@ def write_out_hgrid( north_pole=north_pole_arcx, ) ) - if out_halo > 0: - if x is not None: - x.attrs["_FillValue"] = -9999. - if y is not None: - y.attrs["_FillValue"] = -9999. - if area is not None: - area.attrs["_FillValue"] = -9999. + + var_dict['arcx'] = arcx dataset = xr.Dataset( - data_vars={ - "tile": tile, - "x": x, - "y": y, - "dx": dx, - "dy": dy, - "area": area, - "angle_dx": angle_dx, - "angle_dy": angle_dy, - "arcx": arcx, - } + data_vars=var_dict ) dataset.attrs = global_attrs self.dataset = dataset From b633aeed00d3055fda4443727dfad6b44d040d40 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 10 Apr 2025 13:45:22 -0400 Subject: [PATCH 34/72] Removed functionality for tripolar grid in make_hgrid --- FMSgridtools/make_hgrid/make_hgrid.py | 84 +++++---------------------- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 8435535..57acfe2 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -13,7 +13,6 @@ from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( create_regular_lonlat_grid, - create_tripolar_grid, create_grid_from_file, create_simple_cartesian_grid, create_spectral_grid, @@ -73,22 +72,18 @@ 3. 'regular_lonlat_grid': --nxbnds, --nybnds --xbnds, --ybnds, must be specified to define the grid bounds. - 4. 'tripolar_grid': - --nxbnds, --nybnds, --xbnds, --ybnds, must be - specified to define the grid bounds. --lat_join - is optional with default value 65. - 5 'conformal_cubic_grid' - 6 'gnomonic_ed' - 7. 'simple_cartesian_grid': + 4 'conformal_cubic_grid' + 5 'gnomonic_ed' + 6. 'simple_cartesian_grid': --xbnds, --ybnds must be specified to define the grid bounds location and grid size. number of bounds must be 2 in both and x and y-direction. --simple_dx and --simple_dy must be specified to specify uniform cell length. - 8 . 'f_plane_grid': + 7. 'f_plane_grid': For setting geometric fractors according to f-plane. f_plane_latitude need to be specified. - 9. 'beta_plane_grid': + 8. 'beta_plane_grid': For setting geometric fractors according to beta plane. f_plane_latitude need to be specified @@ -114,21 +109,9 @@ --nlon 720 --nlat 104,48,40,40,48,120 --grid_name om3_grid - --center c_cell + --center c_cell - 3. generating tripolar grid with various grid resolution and C-cell - centered using legacy algorithm (create GFDL CM2/ocean-like grid) - fmsgridtools make_hgrid --grid_type tripolar_grid - --nxbnds 2 - --nybnds 7 - --xbnds -280,80 - --ybnds -82,-30,-10,0,10,30,90 - --dlon 1.0,1.0 - --dlat 1.0,1.0,0.6666667,0.3333333,0.6666667,1.0,1.0 - --grid_name om3_grid - --center c_cell - - 4. generating simple cartesian grid(supergrid size 20x20) + 3. generating simple cartesian grid(supergrid size 20x20) fmsgridtools make_hgrid --grid_type simple_cartesian_grid --xbnds 0,30 --ybnds 50,60 @@ -137,16 +120,16 @@ --simple_dx 1000 --simple_dy 1000 - 5. generating conformal cubic grid. (supergrid size 60x60 for each tile) + 4. generating conformal cubic grid. (supergrid size 60x60 for each tile) fmsgridtools make_hgrid --grid_type conformal_cubic_grid --nlon 60 --nratio 2 - 6. generating gnomonic cubic grid with equal_dist_face_edge(C48 grid) + 5. generating gnomonic cubic grid with equal_dist_face_edge(C48 grid) fmsgridtools make_hgrid --grid_type gnomonic_ed --nlon 96 - 7. generating gnomonic cubic stretched grid. + 6. generating gnomonic cubic stretched grid. fmsgridtools make_hgrid --grid_type gnomonic_ed --nlon 180 --do_schmidt @@ -154,7 +137,7 @@ --target_lat 40. --target_lon 20. - 8. generating gnomonic cubic stretched grid with two nests on tile 6. + 7. generating gnomonic cubic stretched grid with two nests on tile 6. fmsgridtools make_hgrid --grid_type gnomonic_ed --nlon 192 --do_schmidt @@ -170,12 +153,12 @@ --jend_nest 42,82 --halo 3 - 9. generating spectral grid. (supergrid size 128x64) + 8. generating spectral grid. (supergrid size 128x64) fmsgridtools make_hgrid --grid_type spectral_grid --nlon 128 --nlat 64 - 10. Through user-defined grids + 9. Through user-defined grids fmsgridtools make_hgrid --grid_type from_file --my_grid_file my_grid_file --nlon 4 @@ -202,7 +185,7 @@ 30 40 - 11. generating f_plane_grids + 10. generating f_plane_grids fmsgridtools make_hgrid --grid_type f_plane_grid --f_plane_latitude 55 --nxbnd 2 @@ -702,8 +685,6 @@ def make_hgrid( if grid_type == "regular_lonlat_grid": my_grid_type = REGULAR_LONLAT_GRID - elif grid_type == "tripolar_grid": - my_grid_type = TRIPOLAR_GRID elif grid_type == "from_file": my_grid_type = FROM_FILE elif grid_type == "simple_cartesian_grid": @@ -741,7 +722,7 @@ def make_hgrid( Command line argument check """ - if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == TRIPOLAR_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: + if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: nxbnds = nxbnds0 nybnds = nybnds0 if nxbnds < 2 or nybnds < 2: @@ -780,10 +761,6 @@ def make_hgrid( # if my_grid_type != GNOMONIC_ED and nest_grids: # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") - if my_grid_type == TRIPOLAR_GRID: - projection = "tripolar" - if nxbnds != 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', nxbnds should be 2") # elif my_grid_type == FROM_FILE: # if ntiles_file == 0: # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") @@ -899,10 +876,7 @@ def make_hgrid( """ Get super grid size """ - if use_legacy: - nxl[0] = get_legacy_grid_size(nxbnds, xbnds, dx_bnds) - nyl[0] = get_legacy_grid_size(nybnds, ybnds, dy_bnds) - elif my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: + if my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: for n in range(ntiles_global): nxl[n] = nlon[0] nyl[n] = nxl[n] @@ -1013,32 +987,6 @@ def make_hgrid( center, use_great_circle_algorithm, ) - elif(my_grid_type==TRIPOLAR_GRID): - create_tripolar_grid( - nxbnds, - nybnds, - xbnds, - ybnds, - nlon, - nlat, - dx_bnds, - dy_bnds, - use_legacy, - lat_join, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - center, - verbose, - use_great_circle_algorithm, - ) # elif(my_grid_type==FROM_FILE): # for n in range(ntiles): # n1 = n * nxp * nyp From a511adcb736e02c600dfc8ff1b8e347a28c33659 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 11 Apr 2025 09:58:35 -0400 Subject: [PATCH 35/72] Removing Optionals from gridobj, make_hgrid, adding type hinting to hgridobj --- FMSgridtools/__init__.py | 3 +-- FMSgridtools/make_hgrid/hgridobj.py | 4 ++-- FMSgridtools/make_hgrid/make_hgrid.py | 3 +-- FMSgridtools/shared/gridobj.py | 6 +++--- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/FMSgridtools/__init__.py b/FMSgridtools/__init__.py index c9ca1b1..a7043fb 100644 --- a/FMSgridtools/__init__.py +++ b/FMSgridtools/__init__.py @@ -1,7 +1,6 @@ from .shared.gridobj import GridObj from .make_hgrid.make_hgrid import make_hgrid from .make_topog.topogobj import TopogObj -from .shared.gridtools_utils import check_file_is_there -from .shared.gridtools_utils import get_provenance_attrs +from .shared.gridtools_utils import check_file_is_there, get_provenance_attrs from .shared.mosaicobj import MosaicObj from .shared.xgridobj import XGridObj \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 4f8e08f..697c3b7 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -21,8 +21,8 @@ def __init__(self): def write_out_hgrid( self, - tilename, - outfile, + tilename: str, + outfile: str, nx: int, ny: int, nxp: int, diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 57acfe2..e22f2cf 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -5,7 +5,6 @@ import numpy as np import numpy.typing as npt import click -from typing import Optional from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains @@ -521,7 +520,7 @@ ) def make_hgrid( grid_type: str, - my_grid_file: Optional[str], + my_grid_file: str, nxbnds: int, nybnds: int, xbnds: str, diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index b911b9e..9d2e50a 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List import numpy as np import numpy.typing as npt @@ -16,8 +16,8 @@ class GridObj: def __init__( self, - dataset: Optional[xr.Dataset] = None, - grid_file: Optional[str] = None + dataset: xr.Dataset = None, + grid_file: str = None ): if grid_file is not None: check_file_is_there(self.grid_file) From ad97d17771b3d55bc6906f2f91f0c425b79108ad Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 11 Apr 2025 10:21:07 -0400 Subject: [PATCH 36/72] Using instance variable of hgridobj tile for write_out --- FMSgridtools/make_hgrid/hgridobj.py | 7 +++---- FMSgridtools/make_hgrid/make_hgrid.py | 3 +-- FMSgridtools/shared/gridobj.py | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 697c3b7..2e60fd9 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -21,7 +21,6 @@ def __init__(self): def write_out_hgrid( self, - tilename: str, outfile: str, nx: int, ny: int, @@ -49,7 +48,7 @@ def write_out_hgrid( var_dict={} if north_pole_tile == "none": tile = xr.DataArray( - [tilename], + [self.tile], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, @@ -59,7 +58,7 @@ def write_out_hgrid( ) elif projection == "none": tile = xr.DataArray( - [tilename], + [self.tile], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, @@ -70,7 +69,7 @@ def write_out_hgrid( ) else: tile = xr.DataArray( - [tilename], + [self.tile], attrs=dict( standard_name="grid_tile_spec", geometry=geometry, diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index e22f2cf..076a051 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1147,7 +1147,7 @@ def make_hgrid( pos_t = 0 pos_n = 0 for n in range(ntiles): - tilename = "tile" + str(n+1) + grid_obj.tile = "tile" + str(n+1) if ntiles > 1: outfile = grid_name + ".tile" + ".nc" + str(n+1) else: @@ -1218,7 +1218,6 @@ def make_hgrid( prov_attrs = get_provenance_attrs(great_circle_algorithm=use_great_circle_algorithm) grid_obj.write_out_hgrid( - tilename=tilename, outfile=outfile, nx=nx, ny=ny, diff --git a/FMSgridtools/shared/gridobj.py b/FMSgridtools/shared/gridobj.py index 9d2e50a..9214263 100644 --- a/FMSgridtools/shared/gridobj.py +++ b/FMSgridtools/shared/gridobj.py @@ -16,7 +16,7 @@ class GridObj: def __init__( self, - dataset: xr.Dataset = None, + dataset: type[xr.Dataset] = None, grid_file: str = None ): if grid_file is not None: From 63bde7e956bfeab1fd050aed4fddd41c55a13e20 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 11 Apr 2025 10:39:28 -0400 Subject: [PATCH 37/72] Refactor of methods in hgridobj --- FMSgridtools/make_hgrid/hgridobj.py | 38 +++++++++++------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 2e60fd9..8ae8f18 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -214,71 +214,61 @@ def write_out_hgrid( dataset.to_netcdf(outfile) def make_gridobj(self) -> "GridObj": + var_dict = {} if self.dataset is None: - tile = None - x = None - y = None - dx = None - dy = None - angle_dx = None - angle_dy = None - area = None - arcx = None - if self.tile is not None: - tile = xr.DataArray( - [self.tile] - ) + tile = xr.DataArray( + [self.tile] + ) + var_dict['tile'] = tile if self.x is not None: x = xr.DataArray( data=self.x, dims=["nyp", "nxp"], ) + var_dict['x'] = x if self.y is not None: y = xr.DataArray( data=self.y, dims=["nyp", "nxp"], ) + var_dict['y'] = y if self.dx is not None: dx = xr.DataArray( data=self.dx, dims=["nyp", "nx"], ) + var_dict['dx'] = dx if self.dy is not None: dy = xr.DataArray( data=self.dy, dims=["ny", "nxp"], ) + var_dict['dy'] = dy if self.angle_dx is not None: angle_dx = xr.DataArray( data=self.angle_dx, dims=["nyp", "nxp"], ) + var_dict['angle_dx'] = angle_dx if self.angle_dy is not None: angle_dy = xr.DataArray( data=self.angle_dy, dims=["nyp", "nxp"], ) + var_dict['angle_dy'] = angle_dy if self.area is not None: area = xr.DataArray( data=self.area, dims=["ny", "nx"], ) + var_dict['area'] = area if self.arcx is not None: arcx = xr.DataArray( [self.arcx], ) + var_dict['arcx'] = arcx dataset = xr.Dataset( - data_vars = { - "tile": tile, - "x": x, - "y": y, - "dx": dx, - "dy": dy, - "angle_dx": angle_dx, - "angle_dy": angle_dy, - "area": area, - "arcx": arcx - } + data_vars = var_dict ) else: dataset=self.dataset From eb3d6aa15c2a0a5e6d005daf39e0c998428194a8 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 11 Apr 2025 11:05:32 -0400 Subject: [PATCH 38/72] Refactor of setting tile dataarray in hgridobj --- FMSgridtools/make_hgrid/hgridobj.py | 45 +++++++++-------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 8ae8f18..f611837 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -46,39 +46,20 @@ def write_out_hgrid( angle_dy = None arcx = None var_dict={} - if north_pole_tile == "none": - tile = xr.DataArray( - [self.tile], - attrs=dict( - standard_name="grid_tile_spec", - geometry=geometry, - discretization=discretization, - conformal=conformal, - ) - ) - elif projection == "none": - tile = xr.DataArray( - [self.tile], - attrs=dict( - standard_name="grid_tile_spec", - geometry=geometry, - north_pole=north_pole_tile, - discretization=discretization, - conformal=conformal, - ) - ) - else: - tile = xr.DataArray( - [self.tile], - attrs=dict( - standard_name="grid_tile_spec", - geometry=geometry, - north_pole=north_pole_tile, - projection=projection, - discretization=discretization, - conformal=conformal, - ) + + tile = xr.DataArray( + [self.tile], + attrs=dict( + standard_name="grid_tile_spec", + geometry=geometry, + discretization=discretization, + conformal=conformal, ) + ) + if north_pole_tile is "none": + tile = tile.assign_attrs(projection=projection) + if projection is "none": + tile = tile.assign_attrs(north_pole_tile=north_pole_tile) var_dict['tile'] = tile if self.x is not None: From f22a34c8b7c9bef4c9ed5ba267830d294edeb991 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 11:34:14 -0400 Subject: [PATCH 39/72] Adding in loading methods of pyfrenctools --- FMSgridtools/make_hgrid/make_hgrid.py | 53 +- FREnctools_lib/cfrenctools/c_build/.gitkeep | 0 FREnctools_lib/pyfrenctools/__init__.py | 1 + FREnctools_lib/pyfrenctools/cfrenctools.py | 2 + .../make_hgrid/make_hgrid_util.py | 1360 +++++++++-------- 5 files changed, 729 insertions(+), 687 deletions(-) delete mode 100644 FREnctools_lib/cfrenctools/c_build/.gitkeep diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 076a051..c2a28a4 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -10,17 +10,18 @@ from FMSgridtools.make_hgrid.hgridobj import HGridObj from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs -from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( - create_regular_lonlat_grid, - create_grid_from_file, - create_simple_cartesian_grid, - create_spectral_grid, - create_conformal_cubic_grid, - create_gnomonic_cubic_grid_GR, - create_gnomonic_cubic_grid, - create_f_plane_grid, - fill_cubic_grid_halo, -) +# from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( +# create_regular_lonlat_grid, +# create_grid_from_file, +# create_simple_cartesian_grid, +# create_spectral_grid, +# create_conformal_cubic_grid, +# create_gnomonic_cubic_grid_GR, +# create_gnomonic_cubic_grid, +# create_f_plane_grid, +# fill_cubic_grid_halo, +# ) +import pyfrenctools # from FREnctools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size """ @@ -963,7 +964,7 @@ def make_hgrid( jec = ny - 1 if(my_grid_type==REGULAR_LONLAT_GRID): - create_regular_lonlat_grid( + pyfrenctools.make_hgrid_util.create_regular_lonlat_grid( nxbnds, nybnds, xbnds, @@ -992,7 +993,7 @@ def make_hgrid( # n2 = n * nx * nyp # n3 = n * nxp * ny # n4 = n * nx * ny - # create_grid_from_file( + # pyfrenctools.make_hgrid_util.create_grid_from_file( # my_grid_file[n], # nx, # ny, @@ -1006,7 +1007,7 @@ def make_hgrid( # use_angular_midpoint, # ) # elif(my_grid_type==SIMPLE_CARTESIAN_GRID): - # create_simple_cartesian_grid( + # pyfrenctools.make_hgrid_util.create_simple_cartesian_grid( # xbnds, # ybnds, # nx, @@ -1025,7 +1026,7 @@ def make_hgrid( # grid_obj.angle_dx, # ) # elif(my_grid_type==SPECTRAL_GRID): - # create_spectral_grid( + # pyfrenctools.make_hgrid_util.create_spectral_grid( # nx, # ny, # isc, @@ -1041,7 +1042,7 @@ def make_hgrid( # use_great_circle_algorithm, # ) # elif(my_grid_type==CONFORMAL_CUBIC_GRID): - # create_conformal_cubic_grid( + # pyfrenctools.make_hgrid_util.create_conformal_cubic_grid( # nx, # nratio, # method, @@ -1056,7 +1057,7 @@ def make_hgrid( # ) # elif(my_grid_type==GNOMONIC_ED): # if(nest_grids == 1 and parent_tile[0] == 0): - # create_gnomonic_cubic_grid_GR( + # pyfrenctools.make_hgrid_util.create_gnomonic_cubic_grid_GR( # grid_type, # nxl, # nyl, @@ -1084,7 +1085,7 @@ def make_hgrid( # output_length_angle, # ) # else: - # create_gnomonic_cubic_grid( + # pyfrenctools.make_hgrid_util.create_gnomonic_cubic_grid( # grid_type, # nxl, # nyl, @@ -1112,7 +1113,7 @@ def make_hgrid( # output_length_angle, # ) # elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): - # create_f_plane_grid( + # pyfrenctools.make_hgrid_util.create_f_plane_grid( # nxbnds, # nybnds, # xbnds, @@ -1182,21 +1183,21 @@ def make_hgrid( tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) if verbose: print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) grid_obj.x = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) grid_obj.y = tmp.copy() if output_length_angle: - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) grid_obj.angle_dx = tmp.copy() if conformal != "true": - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) grid_obj.angle_dy = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) grid_obj.dx = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) grid_obj.dy = tmp.copy() - fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) + pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) grid_obj.area = tmp.copy() if verbose: diff --git a/FREnctools_lib/cfrenctools/c_build/.gitkeep b/FREnctools_lib/cfrenctools/c_build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/FREnctools_lib/pyfrenctools/__init__.py b/FREnctools_lib/pyfrenctools/__init__.py index 8973272..9ec16e8 100644 --- a/FREnctools_lib/pyfrenctools/__init__.py +++ b/FREnctools_lib/pyfrenctools/__init__.py @@ -1,5 +1,6 @@ from .cfrenctools import cfrenctools from .shared.create_xgrid import create_xgrid +from .make_hgrid import make_hgrid_util cfrenctools.init() diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index ebe854a..7e5b5c6 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -1,6 +1,7 @@ import ctypes import os from .shared.create_xgrid import create_xgrid +from .make_hgrid.make_hgrid_util import make_hgrid_util class cfrenctools(): @@ -10,6 +11,7 @@ class cfrenctools(): @classmethod def init(cls): create_xgrid.init(cls.libpath, cls.lib) + make_hgrid_util.init(cls.libpath, cls.lib) @classmethod def changelib(cls, libpath): diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py index 0fb69ee..6a826e8 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py @@ -10,60 +10,81 @@ set_Cchar, ) -lib = ctypes.CDLL("./FREnctools_lib/cfrenctools/c_build/clib.so") - -def fill_cubic_grid_halo( - nx: int, - ny: int, - halo: int, - data: npt.NDArray[np.float64], - data1_all: npt.NDArray[np.float64], - data2_all: npt.NDArray[np.float64], - tile: int, - ioff: int, - joff: int, -): - nxp = nx + ioff - nyp = ny + joff - nxph = nx + ioff + 2*halo - nyph = ny + joff + 2*halo - - for i in range(nxph*nyph): - data[i] = -9999. - - # first copy computing domain data - for j in range (nyp+1): - for i in range(nxp+1): - data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] - - ntiles = 6 - - if tile%2 == 1: - lw = (tile+ntiles-1)%ntiles - le = (tile+ntiles+2)%ntiles - ls = (tile+ntiles-2)%ntiles - ln = (tile+ntiles+1)%ntiles - for j in range(nyp+1): - data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo - data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo - - for i in range(nxp+1): - data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo - data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo - else: - lw = (tile+ntiles-2)%ntiles - le = (tile+ntiles+1)%ntiles - ls = (tile+ntiles-1)%ntiles - ln = (tile+ntiles+2)%ntiles - for j in range(nyp+1): - data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo - data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo - - for i in range(nxp+1): - data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo - data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo - -def create_regular_lonlat_grid( +# lib = ctypes.CDLL("./FREnctools_lib/cfrenctools/c_build/clib.so") + +class make_hgrid_util(): + __libpath: str = None + __lib: ctypes.CDLL = None + + @classmethod + def init(cls, libpath, lib): + cls.__libpath = libpath + cls.__lib = lib + + @classmethod + @property + def lib(cls): + return cls.__lib + + @classmethod + @property + def libpath(cls): + return cls.__libpath + + @classmethod + def fill_cubic_grid_halo( + cls, + nx: int, + ny: int, + halo: int, + data: npt.NDArray[np.float64], + data1_all: npt.NDArray[np.float64], + data2_all: npt.NDArray[np.float64], + tile: int, + ioff: int, + joff: int, + ): + nxp = nx + ioff + nyp = ny + joff + nxph = nx + ioff + 2*halo + nyph = ny + joff + 2*halo + + for i in range(nxph*nyph): + data[i] = -9999. + + # first copy computing domain data + for j in range (nyp+1): + for i in range(nxp+1): + data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] + + ntiles = 6 + + if tile%2 == 1: + lw = (tile+ntiles-1)%ntiles + le = (tile+ntiles+2)%ntiles + ls = (tile+ntiles-2)%ntiles + ln = (tile+ntiles+1)%ntiles + for j in range(nyp+1): + data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo + data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo + for i in range(nxp+1): + data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo + data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo + else: + lw = (tile+ntiles-2)%ntiles + le = (tile+ntiles+1)%ntiles + ls = (tile+ntiles-1)%ntiles + ln = (tile+ntiles+2)%ntiles + for j in range(nyp+1): + data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo + data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo + for i in range(nxp+1): + data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo + data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo + + @classmethod + def create_regular_lonlat_grid( + cls, nxbnds: int, nybnds: int, xbnds: npt.NDArray, @@ -85,82 +106,85 @@ def create_regular_lonlat_grid( angle_dx: npt.NDArray, center: str, use_great_circle_algorithm: int -): - _create_regular_lonlat_grid = lib.create_regular_lonlat_grid - - nxbnds_c, nxbnds_t = ctypes.c_int(nxbnds), ctypes.POINTER(ctypes.c_int) - nybnds_c, nybnds_t = ctypes.c_int(nybnds), ctypes.POINTER(ctypes.c_int) - xbnds, xbnds_t = setarray_Cdouble(xbnds) - ybnds, ybnds_t = setarray_Cdouble(ybnds) - nlon, nlon_t = setarray_Cint32(nlon) - nlat, nlat_t = setarray_Cint32(nlat) - dlon, dlon_t = setarray_Cdouble(dlon) - dlat, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x, x_t = setarray_Cdouble(x) - y, y_t = setarray_Cdouble(y) - dx, dx_t = setarray_Cdouble(dx) - dy, dy_t = setarray_Cdouble(dy) - area, area_t = setarray_Cdouble(area) - angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - - use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int - - _create_regular_lonlat_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - use_great_circle_algorithm_t, - ] - _create_regular_lonlat_grid.restype = None - - _create_regular_lonlat_grid( - nxbnds_c, - nybnds_c, - xbnds, - ybnds, - nlon, - nlat, - dlon, - dlat, - use_legacy_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x, - y, - dx, - dy, - area, - angle_dx, - center_c, - use_great_circle_algorithm_c, - ) - -def create_tripolar_grid( + ): + _create_regular_lonlat_grid = cls.lib.create_regular_lonlat_grid + + # nxbnds_c, nxbnds_t = ctypes.c_int(nxbnds), ctypes.POINTER(ctypes.c_int) + # nybnds_c, nybnds_t = ctypes.c_int(nybnds), ctypes.POINTER(ctypes.c_int) + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds, xbnds_t = setarray_Cdouble(xbnds) + ybnds, ybnds_t = setarray_Cdouble(ybnds) + nlon, nlon_t = setarray_Cint32(nlon) + nlat, nlat_t = setarray_Cint32(nlat) + dlon, dlon_t = setarray_Cdouble(dlon) + dlat, dlat_t = setarray_Cdouble(dlat) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x, x_t = setarray_Cdouble(x) + y, y_t = setarray_Cdouble(y) + dx, dx_t = setarray_Cdouble(dx) + dy, dy_t = setarray_Cdouble(dy) + area, area_t = setarray_Cdouble(area) + angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int + + _create_regular_lonlat_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + use_great_circle_algorithm_t, + ] + _create_regular_lonlat_grid.restype = None + + _create_regular_lonlat_grid( + nxbnds_c, + nybnds_c, + xbnds, + ybnds, + nlon, + nlat, + dlon, + dlat, + use_legacy_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x, + y, + dx, + dy, + area, + angle_dx, + center_c, + use_great_circle_algorithm_c, + ) + + @classmethod + def create_tripolar_grid( + cls, nxbnds: int, nybnds: int, xbnds: npt.NDArray[np.float64], @@ -184,87 +208,89 @@ def create_tripolar_grid( center: str, verbose: int, use_great_circle_algorithm: int -): - _create_tripolar_grid = lib.create_tripolar_grid - - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - dlon_p, dlon_t = setarray_Cdouble(dlon) - dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - verbose_c, verbose_t = ctypes.c_int(verbose), ctypes.c_int - use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int - - _create_tripolar_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - lat_join_in_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - verbose_t, - use_great_circle_algorithm_t, - ] - _create_tripolar_grid.restype = None - - _create_tripolar_grid( - nxbnds_c, - nybnds_c, - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - dlon_p, - dlat_p, - use_legacy_c, - lat_join_in_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - center_c, - verbose_c, - use_great_circle_algorithm_c, - ) - -def create_grid_from_file( + ): + _create_tripolar_grid = cls.lib.create_tripolar_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + dlon_p, dlon_t = setarray_Cdouble(dlon) + dlat_p, dlat_t = setarray_Cdouble(dlat) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + verbose_c, verbose_t = ctypes.c_int(verbose), ctypes.c_int + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int + + _create_tripolar_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + lat_join_in_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + verbose_t, + use_great_circle_algorithm_t, + ] + _create_tripolar_grid.restype = None + + _create_tripolar_grid( + nxbnds_c, + nybnds_c, + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + dlon_p, + dlat_p, + use_legacy_c, + lat_join_in_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + center_c, + verbose_c, + use_great_circle_algorithm_c, + ) + + @classmethod + def create_grid_from_file( + cls, file: str, nlon: npt.NDArray[np.int32], nlat: npt.NDArray[np.int32], @@ -276,51 +302,53 @@ def create_grid_from_file( angle_dx: npt.NDArray[np.float64], use_great_circle_algorithm: int, use_angular_midpoint: int -): - _create_grid_from_file = lib.create_grid_from_file - - file_c, file_t = set_Cchar(file) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) - use_angular_midpoint_c, use_angular_midpoint_t = ctypes.c_int(use_angular_midpoint), ctypes.c_int - - _create_grid_from_file.argtypes = [ - file_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - use_great_circle_algorithm_t, - use_angular_midpoint_t, - ] - _create_grid_from_file.restype = None - - _create_grid_from_file( - file_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - use_great_circle_algorithm_c, - use_angular_midpoint_c - ) - -def create_simple_cartesian_grid( + ): + _create_grid_from_file = cls.lib.create_grid_from_file + + file_c, file_t = set_Cchar(file) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) + use_angular_midpoint_c, use_angular_midpoint_t = ctypes.c_int(use_angular_midpoint), ctypes.c_int + + _create_grid_from_file.argtypes = [ + file_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + use_great_circle_algorithm_t, + use_angular_midpoint_t, + ] + _create_grid_from_file.restype = None + + _create_grid_from_file( + file_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + use_great_circle_algorithm_c, + use_angular_midpoint_c + ) + + @classmethod + def create_simple_cartesian_grid( + cls, xbnds: npt.NDArray[np.float64], ybnds: npt.NDArray[np.float64], nlon: npt.NDArray[np.int32], @@ -337,67 +365,69 @@ def create_simple_cartesian_grid( dy: npt.NDArray[np.float64], area: npt.NDArray[np.float64], angle_dx: npt.NDArray[np.float64], -): - _create_simple_cartesian_grid = lib.create_simple_cartesian_grid - - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - simple_dx_c, simple_dx_t = setscalar_Cdouble(simple_dx) - simple_dy_c, simple_dy_t = setarray_Cdouble(simple_dy) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - - _create_simple_cartesian_grid.argtypes = [ - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - simple_dx_t, - simple_dy_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - ] - _create_simple_cartesian_grid.restype = None - - _create_simple_cartesian_grid( - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - simple_dx_c, - simple_dy_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - ) - - -def create_spectral_grid( + ): + _create_simple_cartesian_grid = cls.lib.create_simple_cartesian_grid + + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + simple_dx_c, simple_dx_t = setscalar_Cdouble(simple_dx) + simple_dy_c, simple_dy_t = setarray_Cdouble(simple_dy) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + + _create_simple_cartesian_grid.argtypes = [ + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + simple_dx_t, + simple_dy_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + ] + _create_simple_cartesian_grid.restype = None + + _create_simple_cartesian_grid( + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + simple_dx_c, + simple_dy_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + ) + + + @classmethod + def create_spectral_grid( + cls, nlon: npt.NDArray[np.int32], nlat: npt.NDArray[np.int32], isc: int, @@ -411,58 +441,60 @@ def create_spectral_grid( area: npt.NDArray[np.float64], angle_dx: npt.NDArray[np.float64], use_great_circle_algorithm: int, -): - _create_spectral_grid = lib.create_spectral_grid - - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) - - _create_spectral_grid.argtypes = [ - nlon_t, - nlat_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - use_great_circle_algorithm_t, - ] - _create_spectral_grid.restype = None - - _create_spectral_grid( - nlon_p, - nlat_p, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dx_p, - use_great_circle_algorithm_c, - ) - -def create_conformal_cubic_grid( + ): + _create_spectral_grid = cls.lib.create_spectral_grid + + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) + + _create_spectral_grid.argtypes = [ + nlon_t, + nlat_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + use_great_circle_algorithm_t, + ] + _create_spectral_grid.restype = None + + _create_spectral_grid( + nlon_p, + nlat_p, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dx_p, + use_great_circle_algorithm_c, + ) + + @classmethod + def create_conformal_cubic_grid( + cls, npts: int, nratio: int, method: str, @@ -474,51 +506,53 @@ def create_conformal_cubic_grid( area: npt.NDArray[np.float64], angle_dx: npt.NDArray[np.float64], angle_dy: npt.NDArray[np.float64], -): - _create_conformal_cubic_grid = lib.create_conformal_cubic_grid - - npts_c, npts_t = setscalar_Cint32(npts) - nratio_c, nratio_t = setscalar_Cint32(nratio) - method_c, method_t = set_Cchar(method) - orientation_c, orientation_t = set_Cchar(orientation) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - - _create_conformal_cubic_grid.argtypes = [ - npts_t, - nratio_t, - method_t, - orientation_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - ] - _create_conformal_cubic_grid.restype = None - - _create_conformal_cubic_grid( - npts_c, - nratio_c, - method_c, - orientation_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - ) - -def create_gnomonic_cubic_grid_GR( + ): + _create_conformal_cubic_grid = cls.lib.create_conformal_cubic_grid + + npts_c, npts_t = setscalar_Cint32(npts) + nratio_c, nratio_t = setscalar_Cint32(nratio) + method_c, method_t = set_Cchar(method) + orientation_c, orientation_t = set_Cchar(orientation) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) + + _create_conformal_cubic_grid.argtypes = [ + npts_t, + nratio_t, + method_t, + orientation_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + ] + _create_conformal_cubic_grid.restype = None + + _create_conformal_cubic_grid( + npts_c, + nratio_c, + method_c, + orientation_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + ) + + @classmethod + def create_gnomonic_cubic_grid_GR( + cls, grid_type: str, nlon: npt.NDArray[np.int32], nlat: npt.NDArray[np.int32], @@ -544,93 +578,95 @@ def create_gnomonic_cubic_grid_GR( jend_nest: int, halo: int, output_length_angle: int, -): - _create_gnomonic_cubic_grid_GR = lib.create_gnomonic_cubic_gridGR - - grid_type_c, grid_type_t = set_Cchar(grid_type) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) - do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) - do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) - stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) - target_lon_c, target_lon_t = setscalar_Cint32(target_lon) - target_lat_c, target_lat_t = setscalar_Cint32(target_lat) - nest_grid_c, nest_grid_t = setscalar_Cint32(nest_grid) - parent_tile_c, parent_tile_t = setscalar_Cint32(parent_tile) - refine_ratio_c, refine_ratio_t = setscalar_Cint32(refine_ratio) - istart_nest_c, istart_nest_t = setscalar_Cint32(istart_nest) - iend_nest_c, iend_nest_t = setscalar_Cint32(iend_nest) - jstart_nest_c, jstart_nest_t = setscalar_Cint32(jstart_nest) - jend_nest_c, jend_nest_t = setscalar_Cint32(jend_nest) - halo_c, halo_t = setscalar_Cint32(halo) - output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) - - _create_gnomonic_cubic_grid_GR.argtypes = [ - grid_type_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - shift_fac_t, - do_schmidt_t, - do_cube_transform_t, - stretch_factor_t, - target_lon_t, - target_lat_t, - nest_grid_t, - parent_tile_t, - refine_ratio_t, - istart_nest_t, - iend_nest_t, - jstart_nest_t, - jend_nest_t, - halo_t, - output_length_angle_t, - ] - _create_gnomonic_cubic_grid_GR.restype = None - - _create_gnomonic_cubic_grid_GR( - grid_type_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - shift_fac_c, - do_schmidt_c, - do_cube_transform_c, - stretch_factor_c, - target_lon_c, - target_lat_c, - nest_grid_c, - parent_tile_c, - refine_ratio_c, - istart_nest_c, - iend_nest_c, - jstart_nest_c, - jend_nest_c, - halo_c, - output_length_angle_c, - ) - -def create_gnomonic_cubic_grid( + ): + _create_gnomonic_cubic_grid_GR = cls.lib.create_gnomonic_cubic_gridGR + + grid_type_c, grid_type_t = set_Cchar(grid_type) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) + shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) + do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) + do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) + stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) + target_lon_c, target_lon_t = setscalar_Cint32(target_lon) + target_lat_c, target_lat_t = setscalar_Cint32(target_lat) + nest_grid_c, nest_grid_t = setscalar_Cint32(nest_grid) + parent_tile_c, parent_tile_t = setscalar_Cint32(parent_tile) + refine_ratio_c, refine_ratio_t = setscalar_Cint32(refine_ratio) + istart_nest_c, istart_nest_t = setscalar_Cint32(istart_nest) + iend_nest_c, iend_nest_t = setscalar_Cint32(iend_nest) + jstart_nest_c, jstart_nest_t = setscalar_Cint32(jstart_nest) + jend_nest_c, jend_nest_t = setscalar_Cint32(jend_nest) + halo_c, halo_t = setscalar_Cint32(halo) + output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) + + _create_gnomonic_cubic_grid_GR.argtypes = [ + grid_type_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + shift_fac_t, + do_schmidt_t, + do_cube_transform_t, + stretch_factor_t, + target_lon_t, + target_lat_t, + nest_grid_t, + parent_tile_t, + refine_ratio_t, + istart_nest_t, + iend_nest_t, + jstart_nest_t, + jend_nest_t, + halo_t, + output_length_angle_t, + ] + _create_gnomonic_cubic_grid_GR.restype = None + + _create_gnomonic_cubic_grid_GR( + grid_type_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + shift_fac_c, + do_schmidt_c, + do_cube_transform_c, + stretch_factor_c, + target_lon_c, + target_lat_c, + nest_grid_c, + parent_tile_c, + refine_ratio_c, + istart_nest_c, + iend_nest_c, + jstart_nest_c, + jend_nest_c, + halo_c, + output_length_angle_c, + ) + + @classmethod + def create_gnomonic_cubic_grid( + cls, grid_type: str, nlon: npt.NDArray[np.int32], nlat: npt.NDArray[np.int32], @@ -656,93 +692,95 @@ def create_gnomonic_cubic_grid( jend_nest: npt.NDArray[np.int32], halo: int, output_length_angle: int, -): - _create_gnomonic_cubic_grid = lib.create_gnomonic_cubic_grid - - grid_type_c, grid_type_t = set_Cchar(grid_type) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) - do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) - do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) - stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) - target_lon_c, target_lon_t = setscalar_Cdouble(target_lon) - target_lat_c, target_lat_t = setscalar_Cdouble(target_lat) - num_nest_grids_c, num_nest_grids_t = setscalar_Cint32(num_nest_grids) - parent_tile_p, parent_tile_t = setarray_Cint32(parent_tile) - refine_ratio_p, refine_ratio_t = setarray_Cint32(refine_ratio) - istart_nest_p, istart_nest_t = setarray_Cint32(istart_nest) - iend_nest_p, iend_nest_t = setarray_Cint32(iend_nest) - jstart_nest_p, jstart_nest_t = setarray_Cint32(jstart_nest) - jend_nest_p, jend_nest_t = setarray_Cint32(jend_nest) - halo_c, halo_t = setscalar_Cint32(halo) - output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) - - _create_gnomonic_cubic_grid.argtypes = [ - grid_type_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - shift_fac_t, - do_schmidt_t, - do_cube_transform_t, - stretch_factor_t, - target_lon_t, - target_lat_t, - num_nest_grids_t, - parent_tile_t, - refine_ratio_t, - istart_nest_t, - iend_nest_t, - jstart_nest_t, - jend_nest_t, - halo_t, - output_length_angle_t, - ] - _create_gnomonic_cubic_grid.restype = None - - _create_gnomonic_cubic_grid( - grid_type_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - shift_fac_c, - do_schmidt_c, - do_cube_transform_c, - stretch_factor_c, - target_lon_c, - target_lat_c, - num_nest_grids_c, - parent_tile_p, - refine_ratio_p, - istart_nest_p, - iend_nest_p, - jstart_nest_p, - jend_nest_p, - halo_c, - output_length_angle_c, - ) - -def create_f_plane_grid( + ): + _create_gnomonic_cubic_grid = cls.lib.create_gnomonic_cubic_grid + + grid_type_c, grid_type_t = set_Cchar(grid_type) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) + shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) + do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) + do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) + stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) + target_lon_c, target_lon_t = setscalar_Cdouble(target_lon) + target_lat_c, target_lat_t = setscalar_Cdouble(target_lat) + num_nest_grids_c, num_nest_grids_t = setscalar_Cint32(num_nest_grids) + parent_tile_p, parent_tile_t = setarray_Cint32(parent_tile) + refine_ratio_p, refine_ratio_t = setarray_Cint32(refine_ratio) + istart_nest_p, istart_nest_t = setarray_Cint32(istart_nest) + iend_nest_p, iend_nest_t = setarray_Cint32(iend_nest) + jstart_nest_p, jstart_nest_t = setarray_Cint32(jstart_nest) + jend_nest_p, jend_nest_t = setarray_Cint32(jend_nest) + halo_c, halo_t = setscalar_Cint32(halo) + output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) + + _create_gnomonic_cubic_grid.argtypes = [ + grid_type_t, + nlon_t, + nlat_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + angle_dy_t, + shift_fac_t, + do_schmidt_t, + do_cube_transform_t, + stretch_factor_t, + target_lon_t, + target_lat_t, + num_nest_grids_t, + parent_tile_t, + refine_ratio_t, + istart_nest_t, + iend_nest_t, + jstart_nest_t, + jend_nest_t, + halo_t, + output_length_angle_t, + ] + _create_gnomonic_cubic_grid.restype = None + + _create_gnomonic_cubic_grid( + grid_type_c, + nlon_p, + nlat_p, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + angle_dy_p, + shift_fac_c, + do_schmidt_c, + do_cube_transform_c, + stretch_factor_c, + target_lon_c, + target_lat_c, + num_nest_grids_c, + parent_tile_p, + refine_ratio_p, + istart_nest_p, + iend_nest_p, + jstart_nest_p, + jend_nest_p, + halo_c, + output_length_angle_c, + ) + + @classmethod + def create_f_plane_grid( + cls, nxbnds: int, nybnds: int, xbnds: npt.NDArray[np.float64], @@ -764,76 +802,76 @@ def create_f_plane_grid( area: npt.NDArray[np.float64], angle_dx: npt.NDArray[np.float64], center: str -): - _create_f_plane_grid = lib.create_f_plane_grid - - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - dlon_p, dlon_t = setarray_Cdouble(dlon) - dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - f_plane_latitude_c, f_plane_latitude_t = ctypes.c_double(f_plane_latitude), ctypes.c_double - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - - _create_f_plane_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - f_plane_latitude_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - ] - _create_f_plane_grid.restype = None - - _create_f_plane_grid( - nxbnds_c, - nybnds_c, - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - dlon_p, - dlat_p, - use_legacy_c, - f_plane_latitude_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - center_c, - ) + ): + _create_f_plane_grid = cls.lib.create_f_plane_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds_p, xbnds_t = setarray_Cdouble(xbnds) + ybnds_p, ybnds_t = setarray_Cdouble(ybnds) + nlon_p, nlon_t = setarray_Cint32(nlon) + nlat_p, nlat_t = setarray_Cint32(nlat) + dlon_p, dlon_t = setarray_Cdouble(dlon) + dlat_p, dlat_t = setarray_Cdouble(dlat) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + f_plane_latitude_c, f_plane_latitude_t = ctypes.c_double(f_plane_latitude), ctypes.c_double + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x_p, x_t = setarray_Cdouble(x) + y_p, y_t = setarray_Cdouble(y) + dx_p, dx_t = setarray_Cdouble(dx) + dy_p, dy_t = setarray_Cdouble(dy) + area_p, area_t = setarray_Cdouble(area) + angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + + _create_f_plane_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + f_plane_latitude_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + ] + _create_f_plane_grid.restype = None + + _create_f_plane_grid( + nxbnds_c, + nybnds_c, + xbnds_p, + ybnds_p, + nlon_p, + nlat_p, + dlon_p, + dlat_p, + use_legacy_c, + f_plane_latitude_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x_p, + y_p, + dx_p, + dy_p, + area_p, + angle_dx_p, + center_c, + ) From b44404c9cf13db8c3db220a329666fe6bba0107f Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 11:44:57 -0400 Subject: [PATCH 40/72] Hook for pyfrenctools --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9d9932d..5128c45 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def run(self): extras_require=extras_requires, name="fmsgridtools", license="", - packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.*" ]), + packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.pyfrenctools.*" ]), include_package_data=True, version="0.0.1", zip_safe=False, From 4d4c015c96537ec535d039aa103df297898165b4 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 11:46:58 -0400 Subject: [PATCH 41/72] Removed weird space --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5128c45..6f71963 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def run(self): extras_require=extras_requires, name="fmsgridtools", license="", - packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.pyfrenctools.*" ]), + packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.pyfrenctools.*"]), include_package_data=True, version="0.0.1", zip_safe=False, From aad2c7b522aea51d2663dd3a0c72ae101a6c6f71 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 11:55:49 -0400 Subject: [PATCH 42/72] Adding back in .gitkeep --- FREnctools_lib/cfrenctools/c_build/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 FREnctools_lib/cfrenctools/c_build/.gitkeep diff --git a/FREnctools_lib/cfrenctools/c_build/.gitkeep b/FREnctools_lib/cfrenctools/c_build/.gitkeep new file mode 100644 index 0000000..e69de29 From 5c2596f1f849e2339d7bb251e8e0bcddd90112c8 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 13:10:56 -0400 Subject: [PATCH 43/72] Switching over to hold/hgrid --- FMSgridtools/make_hgrid/make_hgrid.py | 13 +------------ FREnctools_lib/pyfrenctools/cfrenctools.py | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index c2a28a4..85d0970 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -10,19 +10,8 @@ from FMSgridtools.make_hgrid.hgridobj import HGridObj from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs -# from FREnctools_lib.pyfrenctools.make_hgrid.make_hgrid_util import ( -# create_regular_lonlat_grid, -# create_grid_from_file, -# create_simple_cartesian_grid, -# create_spectral_grid, -# create_conformal_cubic_grid, -# create_gnomonic_cubic_grid_GR, -# create_gnomonic_cubic_grid, -# create_f_plane_grid, -# fill_cubic_grid_halo, -# ) import pyfrenctools -# from FREnctools_lib.pyfrenctools.shared.tool_util import get_legacy_grid_size + """ Usage of make_hgrid diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index 7e5b5c6..98faaa0 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -5,7 +5,7 @@ class cfrenctools(): - __libpath: str = os.path.dirname(__file__) + "/../cfrenctools/c_build/clib.so" + __libpath: str = os.path.dirname(__file__) + "../cfrenctools/c_build/clib.so" __lib: ctypes.CDLL = ctypes.CDLL(__libpath) @classmethod From 115d3be5a776b771a8edd921001f5bcb0ca5b297 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 13:12:43 -0400 Subject: [PATCH 44/72] Removing comments --- FMSgridtools/make_hgrid/make_hgrid.py | 263 +------------------------- 1 file changed, 2 insertions(+), 261 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 85d0970..e6cb9b5 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -742,118 +742,8 @@ def make_hgrid( mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") if nybnds != nybnds2+1: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") - - # if my_grid_type == CONFORMAL_CUBIC_GRID or my_grid_type == GNOMONIC_ED: - # ntiles = 6 - # ntiles_global = 6 - - # if my_grid_type != GNOMONIC_ED and nest_grids: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --nest_grids can be set only when grid_type = 'gnomonic_ed'") - - # elif my_grid_type == FROM_FILE: - # if ntiles_file == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'from_file', but my_grid_file is not specified") - # ntiles = ntiles_file - # ntiles_global = ntiles_file - # for n in range(ntiles): - # if ".nc" in my_grid_file[n]: - # file_path = my_grid_file[n] + ".nc" - # check_file_is_there(file_path) - # with xr.open_dataset(file_path) as ds: - # if "grid_xt" in ds.sizes: - # if "grid_yt" not in ds.sizes: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_yt should be a dimension when grid_xt is a dimension") - # nlon[n] = ds.sizes["grid_xt"]*2 - # nlat[n] = ds.sizes["grid_yt"]*2 - # elif "rlon" in ds.sizes: - # if "rlat" not in ds.sizes: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: rlat should be a dimension when rlon is a dimension") - # nlon[n] = ds.sizes["rlon"]*2 - # nlat[n] = ds.sizes["rlat"]*2 - # elif "lon" in ds.sizes: - # if "lat" not in ds.sizes: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: lat should be a dimension when lon is a dimension") - # nlon[n] = ds.sizes["lon"]*2 - # nlat[n] = ds.sizes["lat"]*2 - # elif "i" in ds.sizes: - # if "j" not in ds.sizes: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: j should be a dimension when i is a dimension") - # nlon[n] = ds.sizes["i"]*2 - # nlat[n] = ds.sizes["j"]*2 - # elif "x" in ds.sizes: - # if "y" not in ds.sizes: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: y should be a dimension when x is a dimension") - # nlon[n] = ds.sizes["x"]*2 - # nlat[n] = ds.sizes["y"]*2 - # else: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: none of grid_xt, rlon, lon, x, and i is a dimension in input file") - # else: - # if nxbnds2 != ntiles or nybnds2 != ntiles: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'from_file', number entry entered through --nlon and --nlat should be equal to number of files specified through --my_grid_file") - # """ - # For simplification purposes, it is assumed at this point that all tiles will have the same grid size - # """ - # for n in range(1, ntiles): - # if nlon[n] != nlon[0] or nlat[n] != nlat[0]: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is from_file, all the tiles should have same grid size, contact developer") - # elif my_grid_type == SIMPLE_CARTESIAN_GRID: - # geometry = "planar" - # north_pole_tile = "none" - # if nxbnds1 != 2 or nybnds1 != 2: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --xbnds and --ybnds should be 2") - # if nxbnds2 != 1 or nybnds2 != 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'simple_cartesian_grid', number entry entered through --nlon and --nlat should be 1") - # if simple_dx == 0 or simple_dy == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid_type is 'simple_cartesian_grid', both simple_dx and simple_dy both should be specified") - # elif my_grid_type == SPECTRAL_GRID: - # if nxbnds2 != 1 or nybnds2 != 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'spectral_grid', number entry entered through --nlon and --nlat should be 1") - # elif my_grid_type == CONFORMAL_CUBIC_GRID: - # projection = "cube_gnomonic" - # conformal = "FALSE" - # if nxbnds2 != 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', number entry entered through --nlon should be 1") - # if nratio < 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'conformal_cubic_grid', nratio should be a positive integer") - # elif my_grid_type == GNOMONIC_ED: - # projection = "cube_gnomonic" - # conformal = "FALSE" - # if do_schmidt or do_cube_transform: - # if present_stretch_factor == 0 or present_target_lon == 0 or present_target_lat == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon and --target_lat must be set when --do_schmidt or --do_cube_transform is set") - # for n in range(nest_grids): - # if refine_ratio[n] == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --refine_ratio must be set when --nest_grids is set") - # if parent_tile[n] == 0 and mpp.pe() == 0: - # print("NOTE from make_hgrid: parent_tile is 0, the output grid will have resolution refine_ration*nlon", file=sys.stderr) - # else: - # if istart_nest[n] == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --istart_nest must be set when --nest_grids is set") - # if iend_nest[n] == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --iend_nest must be set when --nest_grids is set") - # if jstart_nest[n] == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jstart_nest must be set when --nest_grids is set") - # if jend_nest[n] == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --jend_nest must be set when --nest_grids is set") - # if halo == 0: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --halo must be set when --nest_grids is set") - # ntiles += 1 - # if verbose: - # print(f"Configuration for nest {ntiles} validated.", file=sys.stderr) - # if verbose: - # print(f"Updated number of tiles, including nests (ntiles): {ntiles}", file=sys.stderr) - # if nxbnds2 != 1: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'gnomonic_cubic_grid', number entry entered through --nlon should be 1") - # elif my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: - # if f_plane_latitude > 90 or f_plane_latitude < -90: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: f_plane_latitude should be between -90 and 90.") - # if f_plane_latitude > ybnds[nybnds-1] or f_plane_latitude < ybnds[0]: - # if mpp.pe() == 0: - # print("Warning from make_hgrid: f_plane_latitude is not inside the latitude range of the grid", file=sys.stderr) - # if mpp.pe() == 0: - # print(f"make_hgrid: setting geometric factor according to f-plane with f_plane_latitude = {f_plane_latitude}", file=sys.stderr) - # else: - # mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") + else: + mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") if verbose: print(f"[INFO] make_hgrid: Number of tiles (ntiles): {ntiles}", file=sys.stderr) @@ -976,155 +866,6 @@ def make_hgrid( center, use_great_circle_algorithm, ) - # elif(my_grid_type==FROM_FILE): - # for n in range(ntiles): - # n1 = n * nxp * nyp - # n2 = n * nx * nyp - # n3 = n * nxp * ny - # n4 = n * nx * ny - # pyfrenctools.make_hgrid_util.create_grid_from_file( - # my_grid_file[n], - # nx, - # ny, - # grid_obj.x[n1:], - # grid_obj.y[n1:], - # grid_obj.dx[n2:], - # grid_obj.dy[n3:], - # grid_obj.area[n4:], - # grid_obj.angle_dx[n1:], - # use_great_circle_algorithm, - # use_angular_midpoint, - # ) - # elif(my_grid_type==SIMPLE_CARTESIAN_GRID): - # pyfrenctools.make_hgrid_util.create_simple_cartesian_grid( - # xbnds, - # ybnds, - # nx, - # ny, - # simple_dx, - # simple_dy, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # ) - # elif(my_grid_type==SPECTRAL_GRID): - # pyfrenctools.make_hgrid_util.create_spectral_grid( - # nx, - # ny, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # use_great_circle_algorithm, - # ) - # elif(my_grid_type==CONFORMAL_CUBIC_GRID): - # pyfrenctools.make_hgrid_util.create_conformal_cubic_grid( - # nx, - # nratio, - # method, - # orientation, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # grid_obj.angle_dy, - # ) - # elif(my_grid_type==GNOMONIC_ED): - # if(nest_grids == 1 and parent_tile[0] == 0): - # pyfrenctools.make_hgrid_util.create_gnomonic_cubic_grid_GR( - # grid_type, - # nxl, - # nyl, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # grid_obj.angle_dy, - # shift_fac, - # do_schmidt, - # do_cube_transform, - # stretch_factor, - # target_lon, - # target_lat, - # nest_grids, - # parent_tile[0], - # refine_ratio[0], - # istart_nest[0], - # iend_nest[0], - # jstart_nest[0], - # jend_nest[0], - # halo, - # output_length_angle, - # ) - # else: - # pyfrenctools.make_hgrid_util.create_gnomonic_cubic_grid( - # grid_type, - # nxl, - # nyl, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # grid_obj.angle_dy, - # shift_fac, - # do_schmidt, - # do_cube_transform, - # stretch_factor, - # target_lon, - # target_lat, - # nest_grids, - # parent_tile, - # refine_ratio, - # istart_nest, - # iend_nest, - # jstart_nest, - # jend_nest, - # halo, - # output_length_angle, - # ) - # elif(my_grid_type==F_PLANE_GRID or my_grid_type==BETA_PLANE_GRID): - # pyfrenctools.make_hgrid_util.create_f_plane_grid( - # nxbnds, - # nybnds, - # xbnds, - # ybnds, - # nlon, - # nlat, - # dx_bnds, - # dy_bnds, - # use_legacy, - # f_plane_latitude, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # center, - # ) else: mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") From ac5eeec7a626fbd34aa160c9d8d3fa6e2ccc6286 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 16:02:50 -0400 Subject: [PATCH 45/72] Under construction rework of make_hgrid to match format for other modules --- FMSgridtools/make_hgrid/make_hgrid.py | 726 +++++++----------- FMSgridtools/make_hgrid/make_hgrid_util.py | 194 +++++ FMSgridtools/make_hgrid/make_lonlat_grid.py | 121 +++ FREnctools_lib/pyfrenctools/__init__.py | 2 +- FREnctools_lib/pyfrenctools/cfrenctools.py | 2 +- ...e_hgrid_util.py => make_hgrid_wrappers.py} | 0 6 files changed, 605 insertions(+), 440 deletions(-) create mode 100644 FMSgridtools/make_hgrid/make_hgrid_util.py create mode 100644 FMSgridtools/make_hgrid/make_lonlat_grid.py rename FREnctools_lib/pyfrenctools/make_hgrid/{make_hgrid_util.py => make_hgrid_wrappers.py} (100%) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index e6cb9b5..73b20bc 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -13,219 +13,6 @@ import pyfrenctools -""" -Usage of make_hgrid - -fmsgridtools make_hgrid --grid_type (see types supported below) (string) - --my_grid_file file_name (string) - --nxbnds # - --nybnds # - --xbnds x(1),...,x(nxbnds) - --ybnds y(1),...,y(nybnds) - --nlon nlon(1),...nlon(nxbnds-1) - --nlat nlat(1),...nlat(nybnds-1) - --dlon dlon(1),...dlon(nxbnds) - --dlat dlat(1),...dlat(nybnds) - --lat_join # - --num_lon # - --nratio # - --simple_dx # - --simple_dy # - --grid_name (string) - --center (string) - --verbose (bool) - --shift_fac # - --do_schmidt (bool) - --stretch_fac # - --target_lon # - --target_lat # - --do_cube_transform (bool) - --nest_grids # - --parent_tile parent_tile(1),...parent_tile(nests-1) - --refine_ratio refine_ratio(1),...refine_ratio(nests-1) - --halo # - --istart_nest istart_nest(1),...istart_nest(nests-1) - --iend_nest iend_nest(1),...iend_nest(nests-1) - --jstart_nest jstart_nest(1),...jstart_nest(nests-1) - --jend_nest jend_nest(1),...jend_nest(nests-1) - --use_great_circle_algorithm (bool) - --out_halo # - --no_output_length_angle (bool) - -The available options for grid_type are: - 1. 'from_file': - --my_grid_file must be specified. The grid - specified in my_grid_file should be super grid - vertex. - 2. 'spectral_grid' - 3. 'regular_lonlat_grid': - --nxbnds, --nybnds --xbnds, --ybnds, must be - specified to define the grid bounds. - 4 'conformal_cubic_grid' - 5 'gnomonic_ed' - 6. 'simple_cartesian_grid': - --xbnds, --ybnds must be specified to define - the grid bounds location and grid size. number - of bounds must be 2 in both and x and y-direction. - --simple_dx and --simple_dy must be specified to - specify uniform cell length. - 7. 'f_plane_grid': - For setting geometric fractors according - to f-plane. f_plane_latitude need to be specified. - 8. 'beta_plane_grid': - For setting geometric fractors according - to beta plane. f_plane_latitude need to be - specified - -Example use: - - 1. generating regular lon-lat grid (supergrid size 60x20) - fmsgridtools make_hgrid --grid_type regular_lonlat_grid - --nxbnds 2 - --nybnds 2 - --xbnds 0,30 - --ybnds 50,60 - --nlon 60 - --nlat 20 - - 2. generating tripolar grid with various grid resolution and C-cell - centered using monotonic bi-cub spline interpolation. - fmsgridtools make_hgrid --grid_type tripolar_grid - --nxbnds 2 - --nybnds 7 - --xbnds -280,80 - --ybnds -82,-30,-10,0,10,30,90 - --nlon 720 - --nlat 104,48,40,40,48,120 - --grid_name om3_grid - --center c_cell - - 3. generating simple cartesian grid(supergrid size 20x20) - fmsgridtools make_hgrid --grid_type simple_cartesian_grid - --xbnds 0,30 - --ybnds 50,60 - --nlon 20 - --nlat 20 - --simple_dx 1000 - --simple_dy 1000 - - 4. generating conformal cubic grid. (supergrid size 60x60 for each tile) - fmsgridtools make_hgrid --grid_type conformal_cubic_grid - --nlon 60 - --nratio 2 - - 5. generating gnomonic cubic grid with equal_dist_face_edge(C48 grid) - fmsgridtools make_hgrid --grid_type gnomonic_ed - --nlon 96 - - 6. generating gnomonic cubic stretched grid. - fmsgridtools make_hgrid --grid_type gnomonic_ed - --nlon 180 - --do_schmidt - --stretch_factor 3 - --target_lat 40. - --target_lon 20. - - 7. generating gnomonic cubic stretched grid with two nests on tile 6. - fmsgridtools make_hgrid --grid_type gnomonic_ed - --nlon 192 - --do_schmidt - --stretch_factor 3 - --target_lat 10. - --target_lon 20. - --nest_grids 2 - --parent_tile 6,6 - --refine_ratio 2,2 - --istart_nest 11,51 - --jstart_nest 11,51 - --iend_nest 42,82 - --jend_nest 42,82 - --halo 3 - - 8. generating spectral grid. (supergrid size 128x64) - fmsgridtools make_hgrid --grid_type spectral_grid - --nlon 128 - --nlat 64 - - 9. Through user-defined grids - fmsgridtools make_hgrid --grid_type from_file - --my_grid_file my_grid_file - --nlon 4 - --nlat 4 - - Contents of a sample my_grid_file: - The first line of my_grid_file will be text ( will be ignored) - followed by nlon+1 lines of real value of x-direction supergrid bound - location. Then another line of text ( will be ignored), followed by - nlat+1 lines of real value of y-direction supergrid bound location. - - For example: - - x-grid - 0.0 - 5.0 - 10.0 - 15.0 - 20.0 - y-grid - -10 - 10 - 20 - 30 - 40 - - 10. generating f_plane_grids - fmsgridtools make_hgrid --grid_type f_plane_grid - --f_plane_latitude 55 - --nxbnd 2 - --nybnd 2 - --xbnd 0,30 - --ybnd 50,60 - --nlon 60 - --nlat 20 - -A note on generating cyclic regular lon-lat grids when center = 'c_cell':- -It is possible to have an improperly centered boundary unless care is taken to -ensure local symmetry at the join. -A correctly formed grid is only guaranteed if the first three values of the ---xbnd argument mirror the last 3 and the first two 'nlon' arguments mirror the -last 2. - -For example for a global grid make_hgrid should be invoked as - fmsgridtools make_hgrid --grid_type regular_lonlat_grid ... - --xbnd 0,X1,X2,...,360-X2,360-X1,360 - --nlon N1,N2,...,N2,N1 - --center c_cell - -As an example - - fmsgridtools make_hgrid --grid_type regular_lonlat_grid - --nxbnd 7 - --nybnd 2 - --xbnd 0,15,30,300,330,345,360 - --ybnd 50,60 - --nlon 4,2,6,4,2,4 - --nlat 2 - --center c_cell - - -results in a valid cyclic grid whereas (note the second last value of nlon) - - fmsgridtools make_hgrid --grid_type regular_lonlat_grid - --nxbnd 7 - --nybnd 2 - --xbnd 0,15,30,300,330,345,360 - --ybnd 50,60 - --nlon 4,2,6,4,4,4 - --nlat 2 - --center c_cell - - -is not properly centered across 0,360 - -An informational message is issued if the leftmost and rightmost resolutions -differ by more than 1 part in 10E6 -""" MAXBOUNDS = 100 MAX_NESTS = 128 @@ -240,34 +27,24 @@ BETA_PLANE_GRID = 9 MISSING_VALUE = -9999. +@click.group() +def make_hgrid(): + pass -@click.command() +@make_hgrid.command() @click.option( - "--grid_type", + "--nlon", type=str, - default="regular_lonlat_grid", - help="specify type of topography. See above for grid type option.", + default=None, + help="Number of model grid points(supergrid) for each zonal regions of\ + varying resolution.", ) @click.option( - "--my_grid_file", + "--nlat", type=str, default=None, - help="when this flag is present, the program will read grid information\ - from 'my_grid_file'. The file format can be ascii file or netcdf\ - file. Multiple file entry are allowed but the number should be\ - less than MAXBOUNDS.", -) -@click.option( - "--nxbnds", - type=int, - default=2, - help="Specify number of zonal regions for varying resolution.", -) -@click.option( - "--nybnds", - type=int, - default=2, - help="Specify number of meridinal regions for varying resolution.", + help="Number of model grid points(supergid) for each meridinal regions of\ + varying resolution.", ) @click.option( "--xbnds", @@ -285,20 +62,6 @@ help="Specify boundaries for defining meridional regions of varying\ resolution", ) -@click.option( - "--nlon", - type=str, - default=None, - help="Number of model grid points(supergrid) for each zonal regions of\ - varying resolution.", -) -@click.option( - "--nlat", - type=str, - default=None, - help="Number of model grid points(supergid) for each meridinal regions of\ - varying resolution.", -) @click.option( "--dlon", type=str, @@ -311,161 +74,6 @@ default=None, help="nominal resolution of meridional regions", ) -@click.option( - "--lat_join", - type=float, - default=65., - help="Specify latitude for joining spherical and rotated bipolar grid.\ - Default value is 65 degree.", -) -@click.option( - "--nratio", - type=int, - default=1, - help="Speicify the refinement ratio when calculating cell length and area\ - of supergrid.", -) -@click.option( - "--simple_dx", - type=float, - default=0., - help="Specify the uniform cell length in x-direction for simple cartesian\ - grid.", -) -@click.option( - "--simple_dy", - type=float, - default=0., - help="Specify the uniform cell length in y-direction for simple cartesian\ - grid.", -) -@click.option( - "--grid_name", - type=str, - default="horizontal_grid", - help=("Specify the grid name. The output grid file name will be" - "grid_name.nc if there is one tile and grid_name.tile#.nc if there is" - "more than one tile. The default value will be horizontal_grid."), -) -@click.option( - "--center", - type=str, - default="none", - help="""Specify the center location of grid. Valid entries will be 'none'" - ", 't_cell' or 'c_cell' with default value 'none'. The grid " - "refinement is assumed to be 2 in x and y-direction when center is " - "not 'none'. 'c_cell' should be used for the grid used in MOM.""", -) -@click.option( - "--shift_fac", - type=float, - default=18.0, - help="shift west by 180/shift_fac. Default value is 18.", -) -@click.option( - "--f_plane_latitude", - type=float, - default=100., - help="" -) -@click.option( - "--do_schmidt", - is_flag=True, - default=False, - help=("Set to do Schmidt transformation to create stretched grid. When " - "do_schmidt is set, the following must be set: --stretch_factor, " - " --target_lon and --target_lat."), -) -@click.option( - "--do_cube_transform", - is_flag=True, - default=False, - help=("re-orient the rotated cubed sphere so that tile 6 has 'north' " - "facing upward, which would make analysis and explaining nest " - "placement much easier. When do_cube_transform is set, the " - "following must be set: --stretch_factor, --latget_lon, and " - " --target_lat."), -) -@click.option( - "--stretch_factor", - type=float, - default=0.0, - help="Stretching factor for the grid", -) -@click.option( - "--target_lon", - type=float, - default=0.0, - help="center longitude of the highest resolution tile", -) -@click.option( - "--target_lat", - type=float, - default=0.0, - help="center latitude of the highest resolution tile", -) -@click.option( - "--nest_grids", - type=int, - default=0, - help="""set to create this # nested grids as well as the global grid. This - replaces the option --nest_grid. This option could only be set when - grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid , - files created, there are # more nest grids with - file name = grid_name.tile.nest.nc""", -) -@click.option( - "--parent_tile", - type=str, - default=None, - help="Specify the comma-separated list of the parent tile number(s) of \ - nest grid(s).", -) -@click.option( - "--refine_ratio", - type=str, - default=None, - help="Specify the comma-separated list of refinement ratio(s) for nest\ - grid(s).", -) -@click.option( - "--istart_nest", - type=str, - default=None, - help="Specify the comma-separated list of starting i-direction index(es)\ - of nest grid(s) in parent tile supergrid(Fortran index).", -) -@click.option( - "--iend_nest", - type=str, - default=None, - help="Specify the comma-separated list of ending i-direction index(es) of \ - nest grids in parent tile supergrid( Fortran index).", -) -@click.option( - "--jstart_nest", - type=str, - default=None, - help="Specify the comma-separated list of starting j-direction index(es) of \ - nest grids in parent tile supergrid(Fortran index).", -) -@click.option( - "--jend_nest", - type=str, - default=None, - help="Specify the comma-separated list of ending j-direction index(es) of \ - nest grids in parent tile supergrid (Fortran index).", -) -@click.option( - "--halo", - type=int, - default=0, - help=("halo size is used in the atmosphere cubic sphere model. Its purpose " - "is to make sure the nest, including the halo region, is fully " - "contained within a single parent (coarse) tile. The option may " - "be obsolete and removed in future development. It only needs to " - "be specified when --nest_grid(s) is set."), -) @click.option( "--use_great_circle_algorithm", is_flag=True, @@ -473,41 +81,283 @@ help="When specified, great_circle_algorithm will be used to compute grid \ cell area.", ) -@click.option( - "--out_halo", - type=int, - default=0, - help="extra halo size data to be written out. This is only works for \ - gnomonic_ed.", -) -@click.option( - "--no_output_length_angle", - is_flag=True, - default=False, - help="When specified, will not output length(dx,dy) and angle \ - (angle_dx, angle_dy)" -) -@click.option( - "--angular_midpoint", - is_flag=True, - default=False, - help="" -) -@click.option( - "--rotate_poly", - is_flag=True, - default=False, - help=("Set to calculate polar polygon areas by calculating the area of a " - "copy of the polygon, with the copy being rotated far away from the" - "pole.") -) -@click.option( - "--verbose", - is_flag=True, - default=False, - help=("Will print out running time message when this option is set. " - "Otherwise the run will be silent when there is no error.") -) +def lonlat( + nlon, + nlat, + xbnds, + ybnds, + dlon, + dlat, + use_great_circle_algorithm +): + + +# @click.option( +# "--grid_type", +# type=str, +# default="regular_lonlat_grid", +# help="specify type of topography. See above for grid type option.", +# ) +# @click.option( +# "--my_grid_file", +# type=str, +# default=None, +# help="when this flag is present, the program will read grid information\ +# from 'my_grid_file'. The file format can be ascii file or netcdf\ +# file. Multiple file entry are allowed but the number should be\ +# less than MAXBOUNDS.", +# ) +# @click.option( +# "--nxbnds", +# type=int, +# default=2, +# help="Specify number of zonal regions for varying resolution.", +# ) +# @click.option( +# "--nybnds", +# type=int, +# default=2, +# help="Specify number of meridinal regions for varying resolution.", +# ) +# @click.option( +# "--xbnds", +# type=str, +# default=None, +# help="Specify boundaries for defining zonal regions of varying resolution.\ +# When --tripolar is present, x also defines the longitude of the two\ +# new poles. nxbnds must be 2 and lon_start = x(1), lon_end = x(nxbnds)\ +# are longitude of the two new poles.", +# ) +# @click.option( +# "--ybnds", +# type=str, +# default=None, +# help="Specify boundaries for defining meridional regions of varying\ +# resolution", +# ) +# @click.option( +# "--nlon", +# type=str, +# default=None, +# help="Number of model grid points(supergrid) for each zonal regions of\ +# varying resolution.", +# ) +# @click.option( +# "--nlat", +# type=str, +# default=None, +# help="Number of model grid points(supergid) for each meridinal regions of\ +# varying resolution.", +# ) +# @click.option( +# "--dlon", +# type=str, +# default=None, +# help="nominal resolution of zonal regions", +# ) +# @click.option( +# "--dlat", +# type=str, +# default=None, +# help="nominal resolution of meridional regions", +# ) +# @click.option( +# "--lat_join", +# type=float, +# default=65., +# help="Specify latitude for joining spherical and rotated bipolar grid.\ +# Default value is 65 degree.", +# ) +# @click.option( +# "--nratio", +# type=int, +# default=1, +# help="Speicify the refinement ratio when calculating cell length and area\ +# of supergrid.", +# ) +# @click.option( +# "--simple_dx", +# type=float, +# default=0., +# help="Specify the uniform cell length in x-direction for simple cartesian\ +# grid.", +# ) +# @click.option( +# "--simple_dy", +# type=float, +# default=0., +# help="Specify the uniform cell length in y-direction for simple cartesian\ +# grid.", +# ) +# @click.option( +# "--grid_name", +# type=str, +# default="horizontal_grid", +# help=("Specify the grid name. The output grid file name will be" +# "grid_name.nc if there is one tile and grid_name.tile#.nc if there is" +# "more than one tile. The default value will be horizontal_grid."), +# ) +# @click.option( +# "--center", +# type=str, +# default="none", +# help="""Specify the center location of grid. Valid entries will be 'none'" +# ", 't_cell' or 'c_cell' with default value 'none'. The grid " +# "refinement is assumed to be 2 in x and y-direction when center is " +# "not 'none'. 'c_cell' should be used for the grid used in MOM.""", +# ) +# @click.option( +# "--shift_fac", +# type=float, +# default=18.0, +# help="shift west by 180/shift_fac. Default value is 18.", +# ) +# @click.option( +# "--f_plane_latitude", +# type=float, +# default=100., +# help="" +# ) +# @click.option( +# "--do_schmidt", +# is_flag=True, +# default=False, +# help=("Set to do Schmidt transformation to create stretched grid. When " +# "do_schmidt is set, the following must be set: --stretch_factor, " +# " --target_lon and --target_lat."), +# ) +# @click.option( +# "--do_cube_transform", +# is_flag=True, +# default=False, +# help=("re-orient the rotated cubed sphere so that tile 6 has 'north' " +# "facing upward, which would make analysis and explaining nest " +# "placement much easier. When do_cube_transform is set, the " +# "following must be set: --stretch_factor, --latget_lon, and " +# " --target_lat."), +# ) +# @click.option( +# "--stretch_factor", +# type=float, +# default=0.0, +# help="Stretching factor for the grid", +# ) +# @click.option( +# "--target_lon", +# type=float, +# default=0.0, +# help="center longitude of the highest resolution tile", +# ) +# @click.option( +# "--target_lat", +# type=float, +# default=0.0, +# help="center latitude of the highest resolution tile", +# ) +# @click.option( +# "--nest_grids", +# type=int, +# default=0, +# help="""set to create this # nested grids as well as the global grid. This +# replaces the option --nest_grid. This option could only be set when +# grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid , +# files created, there are # more nest grids with +# file name = grid_name.tile.nest.nc""", +# ) +# @click.option( +# "--parent_tile", +# type=str, +# default=None, +# help="Specify the comma-separated list of the parent tile number(s) of \ +# nest grid(s).", +# ) +# @click.option( +# "--refine_ratio", +# type=str, +# default=None, +# help="Specify the comma-separated list of refinement ratio(s) for nest\ +# grid(s).", +# ) +# @click.option( +# "--istart_nest", +# type=str, +# default=None, +# help="Specify the comma-separated list of starting i-direction index(es)\ +# of nest grid(s) in parent tile supergrid(Fortran index).", +# ) +# @click.option( +# "--iend_nest", +# type=str, +# default=None, +# help="Specify the comma-separated list of ending i-direction index(es) of \ +# nest grids in parent tile supergrid( Fortran index).", +# ) +# @click.option( +# "--jstart_nest", +# type=str, +# default=None, +# help="Specify the comma-separated list of starting j-direction index(es) of \ +# nest grids in parent tile supergrid(Fortran index).", +# ) +# @click.option( +# "--jend_nest", +# type=str, +# default=None, +# help="Specify the comma-separated list of ending j-direction index(es) of \ +# nest grids in parent tile supergrid (Fortran index).", +# ) +# @click.option( +# "--halo", +# type=int, +# default=0, +# help=("halo size is used in the atmosphere cubic sphere model. Its purpose " +# "is to make sure the nest, including the halo region, is fully " +# "contained within a single parent (coarse) tile. The option may " +# "be obsolete and removed in future development. It only needs to " +# "be specified when --nest_grid(s) is set."), +# ) +# @click.option( +# "--use_great_circle_algorithm", +# is_flag=True, +# default=False, +# help="When specified, great_circle_algorithm will be used to compute grid \ +# cell area.", +# ) +# @click.option( +# "--out_halo", +# type=int, +# default=0, +# help="extra halo size data to be written out. This is only works for \ +# gnomonic_ed.", +# ) +# @click.option( +# "--no_output_length_angle", +# is_flag=True, +# default=False, +# help="When specified, will not output length(dx,dy) and angle \ +# (angle_dx, angle_dy)" +# ) +# @click.option( +# "--angular_midpoint", +# is_flag=True, +# default=False, +# help="" +# ) +# @click.option( +# "--rotate_poly", +# is_flag=True, +# default=False, +# help=("Set to calculate polar polygon areas by calculating the area of a " +# "copy of the polygon, with the copy being rotated far away from the" +# "pole.") +# ) +# @click.option( +# "--verbose", +# is_flag=True, +# default=False, +# help=("Will print out running time message when this option is set. " +# "Otherwise the run will be silent when there is no error.") +# ) def make_hgrid( grid_type: str, my_grid_file: str, diff --git a/FMSgridtools/make_hgrid/make_hgrid_util.py b/FMSgridtools/make_hgrid/make_hgrid_util.py new file mode 100644 index 0000000..8ca8cd2 --- /dev/null +++ b/FMSgridtools/make_hgrid/make_hgrid_util.py @@ -0,0 +1,194 @@ +import numpy as np +from numpy.typing import NDArray +import ctypes + +from FMSgridtools.make_hgrid.hgridobj import HGridObj +from FMSgridtools.shared.gridtools_utils import get_provenance_attrs +import pyfrenctools + +def make_grid_info( + grid_obj: HGridObj, + nxbnds: int, + nybnds: int, + ntiles: int = 1, + ntiles_global: int = 1, + nlon: NDArray = None, + nlat: NDArray = None, + nest_grids: int = 0, + parent_tile: NDArray = None, + refine_ratio: NDArray = None, + istart_nest: NDArray = None, + iend_nest: NDArray = None, + jstart_nest: NDArray = None, + jend_nest: NDArray = None, + arcx: str = "small_circle", + grid_type: str = None, +) -> dict: + + nxl = np.empty(shape=ntiles, dtype=np.int32) + nyl = np.empty(shape=ntiles, dtype=np.int32) + + if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": + for n in range(ntiles_global): + nxl[n] = nlon[0] + nyl[n] = nxl[n] + if nest_grids and parent_tile[0] == 0: + nxl[n] *= refine_ratio[0] + nyl[n] *= refine_ratio[0] + + for n in range(ntiles_global, ntiles): + nn = n - ntiles_global + nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] + nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + elif grid_type == "FROM_FILE": + for n in range(ntiles_global): + nxl[n] = nlon[n] + nyl[n] = nlat[n] + else: + nxl[0] = 0 + nyl[0] = 0 + for n in range(nxbnds - 1): + nxl[0] += nlon[n] + for n in range(nybnds - 1): + nyl[0] += nlat[n] + + nx = nxl[0] + ny = nyl[0] + nxp = nx + 1 + nyp = ny + 1 + grid_info_dict = {} + grid_info_dict['nx'] = nx + grid_info_dict['ny'] = ny + grid_info_dict['nxp'] = nxp + grid_info_dict['nyp'] = nyp + grid_info_dict['nxl'] = nxl + grid_info_dict['nyl'] = nyl + + size1 = ctypes.c_ulong(0) + size2 = ctypes.c_ulong(0) + size3 = ctypes.c_ulong(0) + size4 = ctypes.c_ulong(0) + + if grid_type == "FROM_FILE": + for n in range(ntiles_global): + size1.value += (nlon[n] + 1) * (nlat[n] + 1) + size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) + size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + size4.value += (nlon[n] + 1) * (nlat[n] + 1) + else: + size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) + size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) + size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) + size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) + + if not (nest_grids == 1 and parent_tile[0] == 0): + for n_nest in range(ntiles_global, ntiles_global+nest_grids): + size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) + size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) + size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + + grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) + grid_obj.arcx = arcx + grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) + grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) + grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) + grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + + isc = 0 + iec = nx - 1 + jsc = 0 + jec = ny - 1 + + grid_info_dict['isc'] = 0 + grid_info_dict['iec'] = nx - 1 + grid_info_dict['jsc'] = 0 + grid_info_dict['jec'] = ny - 1 + + + return grid_info_dict + +def grid_writer( + grid_obj: HGridObj, + info_dict: dict, + grid_name: str = "horizontal_grid", + ntiles: int = 1, + out_halo: int = 0, +): + north_pole_tile = "0.0 90.0" + north_pole_arcx = "0.0 90.0" + geometry = "spherical" + projection = "none" + conformal = "true" + discretization = "logically_rectangular" + output_length_angle = 1 + pos_c = 0 + pos_e = 0 + pos_t = 0 + pos_n = 0 + for n in range(ntiles): + grid_obj.tile = "tile" + str(n+1) + if ntiles > 1: + outfile = grid_name + ".tile" + ".nc" + str(n+1) + else: + outfile = grid_name + ".nc" + + nx = info_dict['nxl'][n] + ny = info_dict['nyl'][n] + nxp = nx + 1 + nyp = ny + 1 + + if out_halo == 0: + grid_obj.x = grid_obj.x[pos_c:] + grid_obj.y = grid_obj.y[pos_c:] + grid_obj.dx = grid_obj.dx[pos_n:] + grid_obj.dy = grid_obj.dy[pos_e:] + grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] + grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] + grid_obj.area = grid_obj.area[pos_t:] + else: + tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) + grid_obj.x = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) + grid_obj.y = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) + grid_obj.angle_dx = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) + grid_obj.angle_dy = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) + grid_obj.dx = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) + grid_obj.dy = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) + grid_obj.area = tmp.copy() + + nx = info_dict['nxl'][n] + ny = info_dict['nyl'][n] + nxp = nx + 1 + nyp = ny + 1 + pos_c += nxp*nyp + pos_e += nxp*ny + pos_n += nx*nyp + pos_t += nx*ny + + prov_attrs = get_provenance_attrs(great_circle_algorithm=True) + grid_obj.write_out_hgrid( + outfile=outfile, + nx=nx, + ny=ny, + nxp=nxp, + nyp=nyp, + global_attrs=prov_attrs, + north_pole_tile=north_pole_tile, + north_pole_arcx=north_pole_arcx, + projection=projection, + geometry=geometry, + discretization=discretization, + conformal=conformal, + out_halo=out_halo, + output_length_angle=output_length_angle, + ) + diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/make_lonlat_grid.py new file mode 100644 index 0000000..19dcaee --- /dev/null +++ b/FMSgridtools/make_hgrid/make_lonlat_grid.py @@ -0,0 +1,121 @@ +import numpy as np +import ctypes + +from FMSgridtools.make_hgrid.hgridobj import HGridObj +from FMSgridtools.make_hgrid.make_hgrid_util import make_grid_info, grid_writer +import pyfrenctools + +def make( + nlon: int, + nlat: int, + xbnds: str = None, + ybnds: str = None, + dlon: str = None, + dlat: str = None, + use_great_circle_algorithm: bool = False +): + # fmsgridtools make_hgrid --grid_type regular_lonlat_grid + # --nxbnds 2 + # --nybnds 2 + # --xbnds 0,30 + # --ybnds 50,60 + # --nlon 60 + # --nlat 20 + # pyfrenctools.make_hgrid_util.create_regular_lonlat_grid( + # nxbnds, + # nybnds, + # xbnds, + # ybnds, + # nlon, + # nlat, + # dx_bnds, + # dy_bnds, + # use_legacy, + # isc, + # iec, + # jsc, + # jec, + # grid_obj.x, + # grid_obj.y, + # grid_obj.dx, + # grid_obj.dy, + # grid_obj.area, + # grid_obj.angle_dx, + # center, + # use_great_circle_algorithm, + # ) + + center = "none" + grid_obj = HGridObj() + + if nlon is not None: + nlon = np.fromstring(nlon, dtype=np.int32, sep=',') + nxbnds2 = nlon.size + + if nlat is not None: + nlat = np.fromstring(nlat, dtype=np.int32, sep=',') + nybnds2 = nlat.size + + if xbnds is not None: + xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') + nxbnds = xbnds.size + else: + xbnds = np.empty(shape=100, dtype=np.float64) + + if ybnds is not None: + ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') + nybnds = ybnds.size + else: + ybnds = np.empty(shape=100, dtype=np.float64) + + if dlon is not None: + dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') + nxbnds3 = dx_bnds.size + else: + dx_bnds = np.zeros(shape=100, dtype=np.float64) + + if dlat is not None: + dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') + nybnds3 = dy_bnds.size + else: + dy_bnds = np.zeros(shape=100, dtype=np.float64) + + grid_info_dict = make_grid_info( + grid_obj=grid_obj, + nxbnds=nxbnds, + nybnds=nybnds, + nlon=nlon, + nlat=nlat, + ) + + pyfrenctools.make_hgrid_wrappers.create_regular_lonlat_grid( + nxbnds=nxbnds, + nybnds=nybnds, + xbnds=xbnds, + ybnds=ybnds, + nlon=nlon, + nlat=nlat, + dx_bnds=dx_bnds, + dy_bnds=dy_bnds, + isc=grid_info_dict['isc'], + iec=grid_info_dict['iec'], + jsc=grid_info_dict['jsc'], + jec=grid_info_dict['jec'], + x=grid_obj.x, + y=grid_obj.y, + dx=grid_obj.dx, + dy=grid_obj.dy, + area=grid_obj.area, + angle_dx=grid_obj.angle_dx, + center=center, + use_great_circle_algorithm=use_great_circle_algorithm, + ) + + grid_writer( + grid_obj=grid_obj, + info_dict=grid_info_dict, + ) + + + + diff --git a/FREnctools_lib/pyfrenctools/__init__.py b/FREnctools_lib/pyfrenctools/__init__.py index 9ec16e8..e2b670f 100644 --- a/FREnctools_lib/pyfrenctools/__init__.py +++ b/FREnctools_lib/pyfrenctools/__init__.py @@ -1,6 +1,6 @@ from .cfrenctools import cfrenctools from .shared.create_xgrid import create_xgrid -from .make_hgrid import make_hgrid_util +from .make_hgrid import make_hgrid_wrappers cfrenctools.init() diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index 98faaa0..db3097a 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -1,7 +1,7 @@ import ctypes import os from .shared.create_xgrid import create_xgrid -from .make_hgrid.make_hgrid_util import make_hgrid_util +from .make_hgrid.make_hgrid_wrappers import make_hgrid_util class cfrenctools(): diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py similarity index 100% rename from FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_util.py rename to FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py From 438ac571951e7b6e6fcdf423a0c896623467a287 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 23:40:10 -0400 Subject: [PATCH 46/72] Removed redundant install of clib.so from top level setup.py --- setup.py | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/setup.py b/setup.py index 6f71963..4bbfc22 100644 --- a/setup.py +++ b/setup.py @@ -11,25 +11,6 @@ def local_pkg(name: str, relative_path: str) -> str: path = f"{name} @ file://{Path(os.path.abspath(__file__)).parent / relative_path}" return path -class CustomInstall(install): - def run(self): - with open("compile_log.txt", "w") as f: - subprocess.run( - ["cmake", ".."], - cwd="./FREnctools_lib/cfrenctools/c_build", - stdout=f, - stderr=subprocess.STDOUT, - check=True, - ) - subprocess.run( - ["make"], - cwd="./FREnctools_lib/cfrenctools/c_build", - stdout=f, - stderr=subprocess.STDOUT, - check=True, - ) - install.run(self) - test_requirements = ["pytest", "coverage"] develop_requirements = test_requirements + ["pre-commit"] @@ -46,7 +27,8 @@ def run(self): "numpy", "xarray", "netCDF4", - local_pkg("pyfms", "pyFMS") + local_pkg("pyfms", "pyFMS"), + local_pkg("pyfrenctools", "FREnctools_lib") ] setup( @@ -57,11 +39,10 @@ def run(self): extras_require=extras_requires, name="fmsgridtools", license="", - packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*", "FREnctools_lib", "FREnctools_lib.pyfrenctools.*"]), + packages=find_namespace_packages(include=["FMSgridtools", "FMSgridtools.*"]), include_package_data=True, version="0.0.1", zip_safe=False, - cmdclass={'install': CustomInstall}, entry_points={ "console_scripts": [ "make_hgrid = FMSgridtools.make_hgrid.make_hgrid:make_hgrid", # TODO fmsggridtools entrypoint From ed58d508820ee5907290ddaf6394ca0d713ed150 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 23:47:48 -0400 Subject: [PATCH 47/72] Accessing new location for compile_log in CI workflow --- .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 dac177d..6f9f75b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,6 +27,6 @@ jobs: export PATH="$PATH:$CONDA/envs/FMSgridtools/bin" which cmake $CONDA/envs/FMSgridtools/bin/pip install . - cat compile_log.txt + cat $CONDA/envs/FMSgridtools/bin/FREnctools_lib/compile_log.txt - name: Run pytest (just link test for now) run: pytest tests/shared/test_libs.py From 5d16d263dd9bbb2dfe5a4dacd5b1e9737cdcca87 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 24 Apr 2025 23:52:38 -0400 Subject: [PATCH 48/72] Trying again to access compile_log --- .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 6f9f75b..e7b4418 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,6 +27,6 @@ jobs: export PATH="$PATH:$CONDA/envs/FMSgridtools/bin" which cmake $CONDA/envs/FMSgridtools/bin/pip install . - cat $CONDA/envs/FMSgridtools/bin/FREnctools_lib/compile_log.txt + cat FREnctools_lib/compile_log.txt - name: Run pytest (just link test for now) run: pytest tests/shared/test_libs.py From fdb447bf11f8267b1600df43f7bc7b0e9605c137 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 25 Apr 2025 11:47:07 -0400 Subject: [PATCH 49/72] Pre-lim structure for make_hgrid:make_lonlat_grid, non-working --- FMSgridtools/make_hgrid/make_hgrid.py | 768 +------------------- FMSgridtools/make_hgrid/make_lonlat_grid.py | 37 +- FREnctools_lib/pyfrenctools/cfrenctools.py | 8 +- 3 files changed, 20 insertions(+), 793 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 73b20bc..5d94cd6 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -9,24 +9,10 @@ from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains from FMSgridtools.make_hgrid.hgridobj import HGridObj +from FMSgridtools.make_hgrid.make_lonlat_grid import make_lonlat_grid from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs import pyfrenctools - - -MAXBOUNDS = 100 -MAX_NESTS = 128 -REGULAR_LONLAT_GRID = 1 -TRIPOLAR_GRID = 2 -FROM_FILE = 3 -SIMPLE_CARTESIAN_GRID = 4 -SPECTRAL_GRID = 5 -CONFORMAL_CUBIC_GRID = 6 -GNOMONIC_ED = 7 -F_PLANE_GRID = 8 -BETA_PLANE_GRID = 9 -MISSING_VALUE = -9999. - @click.group() def make_hgrid(): pass @@ -36,15 +22,13 @@ def make_hgrid(): "--nlon", type=str, default=None, - help="Number of model grid points(supergrid) for each zonal regions of\ - varying resolution.", + help="Number of model grid points(supergrid) for each zonal regions of varying resolution.", ) @click.option( "--nlat", type=str, default=None, - help="Number of model grid points(supergid) for each meridinal regions of\ - varying resolution.", + help="Number of model grid points(supergid) for each meridinal regions of varying resolution.", ) @click.option( "--xbnds", @@ -90,740 +74,12 @@ def lonlat( dlat, use_great_circle_algorithm ): - - -# @click.option( -# "--grid_type", -# type=str, -# default="regular_lonlat_grid", -# help="specify type of topography. See above for grid type option.", -# ) -# @click.option( -# "--my_grid_file", -# type=str, -# default=None, -# help="when this flag is present, the program will read grid information\ -# from 'my_grid_file'. The file format can be ascii file or netcdf\ -# file. Multiple file entry are allowed but the number should be\ -# less than MAXBOUNDS.", -# ) -# @click.option( -# "--nxbnds", -# type=int, -# default=2, -# help="Specify number of zonal regions for varying resolution.", -# ) -# @click.option( -# "--nybnds", -# type=int, -# default=2, -# help="Specify number of meridinal regions for varying resolution.", -# ) -# @click.option( -# "--xbnds", -# type=str, -# default=None, -# help="Specify boundaries for defining zonal regions of varying resolution.\ -# When --tripolar is present, x also defines the longitude of the two\ -# new poles. nxbnds must be 2 and lon_start = x(1), lon_end = x(nxbnds)\ -# are longitude of the two new poles.", -# ) -# @click.option( -# "--ybnds", -# type=str, -# default=None, -# help="Specify boundaries for defining meridional regions of varying\ -# resolution", -# ) -# @click.option( -# "--nlon", -# type=str, -# default=None, -# help="Number of model grid points(supergrid) for each zonal regions of\ -# varying resolution.", -# ) -# @click.option( -# "--nlat", -# type=str, -# default=None, -# help="Number of model grid points(supergid) for each meridinal regions of\ -# varying resolution.", -# ) -# @click.option( -# "--dlon", -# type=str, -# default=None, -# help="nominal resolution of zonal regions", -# ) -# @click.option( -# "--dlat", -# type=str, -# default=None, -# help="nominal resolution of meridional regions", -# ) -# @click.option( -# "--lat_join", -# type=float, -# default=65., -# help="Specify latitude for joining spherical and rotated bipolar grid.\ -# Default value is 65 degree.", -# ) -# @click.option( -# "--nratio", -# type=int, -# default=1, -# help="Speicify the refinement ratio when calculating cell length and area\ -# of supergrid.", -# ) -# @click.option( -# "--simple_dx", -# type=float, -# default=0., -# help="Specify the uniform cell length in x-direction for simple cartesian\ -# grid.", -# ) -# @click.option( -# "--simple_dy", -# type=float, -# default=0., -# help="Specify the uniform cell length in y-direction for simple cartesian\ -# grid.", -# ) -# @click.option( -# "--grid_name", -# type=str, -# default="horizontal_grid", -# help=("Specify the grid name. The output grid file name will be" -# "grid_name.nc if there is one tile and grid_name.tile#.nc if there is" -# "more than one tile. The default value will be horizontal_grid."), -# ) -# @click.option( -# "--center", -# type=str, -# default="none", -# help="""Specify the center location of grid. Valid entries will be 'none'" -# ", 't_cell' or 'c_cell' with default value 'none'. The grid " -# "refinement is assumed to be 2 in x and y-direction when center is " -# "not 'none'. 'c_cell' should be used for the grid used in MOM.""", -# ) -# @click.option( -# "--shift_fac", -# type=float, -# default=18.0, -# help="shift west by 180/shift_fac. Default value is 18.", -# ) -# @click.option( -# "--f_plane_latitude", -# type=float, -# default=100., -# help="" -# ) -# @click.option( -# "--do_schmidt", -# is_flag=True, -# default=False, -# help=("Set to do Schmidt transformation to create stretched grid. When " -# "do_schmidt is set, the following must be set: --stretch_factor, " -# " --target_lon and --target_lat."), -# ) -# @click.option( -# "--do_cube_transform", -# is_flag=True, -# default=False, -# help=("re-orient the rotated cubed sphere so that tile 6 has 'north' " -# "facing upward, which would make analysis and explaining nest " -# "placement much easier. When do_cube_transform is set, the " -# "following must be set: --stretch_factor, --latget_lon, and " -# " --target_lat."), -# ) -# @click.option( -# "--stretch_factor", -# type=float, -# default=0.0, -# help="Stretching factor for the grid", -# ) -# @click.option( -# "--target_lon", -# type=float, -# default=0.0, -# help="center longitude of the highest resolution tile", -# ) -# @click.option( -# "--target_lat", -# type=float, -# default=0.0, -# help="center latitude of the highest resolution tile", -# ) -# @click.option( -# "--nest_grids", -# type=int, -# default=0, -# help="""set to create this # nested grids as well as the global grid. This -# replaces the option --nest_grid. This option could only be set when -# grid_type is 'gnomonic_ed'. When it is set, besides 6 tile grid , -# files created, there are # more nest grids with -# file name = grid_name.tile.nest.nc""", -# ) -# @click.option( -# "--parent_tile", -# type=str, -# default=None, -# help="Specify the comma-separated list of the parent tile number(s) of \ -# nest grid(s).", -# ) -# @click.option( -# "--refine_ratio", -# type=str, -# default=None, -# help="Specify the comma-separated list of refinement ratio(s) for nest\ -# grid(s).", -# ) -# @click.option( -# "--istart_nest", -# type=str, -# default=None, -# help="Specify the comma-separated list of starting i-direction index(es)\ -# of nest grid(s) in parent tile supergrid(Fortran index).", -# ) -# @click.option( -# "--iend_nest", -# type=str, -# default=None, -# help="Specify the comma-separated list of ending i-direction index(es) of \ -# nest grids in parent tile supergrid( Fortran index).", -# ) -# @click.option( -# "--jstart_nest", -# type=str, -# default=None, -# help="Specify the comma-separated list of starting j-direction index(es) of \ -# nest grids in parent tile supergrid(Fortran index).", -# ) -# @click.option( -# "--jend_nest", -# type=str, -# default=None, -# help="Specify the comma-separated list of ending j-direction index(es) of \ -# nest grids in parent tile supergrid (Fortran index).", -# ) -# @click.option( -# "--halo", -# type=int, -# default=0, -# help=("halo size is used in the atmosphere cubic sphere model. Its purpose " -# "is to make sure the nest, including the halo region, is fully " -# "contained within a single parent (coarse) tile. The option may " -# "be obsolete and removed in future development. It only needs to " -# "be specified when --nest_grid(s) is set."), -# ) -# @click.option( -# "--use_great_circle_algorithm", -# is_flag=True, -# default=False, -# help="When specified, great_circle_algorithm will be used to compute grid \ -# cell area.", -# ) -# @click.option( -# "--out_halo", -# type=int, -# default=0, -# help="extra halo size data to be written out. This is only works for \ -# gnomonic_ed.", -# ) -# @click.option( -# "--no_output_length_angle", -# is_flag=True, -# default=False, -# help="When specified, will not output length(dx,dy) and angle \ -# (angle_dx, angle_dy)" -# ) -# @click.option( -# "--angular_midpoint", -# is_flag=True, -# default=False, -# help="" -# ) -# @click.option( -# "--rotate_poly", -# is_flag=True, -# default=False, -# help=("Set to calculate polar polygon areas by calculating the area of a " -# "copy of the polygon, with the copy being rotated far away from the" -# "pole.") -# ) -# @click.option( -# "--verbose", -# is_flag=True, -# default=False, -# help=("Will print out running time message when this option is set. " -# "Otherwise the run will be silent when there is no error.") -# ) -def make_hgrid( - grid_type: str, - my_grid_file: str, - nxbnds: int, - nybnds: int, - xbnds: str, - ybnds: str, - nlon: str, - nlat: str, - dlon: str, - dlat: str, - lat_join: float, - nratio: int, - simple_dx: float, - simple_dy: float, - grid_name: str, - center: str, - shift_fac: float, - f_plane_latitude: float, - do_schmidt: bool, - do_cube_transform: bool, - stretch_factor: float, - target_lon: float, - target_lat: float, - nest_grids: int, - parent_tile: str, - refine_ratio: str, - istart_nest: str, - iend_nest: str, - jstart_nest: str, - jend_nest: str, - halo: int, - use_great_circle_algorithm: bool, - out_halo: int, - no_output_length_angle: bool, - angular_midpoint: bool, - rotate_poly: bool, - verbose: bool, -): - nratio = 1 - method = "conformal" - orientation = "center_pole" - nxbnds0 = nxbnds - nybnds0 = nybnds - nxbnds1 = 0 - nybnds1 = 0 - nxbnds2 = 0 - nybnds2 = 0 - nxbnds3 = 0 - nybnds3 = 0 - - num_nest_args = 0 - nn = 0 - - present_stretch_factor = 0 - present_target_lon = 0 - present_target_lat = 0 - output_length_angle = 1 - ntiles = 1 - ntiles_global = 1 - ntiles_file = 0 - grid_obj = HGridObj() - - center = "none" - geometry = "spherical" - projection = "none" - arcx = "small_circle" - north_pole_tile = "0.0 90.0" - north_pole_arcx = "0.0 90.0" - discretization = "logically_rectangular" - conformal = "true" - - fms_file = "input.nml" - with open(fms_file, "x") as file: - file.write("") - - #TODO: Will change after pyFMS refactor - pyfms = pyFMS(cFMS_path="./pyFMS/cFMS/libcFMS/.libs/libcFMS.so") - mpp = pyFMS_mpp(cFMS=pyfms.cFMS) - mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) - - if(mpp.npes() > 1): - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: make_hgrid must be run one processor, contact developer") - - if xbnds is not None: - xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') - nxbnds1 = xbnds.size - else: - xbnds = np.empty(shape=100, dtype=np.float64, order="C") - - if ybnds is not None: - ybnds = np.fromstring(ybnds, dtype=np.float64, sep=',') - nybnds1 = ybnds.size - else: - ybnds = np.empty(shape=100, dtype=np.float64, order="C") - - if nlon is not None: - nlon = np.fromstring(nlon, dtype=np.int32, sep=',') - nxbnds2 = nlon.size - - if nlat is not None: - nlat = np.fromstring(nlat, dtype=np.int32, sep=',') - nybnds2 = nlat.size - - if dlon is not None: - dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') - nxbnds3 = dx_bnds.size - else: - dx_bnds = np.zeros(shape=100, dtype=np.float64, order="C") - - if dlat is not None: - dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') - nybnds3 = dy_bnds.size - else: - dy_bnds = np.zeros(shape=100, dtype=np.float64, order="C") - - if stretch_factor != 0.0: - present_stretch_factor = 1 - - if target_lon != 0.0: - present_target_lon = 1 - - if target_lat != 0.0: - present_target_lat = 1 - - if refine_ratio is not None: - refine_ratio = np.fromstring(refine_ratio, dtype=np.int32, sep=',') - num_nest_args = refine_ratio.size - - if parent_tile is not None: - parent_tile = np.fromstring(refine_ratio, dtype=np.int32, sep=',') - num_nest_args = parent_tile.size - - if istart_nest is not None: - istart_nest = np.fromstring(istart_nest, dtype=np.int32, sep=',') - num_nest_args = istart_nest.size - - if iend_nest is not None: - iend_nest = np.fromstring(iend_nest, dtype=np.int32, sep=',') - num_nest_args = iend_nest.size - - if jstart_nest is not None: - jstart_nest = np.fromstring(jstart_nest, dtype=np.int32, sep=',') - num_nest_args = jstart_nest.size - - if jend_nest is not None: - jend_nest = np.fromstring(jend_nest, dtype=np.int32, sep=',') - num_nest_args = jend_nest.size - - if no_output_length_angle: - output_length_angle = 0 - - if angular_midpoint: - use_angular_midpoint = 1 - - if my_grid_file is not None: - my_grid_file = np.array(my_grid_file.split(',')) - ntiles_file = my_grid_file.size - - # TODO: rotate_poly? - - if mpp.pe() == 0 and verbose: - print(f"==>NOTE: the grid type is {grid_type}") - - if grid_type == "regular_lonlat_grid": - my_grid_type = REGULAR_LONLAT_GRID - elif grid_type == "from_file": - my_grid_type = FROM_FILE - elif grid_type == "simple_cartesian_grid": - my_grid_type = SIMPLE_CARTESIAN_GRID - elif grid_type == "spectral_grid": - my_grid_type = SPECTRAL_GRID - elif grid_type == "conformal_cubic_grid": - my_grid_type = CONFORMAL_CUBIC_GRID - elif grid_type == "gnomonic_ed": - my_grid_type = GNOMONIC_ED - elif grid_type == "f_plane_grid": - my_grid_type = F_PLANE_GRID - elif grid_type == "beta_plane_grid": - my_grid_type = BETA_PLANE_GRID - else: - mpp.pyfms_error(errotype=2, errormsg="make_hgrid: only grid_type = 'regular_lonlat_grid', 'tripolar_grid', 'from_file', 'gnomonic_ed', 'conformal_cubic_grid', 'simple_cartesian_grid', 'spectral_grid', 'f_plane_grid' and 'beta_plane_grid' is implemented") - - if my_grid_type != GNOMONIC_ED and out_halo != 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should not be set when grid_type = gnomonic_ed") - if out_halo != 0 and out_halo != 1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: out_halo should be 0 or 1") - - if my_grid_type != GNOMONIC_ED and do_schmidt: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_schmidt should not be set when grid_type is not 'gnomonic_ed'") - - if my_grid_type != GNOMONIC_ED and do_cube_transform: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --do_cube_transform should not be set when grid_type is not 'gnomonic_ed'") - - if do_cube_transform and do_schmidt: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: both --do_cube_transform and --do_schmidt are set") - - use_legacy = 0 - - """ - Command line argument check - """ - - if my_grid_type == REGULAR_LONLAT_GRID or my_grid_type == F_PLANE_GRID or my_grid_type == BETA_PLANE_GRID: - nxbnds = nxbnds0 - nybnds = nybnds0 - if nxbnds < 2 or nybnds < 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', both nxbnds and nybnds should be no less than 2") - if nxbnds != nxbnds1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in xbnds") - if nybnds != nybnds1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid, 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in ybnds") - - num_specify = 0 - if nxbnds2 > 0 and nybnds2 > 0: - num_specify += 1 - if nxbnds3 > 0 and nybnds3 > 0: - num_specify += 1 - use_legacy = 1 - - if num_specify == 0: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', need to specify one of the pair --nlon --nlat or --dlon --dlat") - if num_specify == 2: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'regular_lonlat_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', can not specify both --nlon --nlat and --dlon --dlat") - if use_legacy: - if nxbnds != nxbnds3: - mpp.pfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in dlon") - if nybnds != nybnds3: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in dlat") - else: - if nxbnds != nxbnds2+1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nxbnds does not match number of entry in nlon") - if nybnds != nybnds2+1: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: grid type is 'tripolar_grid', 'tripolar_grid', 'f_plane_grid' or 'beta_plane_grid', nybnds does not match number of entry in nlat") - else: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") - - if verbose: - print(f"[INFO] make_hgrid: Number of tiles (ntiles): {ntiles}", file=sys.stderr) - print(f"[INFO] make_hgrid: Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) - - nxl = np.empty(shape=ntiles, dtype=np.int32) - nyl = np.empty(shape=ntiles, dtype=np.int32) - - """ - Get super grid size - """ - if my_grid_type == GNOMONIC_ED or my_grid_file == CONFORMAL_CUBIC_GRID: - for n in range(ntiles_global): - nxl[n] = nlon[0] - nyl[n] = nxl[n] - if nest_grids and parent_tile[0] == 0: - nxl[n] *= refine_ratio[0] - nyl[n] *= refine_ratio[0] - - for n in range(ntiles_global, ntiles): - nn = n - ntiles_global - nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] - nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] - elif my_grid_type == FROM_FILE: - for n in range(ntiles_global): - nxl[n] = nlon[n] - nyl[n] = nlat[n] - else: - nxl[0] = 0 - nyl[0] = 0 - for n in range(nxbnds - 1): - nxl[0] += nlon[n] - for n in range(nybnds - 1): - nyl[0] += nlat[n] - - nx = nxl[0] - ny = nyl[0] - nxp = nx + 1 - nyp = ny + 1 - - if center == "none" and center == "c_cell" and center == "t_cell": - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: center should be 'none', 'c_cell' or 't_cell' ") - - # --non_length_angle should only be set when grid_type == GNOMONIC_ED - if not output_length_angle and my_grid_type != GNOMONIC_ED: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: --no_length_angle is set but grid_type is not 'gnomonic_ed'") - - """ - Create grid information - """ - - for n_nest in range(ntiles): - print(f"[INFO] tile: {n_nest}, nxl[{nxl[n_nest]}], nyl[{nyl[n_nest]}], ntiles: {ntiles}", file=sys.stderr) - - size1 = ctypes.c_ulong(0) - size2 = ctypes.c_ulong(0) - size3 = ctypes.c_ulong(0) - size4 = ctypes.c_long(0) - - if my_grid_type == FROM_FILE: - for n in range(ntiles_global): - size1.value += (nlon[n] + 1) * (nlat[n] + 1) - size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) - size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) - size4.value += (nlon[n] + 1) * (nlat[n] + 1) - else: - size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) - size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) - size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) - size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - - if not (nest_grids == 1 and parent_tile[0] == 0): - for n_nest in range(ntiles_global, ntiles_global+nest_grids): - if verbose: - print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}", file=sys.stderr) - size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) - size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) - size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - - if verbose: - print(f"[INFO] Allocating arrays of size {size1.value} for x, y based on nxp: {nxp} nyp: {nyp} ntiles: {ntiles}", file=sys.stderr) - grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) - grid_obj.arcx = arcx - if output_length_angle: - grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) - grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) - grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - if conformal != "true": - grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) - - isc = 0 - iec = nx - 1 - jsc = 0 - jec = ny - 1 - - if(my_grid_type==REGULAR_LONLAT_GRID): - pyfrenctools.make_hgrid_util.create_regular_lonlat_grid( - nxbnds, - nybnds, - xbnds, - ybnds, - nlon, - nlat, - dx_bnds, - dy_bnds, - use_legacy, - isc, - iec, - jsc, - jec, - grid_obj.x, - grid_obj.y, - grid_obj.dx, - grid_obj.dy, - grid_obj.area, - grid_obj.angle_dx, - center, - use_great_circle_algorithm, - ) - else: - mpp.pyfms_error(errortype=2, errormsg="make_hgrid: passed grid type is not implemented") - - - """ - Write out data - """ - pos_c = 0 - pos_e = 0 - pos_t = 0 - pos_n = 0 - for n in range(ntiles): - grid_obj.tile = "tile" + str(n+1) - if ntiles > 1: - outfile = grid_name + ".tile" + ".nc" + str(n+1) - else: - outfile = grid_name + ".nc" - - if verbose: - print(f"Writing out {outfile}", file=sys.stderr) - - nx = nxl[n] - ny = nyl[n] - if verbose: - print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}", file=sys.stderr) - nxp = nx + 1 - nyp = ny + 1 - - if out_halo == 0: - if verbose: - print(f"[INFO] START NC XARRAY write out_halo=0 tile number = n: {n} offset = pos_c: {pos_c}", file=sys.stderr) - print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[1]: {grid_obj.x[pos_c+1]} x[2]: {grid_obj.x[pos_c+2]} x[3]: {grid_obj.x[pos_c+3]} x[4]: {grid_obj.x[pos_c+4]} x[5]: {grid_obj.x[pos_c+5]} x[10]: {grid_obj.x[pos_c+10]}", file=sys.stderr) - if n > 0: - print(f"[INFO] XARRAY: n: {n} x[0]: {grid_obj.x[pos_c]} x[-1]: {grid_obj.x[pos_c-1]} x[-2]: {grid_obj.x[pos_c-2]} x[-3]: {grid_obj.x[pos_c-3]} x[-4]: {grid_obj.x[pos_c-4]} x[-5]: {grid_obj.x[pos_c-5]} x[-10]: {grid_obj.x[pos_c-10]}", file=sys.stderr) - grid_obj.x = grid_obj.x[pos_c:] - grid_obj.y = grid_obj.y[pos_c:] - if output_length_angle: - grid_obj.dx = grid_obj.dx[pos_n:] - grid_obj.dy = grid_obj.dy[pos_e:] - grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] - if conformal != "true": - grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] - grid_obj.area = grid_obj.area[pos_t:] - else: - tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) - if verbose: - print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) - grid_obj.x = tmp.copy() - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) - grid_obj.y = tmp.copy() - if output_length_angle: - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) - grid_obj.angle_dx = tmp.copy() - if conformal != "true": - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) - grid_obj.angle_dy = tmp.copy() - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) - grid_obj.dx = tmp.copy() - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) - grid_obj.dy = tmp.copy() - pyfrenctools.make_hgrid_util.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) - grid_obj.area = tmp.copy() - - if verbose: - print(f"About to close {outfile}") - - nx = nxl[n] - ny = nyl[n] - nxp = nx + 1 - nyp = ny + 1 - - if verbose: - print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}", file=sys.stderr) - pos_c += nxp*nyp - if verbose: - print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}.", file=sys.stderr) - pos_e += nxp*ny - pos_n += nx*nyp - pos_t += nx*ny - - prov_attrs = get_provenance_attrs(great_circle_algorithm=use_great_circle_algorithm) - grid_obj.write_out_hgrid( - outfile=outfile, - nx=nx, - ny=ny, - nxp=nxp, - nyp=nyp, - global_attrs=prov_attrs, - north_pole_tile=north_pole_tile, - north_pole_arcx=north_pole_arcx, - projection=projection, - geometry=geometry, - discretization=discretization, - conformal=conformal, - out_halo=out_halo, - output_length_angle=output_length_angle, - ) - - if(mpp.pe() == 0 and verbose): - print("generate_grid is run successfully") - - pyfms.pyfms_end() - - os.remove(fms_file) - - - # End of main - - if __name__ == "__main__": - make_hgrid() \ No newline at end of file + make_lonlat_grid( + nlon=nlon, + nlat=nlat, + xbnds=xbnds, + ybnds=ybnds, + dlon=dlon, + dlat=dlat, + use_great_circle_algorithm=use_great_circle_algorithm, + ) \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/make_lonlat_grid.py index 19dcaee..3cb724e 100644 --- a/FMSgridtools/make_hgrid/make_lonlat_grid.py +++ b/FMSgridtools/make_hgrid/make_lonlat_grid.py @@ -5,7 +5,7 @@ from FMSgridtools.make_hgrid.make_hgrid_util import make_grid_info, grid_writer import pyfrenctools -def make( +def make_lonlat_grid( nlon: int, nlat: int, xbnds: str = None, @@ -14,47 +14,14 @@ def make( dlat: str = None, use_great_circle_algorithm: bool = False ): - # fmsgridtools make_hgrid --grid_type regular_lonlat_grid - # --nxbnds 2 - # --nybnds 2 - # --xbnds 0,30 - # --ybnds 50,60 - # --nlon 60 - # --nlat 20 - # pyfrenctools.make_hgrid_util.create_regular_lonlat_grid( - # nxbnds, - # nybnds, - # xbnds, - # ybnds, - # nlon, - # nlat, - # dx_bnds, - # dy_bnds, - # use_legacy, - # isc, - # iec, - # jsc, - # jec, - # grid_obj.x, - # grid_obj.y, - # grid_obj.dx, - # grid_obj.dy, - # grid_obj.area, - # grid_obj.angle_dx, - # center, - # use_great_circle_algorithm, - # ) - center = "none" grid_obj = HGridObj() if nlon is not None: nlon = np.fromstring(nlon, dtype=np.int32, sep=',') - nxbnds2 = nlon.size if nlat is not None: nlat = np.fromstring(nlat, dtype=np.int32, sep=',') - nybnds2 = nlat.size if xbnds is not None: xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') @@ -70,13 +37,11 @@ def make( if dlon is not None: dx_bnds = np.fromstring(dlon, dtype=np.float64, sep=',') - nxbnds3 = dx_bnds.size else: dx_bnds = np.zeros(shape=100, dtype=np.float64) if dlat is not None: dy_bnds = np.fromstring(dlat, dtype=np.float64, sep=',') - nybnds3 = dy_bnds.size else: dy_bnds = np.zeros(shape=100, dtype=np.float64) diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index db3097a..3ba8be1 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -1,11 +1,17 @@ import ctypes +import importlib.resources import os +from pathlib import Path + from .shared.create_xgrid import create_xgrid from .make_hgrid.make_hgrid_wrappers import make_hgrid_util +relative_path = "cfrenctools/c_build/clib.so" +# /home/Frank.Malatino/.conda/envs/fmsgtenv2/lib/python3.11/cfrenctools/c_build/clib.so + class cfrenctools(): - __libpath: str = os.path.dirname(__file__) + "../cfrenctools/c_build/clib.so" + __libpath: str = os.path.dirname(__file__) + "/../cfrenctools/c_build/clib.so" __lib: ctypes.CDLL = ctypes.CDLL(__libpath) @classmethod From 0b9c30549e4f4d9a46a672f79920370a0b75112f Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 25 Apr 2025 12:11:49 -0400 Subject: [PATCH 50/72] Pre-lim working make_lonlat --- FMSgridtools/make_hgrid/make_lonlat_grid.py | 5 +++-- FREnctools_lib/pyfrenctools/__init__.py | 2 +- FREnctools_lib/pyfrenctools/cfrenctools.py | 9 ++------- .../pyfrenctools/make_hgrid/make_hgrid_wrappers.py | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/make_lonlat_grid.py index 3cb724e..18b9c0f 100644 --- a/FMSgridtools/make_hgrid/make_lonlat_grid.py +++ b/FMSgridtools/make_hgrid/make_lonlat_grid.py @@ -60,8 +60,9 @@ def make_lonlat_grid( ybnds=ybnds, nlon=nlon, nlat=nlat, - dx_bnds=dx_bnds, - dy_bnds=dy_bnds, + dlon=dx_bnds, + dlat=dy_bnds, + use_legacy=0, isc=grid_info_dict['isc'], iec=grid_info_dict['iec'], jsc=grid_info_dict['jsc'], diff --git a/FREnctools_lib/pyfrenctools/__init__.py b/FREnctools_lib/pyfrenctools/__init__.py index e2b670f..4925e8a 100644 --- a/FREnctools_lib/pyfrenctools/__init__.py +++ b/FREnctools_lib/pyfrenctools/__init__.py @@ -1,6 +1,6 @@ from .cfrenctools import cfrenctools from .shared.create_xgrid import create_xgrid -from .make_hgrid import make_hgrid_wrappers +from .make_hgrid.make_hgrid_wrappers import make_hgrid_wrappers cfrenctools.init() diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index 3ba8be1..fc66762 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -1,13 +1,8 @@ import ctypes -import importlib.resources import os -from pathlib import Path from .shared.create_xgrid import create_xgrid -from .make_hgrid.make_hgrid_wrappers import make_hgrid_util - -relative_path = "cfrenctools/c_build/clib.so" -# /home/Frank.Malatino/.conda/envs/fmsgtenv2/lib/python3.11/cfrenctools/c_build/clib.so +from .make_hgrid.make_hgrid_wrappers import make_hgrid_wrappers class cfrenctools(): @@ -17,7 +12,7 @@ class cfrenctools(): @classmethod def init(cls): create_xgrid.init(cls.libpath, cls.lib) - make_hgrid_util.init(cls.libpath, cls.lib) + make_hgrid_wrappers.init(cls.libpath, cls.lib) @classmethod def changelib(cls, libpath): diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py index 6a826e8..8e6fc0b 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py @@ -12,7 +12,7 @@ # lib = ctypes.CDLL("./FREnctools_lib/cfrenctools/c_build/clib.so") -class make_hgrid_util(): +class make_hgrid_wrappers(): __libpath: str = None __lib: ctypes.CDLL = None From 0b3b5f7df132abe02ad289f8f4cdb7b8ce7d8ee5 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 25 Apr 2025 15:43:01 -0400 Subject: [PATCH 51/72] Consolidating hgrid utils in hgridobj.py --- FMSgridtools/make_hgrid/hgridobj.py | 195 ++++++++-- FMSgridtools/make_hgrid/make_hgrid.py | 16 +- FMSgridtools/make_hgrid/make_hgrid_util.py | 382 ++++++++++---------- FMSgridtools/make_hgrid/make_lonlat_grid.py | 18 +- 4 files changed, 366 insertions(+), 245 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index f611837..eda4f58 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -1,11 +1,11 @@ -import dataclasses -from typing import List, Optional +import ctypes import numpy as np -import numpy.typing as npt +from numpy.typing import NDArray import xarray as xr -from FMSgridtools.shared.gridtools_utils import check_file_is_there +from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs from FMSgridtools.shared.gridobj import GridObj +import pyfrenctools class HGridObj(): def __init__(self): @@ -18,35 +18,170 @@ def __init__(self): self.angle_dx = None self.angle_dy = None self.arcx = "" + self.nx = None + self.ny = None + self.nxp = None + self.nyp = None + self.nxl = None + self.nyl = None + self.isc = None + self.iec = None + self.jsc = None + self.jec = None + + def make_grid_info( + self, + nxbnds: int, + nybnds: int, + ntiles: int=1, + ntiles_global: int=1, + nlon: NDArray=None, + nlat: NDArray=None, + nest_grids: int=0, + parent_tile: NDArray=None, + refine_ratio: NDArray=None, + istart_nest: NDArray=None, + iend_nest: NDArray=None, + jstart_nest: NDArray=None, + jend_nest: NDArray=None, + arcx: str="small_circle", + grid_type: str=None, + ): + self.nxl = np.empty(shape=ntiles, dtype=np.int32) + self.nyl = np.empty(shape=ntiles, dtype=np.int32) + + if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": + for n in range(ntiles_global): + self.nxl[n] = nlon[0] + self.nyl[n] = self.nxl[n] + if nest_grids and parent_tile[0] == 0: + self.nxl[n] *= refine_ratio[0] + self.nyl[n] *= refine_ratio[0] + + for n in range(ntiles_global, ntiles): + nn = n - ntiles_global + self.nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] + self.nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + elif grid_type == "FROM_FILE": + for n in range(ntiles_global): + self.nxl[n] = nlon[n] + self.nyl[n] = nlat[n] + else: + self.nxl[0] = 0 + self.nyl[0] = 0 + for n in range(nxbnds - 1): + self.nxl[0] += nlon[n] + for n in range(nybnds - 1): + self.nyl[0] += nlat[n] + + self.nx = self.nxl[0] + self.ny = self.nyl[0] + self.nxp = self.nx + 1 + self.nyp = self.ny + 1 + + size1 = ctypes.c_ulong(0) + size2 = ctypes.c_ulong(0) + size3 = ctypes.c_ulong(0) + size4 = ctypes.c_ulong(0) + + if grid_type == "FROM_FILE": + for n in range(ntiles_global): + size1.value += (nlon[n] + 1) * (nlat[n] + 1) + size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) + size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + size4.value += (nlon[n] + 1) * (nlat[n] + 1) + else: + size1 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) + size2 = ctypes.c_ulong(self.nxp * (self.nyp + 1) * ntiles_global) + size3 = ctypes.c_ulong((self.nxp + 1) * self.nyp * ntiles_global) + size4 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) + + if not (nest_grids == 1 and parent_tile[0] == 0): + for n_nest in range(ntiles_global, ntiles_global+nest_grids): + size1.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+1) + size2.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+2) + size3.value += (self.nxl[n_nest]+2) * (self.nyl[n_nest]+1) + size4.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+1) + + self.x = np.empty(shape=size1.value, dtype=np.float64) + self.y = np.empty(shape=size1.value, dtype=np.float64) + self.area = np.empty(shape=size4.value, dtype=np.float64) + self.arcx = arcx + self.dx = np.empty(shape=size2.value, dtype=np.float64) + self.dy = np.empty(shape=size3.value, dtype=np.float64) + self.angle_dx = np.empty(shape=size1.value, dtype=np.float64) + self.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + self.isc = 0 + self.iec = self.nx - 1 + self.jsc = 0 + self.jec = self.ny - 1 + def write_out_hgrid( self, - outfile: str, - nx: int, - ny: int, - nxp: int, - nyp: int, - global_attrs: dict, - north_pole_tile="none", - north_pole_arcx="none", - projection="none", - geometry="none", - discretization="none", - conformal="none", - out_halo=0, - output_length_angle=0, + grid_name: str="horizontal_grid", + ntiles: int=1, + north_pole_tile: str="0.0 90.0", + north_pole_arcx: str="0.0 90.0", + projection: str="none", + geometry: str="spherical", + discretization: str="logically_rectangular", + conformal: str="true", + out_halo: int=0, + output_length_angle: int=0, ): - tile = None - x = None - y = None - dx = None - dy = None - area = None - angle_dx = None - angle_dy = None - arcx = None + var_dict={} + pos_c = 0 + pos_e = 0 + pos_t = 0 + pos_n = 0 + for n in range(ntiles): + self.tile = "tile" + str(n+1) + if ntiles > 1: + outfile = grid_name + ".tile" + ".nc" + str(n+1) + else: + outfile = grid_name + ".nc" + nx = self.nxl[n] + ny = self.nyl[n] + nxp = nx + 1 + nyp = ny + 1 + + if out_halo == 0: + self.x = self.x[pos_c:] + self.y = self.y[pos_c:] + self.dx = self.dx[pos_n:] + self.dy = self.dy[pos_e:] + self.angle_dx = self.angle_dx[pos_c:] + self.angle_dy = self.angle_dy[pos_c:] + self.area = self.area[pos_t:] + else: + tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) + self.x = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) + self.y = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) + self.angle_dx = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) + self.angle_dy = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) + self.dx = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) + self.dy = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) + self.area = tmp.copy() + + nx = self.nxl[n] + ny = self.nyl[n] + nxp = nx + 1 + nyp = ny + 1 + pos_c += nxp*nyp + pos_e += nxp*ny + pos_n += nx*nyp + pos_t += nx*ny + tile = xr.DataArray( [self.tile], attrs=dict( @@ -185,12 +320,14 @@ def write_out_hgrid( ) ) - var_dict['arcx'] = arcx + var_dict['arcx'] = arcx + + prov_attrs = get_provenance_attrs(great_circle_algorithm=True) dataset = xr.Dataset( data_vars=var_dict ) - dataset.attrs = global_attrs + dataset.attrs = prov_attrs self.dataset = dataset dataset.to_netcdf(outfile) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 5d94cd6..06f65ea 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,17 +1,7 @@ -import sys -import os -import xarray as xr -import ctypes -import numpy as np -import numpy.typing as npt import click -from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains - -from FMSgridtools.make_hgrid.hgridobj import HGridObj from FMSgridtools.make_hgrid.make_lonlat_grid import make_lonlat_grid -from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs -import pyfrenctools + @click.group() def make_hgrid(): @@ -22,13 +12,13 @@ def make_hgrid(): "--nlon", type=str, default=None, - help="Number of model grid points(supergrid) for each zonal regions of varying resolution.", + help="Comma separated list of model grid points(supergrid) for each zonal regions of varying resolution.", ) @click.option( "--nlat", type=str, default=None, - help="Number of model grid points(supergid) for each meridinal regions of varying resolution.", + help="Comma separated of model grid points(supergid) for each meridinal regions of varying resolution.", ) @click.option( "--xbnds", diff --git a/FMSgridtools/make_hgrid/make_hgrid_util.py b/FMSgridtools/make_hgrid/make_hgrid_util.py index 8ca8cd2..2a9c5f2 100644 --- a/FMSgridtools/make_hgrid/make_hgrid_util.py +++ b/FMSgridtools/make_hgrid/make_hgrid_util.py @@ -1,194 +1,194 @@ -import numpy as np -from numpy.typing import NDArray -import ctypes - -from FMSgridtools.make_hgrid.hgridobj import HGridObj -from FMSgridtools.shared.gridtools_utils import get_provenance_attrs -import pyfrenctools - -def make_grid_info( - grid_obj: HGridObj, - nxbnds: int, - nybnds: int, - ntiles: int = 1, - ntiles_global: int = 1, - nlon: NDArray = None, - nlat: NDArray = None, - nest_grids: int = 0, - parent_tile: NDArray = None, - refine_ratio: NDArray = None, - istart_nest: NDArray = None, - iend_nest: NDArray = None, - jstart_nest: NDArray = None, - jend_nest: NDArray = None, - arcx: str = "small_circle", - grid_type: str = None, -) -> dict: +# import numpy as np +# from numpy.typing import NDArray +# import ctypes + +# from FMSgridtools.make_hgrid.hgridobj import HGridObj +# from FMSgridtools.shared.gridtools_utils import get_provenance_attrs +# import pyfrenctools + +# def make_grid_info( +# grid_obj: HGridObj, +# nxbnds: int, +# nybnds: int, +# ntiles: int = 1, +# ntiles_global: int = 1, +# nlon: NDArray = None, +# nlat: NDArray = None, +# nest_grids: int = 0, +# parent_tile: NDArray = None, +# refine_ratio: NDArray = None, +# istart_nest: NDArray = None, +# iend_nest: NDArray = None, +# jstart_nest: NDArray = None, +# jend_nest: NDArray = None, +# arcx: str = "small_circle", +# grid_type: str = None, +# ) -> dict: - nxl = np.empty(shape=ntiles, dtype=np.int32) - nyl = np.empty(shape=ntiles, dtype=np.int32) - - if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": - for n in range(ntiles_global): - nxl[n] = nlon[0] - nyl[n] = nxl[n] - if nest_grids and parent_tile[0] == 0: - nxl[n] *= refine_ratio[0] - nyl[n] *= refine_ratio[0] - - for n in range(ntiles_global, ntiles): - nn = n - ntiles_global - nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] - nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] - elif grid_type == "FROM_FILE": - for n in range(ntiles_global): - nxl[n] = nlon[n] - nyl[n] = nlat[n] - else: - nxl[0] = 0 - nyl[0] = 0 - for n in range(nxbnds - 1): - nxl[0] += nlon[n] - for n in range(nybnds - 1): - nyl[0] += nlat[n] - - nx = nxl[0] - ny = nyl[0] - nxp = nx + 1 - nyp = ny + 1 - grid_info_dict = {} - grid_info_dict['nx'] = nx - grid_info_dict['ny'] = ny - grid_info_dict['nxp'] = nxp - grid_info_dict['nyp'] = nyp - grid_info_dict['nxl'] = nxl - grid_info_dict['nyl'] = nyl - - size1 = ctypes.c_ulong(0) - size2 = ctypes.c_ulong(0) - size3 = ctypes.c_ulong(0) - size4 = ctypes.c_ulong(0) - - if grid_type == "FROM_FILE": - for n in range(ntiles_global): - size1.value += (nlon[n] + 1) * (nlat[n] + 1) - size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) - size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) - size4.value += (nlon[n] + 1) * (nlat[n] + 1) - else: - size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) - size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) - size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) - size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - - if not (nest_grids == 1 and parent_tile[0] == 0): - for n_nest in range(ntiles_global, ntiles_global+nest_grids): - size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) - size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) - size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - - grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) - grid_obj.arcx = arcx - grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) - grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) - grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) - - isc = 0 - iec = nx - 1 - jsc = 0 - jec = ny - 1 - - grid_info_dict['isc'] = 0 - grid_info_dict['iec'] = nx - 1 - grid_info_dict['jsc'] = 0 - grid_info_dict['jec'] = ny - 1 - - - return grid_info_dict - -def grid_writer( - grid_obj: HGridObj, - info_dict: dict, - grid_name: str = "horizontal_grid", - ntiles: int = 1, - out_halo: int = 0, -): - north_pole_tile = "0.0 90.0" - north_pole_arcx = "0.0 90.0" - geometry = "spherical" - projection = "none" - conformal = "true" - discretization = "logically_rectangular" - output_length_angle = 1 - pos_c = 0 - pos_e = 0 - pos_t = 0 - pos_n = 0 - for n in range(ntiles): - grid_obj.tile = "tile" + str(n+1) - if ntiles > 1: - outfile = grid_name + ".tile" + ".nc" + str(n+1) - else: - outfile = grid_name + ".nc" +# nxl = np.empty(shape=ntiles, dtype=np.int32) +# nyl = np.empty(shape=ntiles, dtype=np.int32) + +# if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": +# for n in range(ntiles_global): +# nxl[n] = nlon[0] +# nyl[n] = nxl[n] +# if nest_grids and parent_tile[0] == 0: +# nxl[n] *= refine_ratio[0] +# nyl[n] *= refine_ratio[0] + +# for n in range(ntiles_global, ntiles): +# nn = n - ntiles_global +# nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] +# nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] +# elif grid_type == "FROM_FILE": +# for n in range(ntiles_global): +# nxl[n] = nlon[n] +# nyl[n] = nlat[n] +# else: +# nxl[0] = 0 +# nyl[0] = 0 +# for n in range(nxbnds - 1): +# nxl[0] += nlon[n] +# for n in range(nybnds - 1): +# nyl[0] += nlat[n] + +# nx = nxl[0] +# ny = nyl[0] +# nxp = nx + 1 +# nyp = ny + 1 +# grid_info_dict = {} +# grid_info_dict['nx'] = nx +# grid_info_dict['ny'] = ny +# grid_info_dict['nxp'] = nxp +# grid_info_dict['nyp'] = nyp +# grid_info_dict['nxl'] = nxl +# grid_info_dict['nyl'] = nyl + +# size1 = ctypes.c_ulong(0) +# size2 = ctypes.c_ulong(0) +# size3 = ctypes.c_ulong(0) +# size4 = ctypes.c_ulong(0) + +# if grid_type == "FROM_FILE": +# for n in range(ntiles_global): +# size1.value += (nlon[n] + 1) * (nlat[n] + 1) +# size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) +# size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) +# size4.value += (nlon[n] + 1) * (nlat[n] + 1) +# else: +# size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) +# size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) +# size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) +# size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) + +# if not (nest_grids == 1 and parent_tile[0] == 0): +# for n_nest in range(ntiles_global, ntiles_global+nest_grids): +# size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) +# size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) +# size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) +# size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) + +# grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) +# grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) +# grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) +# grid_obj.arcx = arcx +# grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) +# grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) +# grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) +# grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + +# isc = 0 +# iec = nx - 1 +# jsc = 0 +# jec = ny - 1 + +# grid_info_dict['isc'] = 0 +# grid_info_dict['iec'] = nx - 1 +# grid_info_dict['jsc'] = 0 +# grid_info_dict['jec'] = ny - 1 + + +# return grid_info_dict + +# def grid_writer( +# grid_obj: HGridObj, +# info_dict: dict, +# grid_name: str = "horizontal_grid", +# ntiles: int = 1, +# out_halo: int = 0, +# ): +# north_pole_tile = "0.0 90.0" +# north_pole_arcx = "0.0 90.0" +# geometry = "spherical" +# projection = "none" +# conformal = "true" +# discretization = "logically_rectangular" +# output_length_angle = 1 +# pos_c = 0 +# pos_e = 0 +# pos_t = 0 +# pos_n = 0 +# for n in range(ntiles): +# grid_obj.tile = "tile" + str(n+1) +# if ntiles > 1: +# outfile = grid_name + ".tile" + ".nc" + str(n+1) +# else: +# outfile = grid_name + ".nc" - nx = info_dict['nxl'][n] - ny = info_dict['nyl'][n] - nxp = nx + 1 - nyp = ny + 1 - - if out_halo == 0: - grid_obj.x = grid_obj.x[pos_c:] - grid_obj.y = grid_obj.y[pos_c:] - grid_obj.dx = grid_obj.dx[pos_n:] - grid_obj.dy = grid_obj.dy[pos_e:] - grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] - grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] - grid_obj.area = grid_obj.area[pos_t:] - else: - tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) - grid_obj.x = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) - grid_obj.y = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) - grid_obj.angle_dx = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) - grid_obj.angle_dy = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) - grid_obj.dx = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) - grid_obj.dy = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) - grid_obj.area = tmp.copy() - - nx = info_dict['nxl'][n] - ny = info_dict['nyl'][n] - nxp = nx + 1 - nyp = ny + 1 - pos_c += nxp*nyp - pos_e += nxp*ny - pos_n += nx*nyp - pos_t += nx*ny - - prov_attrs = get_provenance_attrs(great_circle_algorithm=True) - grid_obj.write_out_hgrid( - outfile=outfile, - nx=nx, - ny=ny, - nxp=nxp, - nyp=nyp, - global_attrs=prov_attrs, - north_pole_tile=north_pole_tile, - north_pole_arcx=north_pole_arcx, - projection=projection, - geometry=geometry, - discretization=discretization, - conformal=conformal, - out_halo=out_halo, - output_length_angle=output_length_angle, - ) +# nx = info_dict['nxl'][n] +# ny = info_dict['nyl'][n] +# nxp = nx + 1 +# nyp = ny + 1 + +# if out_halo == 0: +# grid_obj.x = grid_obj.x[pos_c:] +# grid_obj.y = grid_obj.y[pos_c:] +# grid_obj.dx = grid_obj.dx[pos_n:] +# grid_obj.dy = grid_obj.dy[pos_e:] +# grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] +# grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] +# grid_obj.area = grid_obj.area[pos_t:] +# else: +# tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) +# grid_obj.x = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) +# grid_obj.y = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) +# grid_obj.angle_dx = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) +# grid_obj.angle_dy = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) +# grid_obj.dx = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) +# grid_obj.dy = tmp.copy() +# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) +# grid_obj.area = tmp.copy() + +# nx = info_dict['nxl'][n] +# ny = info_dict['nyl'][n] +# nxp = nx + 1 +# nyp = ny + 1 +# pos_c += nxp*nyp +# pos_e += nxp*ny +# pos_n += nx*nyp +# pos_t += nx*ny + +# prov_attrs = get_provenance_attrs(great_circle_algorithm=True) +# grid_obj.write_out_hgrid( +# outfile=outfile, +# nx=nx, +# ny=ny, +# nxp=nxp, +# nyp=nyp, +# global_attrs=prov_attrs, +# north_pole_tile=north_pole_tile, +# north_pole_arcx=north_pole_arcx, +# projection=projection, +# geometry=geometry, +# discretization=discretization, +# conformal=conformal, +# out_halo=out_halo, +# output_length_angle=output_length_angle, +# ) diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/make_lonlat_grid.py index 18b9c0f..d83732a 100644 --- a/FMSgridtools/make_hgrid/make_lonlat_grid.py +++ b/FMSgridtools/make_hgrid/make_lonlat_grid.py @@ -1,8 +1,6 @@ import numpy as np -import ctypes from FMSgridtools.make_hgrid.hgridobj import HGridObj -from FMSgridtools.make_hgrid.make_hgrid_util import make_grid_info, grid_writer import pyfrenctools def make_lonlat_grid( @@ -45,8 +43,7 @@ def make_lonlat_grid( else: dy_bnds = np.zeros(shape=100, dtype=np.float64) - grid_info_dict = make_grid_info( - grid_obj=grid_obj, + grid_obj.make_grid_info( nxbnds=nxbnds, nybnds=nybnds, nlon=nlon, @@ -63,10 +60,10 @@ def make_lonlat_grid( dlon=dx_bnds, dlat=dy_bnds, use_legacy=0, - isc=grid_info_dict['isc'], - iec=grid_info_dict['iec'], - jsc=grid_info_dict['jsc'], - jec=grid_info_dict['jec'], + isc=grid_obj.isc, + iec=grid_obj.iec, + jsc=grid_obj.jsc, + jec=grid_obj.jec, x=grid_obj.x, y=grid_obj.y, dx=grid_obj.dx, @@ -77,10 +74,7 @@ def make_lonlat_grid( use_great_circle_algorithm=use_great_circle_algorithm, ) - grid_writer( - grid_obj=grid_obj, - info_dict=grid_info_dict, - ) + grid_obj.write_out_hgrid() From ce35f9f37228f99efadc4796a412b5210c48f3b3 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 28 Apr 2025 12:11:00 -0400 Subject: [PATCH 52/72] Added in verbose flags for make_hgrid --- FMSgridtools/make_hgrid/hgridobj.py | 122 +++++++++++++++----- FMSgridtools/make_hgrid/make_hgrid.py | 9 +- FMSgridtools/make_hgrid/make_lonlat_grid.py | 6 +- 3 files changed, 103 insertions(+), 34 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index eda4f58..548012a 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -1,9 +1,10 @@ +import sys import ctypes import numpy as np from numpy.typing import NDArray import xarray as xr -from FMSgridtools.shared.gridtools_utils import check_file_is_there, get_provenance_attrs +from FMSgridtools.shared.gridtools_utils import get_provenance_attrs from FMSgridtools.shared.gridobj import GridObj import pyfrenctools @@ -31,8 +32,8 @@ def __init__(self): def make_grid_info( self, - nxbnds: int, - nybnds: int, + nxbnds: int=None, + nybnds: int=None, ntiles: int=1, ntiles_global: int=1, nlon: NDArray=None, @@ -46,11 +47,28 @@ def make_grid_info( jend_nest: NDArray=None, arcx: str="small_circle", grid_type: str=None, + conformal: str="true", + output_length_angle: bool=True, + verbose: bool=False, ): + """Get super grid size""" + self.nxl = np.empty(shape=ntiles, dtype=np.int32) self.nyl = np.empty(shape=ntiles, dtype=np.int32) if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": + """ + NOTE: The if-block in the loop below is changed with multiple nests. + It appeared to allow refinement of the global grid + without using any nests. However, the method used the + nesting parameters "parent_tile" and "refine_ratio" to + achieve this, which was enabled by setting parent_tile = 0 . + This is no longer possible, as parent_tile is now an array. + Instead, if the first value in the list of parent_tile values is 0, + then the first value in the list of refine_ratio values will be + applied to the global grid. This global-refinement application + may not be valid for all permutations of nesting and refinement. [Ahern] + """ for n in range(ntiles_global): self.nxl[n] = nlon[0] self.nyl[n] = self.nxl[n] @@ -62,6 +80,7 @@ def make_grid_info( nn = n - ntiles_global self.nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] self.nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] + elif grid_type == "FROM_FILE": for n in range(ntiles_global): self.nxl[n] = nlon[n] @@ -79,44 +98,59 @@ def make_grid_info( self.nxp = self.nx + 1 self.nyp = self.ny + 1 + """Create grid information""" + size1 = ctypes.c_ulong(0) size2 = ctypes.c_ulong(0) size3 = ctypes.c_ulong(0) size4 = ctypes.c_ulong(0) + for n_nest in range(ntiles): + print(f"[INFO] tile: {n_nest}, {self.nxl[n_nest]}, {self.nyl[n_nest]}, ntiles: {ntiles}\n") + if grid_type == "FROM_FILE": + size1 = 0 + size2 = 0 + size3 = 0 + size4 = 0 for n in range(ntiles_global): size1.value += (nlon[n] + 1) * (nlat[n] + 1) size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) - size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) + size3.value += (nlon[n] + 1 + 1) * (nlat[n] + 1) size4.value += (nlon[n] + 1) * (nlat[n] + 1) else: size1 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) - size2 = ctypes.c_ulong(self.nxp * (self.nyp + 1) * ntiles_global) - size3 = ctypes.c_ulong((self.nxp + 1) * self.nyp * ntiles_global) - size4 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) + size2 = ctypes.c_ulong(self.nx * self.nyp * ntiles_global) + size3 = ctypes.c_ulong(self.nxp * self.ny * ntiles_global) + size4 = ctypes.c_ulong(self.nx * self.ny * ntiles_global) if not (nest_grids == 1 and parent_tile[0] == 0): for n_nest in range(ntiles_global, ntiles_global+nest_grids): + if verbose: + print(f"[INFO] Adding memory size for nest {n_nest}, nest_grids: {nest_grids}\n", file=sys.stderr) size1.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+1) size2.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+2) size3.value += (self.nxl[n_nest]+2) * (self.nyl[n_nest]+1) size4.value += (self.nxl[n_nest]+1) * (self.nyl[n_nest]+1) + if verbose: + print(f"[INFO] Allocating arrays of size {size1.value} for x, y based on nxp: {self.nxp} nyp: {self.nyp} ntiles: {ntiles}\n", file=sys.stderr) + print(f"size1 = {size1.value}, size2 = {size2.value}, size3 = {size3.value}, size4 = {size4.value}") self.x = np.empty(shape=size1.value, dtype=np.float64) self.y = np.empty(shape=size1.value, dtype=np.float64) self.area = np.empty(shape=size4.value, dtype=np.float64) self.arcx = arcx - self.dx = np.empty(shape=size2.value, dtype=np.float64) - self.dy = np.empty(shape=size3.value, dtype=np.float64) - self.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - self.angle_dy = np.empty(shape=size1.value, dtype=np.float64) + if output_length_angle: + self.dx = np.empty(shape=size2.value, dtype=np.float64) + self.dy = np.empty(shape=size3.value, dtype=np.float64) + self.angle_dx = np.empty(shape=size1.value, dtype=np.float64) + if conformal != "true": + self.angle_dy = np.empty(shape=size1.value, dtype=np.float64) self.isc = 0 self.iec = self.nx - 1 self.jsc = 0 self.jec = self.ny - 1 - def write_out_hgrid( self, grid_name: str="horizontal_grid", @@ -128,7 +162,8 @@ def write_out_hgrid( discretization: str="logically_rectangular", conformal: str="true", out_halo: int=0, - output_length_angle: int=0, + output_length_angle: bool=True, + verbose: bool=False, ): var_dict={} @@ -142,42 +177,67 @@ def write_out_hgrid( outfile = grid_name + ".tile" + ".nc" + str(n+1) else: outfile = grid_name + ".nc" + + if verbose: + print(f"Writing out {outfile}\n", file=sys.stderr) + """define dimension""" nx = self.nxl[n] ny = self.nyl[n] + if verbose: + print(f"[INFO] Outputting arrays of size nx: {nx} and ny: {ny} for tile: {n}") nxp = nx + 1 nyp = ny + 1 if out_halo == 0: + if verbose: + print(f"[INFO] START NC XARRAY write out_halo={out_halo} tile number = {n} offset = pos_c: {pos_c}", file=sys.stderr) + print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[1]: {self.x[pos_c+1]} x[2]: {self.x[pos_c+2]} x[3]: {self.x[pos_c+3]} x[4]: {self.x[pos_c+4]} x[5]: {self.x[pos_c+5]} x[10]: {self.x[pos_c+10]}", file=sys.stderr) + if n > 0: + print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[-1]: {self.x[pos_c-1]} x[-2]: {self.x[pos_c-2]} x[-3]: {self.x[pos_c-3]} x[-4]: {self.x[pos_c-4]} x[-5]: {self.x[pos_c-5]} x[-10]: {self.x[pos_c-10]}", file=sys.stderr) self.x = self.x[pos_c:] self.y = self.y[pos_c:] - self.dx = self.dx[pos_n:] - self.dy = self.dy[pos_e:] - self.angle_dx = self.angle_dx[pos_c:] - self.angle_dy = self.angle_dy[pos_c:] self.area = self.area[pos_t:] + if output_length_angle: + self.dx = self.dx[pos_n:] + self.dy = self.dy[pos_e:] + self.angle_dx = self.angle_dx[pos_c:] + if conformal != "true": + self.angle_dy = self.angle_dy[pos_c:] else: tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + if verbose: + print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) self.x = tmp.copy() pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) self.y = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) - self.angle_dx = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) - self.angle_dy = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) - self.dx = tmp.copy() - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) - self.dy = tmp.copy() pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) self.area = tmp.copy() + if output_length_angle: + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) + self.dx = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) + self.dy = tmp.copy() + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) + self.angle_dx = tmp.copy() + if conformal != "true": + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) + self.angle_dy = tmp.copy() + + if verbose: + print(f"About to close {outfile}") nx = self.nxl[n] ny = self.nyl[n] nxp = nx + 1 nyp = ny + 1 + + if verbose: + print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}\n", file=sys.stderr) pos_c += nxp*nyp + if verbose: + print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}\n.", file=sys.stderr) pos_e += nxp*ny pos_n += nx*nyp pos_t += nx*ny @@ -199,7 +259,7 @@ def write_out_hgrid( if self.x is not None: x = xr.DataArray( - data=self.x[:(nyp*nxp)].reshape((nyp,nxp)), + data=self.x.reshape((nyp,nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_east", @@ -214,7 +274,7 @@ def write_out_hgrid( if self.y is not None: y = xr.DataArray( - data=self.y[:(nyp*nxp)].reshape((nyp, nxp)), + data=self.y.reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_north", @@ -230,7 +290,7 @@ def write_out_hgrid( if output_length_angle: if self.dx is not None: dx = xr.DataArray( - data=self.dx[:(nyp*nx)].reshape((nyp, nx)), + data=self.dx.reshape((nyp, nx)), dims=["nyp", "nx"], attrs=dict( units="meters", @@ -245,7 +305,7 @@ def write_out_hgrid( if self.dy is not None: dy = xr.DataArray( - data=self.dy[:(ny*nxp)].reshape((ny, nxp)), + data=self.dy.reshape((ny, nxp)), dims=["ny", "nxp"], attrs=dict( units="meters", @@ -260,7 +320,7 @@ def write_out_hgrid( if self.angle_dx is not None: angle_dx = xr.DataArray( - data=self.angle_dx[:(nyp*nxp)].reshape((nyp, nxp)), + data=self.angle_dx.reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degrees_east", @@ -291,7 +351,7 @@ def write_out_hgrid( if self.area is not None: area = xr.DataArray( - data=self.area[:(ny*nx)].reshape((ny, nx)), + data=self.area.reshape((ny, nx)), dims=["ny", "nx"], attrs=dict( units="m2", diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 06f65ea..181e453 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -55,6 +55,11 @@ def make_hgrid(): help="When specified, great_circle_algorithm will be used to compute grid \ cell area.", ) +@click.option( + "--verbose", + is_flag=True, + default=False, +) def lonlat( nlon, nlat, @@ -62,7 +67,8 @@ def lonlat( ybnds, dlon, dlat, - use_great_circle_algorithm + use_great_circle_algorithm, + verbose, ): make_lonlat_grid( nlon=nlon, @@ -72,4 +78,5 @@ def lonlat( dlon=dlon, dlat=dlat, use_great_circle_algorithm=use_great_circle_algorithm, + verbose=verbose, ) \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/make_lonlat_grid.py index d83732a..aafd099 100644 --- a/FMSgridtools/make_hgrid/make_lonlat_grid.py +++ b/FMSgridtools/make_hgrid/make_lonlat_grid.py @@ -10,7 +10,8 @@ def make_lonlat_grid( ybnds: str = None, dlon: str = None, dlat: str = None, - use_great_circle_algorithm: bool = False + use_great_circle_algorithm: bool = False, + verbose: bool = False, ): center = "none" grid_obj = HGridObj() @@ -48,6 +49,7 @@ def make_lonlat_grid( nybnds=nybnds, nlon=nlon, nlat=nlat, + verbose=verbose, ) pyfrenctools.make_hgrid_wrappers.create_regular_lonlat_grid( @@ -74,7 +76,7 @@ def make_lonlat_grid( use_great_circle_algorithm=use_great_circle_algorithm, ) - grid_obj.write_out_hgrid() + grid_obj.write_out_hgrid(verbose=verbose) From 0153736540db9c02820621d5ffff3fc2280ca47d Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 28 Apr 2025 12:12:48 -0400 Subject: [PATCH 53/72] Removed hgrid_util file --- FMSgridtools/make_hgrid/make_hgrid_util.py | 194 --------------------- 1 file changed, 194 deletions(-) delete mode 100644 FMSgridtools/make_hgrid/make_hgrid_util.py diff --git a/FMSgridtools/make_hgrid/make_hgrid_util.py b/FMSgridtools/make_hgrid/make_hgrid_util.py deleted file mode 100644 index 2a9c5f2..0000000 --- a/FMSgridtools/make_hgrid/make_hgrid_util.py +++ /dev/null @@ -1,194 +0,0 @@ -# import numpy as np -# from numpy.typing import NDArray -# import ctypes - -# from FMSgridtools.make_hgrid.hgridobj import HGridObj -# from FMSgridtools.shared.gridtools_utils import get_provenance_attrs -# import pyfrenctools - -# def make_grid_info( -# grid_obj: HGridObj, -# nxbnds: int, -# nybnds: int, -# ntiles: int = 1, -# ntiles_global: int = 1, -# nlon: NDArray = None, -# nlat: NDArray = None, -# nest_grids: int = 0, -# parent_tile: NDArray = None, -# refine_ratio: NDArray = None, -# istart_nest: NDArray = None, -# iend_nest: NDArray = None, -# jstart_nest: NDArray = None, -# jend_nest: NDArray = None, -# arcx: str = "small_circle", -# grid_type: str = None, -# ) -> dict: - -# nxl = np.empty(shape=ntiles, dtype=np.int32) -# nyl = np.empty(shape=ntiles, dtype=np.int32) - -# if grid_type == "GNOMONIC_ED" or grid_type == "CONFORMAL_CUBIC_GRID": -# for n in range(ntiles_global): -# nxl[n] = nlon[0] -# nyl[n] = nxl[n] -# if nest_grids and parent_tile[0] == 0: -# nxl[n] *= refine_ratio[0] -# nyl[n] *= refine_ratio[0] - -# for n in range(ntiles_global, ntiles): -# nn = n - ntiles_global -# nxl[n] = (iend_nest[nn] - istart_nest[nn] + 1) * refine_ratio[nn] -# nyl[n] = (jend_nest[nn] - jstart_nest[nn] + 1) * refine_ratio[nn] -# elif grid_type == "FROM_FILE": -# for n in range(ntiles_global): -# nxl[n] = nlon[n] -# nyl[n] = nlat[n] -# else: -# nxl[0] = 0 -# nyl[0] = 0 -# for n in range(nxbnds - 1): -# nxl[0] += nlon[n] -# for n in range(nybnds - 1): -# nyl[0] += nlat[n] - -# nx = nxl[0] -# ny = nyl[0] -# nxp = nx + 1 -# nyp = ny + 1 -# grid_info_dict = {} -# grid_info_dict['nx'] = nx -# grid_info_dict['ny'] = ny -# grid_info_dict['nxp'] = nxp -# grid_info_dict['nyp'] = nyp -# grid_info_dict['nxl'] = nxl -# grid_info_dict['nyl'] = nyl - -# size1 = ctypes.c_ulong(0) -# size2 = ctypes.c_ulong(0) -# size3 = ctypes.c_ulong(0) -# size4 = ctypes.c_ulong(0) - -# if grid_type == "FROM_FILE": -# for n in range(ntiles_global): -# size1.value += (nlon[n] + 1) * (nlat[n] + 1) -# size2.value += (nlon[n] + 1) * (nlat[n] + 1 + 1) -# size3.value += (nlon[n] + 1 +1) * (nlat[n] + 1) -# size4.value += (nlon[n] + 1) * (nlat[n] + 1) -# else: -# size1 = ctypes.c_ulong(nxp * nyp * ntiles_global) -# size2 = ctypes.c_ulong(nxp * (nyp + 1) * ntiles_global) -# size3 = ctypes.c_ulong((nxp + 1) * nyp * ntiles_global) -# size4 = ctypes.c_ulong(nxp * nyp * ntiles_global) - -# if not (nest_grids == 1 and parent_tile[0] == 0): -# for n_nest in range(ntiles_global, ntiles_global+nest_grids): -# size1.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) -# size2.value += (nxl[n_nest]+1) * (nyl[n_nest]+2) -# size3.value += (nxl[n_nest]+2) * (nyl[n_nest]+1) -# size4.value += (nxl[n_nest]+1) * (nyl[n_nest]+1) - -# grid_obj.x = np.empty(shape=size1.value, dtype=np.float64) -# grid_obj.y = np.empty(shape=size1.value, dtype=np.float64) -# grid_obj.area = np.empty(shape=size4.value, dtype=np.float64) -# grid_obj.arcx = arcx -# grid_obj.dx = np.empty(shape=size2.value, dtype=np.float64) -# grid_obj.dy = np.empty(shape=size3.value, dtype=np.float64) -# grid_obj.angle_dx = np.empty(shape=size1.value, dtype=np.float64) -# grid_obj.angle_dy = np.empty(shape=size1.value, dtype=np.float64) - -# isc = 0 -# iec = nx - 1 -# jsc = 0 -# jec = ny - 1 - -# grid_info_dict['isc'] = 0 -# grid_info_dict['iec'] = nx - 1 -# grid_info_dict['jsc'] = 0 -# grid_info_dict['jec'] = ny - 1 - - -# return grid_info_dict - -# def grid_writer( -# grid_obj: HGridObj, -# info_dict: dict, -# grid_name: str = "horizontal_grid", -# ntiles: int = 1, -# out_halo: int = 0, -# ): -# north_pole_tile = "0.0 90.0" -# north_pole_arcx = "0.0 90.0" -# geometry = "spherical" -# projection = "none" -# conformal = "true" -# discretization = "logically_rectangular" -# output_length_angle = 1 -# pos_c = 0 -# pos_e = 0 -# pos_t = 0 -# pos_n = 0 -# for n in range(ntiles): -# grid_obj.tile = "tile" + str(n+1) -# if ntiles > 1: -# outfile = grid_name + ".tile" + ".nc" + str(n+1) -# else: -# outfile = grid_name + ".nc" - -# nx = info_dict['nxl'][n] -# ny = info_dict['nyl'][n] -# nxp = nx + 1 -# nyp = ny + 1 - -# if out_halo == 0: -# grid_obj.x = grid_obj.x[pos_c:] -# grid_obj.y = grid_obj.y[pos_c:] -# grid_obj.dx = grid_obj.dx[pos_n:] -# grid_obj.dy = grid_obj.dy[pos_e:] -# grid_obj.angle_dx = grid_obj.angle_dx[pos_c:] -# grid_obj.angle_dy = grid_obj.angle_dy[pos_c:] -# grid_obj.area = grid_obj.area[pos_t:] -# else: -# tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.x, grid_obj.x, n, 1, 1) -# grid_obj.x = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.y, grid_obj.y, n, 1, 1) -# grid_obj.y = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dx, grid_obj.angle_dx, n, 1, 1) -# grid_obj.angle_dx = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.angle_dy, grid_obj.angle_dy, n, 1, 1) -# grid_obj.angle_dy = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dx, grid_obj.dy, n, 0, 1) -# grid_obj.dx = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.dy, grid_obj.dx, n, 1, 0) -# grid_obj.dy = tmp.copy() -# pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, grid_obj.area, grid_obj.area, n, 0, 0) -# grid_obj.area = tmp.copy() - -# nx = info_dict['nxl'][n] -# ny = info_dict['nyl'][n] -# nxp = nx + 1 -# nyp = ny + 1 -# pos_c += nxp*nyp -# pos_e += nxp*ny -# pos_n += nx*nyp -# pos_t += nx*ny - -# prov_attrs = get_provenance_attrs(great_circle_algorithm=True) -# grid_obj.write_out_hgrid( -# outfile=outfile, -# nx=nx, -# ny=ny, -# nxp=nxp, -# nyp=nyp, -# global_attrs=prov_attrs, -# north_pole_tile=north_pole_tile, -# north_pole_arcx=north_pole_arcx, -# projection=projection, -# geometry=geometry, -# discretization=discretization, -# conformal=conformal, -# out_halo=out_halo, -# output_length_angle=output_length_angle, -# ) - From f1dcf6a1746ecaae348dcc58f9be570fd91af115 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 29 Apr 2025 11:38:41 -0400 Subject: [PATCH 54/72] Changes to hgrid write_out_grid looping for multiple file output --- FMSgridtools/make_hgrid/hgridobj.py | 344 +++++++++++++++------------- 1 file changed, 189 insertions(+), 155 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 548012a..3d1000d 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -171,6 +171,7 @@ def write_out_hgrid( pos_e = 0 pos_t = 0 pos_n = 0 + for n in range(ntiles): self.tile = "tile" + str(n+1) if ntiles > 1: @@ -180,6 +181,39 @@ def write_out_hgrid( if verbose: print(f"Writing out {outfile}\n", file=sys.stderr) + + tile = xr.DataArray( + [self.tile], + attrs=dict( + standard_name="grid_tile_spec", + geometry=geometry, + discretization=discretization, + conformal=conformal, + ) + ) + if north_pole_tile is "none": + tile = tile.assign_attrs(projection=projection) + if projection is "none": + tile = tile.assign_attrs(north_pole_tile=north_pole_tile) + var_dict['tile'] = tile + + if north_pole_arcx == "none": + arcx = xr.DataArray( + [self.arcx], + attrs=dict( + standard_name="grid_edge_x_arc_type", + ) + ) + else: + arcx = xr.DataArray( + [self.arcx], + attrs=dict( + standard_name="grid_edge_x_arc_type", + north_pole=north_pole_arcx, + ) + ) + + var_dict['arcx'] = arcx """define dimension""" nx = self.nxl[n] @@ -195,38 +229,175 @@ def write_out_hgrid( print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[1]: {self.x[pos_c+1]} x[2]: {self.x[pos_c+2]} x[3]: {self.x[pos_c+3]} x[4]: {self.x[pos_c+4]} x[5]: {self.x[pos_c+5]} x[10]: {self.x[pos_c+10]}", file=sys.stderr) if n > 0: print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[-1]: {self.x[pos_c-1]} x[-2]: {self.x[pos_c-2]} x[-3]: {self.x[pos_c-3]} x[-4]: {self.x[pos_c-4]} x[-5]: {self.x[pos_c-5]} x[-10]: {self.x[pos_c-10]}", file=sys.stderr) - self.x = self.x[pos_c:] - self.y = self.y[pos_c:] - self.area = self.area[pos_t:] + x = xr.DataArray( + data=self.x[pos_c:].reshape((nyp,nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_east", + standard_name="geographic_longitude", + ) + ) + var_dict['x'] = x + + y = xr.DataArray( + data=self.y[pos_c:].reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_north", + standard_name="geographic_latitude", + ) + ) + var_dict['y'] = y + + area = xr.DataArray( + data=self.area[pos_t:].reshape((ny, nx)), + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", + ) + ) + var_dict['area'] = area + if output_length_angle: - self.dx = self.dx[pos_n:] - self.dy = self.dy[pos_e:] - self.angle_dx = self.angle_dx[pos_c:] + dx = xr.DataArray( + data=self.dx[pos_n:].reshape((nyp, nx)), + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", + ) + ) + var_dict['dx'] = dx + + dy = xr.DataArray( + data=self.dy[pos_e:].reshape((ny, nxp)), + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", + ) + ) + var_dict['dy'] = dy + + angle_dx = xr.DataArray( + data=self.angle_dx[pos_c:].reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", + ) + ) + var_dict['angle_dx'] = angle_dx + if conformal != "true": - self.angle_dy = self.angle_dy[pos_c:] + angle_dy = xr.DataArray( + data=self.angle_dy[pos_c:].reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_north", + standard_name="grid_vertex_y_angle_WRT_geographic_north", + ) + ) + var_dict['angle_dy'] = angle_dy else: tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + if verbose: print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) self.x = tmp.copy() + x = xr.DataArray( + data=self.x.reshape((nyp,nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_east", + standard_name="geographic_longitude", + _FillValue=-9999., + ) + ) + var_dict['x'] = x + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) self.y = tmp.copy() + y = xr.DataArray( + data=self.y.reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degree_north", + standard_name="geographic_latitude", + _FillValue = -9999., + ) + ) + var_dict['y'] = y + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) self.area = tmp.copy() + area = xr.DataArray( + data=self.area.reshape((ny, nx)), + dims=["ny", "nx"], + attrs=dict( + units="m2", + standard_name="grid_cell_area", + _FillValue=-9999., + ) + ) + var_dict['area'] = area + if output_length_angle: pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) self.dx = tmp.copy() + dx = xr.DataArray( + data=self.dx.reshape((nyp, nx)), + dims=["nyp", "nx"], + attrs=dict( + units="meters", + standard_name="grid_edge_x_distance", + _FillValue=-9999., + ) + ) + var_dict['dx'] = dx + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) self.dy = tmp.copy() + dy = xr.DataArray( + data=self.dy.reshape((ny, nxp)), + dims=["ny", "nxp"], + attrs=dict( + units="meters", + standard_name="grid_edge_y_distance", + _FillValue=-9999., + ) + ) + var_dict['dy'] = dy + pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) self.angle_dx = tmp.copy() + angle_dx = xr.DataArray( + data=self.angle_dx.reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_east", + standard_name="grid_vertex_x_angle_WRT_geographic_east", + _FillValue=-9999., + ) + ) + var_dict['angle_dx'] = angle_dx + if conformal != "true": pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) self.angle_dy = tmp.copy() - - if verbose: - print(f"About to close {outfile}") + angle_dy = xr.DataArray( + data=self.angle_dy.reshape((nyp, nxp)), + dims=["nyp", "nxp"], + attrs=dict( + units="degrees_north", + standard_name="grid_vertex_y_angle_WRT_geographic_north", + _FillValue=-9999., + ) + ) + var_dict['angle_dy'] = angle_dy nx = self.nxl[n] ny = self.nyl[n] @@ -242,154 +413,17 @@ def write_out_hgrid( pos_n += nx*nyp pos_t += nx*ny - tile = xr.DataArray( - [self.tile], - attrs=dict( - standard_name="grid_tile_spec", - geometry=geometry, - discretization=discretization, - conformal=conformal, - ) - ) - if north_pole_tile is "none": - tile = tile.assign_attrs(projection=projection) - if projection is "none": - tile = tile.assign_attrs(north_pole_tile=north_pole_tile) - var_dict['tile'] = tile - - if self.x is not None: - x = xr.DataArray( - data=self.x.reshape((nyp,nxp)), - dims=["nyp", "nxp"], - attrs=dict( - units="degree_east", - standard_name="geographic_longitude", - ) - ) - - if out_halo > 0: - x.attrs["_FillValue"] = -9999. - - var_dict['x'] = x - - if self.y is not None: - y = xr.DataArray( - data=self.y.reshape((nyp, nxp)), - dims=["nyp", "nxp"], - attrs=dict( - units="degree_north", - standard_name="geographic_latitude", - ) - ) - - if out_halo > 0: - y.attrs["_FillValue"] = -9999. - - var_dict['y'] = y - - if output_length_angle: - if self.dx is not None: - dx = xr.DataArray( - data=self.dx.reshape((nyp, nx)), - dims=["nyp", "nx"], - attrs=dict( - units="meters", - standard_name="grid_edge_x_distance", - ) - ) - - if out_halo > 0: - dx.attrs["_FillValue"] = -9999. - - var_dict['dx'] = dx - - if self.dy is not None: - dy = xr.DataArray( - data=self.dy.reshape((ny, nxp)), - dims=["ny", "nxp"], - attrs=dict( - units="meters", - standard_name="grid_edge_y_distance", - ) - ) - - if out_halo > 0: - dy.attrs["_FillValue"] = -9999. - - var_dict['dy'] = dy - - if self.angle_dx is not None: - angle_dx = xr.DataArray( - data=self.angle_dx.reshape((nyp, nxp)), - dims=["nyp", "nxp"], - attrs=dict( - units="degrees_east", - standard_name="grid_vertex_x_angle_WRT_geographic_east", - ) - ) - - if out_halo > 0: - angle_dx.attrs["_FillValue"] = -9999. - - var_dict['angle_dx'] = angle_dx - - if conformal != "true": - if self.angle_dy is not None: - angle_dy = xr.DataArray( - data=self.angle_dy.reshape((nyp, nxp)), - dims=["nyp", "nxp"], - attrs=dict( - units="degrees_north", - standard_name="grid_vertex_y_angle_WRT_geographic_north", - ) - ) - - if out_halo > 0: - angle_dy.attrs["_FillValue"] = -9999. - - var_dict['angle_dy'] = angle_dy - - if self.area is not None: - area = xr.DataArray( - data=self.area.reshape((ny, nx)), - dims=["ny", "nx"], - attrs=dict( - units="m2", - standard_name="grid_cell_area", - ) - ) - - if out_halo > 0: - area.attrs["_FillValue"] = -9999. + if verbose: + print(f"About to close {outfile}") - var_dict['area'] = area + prov_attrs = get_provenance_attrs(great_circle_algorithm=True) - if north_pole_arcx == "none": - arcx = xr.DataArray( - [self.arcx], - attrs=dict( - standard_name="grid_edge_x_arc_type", - ) - ) - else: - arcx = xr.DataArray( - [self.arcx], - attrs=dict( - standard_name="grid_edge_x_arc_type", - north_pole=north_pole_arcx, - ) + dataset = xr.Dataset( + data_vars=var_dict ) - - var_dict['arcx'] = arcx - - prov_attrs = get_provenance_attrs(great_circle_algorithm=True) - - dataset = xr.Dataset( - data_vars=var_dict - ) - dataset.attrs = prov_attrs - self.dataset = dataset - dataset.to_netcdf(outfile) + dataset.attrs = prov_attrs + self.dataset = dataset + dataset.to_netcdf(outfile) def make_gridobj(self) -> "GridObj": var_dict = {} From df769dd120f5cf64cd9a687fec64105dc35f0bea Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 29 Apr 2025 11:45:47 -0400 Subject: [PATCH 55/72] Small typo --- FMSgridtools/make_hgrid/hgridobj.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 3d1000d..5bae11e 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -225,7 +225,7 @@ def write_out_hgrid( if out_halo == 0: if verbose: - print(f"[INFO] START NC XARRAY write out_halo={out_halo} tile number = {n} offset = pos_c: {pos_c}", file=sys.stderr) + print(f"[INFO] START NC XARRAY write out_halo = {out_halo} tile number = {n} offset = pos_c: {pos_c}", file=sys.stderr) print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[1]: {self.x[pos_c+1]} x[2]: {self.x[pos_c+2]} x[3]: {self.x[pos_c+3]} x[4]: {self.x[pos_c+4]} x[5]: {self.x[pos_c+5]} x[10]: {self.x[pos_c+10]}", file=sys.stderr) if n > 0: print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[-1]: {self.x[pos_c-1]} x[-2]: {self.x[pos_c-2]} x[-3]: {self.x[pos_c-3]} x[-4]: {self.x[pos_c-4]} x[-5]: {self.x[pos_c-5]} x[-10]: {self.x[pos_c-10]}", file=sys.stderr) @@ -408,7 +408,7 @@ def write_out_hgrid( print(f"[INFO] INDEX Before increment n: {n} pos_c {pos_c} nxp {nxp} nyp {nyp} nxp*nyp {nxp*nyp}\n", file=sys.stderr) pos_c += nxp*nyp if verbose: - print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}\n.", file=sys.stderr) + print(f"[INFO] INDEX After increment n: {n} pos_c {pos_c}\n", file=sys.stderr) pos_e += nxp*ny pos_n += nx*nyp pos_t += nx*ny From 153fae563325de07e6f3fa160ec8e5e3f8ea6b49 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 1 May 2025 11:20:09 -0400 Subject: [PATCH 56/72] Merging in main --- FMSgridtools/shared/mosaicobj.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FMSgridtools/shared/mosaicobj.py b/FMSgridtools/shared/mosaicobj.py index ae368b9..934f782 100755 --- a/FMSgridtools/shared/mosaicobj.py +++ b/FMSgridtools/shared/mosaicobj.py @@ -35,7 +35,7 @@ def _post_init_(self): self.dataset = xr.open_dataset(self.mosaic_file) self.gridfiles = self.get_gridfiles() - def get_gridfiles(self) -> List: + def get_gridfiles(self) -> list: try: return [ifile.decode('ascii') for ifile in self.dataset.gridfiles.values] @@ -43,14 +43,14 @@ def get_gridfiles(self) -> List: print("Error: Mosaic file not provided as an attribute, \ unable to return gridfiles") - def get_ntiles(self) -> List: + def get_ntiles(self) -> list: try: return self.dataset.sizes['ntiles'] except AttributeError: print("Error: Mosaic file not provided as an attribute, \ unable to return number of tiles") - def griddict(self) -> Dict: + def griddict(self) -> dict: if self.gridtiles is None: gridtiles = [tile.decode('ascii') for tile in self.dataset.gridtiles.values] From 745dc8b6a617131443bfa6c5ee95c59040f95c80 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 15 May 2025 14:26:30 -0400 Subject: [PATCH 57/72] Updating pyFMS --- pyFMS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyFMS b/pyFMS index 5ac3671..9efd8d9 160000 --- a/pyFMS +++ b/pyFMS @@ -1 +1 @@ -Subproject commit 5ac36719358fb87b59f89daf3fdcf07a53ab9364 +Subproject commit 9efd8d92716684fd3aa8165efbd251d8aa0d46a9 From ef683c40cea0de506d74acf297795f167a5fa397 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 19 May 2025 10:46:53 -0400 Subject: [PATCH 58/72] In flux change to main branch --- FMSgridtools/make_hgrid/hgridobj.py | 4 +- FMSgridtools/make_hgrid/make_hgrid.py | 16 +- .../make_hgrid/make_hgrid_wrappers.py | 313 +++++++++--------- 3 files changed, 158 insertions(+), 175 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 5bae11e..ed37744 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -191,13 +191,13 @@ def write_out_hgrid( conformal=conformal, ) ) - if north_pole_tile is "none": + if north_pole_tile is None: tile = tile.assign_attrs(projection=projection) if projection is "none": tile = tile.assign_attrs(north_pole_tile=north_pole_tile) var_dict['tile'] = tile - if north_pole_arcx == "none": + if north_pole_arcx is None: arcx = xr.DataArray( [self.arcx], attrs=dict( diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index d64a114..52338de 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -61,14 +61,14 @@ def make_hgrid(): default=False, ) def lonlat( - nlon, - nlat, - xbnds, - ybnds, - dlon, - dlat, - use_great_circle_algorithm, - verbose, + nlon: str, + nlat: str, + xbnds: str, + ybnds: str, + dlon: str, + dlat: str, + use_great_circle_algorithm: bool, + verbose: bool, ): make_lonlat_grid( nlon=nlon, diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py index 8e6fc0b..9da6350 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py @@ -1,6 +1,6 @@ +from ctypes import CDLL, POINTER, c_double, c_int import numpy as np import numpy.typing as npt -import ctypes from pyfms.pyfms_utils.data_handling import ( setscalar_Cint32, @@ -10,179 +10,162 @@ set_Cchar, ) -# lib = ctypes.CDLL("./FREnctools_lib/cfrenctools/c_build/clib.so") +_libpath = None +_lib = None -class make_hgrid_wrappers(): - __libpath: str = None - __lib: ctypes.CDLL = None +def init(libpath: str, lib: type[CDLL]): - @classmethod - def init(cls, libpath, lib): - cls.__libpath = libpath - cls.__lib = lib - - @classmethod - @property - def lib(cls): - return cls.__lib + global _libpath, _lib - @classmethod - @property - def libpath(cls): - return cls.__libpath + _libpath = libpath + _lib = lib - @classmethod - def fill_cubic_grid_halo( - cls, - nx: int, - ny: int, - halo: int, - data: npt.NDArray[np.float64], - data1_all: npt.NDArray[np.float64], - data2_all: npt.NDArray[np.float64], - tile: int, - ioff: int, - joff: int, - ): - nxp = nx + ioff - nyp = ny + joff - nxph = nx + ioff + 2*halo - nyph = ny + joff + 2*halo +def fill_cubic_grid_halo( + nx: int, + ny: int, + halo: int, + data: npt.NDArray[np.float64], + data1_all: npt.NDArray[np.float64], + data2_all: npt.NDArray[np.float64], + tile: int, + ioff: int, + joff: int, +): + nxp = nx + ioff + nyp = ny + joff + nxph = nx + ioff + 2*halo + nyph = ny + joff + 2*halo - for i in range(nxph*nyph): - data[i] = -9999. + for i in range(nxph*nyph): + data[i] = -9999. - # first copy computing domain data - for j in range (nyp+1): - for i in range(nxp+1): - data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] + # first copy computing domain data + for j in range (nyp+1): + for i in range(nxp+1): + data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] - ntiles = 6 + ntiles = 6 - if tile%2 == 1: - lw = (tile+ntiles-1)%ntiles - le = (tile+ntiles+2)%ntiles - ls = (tile+ntiles-2)%ntiles - ln = (tile+ntiles+1)%ntiles - for j in range(nyp+1): - data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo - data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo - for i in range(nxp+1): - data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo - data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo - else: - lw = (tile+ntiles-2)%ntiles - le = (tile+ntiles+1)%ntiles - ls = (tile+ntiles-1)%ntiles - ln = (tile+ntiles+2)%ntiles - for j in range(nyp+1): - data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo - data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo - for i in range(nxp+1): - data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo - data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo - - @classmethod - def create_regular_lonlat_grid( - cls, - nxbnds: int, - nybnds: int, - xbnds: npt.NDArray, - ybnds: npt.NDArray, - nlon: npt.NDArray, - nlat: npt.NDArray, - dlon: npt.NDArray, - dlat: npt.NDArray, - use_legacy: int, - isc: int, - iec: int, - jsc: int, - jec: int, - x: npt.NDArray, - y: npt.NDArray, - dx: npt.NDArray, - dy: npt.NDArray, - area: npt.NDArray, - angle_dx: npt.NDArray, - center: str, - use_great_circle_algorithm: int - ): - _create_regular_lonlat_grid = cls.lib.create_regular_lonlat_grid - - # nxbnds_c, nxbnds_t = ctypes.c_int(nxbnds), ctypes.POINTER(ctypes.c_int) - # nybnds_c, nybnds_t = ctypes.c_int(nybnds), ctypes.POINTER(ctypes.c_int) - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds, xbnds_t = setarray_Cdouble(xbnds) - ybnds, ybnds_t = setarray_Cdouble(ybnds) - nlon, nlon_t = setarray_Cint32(nlon) - nlat, nlat_t = setarray_Cint32(nlat) - dlon, dlon_t = setarray_Cdouble(dlon) - dlat, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x, x_t = setarray_Cdouble(x) - y, y_t = setarray_Cdouble(y) - dx, dx_t = setarray_Cdouble(dx) - dy, dy_t = setarray_Cdouble(dy) - area, area_t = setarray_Cdouble(area) - angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int - - _create_regular_lonlat_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - use_great_circle_algorithm_t, - ] - _create_regular_lonlat_grid.restype = None - - _create_regular_lonlat_grid( - nxbnds_c, - nybnds_c, - xbnds, - ybnds, - nlon, - nlat, - dlon, - dlat, - use_legacy_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x, - y, - dx, - dy, - area, - angle_dx, - center_c, - use_great_circle_algorithm_c, - ) + if tile%2 == 1: + lw = (tile+ntiles-1)%ntiles + le = (tile+ntiles+2)%ntiles + ls = (tile+ntiles-2)%ntiles + ln = (tile+ntiles+1)%ntiles + for j in range(nyp+1): + data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo + data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo + for i in range(nxp+1): + data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo + data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo + else: + lw = (tile+ntiles-2)%ntiles + le = (tile+ntiles+1)%ntiles + ls = (tile+ntiles-1)%ntiles + ln = (tile+ntiles+2)%ntiles + for j in range(nyp+1): + data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo + data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo + for i in range(nxp+1): + data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo + data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo + +def create_regular_lonlat_grid( + nxbnds: int, + nybnds: int, + xbnds: npt.NDArray, + ybnds: npt.NDArray, + nlon: npt.NDArray, + nlat: npt.NDArray, + dlon: npt.NDArray, + dlat: npt.NDArray, + use_legacy: int, + isc: int, + iec: int, + jsc: int, + jec: int, + x: npt.NDArray, + y: npt.NDArray, + dx: npt.NDArray, + dy: npt.NDArray, + area: npt.NDArray, + angle_dx: npt.NDArray, + center: str, + use_great_circle_algorithm: int +): + _create_regular_lonlat_grid = _lib.create_regular_lonlat_grid + + nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + xbnds, xbnds_t = setarray_Cdouble(xbnds) + ybnds, ybnds_t = setarray_Cdouble(ybnds) + nlon, nlon_t = setarray_Cint32(nlon) + nlat, nlat_t = setarray_Cint32(nlat) + dlon, dlon_t = setarray_Cdouble(dlon) + dlat, dlat_t = setarray_Cdouble(dlat) + use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + isc_c, isc_t = setscalar_Cint32(isc) + iec_c, iec_t = setscalar_Cint32(iec) + jsc_c, jsc_t = setscalar_Cint32(jsc) + jec_c, jec_t = setscalar_Cint32(jec) + x, x_t = setarray_Cdouble(x) + y, y_t = setarray_Cdouble(y) + dx, dx_t = setarray_Cdouble(dx) + dy, dy_t = setarray_Cdouble(dy) + area, area_t = setarray_Cdouble(area) + angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) + center_c, center_t = set_Cchar(center) + use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int + + _create_regular_lonlat_grid.argtypes = [ + nxbnds_t, + nybnds_t, + xbnds_t, + ybnds_t, + nlon_t, + nlat_t, + dlon_t, + dlat_t, + use_legacy_t, + isc_t, + iec_t, + jsc_t, + jec_t, + x_t, + y_t, + dx_t, + dy_t, + area_t, + angle_dx_t, + center_t, + use_great_circle_algorithm_t, + ] + + _create_regular_lonlat_grid.restype = None + + _create_regular_lonlat_grid( + nxbnds_c, + nybnds_c, + xbnds, + ybnds, + nlon, + nlat, + dlon, + dlat, + use_legacy_c, + isc_c, + iec_c, + jsc_c, + jec_c, + x, + y, + dx, + dy, + area, + angle_dx, + center_c, + use_great_circle_algorithm_c, + ) - @classmethod def create_tripolar_grid( cls, nxbnds: int, From 4624878013f132f29fcb9551d4ecc89e545f74d3 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Thu, 22 May 2025 14:13:05 -0400 Subject: [PATCH 59/72] Switching to main --- FREnctools_lib/setup.py | 10 ++++------ setup.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/FREnctools_lib/setup.py b/FREnctools_lib/setup.py index 7c9aff2..c7e4a72 100644 --- a/FREnctools_lib/setup.py +++ b/FREnctools_lib/setup.py @@ -1,13 +1,11 @@ -import os import subprocess -from pathlib import Path from typing import List from setuptools import find_namespace_packages, setup -from setuptools.command.install import install +from setuptools.command.build_py import build_py -class CustomInstall(install): +class CustomBuild_Py(build_py): def run(self): with open("compile_log.txt", "w") as f: subprocess.run( @@ -28,7 +26,7 @@ def run(self): stdout=f, stderr=subprocess.STDOUT, ) - install.run(self) + build_py.run(self) test_requirements = ["pytest", "coverage"] develop_requirements = test_requirements + ["pre-commit"] @@ -59,5 +57,5 @@ def run(self): include_package_data=True, version="0.0.1", zip_safe=False, - cmdclass={'install': CustomInstall} + cmdclass={'build_py': CustomBuild_Py} ) diff --git a/setup.py b/setup.py index 47b64a5..9d6f784 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ def local_pkg(name: str, relative_path: str) -> str: "numpy", "xarray", "netCDF4", - local_pkg("pyfms", "pyFMS"), + "pyfms @ git+https://github.com/NOAA-GFDL/pyFMS.git@main", local_pkg("pyfrenctools", "FREnctools_lib") ] From fa84c4d95ebba1385bc8981d64e9358a0d960406 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 23 May 2025 12:09:46 -0400 Subject: [PATCH 60/72] Addressing comments from reviews on 15 May 2025 --- FMSgridtools/__init__.py | 2 +- FMSgridtools/make_hgrid/hgridobj.py | 64 +- .../{make_lonlat_grid.py => lonlat_grid.py} | 2 +- FMSgridtools/make_hgrid/make_hgrid.py | 6 +- FREnctools_lib/MANIFEST.in | 1 + FREnctools_lib/cfrenctools/CMakeLists.txt | 4 +- .../cfrenctools/cmake/FindNetCDF.cmake | 2 +- FREnctools_lib/pyfrenctools/__init__.py | 2 +- FREnctools_lib/pyfrenctools/cfrenctools.py | 4 +- .../make_hgrid/make_hgrid_wrappers.py | 887 ++---------------- 10 files changed, 139 insertions(+), 835 deletions(-) rename FMSgridtools/make_hgrid/{make_lonlat_grid.py => lonlat_grid.py} (98%) create mode 100644 FREnctools_lib/MANIFEST.in diff --git a/FMSgridtools/__init__.py b/FMSgridtools/__init__.py index 9c4cffe..bb5f31f 100644 --- a/FMSgridtools/__init__.py +++ b/FMSgridtools/__init__.py @@ -3,4 +3,4 @@ from .make_hgrid.make_hgrid import make_hgrid from .shared.gridtools_utils import check_file_is_there, get_provenance_attrs from .shared.mosaicobj import MosaicObj -from .shared.xgridobj import XGridObj +# from .shared.xgridobj import XGridObj diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index ed37744..db449e2 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -6,7 +6,55 @@ from FMSgridtools.shared.gridtools_utils import get_provenance_attrs from FMSgridtools.shared.gridobj import GridObj -import pyfrenctools + +def fill_cubic_grid_halo( + nx: int, + ny: int, + halo: int, + data: NDArray[np.float64], + data1_all: NDArray[np.float64], + data2_all: NDArray[np.float64], + tile: int, + ioff: int, + joff: int, +): + nxp = nx + ioff + nyp = ny + joff + nxph = nx + ioff + 2*halo + nyph = ny + joff + 2*halo + + for i in range(nxph*nyph): + data[i] = -9999. + + # first copy computing domain data + for j in range (nyp+1): + for i in range(nxp+1): + data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] + + ntiles = 6 + + if tile%2 == 1: + lw = (tile+ntiles-1)%ntiles + le = (tile+ntiles+2)%ntiles + ls = (tile+ntiles-2)%ntiles + ln = (tile+ntiles+1)%ntiles + for j in range(nyp+1): + data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo + data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo + for i in range(nxp+1): + data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo + data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo + else: + lw = (tile+ntiles-2)%ntiles + le = (tile+ntiles+1)%ntiles + ls = (tile+ntiles-1)%ntiles + ln = (tile+ntiles+2)%ntiles + for j in range(nyp+1): + data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo + data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo + for i in range(nxp+1): + data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo + data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo class HGridObj(): def __init__(self): @@ -306,7 +354,7 @@ def write_out_hgrid( if verbose: print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) self.x = tmp.copy() x = xr.DataArray( data=self.x.reshape((nyp,nxp)), @@ -319,7 +367,7 @@ def write_out_hgrid( ) var_dict['x'] = x - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) self.y = tmp.copy() y = xr.DataArray( data=self.y.reshape((nyp, nxp)), @@ -332,7 +380,7 @@ def write_out_hgrid( ) var_dict['y'] = y - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) self.area = tmp.copy() area = xr.DataArray( data=self.area.reshape((ny, nx)), @@ -346,7 +394,7 @@ def write_out_hgrid( var_dict['area'] = area if output_length_angle: - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) self.dx = tmp.copy() dx = xr.DataArray( data=self.dx.reshape((nyp, nx)), @@ -359,7 +407,7 @@ def write_out_hgrid( ) var_dict['dx'] = dx - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) self.dy = tmp.copy() dy = xr.DataArray( data=self.dy.reshape((ny, nxp)), @@ -372,7 +420,7 @@ def write_out_hgrid( ) var_dict['dy'] = dy - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) self.angle_dx = tmp.copy() angle_dx = xr.DataArray( data=self.angle_dx.reshape((nyp, nxp)), @@ -386,7 +434,7 @@ def write_out_hgrid( var_dict['angle_dx'] = angle_dx if conformal != "true": - pyfrenctools.make_hgrid_wrappers.fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) + fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) self.angle_dy = tmp.copy() angle_dy = xr.DataArray( data=self.angle_dy.reshape((nyp, nxp)), diff --git a/FMSgridtools/make_hgrid/make_lonlat_grid.py b/FMSgridtools/make_hgrid/lonlat_grid.py similarity index 98% rename from FMSgridtools/make_hgrid/make_lonlat_grid.py rename to FMSgridtools/make_hgrid/lonlat_grid.py index aafd099..acedb78 100644 --- a/FMSgridtools/make_hgrid/make_lonlat_grid.py +++ b/FMSgridtools/make_hgrid/lonlat_grid.py @@ -3,7 +3,7 @@ from FMSgridtools.make_hgrid.hgridobj import HGridObj import pyfrenctools -def make_lonlat_grid( +def make( nlon: int, nlat: int, xbnds: str = None, diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 52338de..3b88546 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,11 +1,11 @@ import click -from FMSgridtools.make_hgrid.make_lonlat_grid import make_lonlat_grid +import FMSgridtools.make_hgrid.lonlat_grid as lonlat_grid @click.group() def make_hgrid(): - pass + """Make H-Grid CLI""" @make_hgrid.command() @click.option( @@ -70,7 +70,7 @@ def lonlat( use_great_circle_algorithm: bool, verbose: bool, ): - make_lonlat_grid( + lonlat_grid.make( nlon=nlon, nlat=nlat, xbnds=xbnds, diff --git a/FREnctools_lib/MANIFEST.in b/FREnctools_lib/MANIFEST.in new file mode 100644 index 0000000..7bf36b0 --- /dev/null +++ b/FREnctools_lib/MANIFEST.in @@ -0,0 +1 @@ +global-include *.so \ No newline at end of file diff --git a/FREnctools_lib/cfrenctools/CMakeLists.txt b/FREnctools_lib/cfrenctools/CMakeLists.txt index 33f76c9..1afe7c6 100644 --- a/FREnctools_lib/cfrenctools/CMakeLists.txt +++ b/FREnctools_lib/cfrenctools/CMakeLists.txt @@ -60,11 +60,11 @@ target_link_libraries(clib PUBLIC NetCDF::NetCDF_C # Set the output directory set_target_properties( clib PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/c_build + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../pyfrenctools/c_install POSITION_INDEPENDENT_CODE ON PREFIX "" COMPILE_FLAGS ${OpenACC_C_FLAGS} ) # Install the shared library -install(TARGETS clib DESTINATION c_build) +install(TARGETS clib DESTINATION ../pyfrenctools/c_install) diff --git a/FREnctools_lib/cfrenctools/cmake/FindNetCDF.cmake b/FREnctools_lib/cfrenctools/cmake/FindNetCDF.cmake index 1439ae8..82fe366 100644 --- a/FREnctools_lib/cfrenctools/cmake/FindNetCDF.cmake +++ b/FREnctools_lib/cfrenctools/cmake/FindNetCDF.cmake @@ -334,4 +334,4 @@ foreach( _prefix NetCDF NetCDF4 NETCDF NETCDF4 ${CMAKE_FIND_PACKAGE_NAME} ) set( ${_prefix}_${_COMP}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} ) set( ${_prefix}_${_arg_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} ) endforeach() -endforeach() +endforeach() \ No newline at end of file diff --git a/FREnctools_lib/pyfrenctools/__init__.py b/FREnctools_lib/pyfrenctools/__init__.py index 152a021..54983fd 100644 --- a/FREnctools_lib/pyfrenctools/__init__.py +++ b/FREnctools_lib/pyfrenctools/__init__.py @@ -1,5 +1,5 @@ from . import cfrenctools from .shared import create_xgrid -from .make_hgrid.make_hgrid_wrappers import make_hgrid_wrappers +from .make_hgrid import make_hgrid_wrappers cfrenctools.init() diff --git a/FREnctools_lib/pyfrenctools/cfrenctools.py b/FREnctools_lib/pyfrenctools/cfrenctools.py index a28aa77..7fe55ac 100644 --- a/FREnctools_lib/pyfrenctools/cfrenctools.py +++ b/FREnctools_lib/pyfrenctools/cfrenctools.py @@ -2,9 +2,9 @@ import os from .shared import create_xgrid -from .make_hgrid.make_hgrid_wrappers import make_hgrid_wrappers +from .make_hgrid import make_hgrid_wrappers -_libpath = os.path.dirname(__file__) + "/../cfrenctools/c_build/clib.so" +_libpath = os.path.dirname(__file__) + "/c_install/clib.so" _lib = ctypes.cdll.LoadLibrary(_libpath) def init(libpath: str = None): diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py index 9da6350..ac7fe93 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py @@ -1,13 +1,11 @@ -from ctypes import CDLL, POINTER, c_double, c_int +from ctypes import CDLL, POINTER, c_int, c_double, c_bool, c_char_p import numpy as np import numpy.typing as npt -from pyfms.pyfms_utils.data_handling import ( - setscalar_Cint32, - setscalar_Cdouble, - setarray_Cdouble, - setarray_Cint32, - set_Cchar, +from pyfrenctools.utils.ctypes import ( + set_array, + set_c_int, + set_c_str, ) _libpath = None @@ -18,56 +16,7 @@ def init(libpath: str, lib: type[CDLL]): global _libpath, _lib _libpath = libpath - _lib = lib - -def fill_cubic_grid_halo( - nx: int, - ny: int, - halo: int, - data: npt.NDArray[np.float64], - data1_all: npt.NDArray[np.float64], - data2_all: npt.NDArray[np.float64], - tile: int, - ioff: int, - joff: int, -): - nxp = nx + ioff - nyp = ny + joff - nxph = nx + ioff + 2*halo - nyph = ny + joff + 2*halo - - for i in range(nxph*nyph): - data[i] = -9999. - - # first copy computing domain data - for j in range (nyp+1): - for i in range(nxp+1): - data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] - - ntiles = 6 - - if tile%2 == 1: - lw = (tile+ntiles-1)%ntiles - le = (tile+ntiles+2)%ntiles - ls = (tile+ntiles-2)%ntiles - ln = (tile+ntiles+1)%ntiles - for j in range(nyp+1): - data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo - data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo - for i in range(nxp+1): - data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo - data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo - else: - lw = (tile+ntiles-2)%ntiles - le = (tile+ntiles+1)%ntiles - ls = (tile+ntiles-1)%ntiles - ln = (tile+ntiles+2)%ntiles - for j in range(nyp+1): - data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo - data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo - for i in range(nxp+1): - data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo - data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo + _lib = lib def create_regular_lonlat_grid( nxbnds: int, @@ -93,768 +42,74 @@ def create_regular_lonlat_grid( use_great_circle_algorithm: int ): _create_regular_lonlat_grid = _lib.create_regular_lonlat_grid + # nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) + # nybnds_c, nybnds_t = setscalar_Cint32(nybnds) + # xbnds, xbnds_t = setarray_Cdouble(xbnds) + # ybnds, ybnds_t = setarray_Cdouble(ybnds) + # nlon, nlon_t = setarray_Cint32(nlon) + # nlat, nlat_t = setarray_Cint32(nlat) + # dlon, dlon_t = setarray_Cdouble(dlon) + # dlat, dlat_t = setarray_Cdouble(dlat) + # use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int + # isc_c, isc_t = setscalar_Cint32(isc) + # iec_c, iec_t = setscalar_Cint32(iec) + # jsc_c, jsc_t = setscalar_Cint32(jsc) + # jec_c, jec_t = setscalar_Cint32(jec) + # x, x_t = setarray_Cdouble(x) + # y, y_t = setarray_Cdouble(y) + # dx, dx_t = setarray_Cdouble(dx) + # dy, dy_t = setarray_Cdouble(dy) + # area, area_t = setarray_Cdouble(area) + # angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) + # center_c, center_t = set_Cchar(center) + # use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int + arglist = [] + set_c_int(nxbnds, arglist) + set_c_int(nybnds, arglist) + set_array(xbnds, arglist) + set_array(ybnds, arglist) + set_array(nlon, arglist) + set_array(nlat, arglist) + set_array(dlon, arglist) + set_array(dlat, arglist) + set_c_int(use_legacy, arglist) + set_c_int(isc, arglist) + set_c_int(iec, arglist) + set_c_int(jsc, arglist) + set_c_int(jec, arglist) + set_array(x, arglist) + set_array(y, arglist) + set_array(dx, arglist) + set_array(dy, arglist) + set_array(area, arglist) + set_array(angle_dx, arglist) + set_c_str(center, arglist) + set_c_int(use_great_circle_algorithm, arglist) - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds, xbnds_t = setarray_Cdouble(xbnds) - ybnds, ybnds_t = setarray_Cdouble(ybnds) - nlon, nlon_t = setarray_Cint32(nlon) - nlat, nlat_t = setarray_Cint32(nlat) - dlon, dlon_t = setarray_Cdouble(dlon) - dlat, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x, x_t = setarray_Cdouble(x) - y, y_t = setarray_Cdouble(y) - dx, dx_t = setarray_Cdouble(dx) - dy, dy_t = setarray_Cdouble(dy) - area, area_t = setarray_Cdouble(area) - angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int _create_regular_lonlat_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - use_great_circle_algorithm_t, + POINTER(c_int), + POINTER(c_int), + np.ctypeslib.ndpointer(dtype=xbnds.dtype, ndim=xbnds.ndim, shape=xbnds.shape), + np.ctypeslib.ndpointer(dtype=ybnds.dtype, ndim=ybnds.ndim, shape=ybnds.shape), + np.ctypeslib.ndpointer(dtype=nlon.dtype, ndim=nlon.ndim, shape=nlon.shape), + np.ctypeslib.ndpointer(dtype=nlat.dtype, ndim=nlat.ndim, shape=nlat.ndim), + np.ctypeslib.ndpointer(dtype=dlon.dtype, ndim=dlon.ndim, shape=dlon.shape), + np.ctypeslib.ndpointer(dtype=dlat.dtype, ndim=dlat.ndim, shape=dlat.shape), + c_int, + POINTER(c_int), + POINTER(c_int), + POINTER(c_int), + POINTER(c_int), + np.ctypeslib.ndpointer(dtype=x.dtype, ndim=x.ndim, shape=x.shape), + np.ctypeslib.ndpointer(dtype=y.dtype, ndim=y.ndim, shape=y.shape), + np.ctypeslib.ndpointer(dtype=dx.dtype, ndim=dx.ndim, shape=dx.shape), + np.ctypeslib.ndpointer(dtype=dy.dtype, ndim=dy.ndim, shape=dy.shape), + np.ctypeslib.ndpointer(dtype=area.dtype, ndim=area.ndim, shape=area.shape), + np.ctypeslib.ndpointer(dtype=angle_dx.dtype, ndim=angle_dx.ndim, shape=angle_dx.shape), + c_char_p, + c_int, ] - _create_regular_lonlat_grid.restype = None - _create_regular_lonlat_grid( - nxbnds_c, - nybnds_c, - xbnds, - ybnds, - nlon, - nlat, - dlon, - dlat, - use_legacy_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x, - y, - dx, - dy, - area, - angle_dx, - center_c, - use_great_circle_algorithm_c, - ) - - def create_tripolar_grid( - cls, - nxbnds: int, - nybnds: int, - xbnds: npt.NDArray[np.float64], - ybnds: npt.NDArray[np.float64], - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - dlon: npt.NDArray[np.float64], - dlat: npt.NDArray[np.float64], - use_legacy: int, - lat_join_in: float, - isc: int, - iec: int, - jsc: int, - jec: int, - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - center: str, - verbose: int, - use_great_circle_algorithm: int - ): - _create_tripolar_grid = cls.lib.create_tripolar_grid - - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - dlon_p, dlon_t = setarray_Cdouble(dlon) - dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - lat_join_in_c, lat_join_in_t = setscalar_Cdouble(lat_join_in) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - verbose_c, verbose_t = ctypes.c_int(verbose), ctypes.c_int - use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int - - _create_tripolar_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - lat_join_in_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - verbose_t, - use_great_circle_algorithm_t, - ] - _create_tripolar_grid.restype = None - - _create_tripolar_grid( - nxbnds_c, - nybnds_c, - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - dlon_p, - dlat_p, - use_legacy_c, - lat_join_in_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - center_c, - verbose_c, - use_great_circle_algorithm_c, - ) - - @classmethod - def create_grid_from_file( - cls, - file: str, - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - use_great_circle_algorithm: int, - use_angular_midpoint: int - ): - _create_grid_from_file = cls.lib.create_grid_from_file - - file_c, file_t = set_Cchar(file) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) - use_angular_midpoint_c, use_angular_midpoint_t = ctypes.c_int(use_angular_midpoint), ctypes.c_int - - _create_grid_from_file.argtypes = [ - file_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - use_great_circle_algorithm_t, - use_angular_midpoint_t, - ] - _create_grid_from_file.restype = None - - _create_grid_from_file( - file_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - use_great_circle_algorithm_c, - use_angular_midpoint_c - ) - - @classmethod - def create_simple_cartesian_grid( - cls, - xbnds: npt.NDArray[np.float64], - ybnds: npt.NDArray[np.float64], - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - simple_dx: float, - simple_dy: float, - isc: int, - iec: int, - jsc: int, - jec: int, - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - ): - _create_simple_cartesian_grid = cls.lib.create_simple_cartesian_grid - - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - simple_dx_c, simple_dx_t = setscalar_Cdouble(simple_dx) - simple_dy_c, simple_dy_t = setarray_Cdouble(simple_dy) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - - _create_simple_cartesian_grid.argtypes = [ - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - simple_dx_t, - simple_dy_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - ] - _create_simple_cartesian_grid.restype = None - - _create_simple_cartesian_grid( - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - simple_dx_c, - simple_dy_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - ) - - - @classmethod - def create_spectral_grid( - cls, - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - isc: int, - iec: int, - jsc: int, - jec: int, - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - use_great_circle_algorithm: int, - ): - _create_spectral_grid = cls.lib.create_spectral_grid - - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - use_great_circle_algorithm_c, use_great_circle_algorithm_t = setscalar_Cint32(use_great_circle_algorithm) - - _create_spectral_grid.argtypes = [ - nlon_t, - nlat_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - use_great_circle_algorithm_t, - ] - _create_spectral_grid.restype = None - - _create_spectral_grid( - nlon_p, - nlat_p, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dx_p, - use_great_circle_algorithm_c, - ) - - @classmethod - def create_conformal_cubic_grid( - cls, - npts: int, - nratio: int, - method: str, - orientation: str, - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - angle_dy: npt.NDArray[np.float64], - ): - _create_conformal_cubic_grid = cls.lib.create_conformal_cubic_grid - - npts_c, npts_t = setscalar_Cint32(npts) - nratio_c, nratio_t = setscalar_Cint32(nratio) - method_c, method_t = set_Cchar(method) - orientation_c, orientation_t = set_Cchar(orientation) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - - _create_conformal_cubic_grid.argtypes = [ - npts_t, - nratio_t, - method_t, - orientation_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - ] - _create_conformal_cubic_grid.restype = None - - _create_conformal_cubic_grid( - npts_c, - nratio_c, - method_c, - orientation_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - ) - - @classmethod - def create_gnomonic_cubic_grid_GR( - cls, - grid_type: str, - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - angle_dy: npt.NDArray[np.float64], - shift_fac: float, - do_schmidt: bool, - do_cube_transform: int, - stretch_factor: float, - target_lon: float, - target_lat: float, - nest_grid: int, - parent_tile: int, - refine_ratio: int, - istart_nest: int, - iend_nest: int, - jstart_nest: int, - jend_nest: int, - halo: int, - output_length_angle: int, - ): - _create_gnomonic_cubic_grid_GR = cls.lib.create_gnomonic_cubic_gridGR - - grid_type_c, grid_type_t = set_Cchar(grid_type) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) - do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) - do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) - stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) - target_lon_c, target_lon_t = setscalar_Cint32(target_lon) - target_lat_c, target_lat_t = setscalar_Cint32(target_lat) - nest_grid_c, nest_grid_t = setscalar_Cint32(nest_grid) - parent_tile_c, parent_tile_t = setscalar_Cint32(parent_tile) - refine_ratio_c, refine_ratio_t = setscalar_Cint32(refine_ratio) - istart_nest_c, istart_nest_t = setscalar_Cint32(istart_nest) - iend_nest_c, iend_nest_t = setscalar_Cint32(iend_nest) - jstart_nest_c, jstart_nest_t = setscalar_Cint32(jstart_nest) - jend_nest_c, jend_nest_t = setscalar_Cint32(jend_nest) - halo_c, halo_t = setscalar_Cint32(halo) - output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) - - _create_gnomonic_cubic_grid_GR.argtypes = [ - grid_type_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - shift_fac_t, - do_schmidt_t, - do_cube_transform_t, - stretch_factor_t, - target_lon_t, - target_lat_t, - nest_grid_t, - parent_tile_t, - refine_ratio_t, - istart_nest_t, - iend_nest_t, - jstart_nest_t, - jend_nest_t, - halo_t, - output_length_angle_t, - ] - _create_gnomonic_cubic_grid_GR.restype = None - - _create_gnomonic_cubic_grid_GR( - grid_type_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - shift_fac_c, - do_schmidt_c, - do_cube_transform_c, - stretch_factor_c, - target_lon_c, - target_lat_c, - nest_grid_c, - parent_tile_c, - refine_ratio_c, - istart_nest_c, - iend_nest_c, - jstart_nest_c, - jend_nest_c, - halo_c, - output_length_angle_c, - ) - - @classmethod - def create_gnomonic_cubic_grid( - cls, - grid_type: str, - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - angle_dy: npt.NDArray[np.float64], - shift_fac: float, - do_schmidt: int, - do_cube_transform: int, - stretch_factor: float, - target_lon: float, - target_lat: float, - num_nest_grids: int, - parent_tile: npt.NDArray[np.int32], - refine_ratio: npt.NDArray[np.int32], - istart_nest: npt.NDArray[np.int32], - iend_nest: npt.NDArray[np.int32], - jstart_nest: npt.NDArray[np.int32], - jend_nest: npt.NDArray[np.int32], - halo: int, - output_length_angle: int, - ): - _create_gnomonic_cubic_grid = cls.lib.create_gnomonic_cubic_grid - - grid_type_c, grid_type_t = set_Cchar(grid_type) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - angle_dy_p, angle_dy_t = setarray_Cdouble(angle_dy) - shift_fac_c, shift_fac_t = setscalar_Cdouble(shift_fac) - do_schmidt_c, do_schmidt_t = setscalar_Cint32(do_schmidt) - do_cube_transform_c, do_cube_transform_t = setscalar_Cint32(do_cube_transform) - stretch_factor_c, stretch_factor_t = setscalar_Cdouble(stretch_factor) - target_lon_c, target_lon_t = setscalar_Cdouble(target_lon) - target_lat_c, target_lat_t = setscalar_Cdouble(target_lat) - num_nest_grids_c, num_nest_grids_t = setscalar_Cint32(num_nest_grids) - parent_tile_p, parent_tile_t = setarray_Cint32(parent_tile) - refine_ratio_p, refine_ratio_t = setarray_Cint32(refine_ratio) - istart_nest_p, istart_nest_t = setarray_Cint32(istart_nest) - iend_nest_p, iend_nest_t = setarray_Cint32(iend_nest) - jstart_nest_p, jstart_nest_t = setarray_Cint32(jstart_nest) - jend_nest_p, jend_nest_t = setarray_Cint32(jend_nest) - halo_c, halo_t = setscalar_Cint32(halo) - output_length_angle_c, output_length_angle_t = setscalar_Cint32(output_length_angle) - - _create_gnomonic_cubic_grid.argtypes = [ - grid_type_t, - nlon_t, - nlat_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - angle_dy_t, - shift_fac_t, - do_schmidt_t, - do_cube_transform_t, - stretch_factor_t, - target_lon_t, - target_lat_t, - num_nest_grids_t, - parent_tile_t, - refine_ratio_t, - istart_nest_t, - iend_nest_t, - jstart_nest_t, - jend_nest_t, - halo_t, - output_length_angle_t, - ] - _create_gnomonic_cubic_grid.restype = None - - _create_gnomonic_cubic_grid( - grid_type_c, - nlon_p, - nlat_p, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - angle_dy_p, - shift_fac_c, - do_schmidt_c, - do_cube_transform_c, - stretch_factor_c, - target_lon_c, - target_lat_c, - num_nest_grids_c, - parent_tile_p, - refine_ratio_p, - istart_nest_p, - iend_nest_p, - jstart_nest_p, - jend_nest_p, - halo_c, - output_length_angle_c, - ) - - @classmethod - def create_f_plane_grid( - cls, - nxbnds: int, - nybnds: int, - xbnds: npt.NDArray[np.float64], - ybnds: npt.NDArray[np.float64], - nlon: npt.NDArray[np.int32], - nlat: npt.NDArray[np.int32], - dlon: npt.NDArray[np.float64], - dlat: npt.NDArray[np.float64], - use_legacy: int, - f_plane_latitude: float, - isc: int, - iec: int, - jsc: int, - jec: int, - x: npt.NDArray[np.float64], - y: npt.NDArray[np.float64], - dx: npt.NDArray[np.float64], - dy: npt.NDArray[np.float64], - area: npt.NDArray[np.float64], - angle_dx: npt.NDArray[np.float64], - center: str - ): - _create_f_plane_grid = cls.lib.create_f_plane_grid - - nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - xbnds_p, xbnds_t = setarray_Cdouble(xbnds) - ybnds_p, ybnds_t = setarray_Cdouble(ybnds) - nlon_p, nlon_t = setarray_Cint32(nlon) - nlat_p, nlat_t = setarray_Cint32(nlat) - dlon_p, dlon_t = setarray_Cdouble(dlon) - dlat_p, dlat_t = setarray_Cdouble(dlat) - use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - f_plane_latitude_c, f_plane_latitude_t = ctypes.c_double(f_plane_latitude), ctypes.c_double - isc_c, isc_t = setscalar_Cint32(isc) - iec_c, iec_t = setscalar_Cint32(iec) - jsc_c, jsc_t = setscalar_Cint32(jsc) - jec_c, jec_t = setscalar_Cint32(jec) - x_p, x_t = setarray_Cdouble(x) - y_p, y_t = setarray_Cdouble(y) - dx_p, dx_t = setarray_Cdouble(dx) - dy_p, dy_t = setarray_Cdouble(dy) - area_p, area_t = setarray_Cdouble(area) - angle_dx_p, angle_dx_t = setarray_Cdouble(angle_dx) - center_c, center_t = set_Cchar(center) - - _create_f_plane_grid.argtypes = [ - nxbnds_t, - nybnds_t, - xbnds_t, - ybnds_t, - nlon_t, - nlat_t, - dlon_t, - dlat_t, - use_legacy_t, - f_plane_latitude_t, - isc_t, - iec_t, - jsc_t, - jec_t, - x_t, - y_t, - dx_t, - dy_t, - area_t, - angle_dx_t, - center_t, - ] - _create_f_plane_grid.restype = None - - _create_f_plane_grid( - nxbnds_c, - nybnds_c, - xbnds_p, - ybnds_p, - nlon_p, - nlat_p, - dlon_p, - dlat_p, - use_legacy_c, - f_plane_latitude_c, - isc_c, - iec_c, - jsc_c, - jec_c, - x_p, - y_p, - dx_p, - dy_p, - area_p, - angle_dx_p, - center_c, - ) + _create_regular_lonlat_grid(*arglist) From e7c182628c1da2966f75a81702644353cb5fc1b5 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 23 May 2025 12:14:28 -0400 Subject: [PATCH 61/72] Amending test_libs for new file location --- tests/shared/test_libs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/shared/test_libs.py b/tests/shared/test_libs.py index e422207..c25676f 100644 --- a/tests/shared/test_libs.py +++ b/tests/shared/test_libs.py @@ -3,5 +3,5 @@ # simple test to check if C libraries can be linked in without error def test_c_libs(): - libfile = "./FREnctools_lib/cfrenctools/c_build/clib.so" + libfile = "./FREnctools_lib/pyfrenctools/c_install/clib.so" c_lib = ctypes.CDLL(libfile) From d1f4daf6d03cb52c18414ec8e5fa6c2153977d59 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 23 May 2025 13:52:51 -0400 Subject: [PATCH 62/72] Removing comments --- FMSgridtools/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMSgridtools/__init__.py b/FMSgridtools/__init__.py index bb5f31f..9c4cffe 100644 --- a/FMSgridtools/__init__.py +++ b/FMSgridtools/__init__.py @@ -3,4 +3,4 @@ from .make_hgrid.make_hgrid import make_hgrid from .shared.gridtools_utils import check_file_is_there, get_provenance_attrs from .shared.mosaicobj import MosaicObj -# from .shared.xgridobj import XGridObj +from .shared.xgridobj import XGridObj From 51a8b07c276b9638f0040dc8a2801d7567c59d20 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 23 May 2025 14:00:09 -0400 Subject: [PATCH 63/72] Removing even more comments --- .../make_hgrid/make_hgrid_wrappers.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py index ac7fe93..09ba298 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py @@ -42,27 +42,6 @@ def create_regular_lonlat_grid( use_great_circle_algorithm: int ): _create_regular_lonlat_grid = _lib.create_regular_lonlat_grid - # nxbnds_c, nxbnds_t = setscalar_Cint32(nxbnds) - # nybnds_c, nybnds_t = setscalar_Cint32(nybnds) - # xbnds, xbnds_t = setarray_Cdouble(xbnds) - # ybnds, ybnds_t = setarray_Cdouble(ybnds) - # nlon, nlon_t = setarray_Cint32(nlon) - # nlat, nlat_t = setarray_Cint32(nlat) - # dlon, dlon_t = setarray_Cdouble(dlon) - # dlat, dlat_t = setarray_Cdouble(dlat) - # use_legacy_c, use_legacy_t = ctypes.c_int(use_legacy), ctypes.c_int - # isc_c, isc_t = setscalar_Cint32(isc) - # iec_c, iec_t = setscalar_Cint32(iec) - # jsc_c, jsc_t = setscalar_Cint32(jsc) - # jec_c, jec_t = setscalar_Cint32(jec) - # x, x_t = setarray_Cdouble(x) - # y, y_t = setarray_Cdouble(y) - # dx, dx_t = setarray_Cdouble(dx) - # dy, dy_t = setarray_Cdouble(dy) - # area, area_t = setarray_Cdouble(area) - # angle_dx, angle_dx_t = setarray_Cdouble(angle_dx) - # center_c, center_t = set_Cchar(center) - # use_great_circle_algorithm_c, use_great_circle_algorithm_t = ctypes.c_int(use_great_circle_algorithm), ctypes.c_int arglist = [] set_c_int(nxbnds, arglist) set_c_int(nybnds, arglist) From 57506b25590c01574b5ee15b8b746c99ad920081 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Sat, 24 May 2025 03:52:20 -0400 Subject: [PATCH 64/72] Overriding build instead of build_py in pyfrenctools setup.py --- FREnctools_lib/setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FREnctools_lib/setup.py b/FREnctools_lib/setup.py index c7e4a72..3d8f073 100644 --- a/FREnctools_lib/setup.py +++ b/FREnctools_lib/setup.py @@ -2,10 +2,10 @@ from typing import List from setuptools import find_namespace_packages, setup -from setuptools.command.build_py import build_py +from setuptools.command.build import build -class CustomBuild_Py(build_py): +class CustomBuild(build): def run(self): with open("compile_log.txt", "w") as f: subprocess.run( @@ -26,7 +26,7 @@ def run(self): stdout=f, stderr=subprocess.STDOUT, ) - build_py.run(self) + build.run(self) test_requirements = ["pytest", "coverage"] develop_requirements = test_requirements + ["pre-commit"] @@ -57,5 +57,5 @@ def run(self): include_package_data=True, version="0.0.1", zip_safe=False, - cmdclass={'build_py': CustomBuild_Py} + cmdclass={'build': CustomBuild} ) From 24e7126cafcafb03ff08333e57f28ed6fa8d6dba Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 27 May 2025 11:57:49 -0400 Subject: [PATCH 65/72] Added unit tests for current state of make_hgrid --- FMSgridtools/make_hgrid/hgridobj.py | 33 ++++++------ tests/test_hgrid.py | 83 +++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 tests/test_hgrid.py diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index db449e2..657f699 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -27,8 +27,8 @@ def fill_cubic_grid_halo( data[i] = -9999. # first copy computing domain data - for j in range (nyp+1): - for i in range(nxp+1): + for j in range (1, nyp+1): + for i in range(1, nxp+1): data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] ntiles = 6 @@ -38,10 +38,10 @@ def fill_cubic_grid_halo( le = (tile+ntiles+2)%ntiles ls = (tile+ntiles-2)%ntiles ln = (tile+ntiles+1)%ntiles - for j in range(nyp+1): + for j in range(1, nyp+1): data[j*nxph] = data1_all[lw*nxp*nyp+(j-1)*nxp+nx-1] # west halo data[j*nxph+nxp+1] = data2_all[le*nxp*nyp+ioff*nxp+nyp-j] # east halo - for i in range(nxp+1): + for i in range(1, nxp+1): data[i] = data2_all[ls*nxp*nyp+(nxp-i)*nyp+(nx-1)] # south halo data[(nyp+1)*nxph+i] = data1_all[ln*nxp*nyp+joff*nxp+i-1] # north halo else: @@ -49,10 +49,10 @@ def fill_cubic_grid_halo( le = (tile+ntiles+1)%ntiles ls = (tile+ntiles-1)%ntiles ln = (tile+ntiles+2)%ntiles - for j in range(nyp+1): + for j in range(1, nyp+1): data[j*nxph] = data2_all[lw*nxp*nyp+(ny-1)*nxp+nyp-j] # west halo data[j*nxph+nxp+1] = data1_all[le*nxp*nyp+(j-1)*nxp+ioff] # east halo - for i in range(nxp+1): + for i in range(1, nxp+1): data[i] = data1_all[ls*nxp*nyp+(ny-1)*nxp+i-1] # south halo data[(nyp+1)*nxph+i] = data2_all[ln*nxp*nyp+(nxp-i)*nyp+joff] # north halo @@ -95,7 +95,7 @@ def make_grid_info( jend_nest: NDArray=None, arcx: str="small_circle", grid_type: str=None, - conformal: str="true", + conformal: bool=True, output_length_angle: bool=True, verbose: bool=False, ): @@ -192,7 +192,7 @@ def make_grid_info( self.dx = np.empty(shape=size2.value, dtype=np.float64) self.dy = np.empty(shape=size3.value, dtype=np.float64) self.angle_dx = np.empty(shape=size1.value, dtype=np.float64) - if conformal != "true": + if not conformal: self.angle_dy = np.empty(shape=size1.value, dtype=np.float64) self.isc = 0 self.iec = self.nx - 1 @@ -201,14 +201,15 @@ def make_grid_info( def write_out_hgrid( self, + grid_type = "regular_lonlat_grid", grid_name: str="horizontal_grid", ntiles: int=1, north_pole_tile: str="0.0 90.0", north_pole_arcx: str="0.0 90.0", - projection: str="none", + projection: str=None, geometry: str="spherical", discretization: str="logically_rectangular", - conformal: str="true", + conformal: bool=True, out_halo: int=0, output_length_angle: bool=True, verbose: bool=False, @@ -236,12 +237,12 @@ def write_out_hgrid( standard_name="grid_tile_spec", geometry=geometry, discretization=discretization, - conformal=conformal, + conformal=f"{conformal}", ) ) if north_pole_tile is None: - tile = tile.assign_attrs(projection=projection) - if projection is "none": + tile = tile.assign_attrs(projection=f"{projection}") + if projection is None: tile = tile.assign_attrs(north_pole_tile=north_pole_tile) var_dict['tile'] = tile @@ -338,7 +339,7 @@ def write_out_hgrid( ) var_dict['angle_dx'] = angle_dx - if conformal != "true": + if not conformal: angle_dy = xr.DataArray( data=self.angle_dy[pos_c:].reshape((nyp, nxp)), dims=["nyp", "nxp"], @@ -349,6 +350,8 @@ def write_out_hgrid( ) var_dict['angle_dy'] = angle_dy else: + if grid_type is not "gnomonic_ed": + raise RuntimeError("make_hgrid: out_halo > 0, only working for grid_type = 'gnomonic_ed'") tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) if verbose: @@ -433,7 +436,7 @@ def write_out_hgrid( ) var_dict['angle_dx'] = angle_dx - if conformal != "true": + if not conformal: fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) self.angle_dy = tmp.copy() angle_dy = xr.DataArray( diff --git a/tests/test_hgrid.py b/tests/test_hgrid.py new file mode 100644 index 0000000..8b1a0b6 --- /dev/null +++ b/tests/test_hgrid.py @@ -0,0 +1,83 @@ +import os +from click.testing import CliRunner +import ctypes +import numpy +import xarray +from pathlib import Path +from FMSgridtools.make_hgrid.make_hgrid import make_hgrid +from FMSgridtools.make_hgrid.hgridobj import HGridObj + +def test_lonlat_grid(): + runner = CliRunner() + result = runner.invoke(make_hgrid, ['lonlat', + '--xbnds', '0,30', + '--ybnds', '50,50', + '--nlon', '60', + '--nlat', '20',]) + assert result.exit_code == 0 + os.remove('horizontal_grid.nc') + +def test_make_hgrid_info(): + + hgrid_obj = HGridObj() + + hgrid_obj.make_grid_info( + nxbnds=2, + nybnds=2, + nlon=numpy.array([60]), + nlat=numpy.array([20]), + conformal=False, + ) + + assert hgrid_obj.nxl.shape[0] == 1 + assert hgrid_obj.nxl.size == 1 + assert hgrid_obj.nxl[0] == 60 + assert hgrid_obj.nyl.shape[0] == 1 + assert hgrid_obj.nyl.size == 1 + assert hgrid_obj.nyl[0] == 20 + assert hgrid_obj.nx == hgrid_obj.nxl[0] + assert hgrid_obj.ny == hgrid_obj.nyl[0] + assert hgrid_obj.nxp == hgrid_obj.nx + 1 + assert hgrid_obj.nyp == hgrid_obj.ny + 1 + assert hgrid_obj.x.shape[0] == ctypes.c_ulong(hgrid_obj.nxp * hgrid_obj.nyp).value + assert hgrid_obj.y.shape[0] == ctypes.c_ulong(hgrid_obj.nxp * hgrid_obj.nyp).value + assert hgrid_obj.dx.shape[0] == ctypes.c_ulong(hgrid_obj.nx * hgrid_obj.nyp).value + assert hgrid_obj.dy.shape[0] == ctypes.c_ulong(hgrid_obj.nxp * hgrid_obj.ny).value + assert hgrid_obj.angle_dx.shape[0] == ctypes.c_ulong(hgrid_obj.nxp * hgrid_obj.nyp).value + assert hgrid_obj.angle_dy.shape[0] == ctypes.c_ulong(hgrid_obj.nxp * hgrid_obj.nyp).value + assert hgrid_obj.area.shape[0] == ctypes.c_ulong(hgrid_obj.nx * hgrid_obj.ny).value + assert hgrid_obj.isc == 0 + assert hgrid_obj.iec == hgrid_obj.nx - 1 + assert hgrid_obj.jsc == 0 + assert hgrid_obj.jec == hgrid_obj.ny - 1 + + + + +def test_write_out_hgrid(): + hgrid_obj = HGridObj() + + hgrid_obj.make_grid_info( + nxbnds=2, + nybnds=2, + nlon=numpy.array([60]), + nlat=numpy.array([20]), + conformal=False, + ) + + grid_name = "test_hgrid" + grid_file = grid_name + ".nc" + + hgrid_obj.write_out_hgrid( + grid_name=grid_name, + ) + + assert Path(grid_file).exists() + ds = xarray.open_dataset(grid_file) + assert ds.data_vars['x'].dims == ('nyp','nxp') + assert numpy.array_equal(ds.data_vars['x'].values.flatten(), hgrid_obj.x) + grid_obj = hgrid_obj.make_gridobj() + grid_obj.get_attributes() + assert numpy.array_equal(grid_obj.x.flatten(), hgrid_obj.x) + os.remove(Path(grid_file)) + From 4b13f1a9c5bf263501873f67dc7a1b14b12599db Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 30 May 2025 12:36:05 -0400 Subject: [PATCH 66/72] Beginning of make_hgrid:gnomonic --- FMSgridtools/make_hgrid/gnomonic_grid.py | 185 +++++++++++++++++++++++ FMSgridtools/make_hgrid/lonlat_grid.py | 20 ++- FMSgridtools/make_hgrid/make_hgrid.py | 185 +++++++++++++++++++++++ 3 files changed, 382 insertions(+), 8 deletions(-) create mode 100644 FMSgridtools/make_hgrid/gnomonic_grid.py diff --git a/FMSgridtools/make_hgrid/gnomonic_grid.py b/FMSgridtools/make_hgrid/gnomonic_grid.py new file mode 100644 index 0000000..81dc17c --- /dev/null +++ b/FMSgridtools/make_hgrid/gnomonic_grid.py @@ -0,0 +1,185 @@ +import sys +import numpy as np + +from FMSgridtools.make_hgrid.hgridobj import HGridObj +import pyfrenctools + +def make( + nlon: str, + shift_fac: float, + stretch_factor: float, + target_lon: float, + target_lat: float, + nest_grids: int, + parent_tile: str, + refine_ratio: str, + istart_nest: str, + iend_nest: str, + jstart_nest: str, + jend_nest: str, + halo: int, + out_halo: int, + grid_name: str, + output_length_angle: bool, + do_schmidt: bool, + do_cube_transform: bool, + verbose: bool, +): + + if do_cube_transform and do_schmidt: + raise RuntimeError("make_hgrid: both --do_cube_transform and --do_schmidt are set") + + grid_obj = HGridObj() + + if nlon is not None: + nlon = np.fromstring(nlon, dtype=np.int32, sep=',') + else: + nlon = np.empty(shape=99, dtype=np.int32) + + if parent_tile is not None: + parent_tile = np.fromstring(parent_tile, dtype=np.int32, sep=',') + else: + parent_tile = np.zeros(shape=128, dtype=np.int32) + + if refine_ratio is not None: + refine_ratio = np.fromstring(refine_ratio, dtype=np.int32, sep=',') + else: + refine_ratio = np.zeros(shape=128, dtype=np.int32) + + if istart_nest is not None: + istart_nest = np.fromstring(istart_nest, dtype=np.int32, sep=',') + else: + istart_nest = np.zeros(shape=128, dtype=np.int32) + + if iend_nest is not None: + iend_nest = np.fromstring(iend_nest, dtype=np.int32, sep=',') + else: + iend_nest = np.zeros(shape=128, dtype=np.int32) + + if jstart_nest is not None: + jstart_nest = np.fromstring(jstart_nest, dtype=np.int32, sep=',') + else: + jstart_nest = np.zeros(shape=128, dtype=np.int32) + + if jend_nest is not None: + jend_nest = np.fromstring(jend_nest, dtype=np.int32, sep=',') + else: + jend_nest = np.zeros(shape=128, dtype=np.int32) + + ntiles = 6 + ntiles_global = 6 + + projection = "cube_gnomonic" + conformal = False + + if do_schmidt or do_cube_transform: + raise RuntimeError("make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon\ + and --target_lat must be set when --do_schmidt or --do_cube_transform is set") + + for n in range(nest_grids): + if refine_ratio[n] == 0: + raise RuntimeError("make_hgrid: --refine_ratio must be set when --nest_grids is set") + if parent_tile[n] == 0: + print(f"NOTE from make_hgrid: parent_tile is 0, the output grid will have resolution refine_ration*nlon\n", file=sys.stderr) + else: + if istart_nest[n] == 0: + raise RuntimeError("make_hgrid: --istart_nest must be set when --nest_grids is set") + if iend_nest[n] == 0: + raise RuntimeError("make_hgrid: --iend_nest must be set when --nest_grids is set") + if jstart_nest[n] == 0: + raise RuntimeError("make_hgrid: --jstart_nest must be set when --nest_grids is set") + if jend_nest[n] == 0: + raise RuntimeError("make_hgrid: --jend_nest must be set when --nest_grids is set") + if halo == 0: + raise RuntimeError("make_hgrid: --halo must be set when --nest_grids is set") + ntiles += 1 + if verbose: + print(f"Configuration for nest {ntiles} validated\n", file=sys.stderr) + + if verbose: + print(f"Updated number of tiles, including nests (ntiles): {ntiles}\n", file=sys.stderr) + + grid_obj.make_grid_info( + nlon=nlon, + ntiles=ntiles, + ntiles_global=ntiles_global, + nest_grids=nest_grids, + parent_tile=parent_tile, + refine_ratio=refine_ratio, + istart_nest=istart_nest, + iend_nest=iend_nest, + jstart_nest=jstart_nest, + jend_nest=jend_nest, + grid_type="GNOMONIC_ED", + conformal=conformal, + output_length_angle=output_length_angle, + verbose=verbose, + ) + + # if nest_grids == 1 and parent_tile[0] == 0: + # pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid_GR( + # grid_type=grid_type, + # nxl=grid_obj.nxl, + # nyl=grid_obj.nyl, + # x=grid_obj.x, + # y=grid_obj.y, + # dx=grid_obj.dx, + # dy=grid_obj.dy, + # area=grid_obj.area, + # angle_dx=grid_obj.angle_dx, + # angle_dy=grid_obj.angle_dy, + # shift_fac=shift_fac, + # do_schmidt=do_schmidt, + # do_cube_transform=do_cube_transform, + # stretch_factor=stretch_factor, + # target_lon=target_lon, + # target_lat=target_lat, + # nest_grids=nest_grids, + # parent_tile=parent_tile[0], + # refine_ratio=refine_ratio[0], + # istart_nest=istart_nest[0], + # iend_nest=iend_nest[0], + # jstart_nest=jstart_nest[0], + # jend_nest=jend_nest[0], + # halo=halo, + # output_length_angle=output_length_angle, + # ) + # else: + # pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid( + # grid_type=grid_type, + # nxl=grid_obj.nxl, + # nyl=grid_obj.nyl, + # x=grid_obj.x, + # y=grid_obj.y, + # dx=grid_obj.dx, + # dy=grid_obj.dy, + # area=grid_obj.area, + # angle_dx=grid_obj.angle_dx, + # angle_dy=grid_obj.angle_dy, + # shift_fac=shift_fac, + # do_schmidt=do_schmidt, + # do_cube_transform=do_cube_transform, + # stretch_factor=stretch_factor, + # target_lon=target_lon, + # target_lat=target_lat, + # nest_grids=nest_grids, + # parent_tile=parent_tile, + # refine_ratio=refine_ratio, + # istart_nest=istart_nest, + # iend_nest=iend_nest, + # jstart_nest=jstart_nest, + # jend_nest=jend_nest, + # halo=halo, + # output_length_angle=output_length_angle, + # ) + + # grid_obj.write_out_hgrid( + # grid_type="gnomonic_ed", + # grid_name=grid_name, + # ntiles=ntiles, + # projection=projection, + # conformal=conformal, + # out_halo=out_halo, + # output_length_angle=output_length_angle, + # verbose=verbose, + # ) \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/lonlat_grid.py b/FMSgridtools/make_hgrid/lonlat_grid.py index acedb78..6c65061 100644 --- a/FMSgridtools/make_hgrid/lonlat_grid.py +++ b/FMSgridtools/make_hgrid/lonlat_grid.py @@ -4,23 +4,27 @@ import pyfrenctools def make( - nlon: int, - nlat: int, - xbnds: str = None, - ybnds: str = None, - dlon: str = None, - dlat: str = None, - use_great_circle_algorithm: bool = False, - verbose: bool = False, + nlon: str, + nlat: str, + xbnds: str = None, + ybnds: str = None, + dlon: str = None, + dlat: str = None, + use_great_circle_algorithm: bool = False, + verbose: bool = False, ): center = "none" grid_obj = HGridObj() if nlon is not None: nlon = np.fromstring(nlon, dtype=np.int32, sep=',') + else: + nlon = np.empty(shape=99, dtype=np.int32) if nlat is not None: nlat = np.fromstring(nlat, dtype=np.int32, sep=',') + else: + nlat = np.empty(shape=99, dtype=np.int32) if xbnds is not None: xbnds = np.fromstring(xbnds, dtype=np.float64, sep=',') diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 3b88546..04e5f49 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -1,6 +1,7 @@ import click import FMSgridtools.make_hgrid.lonlat_grid as lonlat_grid +import FMSgridtools.make_hgrid.gnomonic_grid as gnomonic_grid @click.group() @@ -55,6 +56,15 @@ def make_hgrid(): help="When specified, great_circle_algorithm will be used to compute grid \ cell area.", ) +@click.option( + "--grid_name", + type=str, + default="horizontal_grid", + help="Specify the grid name. The output grid file name\ + will be grid_name.nc if there is one tile and\ + grid_name.tile#.nc if there is more than one tile.\ + The default value will be horizontal_grid.", +) @click.option( "--verbose", is_flag=True, @@ -68,6 +78,7 @@ def lonlat( dlon: str, dlat: str, use_great_circle_algorithm: bool, + grid_name: str, verbose: bool, ): lonlat_grid.make( @@ -78,5 +89,179 @@ def lonlat( dlon=dlon, dlat=dlat, use_great_circle_algorithm=use_great_circle_algorithm, + grid_name=grid_name, + verbose=verbose, + ) + +@make_hgrid.command() +@click.option( + "--nlon", + type=str, + default=None, + help="Model grid points(supergrid) for each zonal regions of varying resolution.", +) +@click.option( + "--shift_fac", + type=float, + default=18.0, + help="shift west by 180/shift_fac. Default value is 18." +) +@click.option( + "--stretch_factor", + type=float, + default=0.0, + help="Stretching factor for the grid" +) +@click.option( + "--target_lon", + type=float, + default=0.0, + help="center longitude of the highest resolution tile" +) +@click.option( + "--target_lat", + type=float, + default=0.0, + help="center latitude of the highest resolution tile" +) +@click.option( + "--nest_grids", + type=int, + default=0, + help="set to create this # nested grids as well as the global grid.\ + When it is set, besides 6 tile grid files created, there are #\ + more nest grids with file name = grid_name.tile${parent_tile}.nest.nc" +) +@click.option( + "--parent_tile", + type=str, + default=None, + help="Specify the comma-separated list of the parent tile number(s) of nest grid(s)." +) +@click.option( + "--refine_ratio", + type=str, + default=None, + help="Specify the comma-separated list of refinement ratio(s) for nest grid(s)." +) +@click.option( + "--istart_nest", + type=str, + default=None, + help="Specify the comma-separated list of starting i-direction index(es) of nest grid(s) in parent tile supergrid(Fortran index)." +) +@click.option( + "--iend_nest", + type=str, + default=None, + help="Specify the comma-separated list of ending i-direction index(es) of nest grid(s) in parent tile supergrid(Fortran index)." +) +@click.option( + "--jstart_nest", + type=str, + default=None, + help="Specify the comma-separated list of starting j-direction index(es) of nest grid(s) in parent tile supergrid(Fortran index)." +) +@click.option( + "--jend_nest", + type=str, + default=None, + help="Specify the comma-separated list of ending j-direction index(es) of nest grid(s) in parent tile supergrid(Fortran index)." +) +@click.option( + "--halo", + type=int, + default=0, + help="halo size is used in the atmosphere cubic sphere\ + model. Its purpose is to make sure the nest,\ + including the halo region, is fully contained\ + within a single parent (coarse) tile." +) +@click.option( + "--out_halo", + type=int, + default=0, + help="extra halo size data to be written out." +) +@click.option( + "--grid_name", + type=str, + default="horizontal_grid", + help="Specify the grid name. The output grid file name\ + will be grid_name.nc if there is one tile and\ + grid_name.tile#.nc if there is more than one tile.\ + The default value will be horizontal_grid.", +) +@click.option( + "--output_length_angle", + is_flag=True, + default=True, + help="Default to true, set to false to not output length angle" + +) +@click.option( + "--do_schmidt", + is_flag=True, + default=False, + help="Set to do Schmidt transformation to create\ + stretched grid. When do_schmidt is set, the\ + following must be set: --stretch_factor\ + --target_lon and --target_lat." +) +@click.option( + "--do_cube_transform", + is_flag=True, + default=False, + help="re-orient the rotated cubed sphere so that tile 6\ + has 'north' facing upward, which would make\ + analysis and explaining nest placement much easier.\ + When do_cube_transform is set, the following must\ + be set: --stretch_factor, --latget_lon, and --target_lat." +) +@click.option( + "--verbose", + is_flag=True, + default=False, +) +def gnomonic( + nlon: str, + shift_fac: float, + stretch_factor: float, + target_lon: float, + target_lat: float, + nest_grids: int, + parent_tile: str, + refine_ratio: str, + istart_nest: str, + iend_nest: str, + jstart_nest: str, + jend_nest: str, + halo: int, + out_halo: int, + grid_name: str, + output_length_angle: bool, + do_schmidt: bool, + do_cube_transform: bool, + verbose: bool +): + gnomonic_grid.make( + nlon=nlon, + shift_fac=shift_fac, + stretch_factor=stretch_factor, + target_lon=target_lon, + target_lat=target_lat, + nest_grids=nest_grids, + parent_tile=parent_tile, + refine_ratio=refine_ratio, + istart_nest=istart_nest, + iend_nest=iend_nest, + jstart_nest=jstart_nest, + jend_nest=jend_nest, + halo=halo, + out_halo=out_halo, + grid_name=grid_name, + output_length_angle=output_length_angle, + do_schmidt=do_schmidt, + do_cube_transform=do_cube_transform, verbose=verbose, ) From f2ce46df37010dda76ce1ddb90e2cfcb132470fb Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Fri, 30 May 2025 15:29:37 -0400 Subject: [PATCH 67/72] Calls to wrappers for gnomonic grid generation --- FMSgridtools/make_hgrid/gnomonic_grid.py | 116 ++++++------ FMSgridtools/make_hgrid/hgridobj.py | 2 +- FMSgridtools/make_hgrid/make_hgrid.py | 11 +- .../make_hgrid/make_hgrid_wrappers.py | 175 ++++++++++++++++++ 4 files changed, 245 insertions(+), 59 deletions(-) diff --git a/FMSgridtools/make_hgrid/gnomonic_grid.py b/FMSgridtools/make_hgrid/gnomonic_grid.py index 81dc17c..95cd5a5 100644 --- a/FMSgridtools/make_hgrid/gnomonic_grid.py +++ b/FMSgridtools/make_hgrid/gnomonic_grid.py @@ -20,6 +20,7 @@ def make( halo: int, out_halo: int, grid_name: str, + grid_type: str, output_length_angle: bool, do_schmidt: bool, do_cube_transform: bool, @@ -73,7 +74,8 @@ def make( conformal = False if do_schmidt or do_cube_transform: - raise RuntimeError("make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon\ + if stretch_factor == 0.0 and target_lon == 0.0 and target_lat == 0.0: + raise RuntimeError("make_hgrid: grid type is 'gnomonic_ed, --stretch_factor, --target_lon\ and --target_lat must be set when --do_schmidt or --do_cube_transform is set") for n in range(nest_grids): @@ -116,62 +118,62 @@ def make( verbose=verbose, ) - # if nest_grids == 1 and parent_tile[0] == 0: - # pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid_GR( - # grid_type=grid_type, - # nxl=grid_obj.nxl, - # nyl=grid_obj.nyl, - # x=grid_obj.x, - # y=grid_obj.y, - # dx=grid_obj.dx, - # dy=grid_obj.dy, - # area=grid_obj.area, - # angle_dx=grid_obj.angle_dx, - # angle_dy=grid_obj.angle_dy, - # shift_fac=shift_fac, - # do_schmidt=do_schmidt, - # do_cube_transform=do_cube_transform, - # stretch_factor=stretch_factor, - # target_lon=target_lon, - # target_lat=target_lat, - # nest_grids=nest_grids, - # parent_tile=parent_tile[0], - # refine_ratio=refine_ratio[0], - # istart_nest=istart_nest[0], - # iend_nest=iend_nest[0], - # jstart_nest=jstart_nest[0], - # jend_nest=jend_nest[0], - # halo=halo, - # output_length_angle=output_length_angle, - # ) - # else: - # pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid( - # grid_type=grid_type, - # nxl=grid_obj.nxl, - # nyl=grid_obj.nyl, - # x=grid_obj.x, - # y=grid_obj.y, - # dx=grid_obj.dx, - # dy=grid_obj.dy, - # area=grid_obj.area, - # angle_dx=grid_obj.angle_dx, - # angle_dy=grid_obj.angle_dy, - # shift_fac=shift_fac, - # do_schmidt=do_schmidt, - # do_cube_transform=do_cube_transform, - # stretch_factor=stretch_factor, - # target_lon=target_lon, - # target_lat=target_lat, - # nest_grids=nest_grids, - # parent_tile=parent_tile, - # refine_ratio=refine_ratio, - # istart_nest=istart_nest, - # iend_nest=iend_nest, - # jstart_nest=jstart_nest, - # jend_nest=jend_nest, - # halo=halo, - # output_length_angle=output_length_angle, - # ) + if nest_grids == 1 and parent_tile[0] == 0: + pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid_GR( + grid_type=grid_type, + nlon=grid_obj.nxl, + nlat=grid_obj.nyl, + x=grid_obj.x, + y=grid_obj.y, + dx=grid_obj.dx, + dy=grid_obj.dy, + area=grid_obj.area, + angle_dx=grid_obj.angle_dx, + angle_dy=grid_obj.angle_dy, + shift_fac=shift_fac, + do_schmidt=int(do_schmidt), + do_cube_transform=int(do_cube_transform), + stretch_factor=stretch_factor, + target_lon=target_lon, + target_lat=target_lat, + nest_grids=nest_grids, + parent_tile=parent_tile[0], + refine_ratio=refine_ratio[0], + istart_nest=istart_nest[0], + iend_nest=iend_nest[0], + jstart_nest=jstart_nest[0], + jend_nest=jend_nest[0], + halo=halo, + output_length_angle=int(output_length_angle), + ) + else: + pyfrenctools.make_hgrid_wrappers.create_gnomonic_cubic_grid( + grid_type=grid_type, + nlon=grid_obj.nxl, + nlat=grid_obj.nyl, + x=grid_obj.x, + y=grid_obj.y, + dx=grid_obj.dx, + dy=grid_obj.dy, + area=grid_obj.area, + angle_dx=grid_obj.angle_dx, + angle_dy=grid_obj.angle_dy, + shift_fac=shift_fac, + do_schmidt=int(do_schmidt), + do_cube_transform=int(do_cube_transform), + stretch_factor=stretch_factor, + target_lon=target_lon, + target_lat=target_lat, + num_nest_grids=nest_grids, + parent_tile=parent_tile, + refine_ratio=refine_ratio, + istart_nest=istart_nest, + iend_nest=iend_nest, + jstart_nest=jstart_nest, + jend_nest=jend_nest, + halo=halo, + output_length_angle=int(output_length_angle), + ) # grid_obj.write_out_hgrid( # grid_type="gnomonic_ed", diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 657f699..e7c3600 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -154,7 +154,7 @@ def make_grid_info( size4 = ctypes.c_ulong(0) for n_nest in range(ntiles): - print(f"[INFO] tile: {n_nest}, {self.nxl[n_nest]}, {self.nyl[n_nest]}, ntiles: {ntiles}\n") + print(f"[INFO] tile: {n_nest}, nxl[{self.nxl[n_nest]}], nyl[{self.nyl[n_nest]}], ntiles: {ntiles}\n") if grid_type == "FROM_FILE": size1 = 0 diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index 04e5f49..fda3f89 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -192,6 +192,13 @@ def lonlat( grid_name.tile#.nc if there is more than one tile.\ The default value will be horizontal_grid.", ) +@click.option( + "--grid_type", + type=str, + default="gnomonic_ed", + help="Specify the grid type. Options are 'gnomonic_ed'\ + 'gnomonic_dist', or 'gnomonic_angl'.", +) @click.option( "--output_length_angle", is_flag=True, @@ -238,7 +245,8 @@ def gnomonic( jend_nest: str, halo: int, out_halo: int, - grid_name: str, + grid_name: str, + grid_type: str, output_length_angle: bool, do_schmidt: bool, do_cube_transform: bool, @@ -260,6 +268,7 @@ def gnomonic( halo=halo, out_halo=out_halo, grid_name=grid_name, + grid_type=grid_type, output_length_angle=output_length_angle, do_schmidt=do_schmidt, do_cube_transform=do_cube_transform, diff --git a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py index 09ba298..6126e99 100644 --- a/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py +++ b/FREnctools_lib/pyfrenctools/make_hgrid/make_hgrid_wrappers.py @@ -4,6 +4,7 @@ from pyfrenctools.utils.ctypes import ( set_array, + set_c_double, set_c_int, set_c_str, ) @@ -92,3 +93,177 @@ def create_regular_lonlat_grid( _create_regular_lonlat_grid.restype = None _create_regular_lonlat_grid(*arglist) + +def create_gnomonic_cubic_grid( + grid_type: str, + nlon: npt.NDArray, + nlat: npt.NDArray, + x: npt.NDArray, + y: npt.NDArray, + dx: npt.NDArray, + dy: npt.NDArray, + area: npt.NDArray, + angle_dx: npt.NDArray, + angle_dy: npt.NDArray, + shift_fac: float, + do_schmidt: int, + do_cube_transform: int, + stretch_factor: float, + target_lon: float, + target_lat: float, + num_nest_grids: int, + parent_tile: npt.NDArray, + refine_ratio: npt.NDArray, + istart_nest: npt.NDArray, + iend_nest: npt.NDArray, + jstart_nest: npt.NDArray, + jend_nest: npt.NDArray, + halo: int, + output_length_angle: int, +): + _create_gnomonic_cubic_grid = _lib.create_gnomonic_cubic_grid + + arglist = [] + set_c_str(grid_type, arglist) + set_array(nlon, arglist) + set_array(nlat, arglist) + set_array(x, arglist) + set_array(y, arglist) + set_array(dx, arglist) + set_array(dy, arglist) + set_array(area, arglist) + set_array(angle_dx, arglist) + set_array(angle_dy, arglist) + set_c_double(shift_fac, arglist) + set_c_int(do_schmidt, arglist) + set_c_int(do_cube_transform, arglist) + set_c_double(stretch_factor, arglist) + set_c_double(target_lon, arglist) + set_c_double(target_lat, arglist) + set_c_int(num_nest_grids, arglist) + set_array(parent_tile, arglist) + set_array(refine_ratio, arglist) + set_array(istart_nest, arglist) + set_array(iend_nest, arglist) + set_array(jstart_nest, arglist) + set_array(jend_nest, arglist) + set_c_int(halo, arglist) + set_c_int(output_length_angle, arglist) + + _create_gnomonic_cubic_grid.argtypes = [ + c_char_p, + np.ctypeslib.ndpointer(dtype=nlon.dtype, ndim=nlon.ndim, shape=nlon.shape), + np.ctypeslib.ndpointer(dtype=nlat.dtype, ndim=nlat.ndim, shape=nlat.shape), + np.ctypeslib.ndpointer(dtype=x.dtype, ndim=x.ndim, shape=x.shape), + np.ctypeslib.ndpointer(dtype=y.dtype, ndim=y.ndim, shape=y.shape), + np.ctypeslib.ndpointer(dtype=dx.dtype, ndim=dx.ndim, shape=dx.shape), + np.ctypeslib.ndpointer(dtype=dy.dtype, ndim=dy.ndim, shape=dy.shape), + np.ctypeslib.ndpointer(dtype=area.dtype, ndim=area.ndim, shape=area.shape), + np.ctypeslib.ndpointer(dtype=angle_dx.dtype, ndim=angle_dx.ndim, shape=angle_dx.shape), + np.ctypeslib.ndpointer(dtype=angle_dy.dtype, ndim=angle_dy.ndim, shape=angle_dy.shape), + c_double, + c_int, + c_int, + c_double, + c_double, + c_double, + c_int, + np.ctypeslib.ndpointer(dtype=parent_tile.dtype, ndim=parent_tile.ndim, shape=parent_tile.shape), + np.ctypeslib.ndpointer(dtype=refine_ratio.dtype, ndim=refine_ratio.ndim, shape=refine_ratio.shape), + np.ctypeslib.ndpointer(dtype=istart_nest.dtype, ndim=istart_nest.ndim, shape=istart_nest.shape), + np.ctypeslib.ndpointer(dtype=iend_nest.dtype, ndim=iend_nest.ndim, shape=iend_nest.shape), + np.ctypeslib.ndpointer(dtype=jstart_nest.dtype, ndim=jstart_nest.ndim, shape=jstart_nest.shape), + np.ctypeslib.ndpointer(dtype=jend_nest.dtype, ndim=jend_nest.ndim, shape=jend_nest.shape), + c_int, + c_int, + ] + _create_gnomonic_cubic_grid.restype = None + + _create_gnomonic_cubic_grid(*arglist) + +def create_gnomonic_cubic_grid_GR( + grid_type: str, + nlon: npt.NDArray, + nlat: npt.NDArray, + x: npt.NDArray, + y: npt.NDArray, + dx: npt.NDArray, + dy: npt.NDArray, + area: npt.NDArray, + angle_dx: npt.NDArray, + angle_dy: npt.NDArray, + shift_fac: float, + do_schmidt: int, + do_cube_transform: int, + stretch_factor: float, + target_lon: float, + target_lat: float, + nest_grid: int, + parent_tile: int, + refine_ratio: int, + istart_nest: int, + iend_nest: int, + jstart_nest: int, + jend_nest: int, + halo: int, + output_length_angle: int, +): + _create_gnomonic_cubic_grid_GR = _lib.create_gnomonic_cubic_grid_GR + + arglist = [] + set_c_str(grid_type, arglist) + set_array(nlon, arglist) + set_array(nlat, arglist) + set_array(x, arglist) + set_array(y, arglist) + set_array(dx, arglist) + set_array(dy, arglist) + set_array(area, arglist) + set_array(angle_dx, arglist) + set_array(angle_dy, arglist) + set_c_double(shift_fac, arglist) + set_c_int(do_schmidt, arglist) + set_c_int(do_cube_transform, arglist) + set_c_double(stretch_factor, arglist) + set_c_double(target_lon, arglist) + set_c_double(target_lat, arglist) + set_c_int(nest_grid, arglist) + set_c_int(parent_tile, arglist) + set_c_int(refine_ratio, arglist) + set_c_int(istart_nest, arglist) + set_c_int(iend_nest, arglist) + set_c_int(jstart_nest, arglist) + set_c_int(jend_nest, arglist) + set_c_int(halo, arglist) + set_c_int(output_length_angle, arglist) + + _create_gnomonic_cubic_grid_GR.argtypes = [ + c_char_p, + np.ctypeslib.ndpointer(dtype=nlon.dtype, ndim=nlon.ndim, shape=nlon.shape), + np.ctypeslib.ndpointer(dtype=nlat.dtype, ndim=nlat.ndim, shape=nlat.shape), + np.ctypeslib.ndpointer(dtype=x.dtype, ndim=x.ndim, shape=x.shape), + np.ctypeslib.ndpointer(dtype=y.dtype, ndim=y.ndim, shape=y.shape), + np.ctypeslib.ndpointer(dtype=dx.dtype, ndim=dx.ndim, shape=dx.shape), + np.ctypeslib.ndpointer(dtype=dy.dtype, ndim=dy.ndim, shape=dy.shape), + np.ctypeslib.ndpointer(dtype=area.dtype, ndim=area.ndim, shape=area.shape), + np.ctypeslib.ndpointer(dtype=angle_dx.dtype, ndim=angle_dx.ndim, shape=angle_dx.shape), + np.ctypeslib.ndpointer(dtype=angle_dy.dtype, ndim=angle_dy.ndim, shape=angle_dy.shape), + c_double, + c_int, + c_int, + c_double, + c_double, + c_double, + c_int, + c_int, + c_int, + c_int, + c_int, + c_int, + c_int, + c_int, + c_int, + ] + _create_gnomonic_cubic_grid_GR.restype = None + + _create_gnomonic_cubic_grid_GR(*arglist) From 3aff5d7d91eccfbbb09ec59d977f44efab9bf601 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 2 Jun 2025 12:57:55 -0400 Subject: [PATCH 68/72] Majority of gnomonic grid generation --- FMSgridtools/make_hgrid/gnomonic_grid.py | 20 +++---- FMSgridtools/make_hgrid/hgridobj.py | 20 ++++--- FMSgridtools/make_hgrid/lonlat_grid.py | 6 +- FMSgridtools/make_hgrid/make_hgrid.py | 72 +++++++++++++----------- 4 files changed, 65 insertions(+), 53 deletions(-) diff --git a/FMSgridtools/make_hgrid/gnomonic_grid.py b/FMSgridtools/make_hgrid/gnomonic_grid.py index 95cd5a5..f698c9d 100644 --- a/FMSgridtools/make_hgrid/gnomonic_grid.py +++ b/FMSgridtools/make_hgrid/gnomonic_grid.py @@ -175,13 +175,13 @@ def make( output_length_angle=int(output_length_angle), ) - # grid_obj.write_out_hgrid( - # grid_type="gnomonic_ed", - # grid_name=grid_name, - # ntiles=ntiles, - # projection=projection, - # conformal=conformal, - # out_halo=out_halo, - # output_length_angle=output_length_angle, - # verbose=verbose, - # ) \ No newline at end of file + grid_obj.write_out_hgrid( + grid_type="gnomonic_ed", + grid_name=grid_name, + ntiles=ntiles, + projection=projection, + conformal=conformal, + out_halo=out_halo, + output_length_angle=output_length_angle, + verbose=verbose, + ) \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index e7c3600..1a2a677 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -101,6 +101,10 @@ def make_grid_info( ): """Get super grid size""" + if verbose: + print(f"[INFO] make_hgrid: Number of tiles (ntiles): {ntiles}", file=sys.stderr) + print(f"[INFO] make_hgrid: Number of global tiles (ntiles_global): {ntiles_global}", file=sys.stderr) + self.nxl = np.empty(shape=ntiles, dtype=np.int32) self.nyl = np.empty(shape=ntiles, dtype=np.int32) @@ -224,7 +228,7 @@ def write_out_hgrid( for n in range(ntiles): self.tile = "tile" + str(n+1) if ntiles > 1: - outfile = grid_name + ".tile" + ".nc" + str(n+1) + outfile = grid_name + ".tile" + str(n+1) + ".nc" else: outfile = grid_name + ".nc" @@ -279,7 +283,7 @@ def write_out_hgrid( if n > 0: print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[-1]: {self.x[pos_c-1]} x[-2]: {self.x[pos_c-2]} x[-3]: {self.x[pos_c-3]} x[-4]: {self.x[pos_c-4]} x[-5]: {self.x[pos_c-5]} x[-10]: {self.x[pos_c-10]}", file=sys.stderr) x = xr.DataArray( - data=self.x[pos_c:].reshape((nyp,nxp)), + data=self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_east", @@ -289,7 +293,7 @@ def write_out_hgrid( var_dict['x'] = x y = xr.DataArray( - data=self.y[pos_c:].reshape((nyp, nxp)), + data=self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_north", @@ -299,7 +303,7 @@ def write_out_hgrid( var_dict['y'] = y area = xr.DataArray( - data=self.area[pos_t:].reshape((ny, nx)), + data=self.area[pos_t:pos_t+ny*nx].reshape((ny, nx)), dims=["ny", "nx"], attrs=dict( units="m2", @@ -310,7 +314,7 @@ def write_out_hgrid( if output_length_angle: dx = xr.DataArray( - data=self.dx[pos_n:].reshape((nyp, nx)), + data=self.dx[pos_n:pos_n+nyp*nx].reshape((nyp, nx)), dims=["nyp", "nx"], attrs=dict( units="meters", @@ -320,7 +324,7 @@ def write_out_hgrid( var_dict['dx'] = dx dy = xr.DataArray( - data=self.dy[pos_e:].reshape((ny, nxp)), + data=self.dy[pos_e:pos_e+ny*nxp].reshape((ny, nxp)), dims=["ny", "nxp"], attrs=dict( units="meters", @@ -330,7 +334,7 @@ def write_out_hgrid( var_dict['dy'] = dy angle_dx = xr.DataArray( - data=self.angle_dx[pos_c:].reshape((nyp, nxp)), + data=self.angle_dx[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degrees_east", @@ -341,7 +345,7 @@ def write_out_hgrid( if not conformal: angle_dy = xr.DataArray( - data=self.angle_dy[pos_c:].reshape((nyp, nxp)), + data=self.angle_dy[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degrees_north", diff --git a/FMSgridtools/make_hgrid/lonlat_grid.py b/FMSgridtools/make_hgrid/lonlat_grid.py index 6c65061..eb072db 100644 --- a/FMSgridtools/make_hgrid/lonlat_grid.py +++ b/FMSgridtools/make_hgrid/lonlat_grid.py @@ -11,6 +11,7 @@ def make( dlon: str = None, dlat: str = None, use_great_circle_algorithm: bool = False, + grid_name: str = "horizontal_grid", verbose: bool = False, ): center = "none" @@ -80,7 +81,10 @@ def make( use_great_circle_algorithm=use_great_circle_algorithm, ) - grid_obj.write_out_hgrid(verbose=verbose) + grid_obj.write_out_hgrid( + grid_name=grid_name, + verbose=verbose + ) diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index fda3f89..b9043e2 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -25,17 +25,13 @@ def make_hgrid(): "--xbnds", type=str, default=None, - help="Specify boundaries for defining zonal regions of varying resolution.\ - When --tripolar is present, x also defines the longitude of the two\ - new poles. nxbnds must be 2 and lon_start = x(1), lon_end = x(nxbnds)\ - are longitude of the two new poles.", + help="Specify boundaries for defining zonal regions of varying resolution." ) @click.option( "--ybnds", type=str, default=None, - help="Specify boundaries for defining meridional regions of varying\ - resolution", + help="Specify boundaries for defining meridional regions of varying resolution", ) @click.option( "--dlon", @@ -53,17 +49,16 @@ def make_hgrid(): "--use_great_circle_algorithm", is_flag=True, default=False, - help="When specified, great_circle_algorithm will be used to compute grid \ - cell area.", + help="When specified, great_circle_algorithm will be used to compute grid cell area.", ) @click.option( "--grid_name", type=str, default="horizontal_grid", - help="Specify the grid name. The output grid file name\ - will be grid_name.nc if there is one tile and\ - grid_name.tile#.nc if there is more than one tile.\ - The default value will be horizontal_grid.", + help=""" + Specify the grid name. The output grid file name will be grid_name.nc if there is one tile and + grid_name.tile#.nc if there is more than one tile. The default value will be 'horizontal_grid'. + """, ) @click.option( "--verbose", @@ -128,9 +123,11 @@ def lonlat( "--nest_grids", type=int, default=0, - help="set to create this # nested grids as well as the global grid.\ - When it is set, besides 6 tile grid files created, there are #\ - more nest grids with file name = grid_name.tile${parent_tile}.nest.nc" + help=""" + set to create this # nested grids as well as the global grid. + When it is set, besides 6 tile grid files created, there are # + more nest grids with file name = grid_name.tile${parent_tile}.nest.nc + """, ) @click.option( "--parent_tile", @@ -172,10 +169,12 @@ def lonlat( "--halo", type=int, default=0, - help="halo size is used in the atmosphere cubic sphere\ - model. Its purpose is to make sure the nest,\ - including the halo region, is fully contained\ - within a single parent (coarse) tile." + help=""" + halo size is used in the atmosphere cubic sphere + model. Its purpose is to make sure the nest, + including the halo region, is fully contained + within a single parent (coarse) tile. + """, ) @click.option( "--out_halo", @@ -187,17 +186,18 @@ def lonlat( "--grid_name", type=str, default="horizontal_grid", - help="Specify the grid name. The output grid file name\ - will be grid_name.nc if there is one tile and\ - grid_name.tile#.nc if there is more than one tile.\ - The default value will be horizontal_grid.", + help=""" + Specify the grid name. The output grid file name + will be grid_name.nc if there is one tile and + grid_name.tile#.nc if there is more than one tile. + The default value will be horizontal_grid. + """, ) @click.option( "--grid_type", type=str, default="gnomonic_ed", - help="Specify the grid type. Options are 'gnomonic_ed'\ - 'gnomonic_dist', or 'gnomonic_angl'.", + help="Specify the grid type. Options are 'gnomonic_ed', 'gnomonic_dist', or 'gnomonic_angl'.", ) @click.option( "--output_length_angle", @@ -210,20 +210,24 @@ def lonlat( "--do_schmidt", is_flag=True, default=False, - help="Set to do Schmidt transformation to create\ - stretched grid. When do_schmidt is set, the\ - following must be set: --stretch_factor\ - --target_lon and --target_lat." + help=""" + Set to do Schmidt transformation to create + stretched grid. When do_schmidt is set, the + following must be set: --stretch_factor + --target_lon and --target_lat. + """, ) @click.option( "--do_cube_transform", is_flag=True, default=False, - help="re-orient the rotated cubed sphere so that tile 6\ - has 'north' facing upward, which would make\ - analysis and explaining nest placement much easier.\ - When do_cube_transform is set, the following must\ - be set: --stretch_factor, --latget_lon, and --target_lat." + help=""" + re-orient the rotated cubed sphere so that tile 6 + has 'north' facing upward, which would make + analysis and explaining nest placement much easier. + When do_cube_transform is set, the following must + be set: --stretch_factor, --target_lon, and --target_lat. + """, ) @click.option( "--verbose", From 440c8185e35e292e68a975aedc940a5d1fce9416 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Mon, 2 Jun 2025 15:24:27 -0400 Subject: [PATCH 69/72] Changes for case when out_halo is passed for gnomonic grid write out --- FMSgridtools/make_hgrid/hgridobj.py | 49 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 1a2a677..0fdc2f1 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -172,9 +172,9 @@ def make_grid_info( size4.value += (nlon[n] + 1) * (nlat[n] + 1) else: size1 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) - size2 = ctypes.c_ulong(self.nx * self.nyp * ntiles_global) - size3 = ctypes.c_ulong(self.nxp * self.ny * ntiles_global) - size4 = ctypes.c_ulong(self.nx * self.ny * ntiles_global) + size2 = ctypes.c_ulong(self.nxp * (self.nyp + 1) * ntiles_global) + size3 = ctypes.c_ulong((self.nxp + 1) * self.nyp * ntiles_global) + size4 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) if not (nest_grids == 1 and parent_tile[0] == 0): for n_nest in range(ntiles_global, ntiles_global+nest_grids): @@ -356,15 +356,14 @@ def write_out_hgrid( else: if grid_type is not "gnomonic_ed": raise RuntimeError("make_hgrid: out_halo > 0, only working for grid_type = 'gnomonic_ed'") - tmp = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) if verbose: print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.x, self.x, n, 1, 1) - self.x = tmp.copy() + tmp_x = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_x, self.x, self.x, n, 1, 1) x = xr.DataArray( - data=self.x.reshape((nyp,nxp)), + data=tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degree_east", @@ -374,10 +373,10 @@ def write_out_hgrid( ) var_dict['x'] = x - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.y, self.y, n, 1, 1) - self.y = tmp.copy() + tmp_y = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_y, self.y, self.y, n, 1, 1) y = xr.DataArray( - data=self.y.reshape((nyp, nxp)), + data=tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degree_north", @@ -387,10 +386,10 @@ def write_out_hgrid( ) var_dict['y'] = y - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.area, self.area, n, 0, 0) - self.area = tmp.copy() + tmp_area = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_area, self.area, self.area, n, 0, 0) area = xr.DataArray( - data=self.area.reshape((ny, nx)), + data=tmp_area[:(nx+2*out_halo)*(ny+2*out_halo)].reshape((ny+2*out_halo, nx+2*out_halo)), dims=["ny", "nx"], attrs=dict( units="m2", @@ -401,10 +400,10 @@ def write_out_hgrid( var_dict['area'] = area if output_length_angle: - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dx, self.dy, n, 0, 1) - self.dx = tmp.copy() + tmp_dx = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_dx, self.dx, self.dy, n, 0, 1) dx = xr.DataArray( - data=self.dx.reshape((nyp, nx)), + data=tmp_dx[:(nyp+2*out_halo)*(nx+2*out_halo)].reshape((nyp+2*out_halo, nx+2*out_halo)), dims=["nyp", "nx"], attrs=dict( units="meters", @@ -414,10 +413,10 @@ def write_out_hgrid( ) var_dict['dx'] = dx - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.dy, self.dx, n, 1, 0) - self.dy = tmp.copy() + tmp_dy = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_dy, self.dy, self.dx, n, 1, 0) dy = xr.DataArray( - data=self.dy.reshape((ny, nxp)), + data=tmp_dy[:(ny+2*out_halo)*(nxp+2*out_halo)].reshape((ny+2*out_halo, nxp+2*out_halo)), dims=["ny", "nxp"], attrs=dict( units="meters", @@ -427,10 +426,10 @@ def write_out_hgrid( ) var_dict['dy'] = dy - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dx, self.angle_dx, n, 1, 1) - self.angle_dx = tmp.copy() + tmp_adx = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_adx, self.angle_dx, self.angle_dx, n, 1, 1) angle_dx = xr.DataArray( - data=self.angle_dx.reshape((nyp, nxp)), + data=tmp_adx.reshape((nyp+2*out_halo, nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degrees_east", @@ -441,10 +440,10 @@ def write_out_hgrid( var_dict['angle_dx'] = angle_dx if not conformal: - fill_cubic_grid_halo(nx, ny, out_halo, tmp, self.angle_dy, self.angle_dy, n, 1, 1) - self.angle_dy = tmp.copy() + tmp_ady = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + fill_cubic_grid_halo(nx, ny, out_halo, tmp_ady, self.angle_dy, self.angle_dy, n, 1, 1) angle_dy = xr.DataArray( - data=self.angle_dy.reshape((nyp, nxp)), + data=tmp_ady.reshape((nyp+2*out_halo, nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degrees_north", From 01236579d2d7f5ee2a916e01ff41c2485e40d7bc Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 4 Jun 2025 14:36:19 -0400 Subject: [PATCH 70/72] Square layout only gnomonic grid generation --- FMSgridtools/make_hgrid/hgridobj.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 0fdc2f1..2ccaa2a 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -172,9 +172,9 @@ def make_grid_info( size4.value += (nlon[n] + 1) * (nlat[n] + 1) else: size1 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) - size2 = ctypes.c_ulong(self.nxp * (self.nyp + 1) * ntiles_global) - size3 = ctypes.c_ulong((self.nxp + 1) * self.nyp * ntiles_global) - size4 = ctypes.c_ulong(self.nxp * self.nyp * ntiles_global) + size2 = ctypes.c_ulong(self.nx * self.nyp * ntiles_global) + size3 = ctypes.c_ulong(self.nxp * self.ny * ntiles_global) + size4 = ctypes.c_ulong(self.nx * self.ny * ntiles_global) if not (nest_grids == 1 and parent_tile[0] == 0): for n_nest in range(ntiles_global, ntiles_global+nest_grids): @@ -360,7 +360,7 @@ def write_out_hgrid( if verbose: print(f"[INFO] INDEX NC write with halo tile number = n: {n}", file=sys.stderr) - tmp_x = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_x = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_x, self.x, self.x, n, 1, 1) x = xr.DataArray( data=tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)), @@ -373,7 +373,7 @@ def write_out_hgrid( ) var_dict['x'] = x - tmp_y = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_y = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_y, self.y, self.y, n, 1, 1) y = xr.DataArray( data=tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)), @@ -386,10 +386,10 @@ def write_out_hgrid( ) var_dict['y'] = y - tmp_area = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_area = np.zeros(shape=(nx+2*out_halo)*(ny+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_area, self.area, self.area, n, 0, 0) area = xr.DataArray( - data=tmp_area[:(nx+2*out_halo)*(ny+2*out_halo)].reshape((ny+2*out_halo, nx+2*out_halo)), + data=tmp_area.reshape((ny+2*out_halo, nx+2*out_halo)), dims=["ny", "nx"], attrs=dict( units="m2", @@ -400,10 +400,10 @@ def write_out_hgrid( var_dict['area'] = area if output_length_angle: - tmp_dx = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_dx = np.zeros(shape=(nx+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_dx, self.dx, self.dy, n, 0, 1) dx = xr.DataArray( - data=tmp_dx[:(nyp+2*out_halo)*(nx+2*out_halo)].reshape((nyp+2*out_halo, nx+2*out_halo)), + data=tmp_dx.reshape((nyp+2*out_halo, nx+2*out_halo)), dims=["nyp", "nx"], attrs=dict( units="meters", @@ -413,10 +413,10 @@ def write_out_hgrid( ) var_dict['dx'] = dx - tmp_dy = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_dy = np.zeros(shape=(nxp+2*out_halo)*(ny+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_dy, self.dy, self.dx, n, 1, 0) dy = xr.DataArray( - data=tmp_dy[:(ny+2*out_halo)*(nxp+2*out_halo)].reshape((ny+2*out_halo, nxp+2*out_halo)), + data=tmp_dy.reshape((ny+2*out_halo, nxp+2*out_halo)), dims=["ny", "nxp"], attrs=dict( units="meters", @@ -426,7 +426,7 @@ def write_out_hgrid( ) var_dict['dy'] = dy - tmp_adx = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_adx = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_adx, self.angle_dx, self.angle_dx, n, 1, 1) angle_dx = xr.DataArray( data=tmp_adx.reshape((nyp+2*out_halo, nxp+2*out_halo)), @@ -440,7 +440,7 @@ def write_out_hgrid( var_dict['angle_dx'] = angle_dx if not conformal: - tmp_ady = np.empty(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) + tmp_ady = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_ady, self.angle_dy, self.angle_dy, n, 1, 1) angle_dy = xr.DataArray( data=tmp_ady.reshape((nyp+2*out_halo, nxp+2*out_halo)), From 55855314102a6583d00edc2cd595e2a0dc3ef8a0 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Wed, 18 Jun 2025 10:41:14 -0400 Subject: [PATCH 71/72] Adding transpose of data option to make_hgrid::gnomonic --- FMSgridtools/make_hgrid/gnomonic_grid.py | 2 ++ FMSgridtools/make_hgrid/hgridobj.py | 11 ++++++----- FMSgridtools/make_hgrid/make_hgrid.py | 8 ++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/FMSgridtools/make_hgrid/gnomonic_grid.py b/FMSgridtools/make_hgrid/gnomonic_grid.py index f698c9d..4495f70 100644 --- a/FMSgridtools/make_hgrid/gnomonic_grid.py +++ b/FMSgridtools/make_hgrid/gnomonic_grid.py @@ -24,6 +24,7 @@ def make( output_length_angle: bool, do_schmidt: bool, do_cube_transform: bool, + transpose: bool, verbose: bool, ): @@ -183,5 +184,6 @@ def make( conformal=conformal, out_halo=out_halo, output_length_angle=output_length_angle, + transpose=transpose, verbose=verbose, ) \ No newline at end of file diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 2ccaa2a..962702a 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -216,6 +216,7 @@ def write_out_hgrid( conformal: bool=True, out_halo: int=0, output_length_angle: bool=True, + transpose: bool=False, verbose: bool=False, ): @@ -283,7 +284,7 @@ def write_out_hgrid( if n > 0: print(f"[INFO] XARRAY: n: {n} x[0]: {self.x[pos_c]} x[-1]: {self.x[pos_c-1]} x[-2]: {self.x[pos_c-2]} x[-3]: {self.x[pos_c-3]} x[-4]: {self.x[pos_c-4]} x[-5]: {self.x[pos_c-5]} x[-10]: {self.x[pos_c-10]}", file=sys.stderr) x = xr.DataArray( - data=self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)), + data=self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)).T if transpose else self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_east", @@ -293,7 +294,7 @@ def write_out_hgrid( var_dict['x'] = x y = xr.DataArray( - data=self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), + data=self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)).T if transpose else self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( units="degree_north", @@ -354,7 +355,7 @@ def write_out_hgrid( ) var_dict['angle_dy'] = angle_dy else: - if grid_type is not "gnomonic_ed": + if grid_type != "gnomonic_ed": raise RuntimeError("make_hgrid: out_halo > 0, only working for grid_type = 'gnomonic_ed'") if verbose: @@ -363,7 +364,7 @@ def write_out_hgrid( tmp_x = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_x, self.x, self.x, n, 1, 1) x = xr.DataArray( - data=tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)), + data=tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)).T if transpose else tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degree_east", @@ -376,7 +377,7 @@ def write_out_hgrid( tmp_y = np.zeros(shape=(nxp+2*out_halo)*(nyp+2*out_halo), dtype=np.float64) fill_cubic_grid_halo(nx, ny, out_halo, tmp_y, self.y, self.y, n, 1, 1) y = xr.DataArray( - data=tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)), + data=tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)).T if transpose else tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( units="degree_north", diff --git a/FMSgridtools/make_hgrid/make_hgrid.py b/FMSgridtools/make_hgrid/make_hgrid.py index b9043e2..de1ae9f 100644 --- a/FMSgridtools/make_hgrid/make_hgrid.py +++ b/FMSgridtools/make_hgrid/make_hgrid.py @@ -229,6 +229,12 @@ def lonlat( be set: --stretch_factor, --target_lon, and --target_lat. """, ) +@click.option( + "--transpose", + is_flag=True, + default=False, + help="This flag will transpose the x(lon) and y(lat) output arrays" +) @click.option( "--verbose", is_flag=True, @@ -254,6 +260,7 @@ def gnomonic( output_length_angle: bool, do_schmidt: bool, do_cube_transform: bool, + transpose: bool, verbose: bool ): gnomonic_grid.make( @@ -276,5 +283,6 @@ def gnomonic( output_length_angle=output_length_angle, do_schmidt=do_schmidt, do_cube_transform=do_cube_transform, + transpose=transpose, verbose=verbose, ) From 120e94212e791c95e40d9d299f9c31472d72c209 Mon Sep 17 00:00:00 2001 From: Frank Malatino Date: Tue, 1 Jul 2025 11:42:57 -0400 Subject: [PATCH 72/72] Adding 'ordering' attribute for tracking of layout for output data from make_hgrid --- FMSgridtools/make_hgrid/hgridobj.py | 57 +++++++++++++++++------------ 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/FMSgridtools/make_hgrid/hgridobj.py b/FMSgridtools/make_hgrid/hgridobj.py index 962702a..60aaf72 100644 --- a/FMSgridtools/make_hgrid/hgridobj.py +++ b/FMSgridtools/make_hgrid/hgridobj.py @@ -1,17 +1,19 @@ -import sys import ctypes +import sys + import numpy as np -from numpy.typing import NDArray import xarray as xr +from numpy.typing import NDArray -from FMSgridtools.shared.gridtools_utils import get_provenance_attrs from FMSgridtools.shared.gridobj import GridObj +from FMSgridtools.shared.gridtools_utils import get_provenance_attrs + def fill_cubic_grid_halo( - nx: int, - ny: int, - halo: int, - data: NDArray[np.float64], + nx: int, + ny: int, + halo: int, + data: NDArray[np.float64], data1_all: NDArray[np.float64], data2_all: NDArray[np.float64], tile: int, @@ -22,7 +24,7 @@ def fill_cubic_grid_halo( nyp = ny + joff nxph = nx + ioff + 2*halo nyph = ny + joff + 2*halo - + for i in range(nxph*nyph): data[i] = -9999. @@ -30,9 +32,9 @@ def fill_cubic_grid_halo( for j in range (1, nyp+1): for i in range(1, nxp+1): data[j*nxph+i] = data1_all[tile*nxp*nyp+(j-1)*nxp+(i-1)] - + ntiles = 6 - + if tile%2 == 1: lw = (tile+ntiles-1)%ntiles le = (tile+ntiles+2)%ntiles @@ -219,7 +221,7 @@ def write_out_hgrid( transpose: bool=False, verbose: bool=False, ): - + var_dict={} pos_c = 0 pos_e = 0 @@ -268,7 +270,7 @@ def write_out_hgrid( ) var_dict['arcx'] = arcx - + """define dimension""" nx = self.nxl[n] ny = self.nyl[n] @@ -287,7 +289,7 @@ def write_out_hgrid( data=self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)).T if transpose else self.x[pos_c:pos_c+nyp*nxp].reshape((nyp,nxp)), dims=["nyp", "nxp"], attrs=dict( - units="degree_east", + units="degree_east", standard_name="geographic_longitude", ) ) @@ -297,7 +299,7 @@ def write_out_hgrid( data=self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)).T if transpose else self.y[pos_c:pos_c+nyp*nxp].reshape((nyp, nxp)), dims=["nyp", "nxp"], attrs=dict( - units="degree_north", + units="degree_north", standard_name="geographic_latitude", ) ) @@ -318,7 +320,7 @@ def write_out_hgrid( data=self.dx[pos_n:pos_n+nyp*nx].reshape((nyp, nx)), dims=["nyp", "nx"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_x_distance", ) ) @@ -328,7 +330,7 @@ def write_out_hgrid( data=self.dy[pos_e:pos_e+ny*nxp].reshape((ny, nxp)), dims=["ny", "nxp"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_y_distance", ) ) @@ -367,7 +369,7 @@ def write_out_hgrid( data=tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)).T if transpose else tmp_x.reshape((nyp+2*out_halo,nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( - units="degree_east", + units="degree_east", standard_name="geographic_longitude", _FillValue=-9999., ) @@ -380,7 +382,7 @@ def write_out_hgrid( data=tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)).T if transpose else tmp_y.reshape((nyp+2*out_halo, nxp+2*out_halo)), dims=["nyp", "nxp"], attrs=dict( - units="degree_north", + units="degree_north", standard_name="geographic_latitude", _FillValue = -9999., ) @@ -407,7 +409,7 @@ def write_out_hgrid( data=tmp_dx.reshape((nyp+2*out_halo, nx+2*out_halo)), dims=["nyp", "nx"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_x_distance", _FillValue=-9999., ) @@ -420,7 +422,7 @@ def write_out_hgrid( data=tmp_dy.reshape((ny+2*out_halo, nxp+2*out_halo)), dims=["ny", "nxp"], attrs=dict( - units="meters", + units="meters", standard_name="grid_edge_y_distance", _FillValue=-9999., ) @@ -454,6 +456,17 @@ def write_out_hgrid( ) var_dict['angle_dy'] = angle_dy + if transpose: + ordering = xr.DataArray( + ["row_major"], + ) + else: + ordering = xr.DataArray( + ["column_major"], + ) + + var_dict['ordering'] = ordering + nx = self.nxl[n] ny = self.nyl[n] nxp = nx + 1 @@ -471,7 +484,7 @@ def write_out_hgrid( if verbose: print(f"About to close {outfile}") - prov_attrs = get_provenance_attrs(great_circle_algorithm=True) + prov_attrs = get_provenance_attrs(great_circle_algorithm=True) dataset = xr.Dataset( data_vars=var_dict @@ -540,5 +553,3 @@ def make_gridobj(self) -> "GridObj": else: dataset=self.dataset return GridObj(dataset=dataset) - -