From 7bb4a0b1d36c923c091ec45558dd3977b40b0d0d Mon Sep 17 00:00:00 2001 From: mlee03 Date: Tue, 8 Apr 2025 12:28:55 -0400 Subject: [PATCH 01/14] prototype --- pyfms/__init__.py | 3 ++ pyfms/cfms.py | 29 ++++++++++++ pyfms/py_data_override/py_data_override.py | 53 ++++++++++++++++------ testme.py | 9 ++++ 4 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 pyfms/cfms.py create mode 100755 testme.py diff --git a/pyfms/__init__.py b/pyfms/__init__.py index 7a47c02..18623c0 100644 --- a/pyfms/__init__.py +++ b/pyfms/__init__.py @@ -11,3 +11,6 @@ from .pyfms import pyFMS from .pyfms_utils import data_handling from .pyfms_utils.grid_utils import GridUtils + +from .cfms import cFMS +cFMS.init() diff --git a/pyfms/cfms.py b/pyfms/cfms.py new file mode 100644 index 0000000..d1f0cec --- /dev/null +++ b/pyfms/cfms.py @@ -0,0 +1,29 @@ +import ctypes +import os +from pyfms import pyDataOverride + +class cFMS(): + + __cfms_path: str = os.path.dirname(__file__) + "/../cFMS/cLIBFMS/lib/libcFMS.so" + __cfms: ctypes.CDLL = ctypes.CDLL(__cfms_path) + __initialized = False + + @classmethod + def init(cls): + if cls.__initialized: pass + pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) + cls.__initialized = True + + @classmethod + def changelib(cls, cfms_path): + cls.__cfms_path = cfms_path + cls.__cfms = ctypes.CDLL(cls.__cfms_path) + pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) + cls.__initialized = True + + def is_initialized(cls): + return cls.__initialized + + @classmethod + def getlib(cls): + return cls.__cfms_path, cls.__cfms diff --git a/pyfms/py_data_override/py_data_override.py b/pyfms/py_data_override/py_data_override.py index 3ee7e1c..4617314 100644 --- a/pyfms/py_data_override/py_data_override.py +++ b/pyfms/py_data_override/py_data_override.py @@ -7,11 +7,36 @@ class pyDataOverride: - def __init__(self, cFMS: ctypes.CDLL = None): - self.cfms = cFMS - + __cfms_path: str = None + __cfms: ctypes.CDLL = None + __initialized = False + + @classmethod + def setlib(cls, cfms_path, cfms): + if cls.__initialized: pass + cls.__cfms_path = cfms_path + cls.__cfms = cfms + cls.__initialized = True + + @classmethod + def changelib(cls, cfms): + cls.__cfms = cfms + cls.__initialized = True + + @classmethod + def getlib(cls): + return cls.__cfms_path, cls.__cfms + + @classmethod + def get_initialized(cls): + return cls.__is_initialized + + #def __init__(self, cFMS: ctypes.CDLL = None): + # self.cfms = cFMS + + @classmethod def init( - self, + cls, atm_domain_id: int = None, ocn_domain_id: int = None, ice_domain_id: int = None, @@ -20,7 +45,7 @@ def init( mode: int = None, ): - _data_override_init = self.cfms.cFMS_data_override_init + _data_override_init = cls.__cfms.cFMS_data_override_init atm_domain_id_t = ctypes.c_int ocn_domain_id_t = ctypes.c_int @@ -68,7 +93,7 @@ def init( ) def set_time( - self, + cls, year: int = None, month: int = None, day: int = None, @@ -78,7 +103,7 @@ def set_time( tick: int = None, ): - _data_override_set_time = self.cfms.cFMS_data_override_set_time + _data_override_set_time = cls.__cfms.cFMS_data_override_set_time year_t = ctypes.c_int month_t = ctypes.c_int @@ -115,14 +140,14 @@ def set_time( ) def override_scalar( - self, + cls, gridname: str, fieldname: str, data_type: Any, data_index: int = None, ) -> np.float32 | np.float64: - _data_override_scalar = self.cfms.cFMS_data_override_0d_cdouble + _data_override_scalar = cls.__cfms.cFMS_data_override_0d_cdouble gridname_t = ctypes.c_char_p fieldname_t = ctypes.c_char_p data_t = ctypes.c_float if data_type is np.float32 else ctypes.c_double @@ -150,7 +175,7 @@ def override_scalar( return data_c.value def override( - self, + cls, gridname: str, fieldname: str, data_shape: list[int], @@ -165,14 +190,14 @@ def override( if data_type is np.float32: if nshape == 2: - _data_override = self.cfms.cFMS_data_override_2d_cfloat + _data_override = cls.__cfms.cFMS_data_override_2d_cfloat if nshape == 3: - _data_override = self.cfms.cFMS_data_override_3d_cfloat + _data_override = cls.__cfms.cFMS_data_override_3d_cfloat elif data_type is np.float64: if nshape == 2: - _data_override = self.cfms.cFMS_data_override_2d_cdouble + _data_override = cls.__cfms.cFMS_data_override_2d_cdouble if nshape == 3: - _data_override = self.cfms.cFMS_data_override_3d_cdouble + _data_override = cls.__cfms.cFMS_data_override_3d_cdouble else: # add cFMS_end raise RuntimeError("Data_override, datatype not supported") diff --git a/testme.py b/testme.py new file mode 100755 index 0000000..4ca471b --- /dev/null +++ b/testme.py @@ -0,0 +1,9 @@ +import pyfms + +cfms_path, cfms = pyfms.cFMS.getlib() +cfms_path_in_do, cfms_in_do = pyfms.pyDataOverride.getlib() + +assert(cfms_path == cfms_path_in_do) +assert(id(cfms)==id(cfms_in_do)) + +pyfms.pyDataOverride.init() From f14c7babb31835edf8f4258ecb1c32fb5a5898b8 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Tue, 8 Apr 2025 12:40:55 -0400 Subject: [PATCH 02/14] add one more thing to testme --- testme.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testme.py b/testme.py index 4ca471b..f6af112 100755 --- a/testme.py +++ b/testme.py @@ -6,4 +6,9 @@ assert(cfms_path == cfms_path_in_do) assert(id(cfms)==id(cfms_in_do)) +fake_path = "None" +pyfms.cFMS.cfms_path = fake_path +assert(pyfms.cFMS.getlib()[0] is not fake_path) + pyfms.pyDataOverride.init() + From c5ffb32749ccd5d51738f8a8adf3db758b25e4e3 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Tue, 8 Apr 2025 12:41:49 -0400 Subject: [PATCH 03/14] better --- testme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testme.py b/testme.py index f6af112..01d75d0 100755 --- a/testme.py +++ b/testme.py @@ -6,7 +6,7 @@ assert(cfms_path == cfms_path_in_do) assert(id(cfms)==id(cfms_in_do)) -fake_path = "None" +fake_path = "I/dont/exist" pyfms.cFMS.cfms_path = fake_path assert(pyfms.cFMS.getlib()[0] is not fake_path) From 6790b2c0254a5c10734ac179e264ebe1f9257989 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Tue, 8 Apr 2025 13:19:38 -0400 Subject: [PATCH 04/14] better --- pyfms/cfms.py | 8 ++- pyfms/pyfms.py | 131 ++++++++++++++++++------------------------------- testme.py | 13 +++++ 3 files changed, 68 insertions(+), 84 deletions(-) diff --git a/pyfms/cfms.py b/pyfms/cfms.py index d1f0cec..e54ae6a 100644 --- a/pyfms/cfms.py +++ b/pyfms/cfms.py @@ -1,6 +1,7 @@ import ctypes import os from pyfms import pyDataOverride +from pyfms import pyFMS class cFMS(): @@ -11,14 +12,17 @@ class cFMS(): @classmethod def init(cls): if cls.__initialized: pass + pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) - cls.__initialized = True - + pyFMS.setlib(cls.__cfms_path, cls.__cfms) + cls.__initialized = True + @classmethod def changelib(cls, cfms_path): cls.__cfms_path = cfms_path cls.__cfms = ctypes.CDLL(cls.__cfms_path) pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) + pyFMS.setlib(cls.__cfms_path, cls.__cfms) cls.__initialized = True def is_initialized(cls): diff --git a/pyfms/pyfms.py b/pyfms/pyfms.py index eba41a1..8bab5fe 100755 --- a/pyfms/pyfms.py +++ b/pyfms/pyfms.py @@ -2,89 +2,45 @@ import ctypes import os -from typing import Optional - from .pyfms_utils.data_handling import set_Cchar, setscalar_Cint32 - class pyFMS: - def __init__( - self, - cFMS_path: Optional[str] = os.path.dirname(__file__) - + "/../cFMS/cLIBFMS/lib/libcFMS.so", - cFMS: ctypes.CDLL = None, - alt_input_nml_path: str = None, - localcomm: int = None, - ndomain: int = None, - nnest_domain: int = None, - calendar_type: int = None, - ): - self.cFMS_path = cFMS_path - self.cFMS = cFMS - self.alt_input_nml_path = alt_input_nml_path - self.localcomm = localcomm - self.ndomain = ndomain - self.nnest_domain = nnest_domain - self.calendar_type = calendar_type - - if self.cFMS_path is None: - raise ValueError( - "Please define the library file path, e.g., as libFMS(cFMS_path=./cFMS.so)" - ) - - if not os.path.isfile(self.cFMS_path): - raise ValueError(f"Library {self.cFMS_path} does not exist") - - if self.cFMS is None: - self.cFMS = ctypes.cdll.LoadLibrary(self.cFMS_path) - - self.pyfms_init( - self.localcomm, - self.alt_input_nml_path, - self.ndomain, - self.nnest_domain, - self.calendar_type, - ) - - """ - Subroutine: pyfms_end - - Calls the termination routines for all modules in the MPP package. - Termination routine for the fms module. It also calls destructor routines - for the mpp, mpp_domains, and mpp_io modules. If this routine is called - more than once it will return silently. There are no arguments. - """ - - def pyfms_end(self): - _cfms_end = self.cFMS.cFMS_end - - _cfms_end.restype = None - _cfms_end() - - """ - Subroutine: pyfms_init - - Initializes the FMS module and also calls the initialization routines for - all modules in the MPP package. Will be called automatically if the user - does not call it. - Initialization routine for the fms module. It also calls initialization - routines for the mpp, mpp_domains, and mpp_io modules. Although this - routine will be called automatically by other fms_mod routines, users - should explicitly call fms_init. If this routine is called more than once - it will return silently. There are no arguments. - """ - - def pyfms_init( - self, - localcomm: Optional[int] = None, - alt_input_nml_path: Optional[str] = None, - ndomain: Optional[int] = None, - nnest_domain: Optional[int] = None, - calendar_type: Optional[int] = None, + __cfms_path: str = None + __cfms: ctypes.CDLL = None + __initialized = False + + @classmethod + def setlib(cls, cfms_path, cfms): + if cls.__initialized: pass + cls.__cfms_path = cfms_path + cls.__cfms = cfms + cls.__initialized = True + + @classmethod + def changelib(cls, cfms): + cls.__cfms = cfms + cls.__initialized = True + + @classmethod + def getlib(cls): + return cls.__cfms_path, cls.__cfms + + @classmethod + def get_initialized(cls): + return cls.__is_initialized + + @classmethod + def init(cls, + alt_input_nml_path: str = None, + localcomm: int = None, + ndomain: int = None, + nnest_domain: int = None, + calendar_type: int = None, ): - _cfms_init = self.cFMS.cFMS_init - + + _cfms_init = cls.__cfms.cFMS_init + localcomm_c, localcomm_t = setscalar_Cint32(localcomm) alt_input_nml_path_c, alt_input_nml_path_t = set_Cchar(alt_input_nml_path) ndomain_c, ndomain_t = setscalar_Cint32(ndomain) @@ -109,13 +65,24 @@ def pyfms_init( ) """ - Subroutine: pyfms_set_pelist_npes + Subroutine: pyfms_end - This method is used to set a npes variable of the cFMS module it wraps + Calls the termination routines for all modules in the MPP package. + Termination routine for the fms module. It also calls destructor routines + for the mpp, mpp_domains, and mpp_io modules. If this routine is called + more than once it will return silently. There are no arguments. """ - def set_pelist_npes(self, npes_in: int): - _cfms_set_npes = self.cFMS.cFMS_set_pelist_npes + @classmethod + def pyfms_end(cls): + _cfms_end = cls.__cfms.cFMS_end + _cfms_end.restype = None + _cfms_end() + + + @classmethod + def set_pelist_npes(cls, npes_in: int): + _cfms_set_npes = cls.__cfms.cFMS_set_pelist_npes npes_in_c, npes_in_t = setscalar_Cint32(npes_in) diff --git a/testme.py b/testme.py index 01d75d0..5cefbd9 100755 --- a/testme.py +++ b/testme.py @@ -1,5 +1,11 @@ +import os +import numpy as np +from mpi4py import MPI import pyfms +input_nml = open("input.nml", "w") +input_nml.close() + cfms_path, cfms = pyfms.cFMS.getlib() cfms_path_in_do, cfms_in_do = pyfms.pyDataOverride.getlib() @@ -10,5 +16,12 @@ pyfms.cFMS.cfms_path = fake_path assert(pyfms.cFMS.getlib()[0] is not fake_path) +pyfms.pyFMS.init(alt_input_nml_path=None, + localcomm=MPI.COMM_WORLD.Get_rank(), + ndomain=1, + nnest_domain=1, + calendar_type=None) + pyfms.pyDataOverride.init() +os.remove("input.nml") From 343fa8d7ca24c894003764b06d466913fe5ce50f Mon Sep 17 00:00:00 2001 From: mlee03 Date: Thu, 10 Apr 2025 18:18:01 -0400 Subject: [PATCH 05/14] intermediate saving before merging --- pyfms/__init__.py | 6 ++- pyfms/cfms.py | 39 ++++++++---------- pyfms/py_data_override/py_data_override.py | 48 +++++++++------------- pyfms/pyfms.py | 45 +++++++------------- testme.py | 29 +++++++------ 5 files changed, 72 insertions(+), 95 deletions(-) diff --git a/pyfms/__init__.py b/pyfms/__init__.py index 18623c0..f8a9a15 100644 --- a/pyfms/__init__.py +++ b/pyfms/__init__.py @@ -1,4 +1,4 @@ -from .py_data_override.py_data_override import pyDataOverride +from .py_data_override.py_data_override import data_override from .py_field_manager.py_field_manager import FieldTable from .py_horiz_interp.py_horiz_interp import HorizInterp from .py_mpp.py_mpp import pyFMS_mpp @@ -8,9 +8,11 @@ pyFMS_mpp_domains, pyNestDomain, ) -from .pyfms import pyFMS +from .pyfms import fms from .pyfms_utils import data_handling from .pyfms_utils.grid_utils import GridUtils from .cfms import cFMS + + cFMS.init() diff --git a/pyfms/cfms.py b/pyfms/cfms.py index e54ae6a..fc1a961 100644 --- a/pyfms/cfms.py +++ b/pyfms/cfms.py @@ -1,33 +1,30 @@ import ctypes import os -from pyfms import pyDataOverride -from pyfms import pyFMS +import pyfms class cFMS(): - __cfms_path: str = os.path.dirname(__file__) + "/../cFMS/cLIBFMS/lib/libcFMS.so" - __cfms: ctypes.CDLL = ctypes.CDLL(__cfms_path) - __initialized = False + __libpath: str = os.path.dirname(__file__) + "/../cFMS/cLIBFMS/lib/libcFMS.so" + __lib: ctypes.CDLL = ctypes.CDLL(__libpath) @classmethod def init(cls): - if cls.__initialized: pass - - pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) - pyFMS.setlib(cls.__cfms_path, cls.__cfms) - cls.__initialized = True + pyfms.data_override.setlib(cls.libpath, cls.lib) + pyfms.fms.setlib(cls.libpath, cls.lib) @classmethod - def changelib(cls, cfms_path): - cls.__cfms_path = cfms_path - cls.__cfms = ctypes.CDLL(cls.__cfms_path) - pyDataOverride.setlib(cls.__cfms_path, cls.__cfms) - pyFMS.setlib(cls.__cfms_path, cls.__cfms) - cls.__initialized = True + def changelib(cls, libpath): + cls.__libpath = libpath + cls.__lib = ctypes.CDLL(cls.__libpath) + pyfms.data_override.setlib(cls.libpath, cls.lib) + #pyfms.init.setlib(cls.__libpath, cls.__lib) + + @classmethod + @property + def lib(cls): + return cls.__lib - def is_initialized(cls): - return cls.__initialized - @classmethod - def getlib(cls): - return cls.__cfms_path, cls.__cfms + @property + def libpath(cls): + return cls.__libpath diff --git a/pyfms/py_data_override/py_data_override.py b/pyfms/py_data_override/py_data_override.py index 4617314..1b14dcd 100644 --- a/pyfms/py_data_override/py_data_override.py +++ b/pyfms/py_data_override/py_data_override.py @@ -4,35 +4,27 @@ import numpy as np import numpy.typing as npt +import pyfms -class pyDataOverride: +class data_override: - __cfms_path: str = None - __cfms: ctypes.CDLL = None - __initialized = False + __libpath: str = None + __lib: ctypes.CDLL = None @classmethod - def setlib(cls, cfms_path, cfms): - if cls.__initialized: pass - cls.__cfms_path = cfms_path - cls.__cfms = cfms - cls.__initialized = True + def setlib(cls, libpath, lib): + cls.__libpath = libpath + cls.__lib = lib @classmethod - def changelib(cls, cfms): - cls.__cfms = cfms - cls.__initialized = True + @property + def lib(cls): + return cls.__lib @classmethod - def getlib(cls): - return cls.__cfms_path, cls.__cfms - - @classmethod - def get_initialized(cls): - return cls.__is_initialized - - #def __init__(self, cFMS: ctypes.CDLL = None): - # self.cfms = cFMS + @property + def libpath(cls): + return cls.__libpath @classmethod def init( @@ -45,7 +37,7 @@ def init( mode: int = None, ): - _data_override_init = cls.__cfms.cFMS_data_override_init + _data_override_init = cls.lib.cFMS_data_override_init atm_domain_id_t = ctypes.c_int ocn_domain_id_t = ctypes.c_int @@ -103,7 +95,7 @@ def set_time( tick: int = None, ): - _data_override_set_time = cls.__cfms.cFMS_data_override_set_time + _data_override_set_time = cls.lib.cFMS_data_override_set_time year_t = ctypes.c_int month_t = ctypes.c_int @@ -147,7 +139,7 @@ def override_scalar( data_index: int = None, ) -> np.float32 | np.float64: - _data_override_scalar = cls.__cfms.cFMS_data_override_0d_cdouble + _data_override_scalar = cls.lib.cFMS_data_override_0d_cdouble gridname_t = ctypes.c_char_p fieldname_t = ctypes.c_char_p data_t = ctypes.c_float if data_type is np.float32 else ctypes.c_double @@ -190,14 +182,14 @@ def override( if data_type is np.float32: if nshape == 2: - _data_override = cls.__cfms.cFMS_data_override_2d_cfloat + _data_override = cls.lib.cFMS_data_override_2d_cfloat if nshape == 3: - _data_override = cls.__cfms.cFMS_data_override_3d_cfloat + _data_override = cls.lib.cFMS_data_override_3d_cfloat elif data_type is np.float64: if nshape == 2: - _data_override = cls.__cfms.cFMS_data_override_2d_cdouble + _data_override = cls.lib.cFMS_data_override_2d_cdouble if nshape == 3: - _data_override = cls.__cfms.cFMS_data_override_3d_cdouble + _data_override = cls.lib.cFMS_data_override_3d_cdouble else: # add cFMS_end raise RuntimeError("Data_override, datatype not supported") diff --git a/pyfms/pyfms.py b/pyfms/pyfms.py index 8bab5fe..ab865a2 100755 --- a/pyfms/pyfms.py +++ b/pyfms/pyfms.py @@ -4,31 +4,26 @@ import os from .pyfms_utils.data_handling import set_Cchar, setscalar_Cint32 -class pyFMS: +class fms: - __cfms_path: str = None - __cfms: ctypes.CDLL = None + __libpath: str = None + __lib: ctypes.CDLL = None __initialized = False @classmethod - def setlib(cls, cfms_path, cfms): - if cls.__initialized: pass - cls.__cfms_path = cfms_path - cls.__cfms = cfms - cls.__initialized = True + def setlib(cls, libpath, lib): + cls.__lib_path = libpath + cls.__lib = lib @classmethod - def changelib(cls, cfms): - cls.__cfms = cfms - cls.__initialized = True + @property + def lib(cls): + return cls.__lib @classmethod - def getlib(cls): - return cls.__cfms_path, cls.__cfms - - @classmethod - def get_initialized(cls): - return cls.__is_initialized + @property + def libpath(cls): + return cls.__libpath @classmethod def init(cls, @@ -39,7 +34,7 @@ def init(cls, calendar_type: int = None, ): - _cfms_init = cls.__cfms.cFMS_init + _cfms_init = cls.lib.cFMS_init localcomm_c, localcomm_t = setscalar_Cint32(localcomm) alt_input_nml_path_c, alt_input_nml_path_t = set_Cchar(alt_input_nml_path) @@ -75,18 +70,6 @@ def init(cls, @classmethod def pyfms_end(cls): - _cfms_end = cls.__cfms.cFMS_end + _cfms_end = cls.lib.cFMS_end _cfms_end.restype = None _cfms_end() - - - @classmethod - def set_pelist_npes(cls, npes_in: int): - _cfms_set_npes = cls.__cfms.cFMS_set_pelist_npes - - npes_in_c, npes_in_t = setscalar_Cint32(npes_in) - - _cfms_set_npes.argtypes = [npes_in_t] - _cfms_set_npes.restype = None - - _cfms_set_npes(npes_in_c) diff --git a/testme.py b/testme.py index 5cefbd9..411a2f3 100755 --- a/testme.py +++ b/testme.py @@ -6,22 +6,25 @@ input_nml = open("input.nml", "w") input_nml.close() -cfms_path, cfms = pyfms.cFMS.getlib() -cfms_path_in_do, cfms_in_do = pyfms.pyDataOverride.getlib() +cfms = pyfms.cFMS.lib +cfms_do = pyfms.data_override.lib -assert(cfms_path == cfms_path_in_do) -assert(id(cfms)==id(cfms_in_do)) +cfms_path = pyfms.cFMS.libpath +cfms_path_do = pyfms.data_override.libpath -fake_path = "I/dont/exist" -pyfms.cFMS.cfms_path = fake_path -assert(pyfms.cFMS.getlib()[0] is not fake_path) +assert(id(cfms)==id(cfms_do)) +assert(cfms_path == cfms_path_do) -pyfms.pyFMS.init(alt_input_nml_path=None, - localcomm=MPI.COMM_WORLD.Get_rank(), - ndomain=1, - nnest_domain=1, - calendar_type=None) +#fake_path = "I/dont/exist" +#pyfms.cFMS.cfms_path = fake_path +#assert(pyfms.cFMS.lib()[0] is not fake_path) -pyfms.pyDataOverride.init() +#pyfms.pyFMS.init(alt_input_nml_path=None, +# localcomm=MPI.COMM_WORLD.Get_rank(), +# ndomain=1, +# nnest_domain=1, +# calendar_type=None) + +#pyfms.data_override.init() os.remove("input.nml") From 7101c5e9ebc09538d385abb3eb04c54a72119c5c Mon Sep 17 00:00:00 2001 From: mlee03 Date: Thu, 10 Apr 2025 19:19:20 -0400 Subject: [PATCH 06/14] push before losing --- pyfms/__init__.py | 20 +- pyfms/cfms.py | 10 +- pyfms/py_data_override/py_data_override.py | 3 + ...fms_diag_manager.py => py_diag_manager.py} | 131 ++-- pyfms/py_horiz_interp/py_horiz_interp.py | 77 ++- pyfms/py_mpp/py_mpp.py | 315 +++++---- pyfms/py_mpp/py_mpp_domains.py | 646 +++++------------- pyfms/pyfms_utils/grid_utils.py | 107 +-- tests/py_data_override/test_data_override.py | 33 +- 9 files changed, 559 insertions(+), 783 deletions(-) rename pyfms/py_diag_manager/{pyfms_diag_manager.py => py_diag_manager.py} (85%) diff --git a/pyfms/__init__.py b/pyfms/__init__.py index bb67f00..82fe082 100644 --- a/pyfms/__init__.py +++ b/pyfms/__init__.py @@ -1,20 +1,14 @@ - +from .cfms import cFMS from .py_data_override.py_data_override import data_override -from .py_diag_manager.pyfms_diag_manager import DiagManager -from .py_field_manager.py_field_manager import FieldTable -from .py_horiz_interp.py_horiz_interp import HorizInterp -from .py_mpp.py_mpp import pyFMS_mpp -from .py_mpp.py_mpp_domains import ( - pyDomain, - pyDomainData, - pyFMS_mpp_domains, - pyNestDomain, -) +from .py_diag_manager.py_diag_manager import diag_manager from .pyfms import fms +from .py_field_manager.py_field_manager import FieldTable +from .py_horiz_interp.py_horiz_interp import horiz_interp +from .py_mpp.py_mpp import mpp +from .py_mpp.py_mpp_domains import mpp_domains from .pyfms_utils import data_handling -from .pyfms_utils.grid_utils import GridUtils +from .pyfms_utils.grid_utils import grid_utils -from .cfms import cFMS cFMS.init() diff --git a/pyfms/cfms.py b/pyfms/cfms.py index fc1a961..be2b0a7 100644 --- a/pyfms/cfms.py +++ b/pyfms/cfms.py @@ -11,14 +11,18 @@ class cFMS(): def init(cls): pyfms.data_override.setlib(cls.libpath, cls.lib) pyfms.fms.setlib(cls.libpath, cls.lib) + pyfms.diag_manager.setlib(cls.libpath, cls.lib) + pyfms.grid_utils.setlib(cls.libpath, cls.lib) + pyfms.horiz_interp.setlib(cls.libpath, cls.lib) + pyfms.mpp.setlib(cls.libpath, cls.lib) + pyfms.mpp_domains.setlib(cls.libpath, cls.lib) @classmethod def changelib(cls, libpath): cls.__libpath = libpath cls.__lib = ctypes.CDLL(cls.__libpath) - pyfms.data_override.setlib(cls.libpath, cls.lib) - #pyfms.init.setlib(cls.__libpath, cls.__lib) - + cls.init() + @classmethod @property def lib(cls): diff --git a/pyfms/py_data_override/py_data_override.py b/pyfms/py_data_override/py_data_override.py index 1b14dcd..b8ec205 100644 --- a/pyfms/py_data_override/py_data_override.py +++ b/pyfms/py_data_override/py_data_override.py @@ -84,6 +84,7 @@ def init( mode_c, ) + @classmethod def set_time( cls, year: int = None, @@ -131,6 +132,7 @@ def set_time( year_c, month_c, day_c, hour_c, minute_c, second_c, tick_c, err_msg_c ) + @classmethod def override_scalar( cls, gridname: str, @@ -166,6 +168,7 @@ def override_scalar( # TODO: add check for override return data_c.value + @classmethod def override( cls, gridname: str, diff --git a/pyfms/py_diag_manager/pyfms_diag_manager.py b/pyfms/py_diag_manager/py_diag_manager.py similarity index 85% rename from pyfms/py_diag_manager/pyfms_diag_manager.py rename to pyfms/py_diag_manager/py_diag_manager.py index 16449ac..9e1d5a5 100644 --- a/pyfms/py_diag_manager/pyfms_diag_manager.py +++ b/pyfms/py_diag_manager/py_diag_manager.py @@ -15,29 +15,43 @@ ) -class DiagManager: - - # To be class var after refactor, accessed directly from cFMS - DIAG_ALL = 2 - - def __init__(self, clibFMS: ctypes.CDLL = None): - self.clibFMS = clibFMS - - def end(self): - _cfms_diag_end = self.clibFMS.cFMS_diag_end - - _cfms_diag_end.restype = None - - _cfms_diag_end() - +class diag_manager(): + + __libpath: str = None + __lib: ctypes.CDLL = None + + DIAG_ALL: int = None + DIAG_OCEAN: int = None + DIAG_OTHER: int = None + + @classmethod + def setlib(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 init( - self, + cls, diag_model_subset: int = None, time_init: NDArray = None, ) -> str: err_msg = " " - _cfms_diag_init = self.clibFMS.cFMS_diag_init + cls.DIAG_OTHER = ctypes.c_int.in_dll(cls.lib, "DIAG_OTHER") + cls.DIAG_OCEAN = ctypes.c_int.in_dll(cls.lib, "DIAG_OCEAN") + cls.DIAG_ALL = ctypes.c_int.in_dll(cls.lib,"DIAG_ALL") + + _cfms_diag_init = cls.lib.cFMS_diag_init diag_model_subset_c, diag_model_subset_t = setscalar_Cint32(diag_model_subset) time_init_p, time_init_t = setarray_Cint32(time_init) @@ -54,14 +68,21 @@ def init( return err_msg_c.value.decode("utf-8") + @classmethod + def end(cls): + _cfms_diag_end = cls.lib.cFMS_diag_end + _cfms_diag_end.restype = None + _cfms_diag_end() + + @classmethod def send_complete( - self, + cls, diag_field_id: int, ) -> str: err_msg = " " - _cfms_diag_send_complete = self.clibFMS.cFMS_diag_send_complete + _cfms_diag_send_complete = cls.lib.cFMS_diag_send_complete diag_field_id_c, diag_field_id_t = setscalar_Cint32(diag_field_id) err_msg_c, err_msg_t = set_Cchar(err_msg) @@ -73,8 +94,9 @@ def send_complete( return err_msg_c.value.decode("utf-8") + @classmethod def set_field_init_time( - self, + cls, year: int, month: int, day: int, @@ -86,7 +108,7 @@ def set_field_init_time( err_msg = " " - _cfms_diag_set_field_init_time = self.clibFMS.cFMS_diag_set_field_init_time + _cfms_diag_set_field_init_time = cls.lib.cFMS_diag_set_field_init_time year_c, year_t = setscalar_Cint32(year) month_c, month_t = setscalar_Cint32(month) @@ -115,8 +137,9 @@ def set_field_init_time( return err_msg_c.value.decode("utf-8") + @classmethod def set_field_timestep( - self, + cls, diag_field_id: int, dseconds: int, ddays: int = None, @@ -125,7 +148,7 @@ def set_field_timestep( err_msg = " " - _cfms_diag_set_field_timestep = self.clibFMS.cFMS_diag_set_field_timestep + _cfms_diag_set_field_timestep = cls.lib.cFMS_diag_set_field_timestep diag_field_id_c, diag_field_id_t = setscalar_Cint32(diag_field_id) dseconds_c, dseconds_t = setscalar_Cint32(dseconds) @@ -148,11 +171,12 @@ def set_field_timestep( return err_msg_c.value.decode("utf-8") + @classmethod def advance_field_time( - self, + cls, diag_field_id: int, ): - _cfms_diag_advance_field_time = self.clibFMS.cFMS_diag_advance_field_time + _cfms_diag_advance_field_time = cls.lib.cFMS_diag_advance_field_time diag_field_id_c, diag_field_id_t = setscalar_Cint32(diag_field_id) @@ -161,8 +185,9 @@ def advance_field_time( _cfms_diag_advance_field_time(diag_field_id_c) + @classmethod def set_time_end( - self, + cls, year: int = None, month: int = None, day: int = None, @@ -175,7 +200,7 @@ def set_time_end( if err_msg is not None: err_msg = err_msg[:128] - _cfms_set_time_end = self.clibFMS.cFMS_diag_set_time_end + _cfms_set_time_end = cls.lib.cFMS_diag_set_time_end year_c, year_t = setscalar_Cint32(year) month_c, month_t = setscalar_Cint32(month) @@ -209,8 +234,9 @@ def set_time_end( err_msg_c, ) + @classmethod def axis_init( - self, + cls, name: str, axis_data: NDArray, units: str, @@ -244,10 +270,10 @@ def axis_init( not_xy_c, not_xy_t = setscalar_Cbool(not_xy) if axis_data.dtype == np.float64: - _cfms_diag_axis_init_ = self.clibFMS.cFMS_diag_axis_init_cdouble + _cfms_diag_axis_init_ = cls.lib.cFMS_diag_axis_init_cdouble axis_data_p, axis_data_t = setarray_Cdouble(axis_data) elif axis_data.dtype == np.float32: - _cfms_diag_axis_init_ = self.clibFMS.cFMS_diag_axis_init_cfloat + _cfms_diag_axis_init_ = cls.lib.cFMS_diag_axis_init_cfloat axis_data_p, axis_data_t = setarray_Cfloat(axis_data) else: raise RuntimeError("diag_axis_init datatype not supported") @@ -287,8 +313,9 @@ def axis_init( not_xy_c, ) + @classmethod def register_field_array( - self, + cls, module_name: str, field_name: str, datatype, @@ -351,19 +378,19 @@ def register_field_array( if datatype == np.int32: _cfms_register_diag_field_array_ = ( - self.clibFMS.cFMS_register_diag_field_array_cint + cls.lib.cFMS_register_diag_field_array_cint ) range_data_p, range_data_t = setarray_Cint32(range_data) missing_value_c, missing_value_t = setscalar_Cint32(missing_value) elif datatype == np.float64: _cfms_register_diag_field_array_ = ( - self.clibFMS.cFMS_register_diag_field_array_cdouble + cls.lib.cFMS_register_diag_field_array_cdouble ) range_data_p, range_data_t = setarray_Cdouble(range_data) missing_value_c, missing_value_t = setscalar_Cdouble(missing_value) elif datatype == np.float32: _cfms_register_diag_field_array_ = ( - self.clibFMS.cFMS_register_diag_field_array_cfloat + cls.lib.cFMS_register_diag_field_array_cfloat ) range_data_p, range_data_t = setarray_Cfloat(range_data) missing_value_c, missing_value_t = setscalar_Cfloat(missing_value) @@ -415,8 +442,9 @@ def register_field_array( multiple_send_data_c, ) + @classmethod def register_field_scalar( - self, + cls, module_name: str, field_name: str, datatype, @@ -459,19 +487,19 @@ def register_field_scalar( if datatype == np.int32: _cfms_register_diag_field_scalar_ = ( - self.clibFMS.cFMS_register_diag_field_array_cint + cls.lib.cFMS_register_diag_field_array_cint ) range_data_p, range_data_t = setarray_Cint32(range_data) missing_value_c, missing_value_t = setscalar_Cint32(missing_value) elif datatype == np.float64: _cfms_register_diag_field_scalar_ = ( - self.clibFMS.cFMS_register_diag_field_array_cdouble + cls.lib.cFMS_register_diag_field_array_cdouble ) range_data_p, range_data_t = setarray_Cdouble(range_data) missing_value_c, missing_value_t = setscalar_Cdouble(missing_value) elif datatype == np.float32: _cfms_register_diag_field_scalar_ = ( - self.clibFMS.cFMS_register_diag_field_array_cfloat + cls.lib.cFMS_register_diag_field_array_cfloat ) range_data_p, range_data_t = setarray_Cfloat(range_data) missing_value_c, missing_value_t = setscalar_Cfloat(missing_value) @@ -513,8 +541,9 @@ def register_field_scalar( multiple_send_data_c, ) + @classmethod def send_data( - self, + cls, diag_field_id: int, field_shape: list[int], field: NDArray, @@ -529,49 +558,49 @@ def send_data( if field_shape_arr.size == 2: if field.dtype == np.int32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_2d_cint + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_2d_cint field_p, field_t = setarray_Cint32(field) elif field.dtype == np.float64: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_2d_cdouble + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_2d_cdouble field_p, field_t = setarray_Cdouble(field) elif field.dtype == np.float32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_2d_cfloat + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_2d_cfloat field_p, field_t = setarray_Cfloat(field) else: raise RuntimeError(f"diag_send_data {field.dtype} unsupported") elif field_shape_arr.size == 3: if field.dtype == np.int32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_3d_cint + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_3d_cint field_p, field_t = setarray_Cint32(field) elif field.dtype == np.float64: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_3d_cdouble + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_3d_cdouble field_p, field_t = setarray_Cdouble(field) elif field.dtype == np.float32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_3d_cfloat + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_3d_cfloat field_p, field_t = setarray_Cfloat(field) else: raise RuntimeError(f"diag_send_data {field.dtype} unsupported") elif field_shape_arr.size == 4: if field.dtype == np.int32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_4d_cint + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_4d_cint field_p, field_t = setarray_Cint32(field) elif field.dtype == np.float64: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_4d_cdouble + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_4d_cdouble field_p, field_t = setarray_Cdouble(field) elif field.dtype == np.float32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_4d_cfloat + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_4d_cfloat field_p, field_t = setarray_Cfloat(field) else: raise RuntimeError(f"diag_send_data {field.dtype} unsupported") elif field_shape_arr.size == 5: if field.dtype == np.int32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_5d_cint + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_5d_cint field_p, field_t = setarray_Cint32(field) elif field.dtype == np.float64: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_5d_cdouble + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_5d_cdouble field_p, field_t = setarray_Cdouble(field) elif field.dtype == np.float32: - _cfms_diag_send_data_ = self.clibFMS.cFMS_diag_send_data_5d_cfloat + _cfms_diag_send_data_ = cls.lib.cFMS_diag_send_data_5d_cfloat field_p, field_t = setarray_Cfloat(field) else: raise RuntimeError(f"diag_send_data {field.dtype} unsupported") diff --git a/pyfms/py_horiz_interp/py_horiz_interp.py b/pyfms/py_horiz_interp/py_horiz_interp.py index 92caa2b..15865db 100644 --- a/pyfms/py_horiz_interp/py_horiz_interp.py +++ b/pyfms/py_horiz_interp/py_horiz_interp.py @@ -4,16 +4,56 @@ import numpy.typing as npt -class HorizInterp: - def __init__(self, cfms: ctypes.CDLL): - self.cfms = cfms +class horiz_interp(): - def get_maxxgrid(self) -> np.int32: - self.cfms.get_maxxgrid.restype = np.int32 - return self.cfms.get_maxxgrid() + __libpath: str = None + __lib: ctypes.CDLL = None + @classmethod + def setlib(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 init(cls, ninterp: int = None): + _cfms_horiz_interp_init = cls.lib.cFMS_horiz_interp_init + + ninterp_c, ninterp_t = ctypes.c_int(ninterp), ctypes.POINTER(ctypes.c_int) + + _cfms_horiz_interp_init.argtypes = [ninterp_t] + _cfms_horiz_interp_init.restype = None + + _cfms_horiz_interp_init(ctypes.byref(ninterp_c)) + + @classmethod + def set_current_interp(cls, interp_id: int = None): + _cfms_set_current_interp = cls.lib.cFMS_set_current_interp + + interp_id_c, interp_id_t = ctypes.c_int(interp_id), ctypes.POINTER(ctypes.c_int) + + _cfms_set_current_interp.argtypes = [interp_id_t] + _cfms_set_current_interp.restype = None + + _cfms_set_current_interp(ctypes.byref(interp_id_c)) + + @classmethod + def get_maxxgrid(cls) -> np.int32: + cls.lib.get_maxxgrid.restype = np.int32 + return cls.lib.get_maxxgrid() + + @classmethod def create_xgrid_2dx2d_order1( - self, + cls, nlon_src: int, nlat_src: int, nlon_tgt: int, @@ -31,7 +71,7 @@ def create_xgrid_2dx2d_order1( ngrid_src_p1 = (nlon_src + 1) * (nlat_src + 1) ngrid_tgt_p1 = (nlon_tgt + 1) * (nlat_tgt + 1) - maxxgrid = self.get_maxxgrid() + maxxgrid = cls.get_maxxgrid() nlon_src_t = ctypes.c_int nlat_src_t = ctypes.c_int @@ -75,7 +115,7 @@ def create_xgrid_2dx2d_order1( j_tgt = np.zeros(maxxgrid, dtype=np.int32) xarea = np.zeros(maxxgrid, dtype=np.float64) - _create_xgrid = self.cfms.cFMS_create_xgrid_2dx2d_order1 + _create_xgrid = cls.lib.cFMS_create_xgrid_2dx2d_order1 _create_xgrid.restype = ctypes.c_int _create_xgrid.argtypes = [ @@ -129,22 +169,3 @@ def create_xgrid_2dx2d_order1( "xarea": xarea[:nxgrid], } - def horiz_interp_init(self, ninterp: int = None): - _cfms_horiz_interp_init = self.cfms.cFMS_horiz_interp_init - - ninterp_c, ninterp_t = ctypes.c_int(ninterp), ctypes.POINTER(ctypes.c_int) - - _cfms_horiz_interp_init.argtypes = [ninterp_t] - _cfms_horiz_interp_init.restype = None - - _cfms_horiz_interp_init(ctypes.byref(ninterp_c)) - - def set_current_interp(self, interp_id: int = None): - _cfms_set_current_interp = self.cfms.cFMS_set_current_interp - - interp_id_c, interp_id_t = ctypes.c_int(interp_id), ctypes.POINTER(ctypes.c_int) - - _cfms_set_current_interp.argtypes = [interp_id_t] - _cfms_set_current_interp.restype = None - - _cfms_set_current_interp(ctypes.byref(interp_id_c)) diff --git a/pyfms/py_mpp/py_mpp.py b/pyfms/py_mpp/py_mpp.py index e02ee2e..c5b1651 100644 --- a/pyfms/py_mpp/py_mpp.py +++ b/pyfms/py_mpp/py_mpp.py @@ -12,161 +12,160 @@ ) -class pyFMS_mpp: - - def __init__(self, cFMS: ctypes.CDLL = None): - self.cFMS = cFMS - - """ - Subroutine: declare_pelist - - This method is written specifically to accommodate a MPI restriction - that requires a parent communicator to create a child communicator. - In other words: a pelist cannot go off and declare a communicator, - but every PE in the parent, including those not in pelist(:), must get - together for the MPI_COMM_CREATE call. The parent is typically MPI_COMM_WORLD, - though it could also be a subset that includes all PEs in pelist. - - This call implies synchronization across the PEs in the current pelist, - of which pelist is a subset. - - The size of the passed pelist must match the current number - of npes; pelist(npes) - - Returns: commID is returned, and the object passed to the method should be - set to the result of the call - """ - - def declare_pelist( - self, - pelist: NDArray, - name: Optional[str] = None, - commID: Optional[int] = None, - ) -> int | None: - _cfms_declare_pelist = self.cFMS.cFMS_declare_pelist - - pelist_p, pelist_t = setarray_Cint32(pelist) - name_c, name_t = set_Cchar(name) - commID_c, commID_t = setscalar_Cint32(commID) - - _cfms_declare_pelist.argtypes = [pelist_t, name_t, commID_t] - _cfms_declare_pelist.restype = None - - _cfms_declare_pelist(pelist_p, name_c, commID_c) - - if commID is not None: - commID = commID_c.value - return commID - - """ - Subroutine: pyfms_error - - Error messaging method - - Returns: No return - """ - - def pyfms_error(self, errortype: int, errormsg: Optional[str] = None): - # truncating string - if errormsg is not None: - errormsg = errormsg[:128] - - _cfms_error = self.cFMS.cFMS_error - - errortype_c, errortype_t = setscalar_Cint32(errortype) - errormsg_c, errormsg_t = set_Cchar(errormsg) - - _cfms_error.argtypes = [errortype_t, errormsg_t] - _cfms_error.restype = None - - _cfms_error(errortype_c, errormsg_c) - - """ - Subroutine: get_current_pelist - - Passed pelist will be populated with the current pelist - - The size of the passed pelist must match the current number - of npes; pelist(npes) - - Returns: NDArray containing pelist - """ - - def get_current_pelist( - self, - name: Optional[str] = None, - commID: Optional[int] = None, - ) -> NDArray: - - npes = ctypes.c_int.in_dll(self.cFMS, "cFMS_pelist_npes") - pelist = np.empty(shape=npes.value, dtype=np.int32, order="C") - - _cfms_get_current_pelist = self.cFMS.cFMS_get_current_pelist - - pelist_p, pelist_t = setarray_Cint32(pelist) - name_c, name_t = set_Cchar(name) - commID_c, commID_t = setscalar_Cint32(commID) - - _cfms_get_current_pelist.argtypes = [pelist_t, name_t, commID_t] - _cfms_get_current_pelist.restype = None - - _cfms_get_current_pelist(pelist_p, name_c, commID_c) - - # TODO: allow for return of name after cFMS fix - - # if name is not None: - # name = name_c.value.decode("utf-8") - - # return commID, name - - return pelist - - """ - Function: npes - - Returns: number of pes in use - """ - - def npes(self) -> int: - _cfms_npes = self.cFMS.cFMS_npes - - _cfms_npes.restype = ctypes.c_int32 - - return _cfms_npes() - - """ - Function: pe - - Returns: pe number of calling pe - """ - - def pe(self) -> int: - _cfms_pe = self.cFMS.cFMS_pe - - _cfms_pe.restype = ctypes.c_int32 - - return _cfms_pe() - - """ - Subroutine: set_current_pelist - - Passed pelist will be used to set the current pelist - - The size of the passed pelist must match the current number - of npes; pelist(npes) - - Returns: No return - """ - - def set_current_pelist( - self, pelist: Optional[NDArray] = None, no_sync: Optional[bool] = None - ): - _cfms_set_current_pelist = self.cFMS.cFMS_set_current_pelist - - pelist_p, pelist_t = setarray_Cint32(pelist) - no_sync_c, no_sync_t = setscalar_Cbool(no_sync) - - _cfms_set_current_pelist.argtypes = [pelist_t, no_sync_t] - _cfms_set_current_pelist.restype = None - - _cfms_set_current_pelist(pelist_p, no_sync_c) +class mpp(): + + __libpath: str = None + __lib: ctypes.CDLL = None + + @classmethod + def setlib(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 + + + """ + Subroutine: declare_pelist + + This method is written specifically to accommodate a MPI restriction + that requires a parent communicator to create a child communicator. + In other words: a pelist cannot go off and declare a communicator, + but every PE in the parent, including those not in pelist(:), must get + together for the MPI_COMM_CREATE call. The parent is typically MPI_COMM_WORLD, + though it could also be a subset that includes all PEs in pelist. + + This call implies synchronization across the PEs in the current pelist, + of which pelist is a subset. + + The size of the passed pelist must match the current number + of npes; pelist(npes) + + Returns: commID is returned, and the object passed to the method should be + set to the result of the call + """ + + @classmethod + def declare_pelist( + cls, + pelist: NDArray, + name: str = None, + commID: int = None, + ) -> int | None: + _cfms_declare_pelist = cls.cFMS.cFMS_declare_pelist + + pelist_p, pelist_t = setarray_Cint32(pelist) + name_c, name_t = set_Cchar(name) + commID_c, commID_t = setscalar_Cint32(commID) + + _cfms_declare_pelist.argtypes = [pelist_t, name_t, commID_t] + _cfms_declare_pelist.restype = None + + _cfms_declare_pelist(pelist_p, name_c, commID_c) + + if commID is not None: + commID = commID_c.value + return commID + + """ + Subroutine: get_current_pelist + + Passed pelist will be populated with the current pelist + + The size of the passed pelist must match the current number + of npes; pelist(npes) + + Returns: NDArray containing pelist + """ + + @classmethod + def get_current_pelist( + cls, + name: str = None, + commID: int = None, + ) -> NDArray: + + npes = ctypes.c_int.in_dll(cls.cFMS, "cFMS_pelist_npes") + pelist = np.empty(shape=npes.value, dtype=np.int32, order="C") + + _cfms_get_current_pelist = cls.cFMS.cFMS_get_current_pelist + + pelist_p, pelist_t = setarray_Cint32(pelist) + name_c, name_t = set_Cchar(name) + commID_c, commID_t = setscalar_Cint32(commID) + + _cfms_get_current_pelist.argtypes = [pelist_t, name_t, commID_t] + _cfms_get_current_pelist.restype = None + + _cfms_get_current_pelist(pelist_p, name_c, commID_c) + + # TODO: allow for return of name after cFMS fix + + # if name is not None: + # name = name_c.value.decode("utf-8") + + # return commID, name + + return pelist + + """ + Function: npes + + Returns: number of pes in use + """ + + @classmethod + def npes(cls) -> int: + _cfms_npes = cls.lib.cFMS_npes + + _cfms_npes.restype = ctypes.c_int32 + + return _cfms_npes() + + """ + Function: pe + + Returns: pe number of calling pe + """ + + @classmethod + def pe(cls) -> int: + _cfms_pe = cls.lib.cFMS_pe + + _cfms_pe.restype = ctypes.c_int32 + + return _cfms_pe() + + """ + Subroutine: set_current_pelist + + Passed pelist will be used to set the current pelist + + The size of the passed pelist must match the current number + of npes; pelist(npes) + + Returns: No return + """ + + @classmethod + def set_current_pelist( + cls, pelist: Optional[NDArray] = None, no_sync: Optional[bool] = None + ): + _cfms_set_current_pelist = cls.lib.cFMS_set_current_pelist + + pelist_p, pelist_t = setarray_Cint32(pelist) + no_sync_c, no_sync_t = setscalar_Cbool(no_sync) + + _cfms_set_current_pelist.argtypes = [pelist_t, no_sync_t] + _cfms_set_current_pelist.restype = None + + _cfms_set_current_pelist(pelist_p, no_sync_c) + diff --git a/pyfms/py_mpp/py_mpp_domains.py b/pyfms/py_mpp/py_mpp_domains.py index dbf7ae3..2fd27e7 100644 --- a/pyfms/py_mpp/py_mpp_domains.py +++ b/pyfms/py_mpp/py_mpp_domains.py @@ -13,38 +13,27 @@ ) -class pyDomainData: - def __init__( - self, - xbegin=0, - xend=0, - ybegin=0, - yend=0, - xsize=0, - xmax_size=0, - ysize=0, - ymax_size=0, - x_is_global=False, - y_is_global=False, - tile_count=0, - ): - self.xbegin = ctypes.c_int(xbegin) - self.xend = ctypes.c_int(xend) - self.ybegin = ctypes.c_int(ybegin) - self.yend = ctypes.c_int(yend) - self.xsize = ctypes.c_int(xsize) - self.xmax_size = ctypes.c_int(xmax_size) - self.ysize = ctypes.c_int(ysize) - self.ymax_size = ctypes.c_int(ymax_size) - self.x_is_global = ctypes.c_bool(x_is_global) - self.y_is_global = ctypes.c_bool(y_is_global) - self.tile_count = ctypes.c_int(tile_count) - - -class pyFMS_mpp_domains: - def __init__(self, cFMS: ctypes.CDLL = None): - self.cFMS = cFMS +class mpp_domains(): + + __libpath: str = None + __lib: ctypes.CDLL = None + + @classmethod + def setlib(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 + + """ Subroutine: define_domains @@ -56,9 +45,9 @@ def __init__(self, cFMS: ctypes.CDLL = None): passed for the tile_count and tile_id arguments should also be set to the result of the method to update their values. """ - + @classmethod def define_domains( - self, + cls, global_indices: list[int], layout: list[int], domain_id: Optional[int] = None, @@ -85,7 +74,7 @@ def define_domains( y_cyclic_offset: Optional[int] = None, ): - _cfms_define_domains = self.cFMS.cFMS_define_domains + _cfms_define_domains = cls.lib.cFMS_define_domains global_indices_arr = np.array(global_indices, dtype=np.int32) layout_arr = np.array(layout, dtype=np.int32) @@ -179,8 +168,9 @@ def define_domains( Returns: No return """ - def define_io_domain(self, io_layout: list[int], domain_id: Optional[int] = None): - _cfms_define_io_domain = self.cFMS.cFMS_define_io_domain + @classmethod + def define_io_domain(cls, io_layout: list[int], domain_id: int = None): + _cfms_define_io_domain = cls.lib.cFMS_define_io_domain io_layout_arr = np.array(io_layout, dtype=np.int32) @@ -200,8 +190,9 @@ def define_io_domain(self, io_layout: list[int], domain_id: Optional[int] = None Returns: A NDArray containing the layout """ + @classmethod def define_layout( - self, + cls, global_indices: list[int], ndivs: int, ) -> list: @@ -210,7 +201,7 @@ def define_layout( global_indices_arr = np.array(global_indices, dtype=np.int32) - _cfms_define_layout = self.cFMS.cFMS_define_layout + _cfms_define_layout = cls.lib.cFMS_define_layout global_indices_p, global_indices_t = setarray_Cint32(global_indices_arr) ndivs_c, ndivs_t = setscalar_Cint32(ndivs) @@ -231,8 +222,9 @@ def define_layout( Returns: No return """ + @classmethod def define_nest_domains( - self, + cls, num_nest: int, ntiles: int, nest_level: NDArray, @@ -245,12 +237,12 @@ def define_nest_domains( npes_nest_tile: NDArray, x_refine: NDArray, y_refine: NDArray, - nest_domain_id: Optional[int] = None, - domain_id: Optional[int] = None, - extra_halo: Optional[int] = None, - name: Optional[str] = None, + nest_domain_id: int = None, + domain_id: int = None, + extra_halo: int = None, + name: str = None, ): - _cfms_define_nest_domain = self.cFMS.cFMS_define_nest_domains + _cfms_define_nest_domain = cls.lib.cFMS_define_nest_domains num_nest_p, num_nest_t = setscalar_Cint32(num_nest) ntiles_c, ntiles_t = setscalar_Cint32(ntiles) @@ -317,8 +309,9 @@ def define_nest_domains( Returns: Boolean """ - def domain_is_initialized(self, domain_id: Optional[int] = None) -> bool: - _cfms_domain_is_initialized = self.cFMS.cFMS_domain_is_initialized + @classmethod + def domain_is_initialized(cls, domain_id: int = None) -> bool: + _cfms_domain_is_initialized = cls.lib.cFMS_domain_is_initialized domain_id_c, domain_id_t = setscalar_Cint32(domain_id) @@ -341,80 +334,17 @@ def domain_is_initialized(self, domain_id: Optional[int] = None) -> bool: which were passed, overwriting the passed value. """ + @classmethod def get_compute_domain( - self, - domain_data: pyDomainData, - domain_id: Optional[int] = None, - position: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + cls, + domain_id: int = None, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None, ): - _cfms_get_compute_domain = self.cFMS.cFMS_get_compute_domain - - domain_id_c, domain_id_t = setscalar_Cint32(domain_id) - xbegin_c, xbegin_t = setscalar_Cint32(domain_data.xbegin) - xend_c, xend_t = setscalar_Cint32(domain_data.xend) - ybegin_c, ybegin_t = setscalar_Cint32(domain_data.ybegin) - yend_c, yend_t = setscalar_Cint32(domain_data.yend) - xsize_c, xsize_t = setscalar_Cint32(domain_data.xsize) - xmax_size_c, xmax_size_t = setscalar_Cint32(domain_data.xmax_size) - ysize_c, ysize_t = setscalar_Cint32(domain_data.ysize) - ymax_size_c, ymax_size_t = setscalar_Cint32(domain_data.ymax_size) - x_is_global_c, x_is_global_t = setscalar_Cbool(domain_data.x_is_global) - y_is_global_c, y_is_global_t = setscalar_Cbool(domain_data.y_is_global) - tile_count_c, tile_count_t = setscalar_Cint32(domain_data.tile_count) - position_c, position_t = setscalar_Cint32(position) - whalo_c, whalo_t = setscalar_Cint32(whalo) - shalo_c, shalo_t = setscalar_Cint32(shalo) - - _cfms_get_compute_domain.argtypes = [ - domain_id_t, - xbegin_t, - xend_t, - ybegin_t, - yend_t, - xsize_t, - xmax_size_t, - ysize_t, - ymax_size_t, - x_is_global_t, - y_is_global_t, - tile_count_t, - position_t, - whalo_t, - shalo_t, - ] - _cfms_get_compute_domain.restype = None - - _cfms_get_compute_domain( - domain_id_c, - xbegin_c, - xend_c, - ybegin_c, - yend_c, - xsize_c, - xmax_size_c, - ysize_c, - ymax_size_c, - x_is_global_c, - y_is_global_c, - tile_count_c, - position_c, - whalo_c, - shalo_c, - ) - - def get_compute_domain2( - self, - domain_id: int | None = None, - position: int | None = None, - tile_count: int | None = None, - whalo: int | None = None, - shalo: int | None = None, - ): - - _cfms_get_compute_domain = self.cFMS.cFMS_get_compute_domain + _cfms_get_compute_domain = cls.lib.cFMS_get_compute_domain default_i = 0 default_b = False @@ -517,52 +447,74 @@ def get_compute_domain2( which were passed, overwriting the passed value. """ + @classmethod def get_data_domain( - self, - domain_data: pyDomainData, - domain_id: Optional[int] = None, - position: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + cls, + domain_id: int = None, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None, ): - _cfms_get_data_domain = self.cFMS.cFMS_get_data_domain - domain_id_c, domain_id_t = setscalar_Cint32(domain_id) - xbegin_c, xbegin_t = setscalar_Cint32(domain_data.xbegin) - xend_c, xend_t = setscalar_Cint32(domain_data.xend) - ybegin_c, ybegin_t = setscalar_Cint32(domain_data.ybegin) - yend_c, yend_t = setscalar_Cint32(domain_data.yend) - xsize_c, xsize_t = setscalar_Cint32(domain_data.xsize) - xmax_size_c, xmax_size_t = setscalar_Cint32(domain_data.xmax_size) - ysize_c, ysize_t = setscalar_Cint32(domain_data.ysize) - ymax_size_c, ymax_size_t = setscalar_Cint32(domain_data.ymax_size) - x_is_global_c, x_is_global_t = setscalar_Cbool(domain_data.x_is_global) - y_is_global_c, y_is_global_t = setscalar_Cbool(domain_data.y_is_global) - tile_count_c, tile_count_t = setscalar_Cint32(domain_data.tile_count) - position_c, position_t = setscalar_Cint32(position) - whalo_c, whalo_t = setscalar_Cint32(whalo) - shalo_c, shalo_t = setscalar_Cint32(shalo) + _cfms_get_data_domain = cls.lib.cFMS_get_data_domain - _cfms_get_data_domain.argtypes = [ - domain_id_t, - xbegin_t, - xend_t, - ybegin_t, - yend_t, - xsize_t, - xmax_size_t, - ysize_t, - ymax_size_t, - x_is_global_t, - y_is_global_t, - tile_count_t, - position_t, - whalo_t, - shalo_t, + default_i = 0 + default_b = False + + domain_id_t = ctypes.c_int + xbegin_t = ctypes.c_int + xend_t = ctypes.c_int + ybegin_t = ctypes.c_int + yend_t = ctypes.c_int + xsize_t = ctypes.c_int + xmax_size_t = ctypes.c_int + ysize_t = ctypes.c_int + ymax_size_t = ctypes.c_int + x_is_global_t = ctypes.c_bool + y_is_global_t = ctypes.c_bool + tile_count_t = ctypes.c_int + position_t = ctypes.c_int + whalo_t = ctypes.c_int + shalo_t = ctypes.c_int + + xbegin_c = xbegin_t(default_i) + xend_c = xend_t(default_i) + ybegin_c = ybegin_t(default_i) + yend_c = yend_t(default_i) + xsize_c = xsize_t(default_i) + xmax_size_c = xmax_size_t(default_i) + ysize_c = ysize_t(default_i) + ymax_size_c = ymax_size_t(default_i) + x_is_global_c = x_is_global_t(default_b) + y_is_global_c = y_is_global_t(default_b) + domain_id_c = domain_id_t(domain_id) if domain_id is not None else None + tile_count_c = tile_count_t(tile_count) if tile_count is not None else None + position_c = position_t(position) if tile_count is not None else None + whalo_c = whalo_t(whalo) if whalo is not None else None + shalo_c = shalo_t(shalo) if shalo is not None else None + + _cfms_get_compute_domain.argtypes = [ + ctypes.POINTER(domain_id_t), + ctypes.POINTER(xbegin_t), + ctypes.POINTER(xend_t), + ctypes.POINTER(ybegin_t), + ctypes.POINTER(yend_t), + ctypes.POINTER(xsize_t), + ctypes.POINTER(xmax_size_t), + ctypes.POINTER(ysize_t), + ctypes.POINTER(ymax_size_t), + ctypes.POINTER(x_is_global_t), + ctypes.POINTER(y_is_global_t), + ctypes.POINTER(tile_count_t), + ctypes.POINTER(position_t), + ctypes.POINTER(whalo_t), + ctypes.POINTER(shalo_t), ] - _cfms_get_data_domain.restype = None - _cfms_get_data_domain( + _cfms_get_compute_domain.restype = None + + _cfms_get_compute_domain( domain_id_c, xbegin_c, xend_c, @@ -580,6 +532,20 @@ def get_data_domain( shalo_c, ) + return dict( + domain_id=domain_id_c.value, + xbegin=xbegin_c.value, + ybegin=ybegin_c.value, + xend=xend_c.value, + yend=yend_c.value, + xsize=xsize_c.value, + ysize=ysize_c.value, + xmax_size=xmax_size_c.value, + ymax_size=ymax_size_c.value, + x_is_global=x_is_global_c.value, + y_is_global=y_is_global_c.value, + ) + """ Subroutine: get_domain_name @@ -591,8 +557,9 @@ def get_data_domain( its value as well. """ - def get_domain_name(self, domain_id: Optional[int] = None) -> str: - _cfms_get_domain_name = self.cFMS.cFMS_get_domain_name + @classmethod + def get_domain_name(cls, domain_id: int = None) -> str: + _cfms_get_domain_name = cls.lib.cFMS_get_domain_name domain_name = "" @@ -614,11 +581,12 @@ def get_domain_name(self, domain_id: Optional[int] = None) -> str: Returns: NDArray with layout info """ - def get_layout(self, domain_id: Optional[int] = None) -> NDArray: + @classmethod + def get_layout(cls, domain_id: int = None) -> NDArray: layout = np.empty(shape=2, dtype=np.int32, order="C") - _cfms_get_layout = self.cFMS.cFMS_get_layout + _cfms_get_layout = cls.lib.cFMS_get_layout layout_p, layout_t = setarray_Cint32(layout) domain_id_c, domain_id_t = setscalar_Cint32(domain_id) @@ -636,12 +604,13 @@ def get_layout(self, domain_id: Optional[int] = None) -> NDArray: Returns: NDArray containing pelist """ - def get_domain_pelist(self, domain_id: Optional[int]) -> NDArray: + @classmethod + def get_domain_pelist(cls, domain_id: int = None) -> NDArray: - npes = ctypes.c_int.in_dll(self.cFMS, "cFMS_pelist_npes") + npes = ctypes.c_int.in_dll(cls.lib, "cFMS_pelist_npes") pelist = np.empty(shape=npes.value, dtype=np.int32, order="C") - _cfms_get_domain_pelist = self.cFMS.cFMS_get_domain_pelist + _cfms_get_domain_pelist = cls.lib.cFMS_get_domain_pelist pelist_p, pelist_t = setarray_Cint32(pelist) domain_id_c, domain_id_t = setscalar_Cint32(domain_id) @@ -670,22 +639,23 @@ def get_domain_pelist(self, domain_id: Optional[int]) -> NDArray: which were passed, overwriting the passed value. """ + @classmethod def set_compute_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + cls, + xbegin: int = None, + xend: int = None, + ybegin: int = None, + yend: int = None, + xsize: int = None, + ysize: int = None, + x_is_global: bool = None, + y_is_global: bool = None, + tile_count: int = None, + domain_id: int = None, + whalo: int = None, + shalo: int = None, ): - _cfms_set_compute_domain = self.cFMS.cFMS_set_compute_domain + _cfms_set_compute_domain = cls.lib.cFMS_set_compute_domain domain_id_c, domain_id_t = setscalar_Cint32(domain_id) xbegin_c, xbegin_t = setscalar_Cint32(xbegin) @@ -738,8 +708,9 @@ def set_compute_domain( to domain_id """ - def set_current_domain(self, domain_id: Optional[int] = None): - _cfms_set_current_domain = self.cFMS.cFMS_set_current_domain + @classmethod + def set_current_domain(cls, domain_id: int = None): + _cfms_set_current_domain = cls.lib.cFMS_set_current_domain domain_id_c, domain_id_t = setscalar_Cint32(domain_id) @@ -755,8 +726,9 @@ def set_current_domain(self, domain_id: Optional[int] = None): to nest_domain_id """ - def set_current_nest_domain(self, nest_domain_id: Optional[int] = None): - _cfms_set_current_nest_domain = self.cFMS.cFMS_set_current_nest_domain + @classmethod + def set_current_nest_domain(cls, nest_domain_id: int = None): + _cfms_set_current_nest_domain = cls.lib.cFMS_set_current_nest_domain nest_domain_id_c, nest_domain_id_t = setscalar_Cint32(nest_domain_id) @@ -778,22 +750,23 @@ def set_current_nest_domain(self, nest_domain_id: Optional[int] = None): which were passed, overwriting the passed value. """ + @classmethod def set_data_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + cls, + xbegin: int = None, + xend: int = None, + ybegin: int = None, + yend: int = None, + xsize: int = None, + ysize: int = None, + x_is_global: bool = None, + y_is_global: bool = None, + tile_count: int = None, + domain_id: int = None, + whalo: int = None, + shalo: int = None, ): - _cfms_set_data_domain = self.cFMS.cFMS_set_data_domain + _cfms_set_data_domain = cls.lib.cFMS_set_data_domain domain_id_c, domain_id_t = setscalar_Cint32(domain_id) xbegin_c, xbegin_t = setscalar_Cint32(xbegin) @@ -856,20 +829,21 @@ def set_data_domain( which were passed, overwriting the passed value. """ + @classmethod def set_global_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + cls, + xbegin: int = None, + xend: int = None, + ybegin: int = None, + yend: int = None, + xsize: int = None, + ysize: int = None, + tile_count: int = None, + domain_id: int = None, + whalo: int = None, + shalo: int = None, ): - _cfms_set_global_domain = self.cFMS.cFMS_set_global_domain + _cfms_set_global_domain = cls.lib.cFMS_set_global_domain domain_id_c, domain_id_t = setscalar_Cint32(domain_id) xbegin_c, xbegin_t = setscalar_Cint32(xbegin) @@ -908,259 +882,3 @@ def set_global_domain( whalo_c, shalo_c, ) - - -class pyDomain: - def __init__( - self, - mpp_domains_obj: pyFMS_mpp_domains, - global_indices: list[int], - layout: list[int], - domain_id: Optional[int] = None, - pelist: Optional[NDArray] = None, - xflags: Optional[int] = None, - yflags: Optional[int] = None, - xhalo: Optional[int] = None, - yhalo: Optional[int] = None, - xextent: Optional[NDArray] = None, - yextent: Optional[NDArray] = None, - maskmap: Optional[NDArray[np.bool_]] = None, - name: Optional[str] = None, - symmetry: Optional[bool] = None, - memory_size: Optional[NDArray] = None, - whalo: Optional[int] = None, - ehalo: Optional[int] = None, - shalo: Optional[int] = None, - nhalo: Optional[int] = None, - is_mosaic: Optional[bool] = None, - tile_count: Optional[int] = None, - tile_id: Optional[int] = None, - complete: Optional[bool] = None, - x_cyclic_offset: Optional[int] = None, - y_cyclic_offset: Optional[int] = None, - ): - self.mpp_domains_obj = mpp_domains_obj - self.global_indices = global_indices - self.layout = layout - self.domain_id = domain_id - self.pelist = pelist - self.xflags = xflags - self.yflags = yflags - self.xhalo = xhalo - self.yhalo = yhalo - self.xextent = xextent - self.yextent = yextent - self.maskmap = maskmap - self.name = name - self.symmetry = symmetry - self.memory_size = memory_size - self.whalo = whalo - self.ehalo = ehalo - self.shalo = shalo - self.nhalo = nhalo - self.is_mosaic = is_mosaic - self.tile_count = tile_count - self.tile_id = tile_id - self.complete = complete - self.x_cyclic_offset = x_cyclic_offset - self.y_cyclic_offset = y_cyclic_offset - self.compute_domain = pyDomainData() - self.data_domain = pyDomainData() - - self.mpp_domains_obj.define_domains( - global_indices=self.global_indices, - layout=self.layout, - domain_id=self.domain_id, - pelist=self.pelist, - xflags=self.xflags, - yflags=self.yflags, - xhalo=self.xhalo, - yhalo=self.yhalo, - xextent=self.xextent, - yextent=self.yextent, - maskmap=self.maskmap, - name=self.name, - symmetry=self.symmetry, - memory_size=self.memory_size, - whalo=self.whalo, - ehalo=self.ehalo, - shalo=self.shalo, - nhalo=self.nhalo, - is_mosaic=self.is_mosaic, - tile_count=self.tile_count, - tile_id=self.tile_id, - complete=self.complete, - x_cyclic_offset=self.x_cyclic_offset, - y_cyclic_offset=self.y_cyclic_offset, - ) - self.mpp_domains_obj.get_compute_domain( - domain_data=self.compute_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - self.mpp_domains_obj.get_data_domain( - domain_data=self.data_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_compute_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_compute_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - x_is_global=x_is_global, - y_is_global=y_is_global, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - - self.mpp_domains_obj.get_compute_domain( - domain_data=self.compute_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_data_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_data_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - x_is_global=x_is_global, - y_is_global=y_is_global, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - - self.mpp_domains_obj.get_data_domain( - domain_data=self.data_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_global_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_global_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - - -class pyNestDomain: - def __init__( - self, - mpp_domains_obj: pyFMS_mpp_domains, - num_nest: int, - ntiles: int, - nest_level: NDArray, - tile_fine: NDArray, - tile_coarse: NDArray, - istart_coarse: NDArray, - icount_coarse: NDArray, - jstart_coarse: NDArray, - jcount_coarse: NDArray, - npes_nest_tile: NDArray, - x_refine: NDArray, - y_refine: NDArray, - nest_domain_id: Optional[int] = None, - domain_id: Optional[int] = None, - extra_halo: Optional[int] = None, - name: Optional[str] = None, - ): - self.mpp_domains_obj = mpp_domains_obj - self.num_nest = num_nest - self.ntiles = ntiles - self.nest_level = nest_level - self.tile_fine = tile_fine - self.tile_coarse = tile_coarse - self.istart_coarse = istart_coarse - self.icount_coarse = icount_coarse - self.jstart_coarse = jstart_coarse - self.jcount_coarse = jcount_coarse - self.npes_nest_tile = npes_nest_tile - self.x_refine = x_refine - self.y_refine = y_refine - self.nest_domain_id = nest_domain_id - self.domain_id = domain_id - self.extra_halo = extra_halo - self.name = name - - self.mpp_domains_obj.define_nest_domains( - num_nest=self.num_nest, - ntiles=self.ntiles, - nest_level=self.nest_level, - tile_fine=self.tile_fine, - tile_coarse=self.tile_coarse, - istart_coarse=self.istart_coarse, - icount_coarse=self.icount_coarse, - jstart_coarse=self.jstart_coarse, - jcount_coarse=self.jcount_coarse, - npes_nest_tile=self.npes_nest_tile, - x_refine=self.x_refine, - y_refine=self.y_refine, - nest_domain_id=self.nest_domain_id, - domain_id=self.domain_id, - extra_halo=self.extra_halo, - name=self.name, - ) diff --git a/pyfms/pyfms_utils/grid_utils.py b/pyfms/pyfms_utils/grid_utils.py index 2cf8251..535527c 100644 --- a/pyfms/pyfms_utils/grid_utils.py +++ b/pyfms/pyfms_utils/grid_utils.py @@ -4,49 +4,66 @@ import numpy.typing as npt -class GridUtils: - @staticmethod - def get_grid_area( - cfms: ctypes.CDLL, - nlon: int, - nlat: int, - lon: npt.NDArray[np.float64], - lat: npt.NDArray[np.float64], - ) -> npt.NDArray[np.float64]: +class grid_utils(): - ncells = nlon * nlat - ngridpts = (nlon + 1) * (nlat + 1) - - nlon_t = ctypes.c_int - nlat_t = ctypes.c_int - lon_ndp = np.ctypeslib.ndpointer( - dtype=np.float64, shape=(ngridpts), flags="C_CONTIGUOUS" - ) - lat_ndp = np.ctypeslib.ndpointer( - dtype=np.float64, shape=(ngridpts), flags="C_CONTIGUOUS" - ) - area_ndp = np.ctypeslib.ndpointer( - dtype=np.float64, shape=(ncells), flags="C_CONTIGUOUS" - ) - - nlon_c = nlon_t(nlon) - nlat_c = nlat_t(nlat) - area = np.zeros(ncells, dtype=np.float64) - - _get_grid_area = cfms.cFMS_get_grid_area - - _get_grid_area.restype = None - _get_grid_area.argtypes = [ - ctypes.POINTER(nlon_t), - ctypes.POINTER(nlat_t), - lon_ndp, - lat_ndp, - area_ndp, - ] - - nlon_c = nlon_t(nlon) - nlat_c = nlat_t(nlat) - - _get_grid_area(ctypes.byref(nlon_c), ctypes.byref(nlat_c), lon, lat, area) - - return area + __libpath: str = None + __lib: ctypes.CDLL = None + + @classmethod + def setlib(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 + + def get_grid_area( + nlon: int, + nlat: int, + lon: npt.NDArray[np.float64], + lat: npt.NDArray[np.float64], + ) -> npt.NDArray[np.float64]: + + ncells = nlon * nlat + ngridpts = (nlon + 1) * (nlat + 1) + + nlon_t = ctypes.c_int + nlat_t = ctypes.c_int + lon_ndp = np.ctypeslib.ndpointer( + dtype=np.float64, shape=(ngridpts), flags="C_CONTIGUOUS" + ) + lat_ndp = np.ctypeslib.ndpointer( + dtype=np.float64, shape=(ngridpts), flags="C_CONTIGUOUS" + ) + area_ndp = np.ctypeslib.ndpointer( + dtype=np.float64, shape=(ncells), flags="C_CONTIGUOUS" + ) + + nlon_c = nlon_t(nlon) + nlat_c = nlat_t(nlat) + area = np.zeros(ncells, dtype=np.float64) + + _get_grid_area = cfms.cFMS_get_grid_area + + _get_grid_area.restype = None + _get_grid_area.argtypes = [ + ctypes.POINTER(nlon_t), + ctypes.POINTER(nlat_t), + lon_ndp, + lat_ndp, + area_ndp, + ] + + nlon_c = nlon_t(nlon) + nlat_c = nlat_t(nlat) + + _get_grid_area(ctypes.byref(nlon_c), ctypes.byref(nlat_c), lon, lat, area) + + return area diff --git a/tests/py_data_override/test_data_override.py b/tests/py_data_override/test_data_override.py index 6e64825..97c6188 100644 --- a/tests/py_data_override/test_data_override.py +++ b/tests/py_data_override/test_data_override.py @@ -10,11 +10,6 @@ @pytest.mark.parallel def test_data_override(): - pyfmsobj = pyfms.pyFMS() - cfms = pyfmsobj.cFMS - mpp = pyfms.pyFMS_mpp(cFMS=cfms) - mpp_domains = pyfms.pyFMS_mpp_domains(cFMS=cfms) - ocn_domain_id = 0 nx = 360 ny = 180 @@ -22,14 +17,11 @@ def test_data_override(): ehalo = 2 whalo = 2 shalo = 2 - nhalo = 2 - - global_indices = np.array([0, nx - 1, 0, ny - 1], dtype=np.int32, order="C") - layout = np.array([2, 3], dtype=np.int32, order="C") - - mpp_domains.define_domains( - global_indices=global_indices, - layout=layout, + nhalo = 2 + + pyfms.mpp_domains.define_domains( + global_indices=[0, nx-1, 0, ny-1], + layout=[2,3], ehalo=ehalo, whalo=whalo, shalo=shalo, @@ -37,20 +29,19 @@ def test_data_override(): domain_id=ocn_domain_id, ) - compute_dict = mpp_domains.get_compute_domain2(domain_id=ocn_domain_id) + compute_dict = pyfms.mpp_domains.get_compute_domain(domain_id=ocn_domain_id) xsize = compute_dict["xsize"] ysize = compute_dict["ysize"] - data_override = pyfms.pyDataOverride(cfms) - data_override.init(ocn_domain_id=ocn_domain_id) - data_override.set_time(year=1, month=1, day=3, hour=0, minute=0, second=0, tick=0) + pyfms.data_override.init(ocn_domain_id=ocn_domain_id) + pyfms.data_override.set_time(year=1, month=1, day=3, hour=0, minute=0, second=0, tick=0) - data = data_override.override_scalar( + data = pyfms.data_override.override_scalar( gridname="OCN", fieldname="runoff_scalar", data_type=np.float64 ) assert data == 2.0 - data = data_override.override( + data = pyfms.data_override.override( gridname="OCN", fieldname="runoff_2d", data_shape=(xsize, ysize), @@ -58,7 +49,7 @@ def test_data_override(): ) assert np.all(data == 200.0) - data = data_override.override( + data = pyfms.data_override.override( gridname="OCN", fieldname="runoff_3d", data_shape=(xsize, ysize, nz), @@ -69,7 +60,7 @@ def test_data_override(): ) assert np.all(data == answers) - pyfmsobj.pyfms_end() + pyfms.fms.end() @pytest.mark.remove From 73be11a2efe126019250a4e52e2a5374fc7e90a1 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Thu, 10 Apr 2025 20:28:45 -0400 Subject: [PATCH 07/14] changes to diag_manager --- pyfms/py_diag_manager/py_diag_manager.py | 24 ++++--- pyfms/pyfms.py | 18 ++++- run_tests.sh | 28 ++++---- testme.py | 43 +++++++++--- tests/py_data_override/test_data_override.py | 5 +- tests/py_diag_manager/test_diag_manager.py | 74 +++++++++----------- 6 files changed, 117 insertions(+), 75 deletions(-) diff --git a/pyfms/py_diag_manager/py_diag_manager.py b/pyfms/py_diag_manager/py_diag_manager.py index 9e1d5a5..c4fc158 100644 --- a/pyfms/py_diag_manager/py_diag_manager.py +++ b/pyfms/py_diag_manager/py_diag_manager.py @@ -2,6 +2,7 @@ import numpy as np from numpy.typing import NDArray +from typing import Any from pyfms.pyfms_utils.data_handling import ( set_Cchar, @@ -323,7 +324,7 @@ def register_field_array( long_name: str = None, units: str = None, missing_value: int = None, - range_data: NDArray = None, + range_data: list[np.int32|np.int64|np.float32|np.float64] = None, mask_variant: bool = None, standard_name: str = None, verbose: bool = None, @@ -352,13 +353,14 @@ def register_field_array( realm = realm[:64] if axes is not None: - if len(axes) < 5: - for i in range(5 - len(axes)): - axes.append(0) - axes_arr = np.array(axes, dtype=np.int32) - else: - axes_arr = None - + axes_arr = axes + while len(axes_arr) < 5: + axes_arr.append(0) + axes_arr = np.array(axes_arr, dtype=np.int32) + + if range_data is not None: + range_data_arr = np.array(range_data, dtype=datatype) + module_name_c, module_name_t = set_Cchar(module_name) field_name_c, field_name_t = set_Cchar(field_name) axes_p, axes_t = setarray_Cint32(axes_arr) @@ -380,19 +382,19 @@ def register_field_array( _cfms_register_diag_field_array_ = ( cls.lib.cFMS_register_diag_field_array_cint ) - range_data_p, range_data_t = setarray_Cint32(range_data) + range_data_p, range_data_t = setarray_Cint32(range_data_arr) missing_value_c, missing_value_t = setscalar_Cint32(missing_value) elif datatype == np.float64: _cfms_register_diag_field_array_ = ( cls.lib.cFMS_register_diag_field_array_cdouble ) - range_data_p, range_data_t = setarray_Cdouble(range_data) + range_data_p, range_data_t = setarray_Cdouble(range_data_arr) missing_value_c, missing_value_t = setscalar_Cdouble(missing_value) elif datatype == np.float32: _cfms_register_diag_field_array_ = ( cls.lib.cFMS_register_diag_field_array_cfloat ) - range_data_p, range_data_t = setarray_Cfloat(range_data) + range_data_p, range_data_t = setarray_Cfloat(range_data_arr) missing_value_c, missing_value_t = setscalar_Cfloat(missing_value) else: raise RuntimeError( diff --git a/pyfms/pyfms.py b/pyfms/pyfms.py index ab865a2..19cfa05 100755 --- a/pyfms/pyfms.py +++ b/pyfms/pyfms.py @@ -10,6 +10,14 @@ class fms: __lib: ctypes.CDLL = None __initialized = False + NOTE : int = None + WARNING: int = None + FATAL: int = None + THIRTY_DAY_MONTHS: int = None + GREGORIAN: int = None + JULIAN: int = None + NOLEAP: int = None + @classmethod def setlib(cls, libpath, lib): cls.__lib_path = libpath @@ -33,6 +41,14 @@ def init(cls, nnest_domain: int = None, calendar_type: int = None, ): + + cls.NOTE = ctypes.c_int.in_dll(cls.lib, "NOTE") + cls.WARNING = ctypes.c_int.in_dll(cls.lib, "WARNING") + cls.FATAL = ctypes.c_int.in_dll(cls.lib, "FATAL") + cls.THIRTY_DAY_MONTHS = ctypes.c_int.in_dll(cls.lib, "THIRTY_DAY_MONTHS") + cls.GREGORIAN = ctypes.c_int.in_dll(cls.lib, "GREGORIAN") + cls.JULIAN = ctypes.c_int.in_dll(cls.lib, "JULIAN") + cls.NOLEAP = ctypes.c_int.in_dll(cls.lib, "NOLEAP") _cfms_init = cls.lib.cFMS_init @@ -69,7 +85,7 @@ def init(cls, """ @classmethod - def pyfms_end(cls): + def end(cls): _cfms_end = cls.lib.cFMS_end _cfms_end.restype = None _cfms_end() diff --git a/run_tests.sh b/run_tests.sh index a02a022..035b2da 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -16,22 +16,22 @@ function run_test() { run_test "pytest tests/test_build.py" -test="tests/test_pyfms.py" -create_input $test -run_test "pytest -m parallel $test" -remove_input $test +#test="tests/test_pyfms.py" +#create_input $test +#run_test "pytest -m parallel $test" +#remove_input $test -test="tests/py_mpp/test_define_domains.py" -create_input $test -run_test "mpirun -n 8 python -m pytest -m 'parallel' $test" -remove_input $test +#test="tests/py_mpp/test_define_domains.py" +#create_input $test +#run_test "mpirun -n 8 python -m pytest -m 'parallel' $test" +#remove_input $test -test="tests/py_mpp/test_getset_domains.py" -create_input $test -run_test "mpirun -n 4 python -m pytest -m 'parallel' tests/py_mpp/test_getset_domains.py" -remove_input $test +#test="tests/py_mpp/test_getset_domains.py" +#create_input $test +#run_test "mpirun -n 4 python -m pytest -m 'parallel' tests/py_mpp/test_getset_domains.py" +#remove_input $test -run_test "pytest tests/py_horiz_interp" +#run_test "pytest tests/py_horiz_interp" run_test "pytest tests/py_data_override/test_generate_files.py" run_test "mpirun -n 6 python -m pytest -m 'parallel' tests/py_data_override/test_data_override.py" @@ -39,6 +39,6 @@ remove_input "tests/py_data_override/test_data_override.py" run_test "pytest tests/py_diag_manager/test_generate_files.py" run_test "mpirun -n 1 python -m pytest tests/py_diag_manager/test_diag_manager.py" -remove_input "tests/py_diag_manager/test_diag_manager.py +remove_input "tests/py_diag_manager/test_diag_manager.py" rm -rf INPUT *logfile* *warnfile* diff --git a/testme.py b/testme.py index 411a2f3..3dd7cfc 100755 --- a/testme.py +++ b/testme.py @@ -7,23 +7,48 @@ input_nml.close() cfms = pyfms.cFMS.lib +print(cfms) + cfms_do = pyfms.data_override.lib +print(cfms_do) + +cfms_fms = pyfms.fms.lib +print(cfms_fms) + +cfms_diag_manager = pyfms.diag_manager.lib +print(cfms_diag_manager) + +cfms_horiz_interp = pyfms.horiz_interp.lib +print(cfms_horiz_interp) + +cfms_grid_utils = pyfms.grid_utils.lib +print(cfms_horiz_interp) + +cfms_mpp = pyfms.mpp.lib +print(cfms_mpp) + +cfms_mpp_domains = pyfms.mpp_domains.lib +print(cfms_mpp_domains) + +pyfms.fms.init(alt_input_nml_path=None, + localcomm=MPI.COMM_WORLD.Get_rank(), + ndomain=1, + nnest_domain=1, + calendar_type=None) + +#pyfms.diag_manager.init() +#cfms_path = pyfms.cFMS.libpath +#cfms_path_do = pyfms.data_override.libpath -cfms_path = pyfms.cFMS.libpath -cfms_path_do = pyfms.data_override.libpath -assert(id(cfms)==id(cfms_do)) -assert(cfms_path == cfms_path_do) +#assert(id(cfms)==id(cfms_do)) +#assert(cfms_path == cfms_path_do) #fake_path = "I/dont/exist" #pyfms.cFMS.cfms_path = fake_path #assert(pyfms.cFMS.lib()[0] is not fake_path) -#pyfms.pyFMS.init(alt_input_nml_path=None, -# localcomm=MPI.COMM_WORLD.Get_rank(), -# ndomain=1, -# nnest_domain=1, -# calendar_type=None) +#pyfms.pyFMS.init( #pyfms.data_override.init() diff --git a/tests/py_data_override/test_data_override.py b/tests/py_data_override/test_data_override.py index 97c6188..318a4c8 100644 --- a/tests/py_data_override/test_data_override.py +++ b/tests/py_data_override/test_data_override.py @@ -18,7 +18,8 @@ def test_data_override(): whalo = 2 shalo = 2 nhalo = 2 - + + pyfms.fms.init() pyfms.mpp_domains.define_domains( global_indices=[0, nx-1, 0, ny-1], layout=[2,3], @@ -71,3 +72,5 @@ def test_remove_files(): assert not os.path.exists("INPUT") assert not os.path.isfile("input.nml") assert not os.path.isfile("data_table.yaml") + + diff --git a/tests/py_diag_manager/test_diag_manager.py b/tests/py_diag_manager/test_diag_manager.py index ce65291..8636251 100644 --- a/tests/py_diag_manager/test_diag_manager.py +++ b/tests/py_diag_manager/test_diag_manager.py @@ -1,7 +1,5 @@ import numpy as np - -from pyfms import DiagManager, pyFMS, pyFMS_mpp_domains - +import pyfms def test_send_data(): @@ -10,13 +8,15 @@ def test_send_data(): NZ = 2 domain_id = 0 - calendar_type = 4 + calendar_type = pyfms.fms.NOLEAP + DIAG_ALL = pyfms.diag_manager.DIAG_ALL + var2_shape = [NX, NY] - var2 = np.empty(shape=(NX, NY), dtype=np.float32) - + var2 = np.empty(shape=var2_shape, dtype=np.float32) + var3_shape = [NX, NY, NZ] - var3 = np.empty(shape=(NX, NY, NZ), dtype=np.float32) + var3 = np.empty(shape=var3_shape, dtype=np.float32) for i in range(NX): for j in range(NY): @@ -27,21 +27,18 @@ def test_send_data(): for j in range(NY): var2[i][j] = i * 10.0 + j * 1.0 - cfms_path = "./cFMS/libcFMS/.libs/libcFMS.so" - - pyfms = pyFMS(cFMS_path=cfms_path, calendar_type=calendar_type) - mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) - + pyfms.fms.init() + global_indices = [0, (NX - 1), 0, (NY - 1)] layout = [1, 1] io_layout = [1, 1] - mpp_domains.define_domains( + pyfms.mpp_domains.define_domains( domain_id=domain_id, global_indices=global_indices, layout=layout, ) - mpp_domains.define_io_domain( + pyfms.mpp_domains.define_io_domain( domain_id=domain_id, io_layout=io_layout, ) @@ -50,17 +47,16 @@ def test_send_data(): diag manager init """ - diag_manager = DiagManager(clibFMS=pyfms.cFMS) - diag_manager.init(diag_model_subset=diag_manager.DIAG_ALL) + pyfms.diag_manager.init(diag_model_subset=DIAG_ALL) - mpp_domains.set_current_domain(domain_id=domain_id) + pyfms.mpp_domains.set_current_domain(domain_id=domain_id) """ diag axis init x """ x = np.arange(NX, dtype=np.float64) - id_x = diag_manager.axis_init( + id_x = pyfms.diag_manager.axis_init( name="x", axis_data=x, units="point_E", @@ -74,7 +70,7 @@ def test_send_data(): """ y = np.arange(NY, dtype=np.float64) - id_y = diag_manager.axis_init( + id_y = pyfms.diag_manager.axis_init( name="y", axis_data=y, units="point_N", @@ -89,7 +85,7 @@ def test_send_data(): z = np.arange(NZ, dtype=np.float64) - id_z = diag_manager.axis_init( + id_z = pyfms.diag_manager.axis_init( name="z", axis_data=z, units="point_Z", @@ -104,9 +100,9 @@ def test_send_data(): """ axes_3d = [id_x, id_y, id_z] - range_3d = np.array([-1000.0, 1000.0], dtype=np.float32) + range_3d = [-1000.0, 1000.0] - diag_manager.set_field_init_time( + pyfms.diag_manager.set_field_init_time( year=2, month=1, day=1, @@ -115,7 +111,7 @@ def test_send_data(): second=1, ) - id_var3 = diag_manager.register_field_array( + id_var3 = pyfms.diag_manager.register_field_array( module_name="atm_mod", field_name="var_3d", datatype=np.float32, @@ -125,8 +121,9 @@ def test_send_data(): missing_value=-99.99, range_data=range_3d, ) + - diag_manager.set_field_timestep( + pyfms.diag_manager.set_field_timestep( diag_field_id=id_var3, dseconds=60 * 60, ddays=0, dticks=0 ) @@ -135,9 +132,9 @@ def test_send_data(): """ axes_2d = [id_x, id_y] - range_2d = np.array([-1000.0, 1000.0], dtype=np.float32) + range_2d = [-1000.0, 1000.0] - diag_manager.set_field_init_time( + pyfms.diag_manager.set_field_init_time( year=2, month=1, day=1, @@ -146,7 +143,7 @@ def test_send_data(): second=1, ) - id_var2 = diag_manager.register_field_array( + id_var2 = pyfms.diag_manager.register_field_array( module_name="atm_mod", field_name="var_2d", datatype=np.float32, @@ -157,7 +154,7 @@ def test_send_data(): range_data=range_2d, ) - diag_manager.set_field_timestep( + pyfms.diag_manager.set_field_timestep( diag_field_id=id_var2, dseconds=60 * 60, ddays=0, @@ -168,7 +165,7 @@ def test_send_data(): diag set time end """ - diag_manager.set_time_end( + pyfms.diag_manager.set_time_end( year=2, month=1, day=2, @@ -182,7 +179,7 @@ def test_send_data(): send data """ - diag_manager.send_data( + pyfms.diag_manager.send_data( diag_field_id=id_var3, field_shape=var3_shape, field=var3, @@ -193,27 +190,26 @@ def test_send_data(): var3 = -var3 - diag_manager.advance_field_time(diag_field_id=id_var3) - diag_manager.send_data( + pyfms.diag_manager.advance_field_time(diag_field_id=id_var3) + pyfms.diag_manager.send_data( diag_field_id=id_var3, field_shape=var3_shape, field=var3, ) - diag_manager.send_complete(diag_field_id=id_var3) + pyfms.diag_manager.send_complete(diag_field_id=id_var3) var2 = -var2 - diag_manager.advance_field_time(diag_field_id=id_var2) - diag_manager.send_data( + pyfms.diag_manager.advance_field_time(diag_field_id=id_var2) + pyfms.diag_manager.send_data( diag_field_id=id_var2, field_shape=var2_shape, field=var2, ) - diag_manager.send_complete(diag_field_id=id_var2) - - diag_manager.end() + pyfms.diag_manager.send_complete(diag_field_id=id_var2) - pyfms.pyfms_end() + pyfms.diag_manager.end() + pyfms.fms.end() if __name__ == "__main__": From e73a385e25cd6c9de8851b697b018cc10e249c12 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Thu, 10 Apr 2025 20:38:55 -0400 Subject: [PATCH 08/14] save intermediate --- pyfms/pyfms_utils/grid_utils.py | 8 ++++-- run_tests.sh | 2 +- tests/py_horiz_interp/test_horiz_interp.py | 11 +++----- tests/py_mpp/test_getset_domains.py | 32 ++++++++++------------ 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/pyfms/pyfms_utils/grid_utils.py b/pyfms/pyfms_utils/grid_utils.py index 535527c..fed80df 100644 --- a/pyfms/pyfms_utils/grid_utils.py +++ b/pyfms/pyfms_utils/grid_utils.py @@ -23,8 +23,10 @@ def lib(cls): @property def libpath(cls): return cls.__libpath - - def get_grid_area( + + @classmethod + def get_grid_area( + cls, nlon: int, nlat: int, lon: npt.NDArray[np.float64], @@ -50,7 +52,7 @@ def get_grid_area( nlat_c = nlat_t(nlat) area = np.zeros(ncells, dtype=np.float64) - _get_grid_area = cfms.cFMS_get_grid_area + _get_grid_area = cls.lib.cFMS_get_grid_area _get_grid_area.restype = None _get_grid_area.argtypes = [ diff --git a/run_tests.sh b/run_tests.sh index 035b2da..034e024 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -31,7 +31,7 @@ run_test "pytest tests/test_build.py" #run_test "mpirun -n 4 python -m pytest -m 'parallel' tests/py_mpp/test_getset_domains.py" #remove_input $test -#run_test "pytest tests/py_horiz_interp" +run_test "pytest tests/py_horiz_interp" run_test "pytest tests/py_data_override/test_generate_files.py" run_test "mpirun -n 6 python -m pytest -m 'parallel' tests/py_data_override/test_data_override.py" diff --git a/tests/py_horiz_interp/test_horiz_interp.py b/tests/py_horiz_interp/test_horiz_interp.py index 67cbecf..1bbee79 100755 --- a/tests/py_horiz_interp/test_horiz_interp.py +++ b/tests/py_horiz_interp/test_horiz_interp.py @@ -5,9 +5,6 @@ import pyfms -cfms_path = os.path.dirname(__file__) + "/../../cFMS/cLIBFMS/lib/libcFMS.so" - - def test_create_input_nml(): inputnml = open("input.nml", "w") inputnml.close() @@ -16,8 +13,8 @@ def test_create_input_nml(): def test_create_xgrid(): - cfms = pyfms.pyFMS(cFMS_path=cfms_path).cFMS - create_xgrid = pyfms.HorizInterp(cfms=cfms).create_xgrid_2dx2d_order1 + pyfms.fms.init() + create_xgrid = pyfms.horiz_interp.create_xgrid_2dx2d_order1 refine = 1 lon_init = 0.0 @@ -70,8 +67,8 @@ def test_create_xgrid(): ) # answer checking - area = pyfms.GridUtils.get_grid_area( - cfms=cfms, nlon=nlon_src, nlat=nlat_src, lon=lon_src, lat=lat_src + area = pyfms.grid_utils.get_grid_area( + nlon=nlon_src, nlat=nlat_src, lon=lon_src, lat=lat_src ) assert xgrid["nxgrid"] == nlon_src * nlat_src diff --git a/tests/py_mpp/test_getset_domains.py b/tests/py_mpp/test_getset_domains.py index 8438371..e2b834e 100644 --- a/tests/py_mpp/test_getset_domains.py +++ b/tests/py_mpp/test_getset_domains.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from pyfms import pyDomain, pyFMS, pyFMS_mpp, pyFMS_mpp_domains +import pyfms @pytest.mark.create @@ -35,25 +35,23 @@ def test_getset_domains(): nhalo = 2 name = "test domain" - pyfms = pyFMS(cFMS_path="./cFMS/libcFMS/.libs/libcFMS.so") - mpp = pyFMS_mpp(cFMS=pyfms.cFMS) - mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) + pyfms.fms.init() # set domain - layout = mpp_domains.define_layout(global_indices=global_indices, ndivs=ndiv) - - domain = pyDomain( - global_indices=global_indices, - layout=layout, - mpp_domains_obj=mpp_domains, - domain_id=domain_id, - name=name, - whalo=whalo, - ehalo=ehalo, - shalo=shalo, - nhalo=nhalo, - ) + layout = pyfms.mpp_domains.define_layout(global_indices=global_indices, ndivs=ndiv) + + #domain = pyDomain( + # global_indices=global_indices, + # layout=layout, + # mpp_domains_obj=mpp_domains, + # domain_id=domain_id, + # name=name, + # whalo=whalo, + # ehalo=ehalo, + # shalo=shalo, + # nhalo=nhalo, + #) if not mpp_domains.domain_is_initialized(domain_id): mpp.pyfms_error(1, "error in setting domain") From a710e3af002e9ac964b28e7a1cb6fa337021c91f Mon Sep 17 00:00:00 2001 From: mlee03 Date: Fri, 11 Apr 2025 14:34:09 -0400 Subject: [PATCH 09/14] mpp cleanup --- pyfms/py_mpp/py_mpp.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/pyfms/py_mpp/py_mpp.py b/pyfms/py_mpp/py_mpp.py index e02ee2e..bd98520 100644 --- a/pyfms/py_mpp/py_mpp.py +++ b/pyfms/py_mpp/py_mpp.py @@ -39,13 +39,15 @@ def __init__(self, cFMS: ctypes.CDLL = None): def declare_pelist( self, - pelist: NDArray, - name: Optional[str] = None, - commID: Optional[int] = None, - ) -> int | None: + pelist: list[int], + name: str = None, + ) -> int: + _cfms_declare_pelist = self.cFMS.cFMS_declare_pelist - pelist_p, pelist_t = setarray_Cint32(pelist) + commID = 0 + + pelist_p, pelist_t = setarray_Cint32(np.array(pelist)) name_c, name_t = set_Cchar(name) commID_c, commID_t = setscalar_Cint32(commID) @@ -54,9 +56,7 @@ def declare_pelist( _cfms_declare_pelist(pelist_p, name_c, commID_c) - if commID is not None: - commID = commID_c.value - return commID + return commID_c.value """ Subroutine: pyfms_error @@ -66,7 +66,7 @@ def declare_pelist( Returns: No return """ - def pyfms_error(self, errortype: int, errormsg: Optional[str] = None): + def pyfms_error(self, errortype: int, errormsg: str = None): # truncating string if errormsg is not None: errormsg = errormsg[:128] @@ -94,12 +94,14 @@ def pyfms_error(self, errortype: int, errormsg: Optional[str] = None): def get_current_pelist( self, - name: Optional[str] = None, - commID: Optional[int] = None, - ) -> NDArray: + get_name: str = None, + get_commID: bool = False, + ) -> (NDArray, Optional[int], Optional[str]): + commID = 0 if get_commID else None + npes = ctypes.c_int.in_dll(self.cFMS, "cFMS_pelist_npes") - pelist = np.empty(shape=npes.value, dtype=np.int32, order="C") + pelist = np.empty(shape=npes.value, dtype=np.int32) _cfms_get_current_pelist = self.cFMS.cFMS_get_current_pelist @@ -119,8 +121,9 @@ def get_current_pelist( # return commID, name - return pelist - + if get_commID: return pelist.tolist(), commID_c.value + else: return pelist.tolist() + """ Function: npes @@ -159,11 +162,11 @@ def pe(self) -> int: """ def set_current_pelist( - self, pelist: Optional[NDArray] = None, no_sync: Optional[bool] = None + self, pelist: list[int] = None, no_sync: bool = None ): _cfms_set_current_pelist = self.cFMS.cFMS_set_current_pelist - pelist_p, pelist_t = setarray_Cint32(pelist) + pelist_p, pelist_t = setarray_Cint32(np.array(pelist)) no_sync_c, no_sync_t = setscalar_Cbool(no_sync) _cfms_set_current_pelist.argtypes = [pelist_t, no_sync_t] From 1abca807f8c52ec65fafcf583aa206ff4b053e72 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Mon, 14 Apr 2025 09:59:58 -0400 Subject: [PATCH 10/14] fixing mpp --- pyfms/__init__.py | 4 +- pyfms/py_mpp/py_mpp_domains.py | 609 ++++++++++----------------------- 2 files changed, 187 insertions(+), 426 deletions(-) diff --git a/pyfms/__init__.py b/pyfms/__init__.py index 8f12b9d..612be33 100644 --- a/pyfms/__init__.py +++ b/pyfms/__init__.py @@ -5,9 +5,7 @@ from .py_mpp.py_mpp import pyFMS_mpp from .py_mpp.py_mpp_domains import ( pyDomain, - pyDomainData, - pyFMS_mpp_domains, - pyNestDomain, + mpp_domains, ) from .pyfms import pyFMS from .pyfms_utils import data_handling diff --git a/pyfms/py_mpp/py_mpp_domains.py b/pyfms/py_mpp/py_mpp_domains.py index dbf7ae3..e66922b 100644 --- a/pyfms/py_mpp/py_mpp_domains.py +++ b/pyfms/py_mpp/py_mpp_domains.py @@ -13,35 +13,54 @@ ) -class pyDomainData: - def __init__( - self, - xbegin=0, - xend=0, - ybegin=0, - yend=0, - xsize=0, - xmax_size=0, - ysize=0, - ymax_size=0, - x_is_global=False, - y_is_global=False, - tile_count=0, - ): - self.xbegin = ctypes.c_int(xbegin) - self.xend = ctypes.c_int(xend) - self.ybegin = ctypes.c_int(ybegin) - self.yend = ctypes.c_int(yend) - self.xsize = ctypes.c_int(xsize) - self.xmax_size = ctypes.c_int(xmax_size) - self.ysize = ctypes.c_int(ysize) - self.ymax_size = ctypes.c_int(ymax_size) - self.x_is_global = ctypes.c_bool(x_is_global) - self.y_is_global = ctypes.c_bool(y_is_global) - self.tile_count = ctypes.c_int(tile_count) - - -class pyFMS_mpp_domains: +class pyDomain(): + + def __init__(self): + self.domain_id = domain_id + self.isc + self.jsc + self.iec + self.jec + self.isd + self.jsd + self.ied + self.jed + self.tile + self.pe + self.layout + + def update_compute_domain(self, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None): + compute = self.get_compute_domain(domain_id=self.domain_id, + tile_count=tile_count, + position = position, + whalo=whalo, + shalo=shalo) + self.isc = compute["xbegin"] + self.jsc = compute["ybegin"] + self.iec = compute["xend"] + self.iec = compute["yend"] + + def update_data_domain(self, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None): + data = self.get_data_domain(domain_id=self.domain_id, + tile_count=tile_count, + position = position, + whalo=whalo, + shalo=shalo) + self.isd = data["xbegin"] + self.jsd = data["ybegin"] + self.ied = data["xend"] + self.jed = data["yend"] + + +class mpp_domains: def __init__(self, cFMS: ctypes.CDLL = None): self.cFMS = cFMS @@ -61,28 +80,28 @@ def define_domains( self, global_indices: list[int], layout: list[int], - domain_id: Optional[int] = None, - pelist: Optional[NDArray] = None, - xflags: Optional[int] = None, - yflags: Optional[int] = None, - xhalo: Optional[int] = None, - yhalo: Optional[int] = None, - xextent: Optional[NDArray] = None, - yextent: Optional[NDArray] = None, - maskmap: Optional[NDArray[np.bool_]] = None, - name: Optional[str] = None, - symmetry: Optional[bool] = None, - memory_size: Optional[NDArray] = None, - whalo: Optional[int] = None, - ehalo: Optional[int] = None, - shalo: Optional[int] = None, - nhalo: Optional[int] = None, - is_mosaic: Optional[bool] = None, - tile_count: Optional[int] = None, - tile_id: Optional[int] = None, - complete: Optional[bool] = None, - x_cyclic_offset: Optional[int] = None, - y_cyclic_offset: Optional[int] = None, + domain_id: int = None, + pelist: NDArray = None, + xflags: int = None, + yflags: int = None, + xhalo: int = None, + yhalo: int = None, + xextent: NDArray = None, + yextent: NDArray = None, + maskmap: NDArray[np.bool_] = None, + name: str = None, + symmetry: bool = None, + memory_size: NDArray = None, + whalo: int = None, + ehalo: int = None, + shalo: int = None, + nhalo: int = None, + is_mosaic: bool = None, + tile_count: int = None, + tile_id: int = None, + complete: bool = None, + x_cyclic_offset: int = None, + y_cyclic_offset: int = None, ): _cfms_define_domains = self.cFMS.cFMS_define_domains @@ -171,6 +190,10 @@ def define_domains( y_cyclic_offset_c, ) + return pyDomain(domain_id=domain_id, + layout=layout, + tile_id=tile_id) + """ Subroutine: define_io_domains @@ -179,7 +202,7 @@ def define_domains( Returns: No return """ - def define_io_domain(self, io_layout: list[int], domain_id: Optional[int] = None): + def define_io_domain(self, io_layout: list[int], domain_id: int = None): _cfms_define_io_domain = self.cFMS.cFMS_define_io_domain io_layout_arr = np.array(io_layout, dtype=np.int32) @@ -245,25 +268,35 @@ def define_nest_domains( npes_nest_tile: NDArray, x_refine: NDArray, y_refine: NDArray, - nest_domain_id: Optional[int] = None, - domain_id: Optional[int] = None, - extra_halo: Optional[int] = None, - name: Optional[str] = None, + nest_domain_id: int = None, + domain_id: int = None, + extra_halo: int = None, + name: str = None, ): _cfms_define_nest_domain = self.cFMS.cFMS_define_nest_domains + nest_level_arr = np.array(nest_level, dtype=np.int32) + tile_fine_arr = np.array(tile_fine, dtype=np.int32) + tile_coarse_arr = np.array(tile_coarse, dtype=np.int32) + istart_coarse_arr = np.array(istart_coarse, dtype=np.int32) + jstart_coarse_arr = np.array(jstart_coarse, dtype=np.int32) + jcount_coarse_arr = np.array(jcount_coarse, dtype=np.int32) + npes_nest_tile_arr = np.array(npes_nest_tile, dtype=np.int32) + x_refine_arr = np.array(x_refine, dtype=np.int32) + y_refine_arr = np.array(y_refine, dtype=np.int32) + num_nest_p, num_nest_t = setscalar_Cint32(num_nest) ntiles_c, ntiles_t = setscalar_Cint32(ntiles) - nest_level_p, nest_level_t = setarray_Cint32(nest_level) - tile_fine_p, tile_fine_t = setarray_Cint32(tile_fine) - tile_coarse_p, tile_coarse_t = setarray_Cint32(tile_coarse) - istart_coarse_p, istart_coarse_t = setarray_Cint32(istart_coarse) - icount_coarse_p, icount_coarse_t = setarray_Cint32(icount_coarse) - jstart_coarse_p, jstart_coarse_t = setarray_Cint32(jstart_coarse) - jcount_coarse_p, jcount_coarse_t = setarray_Cint32(jcount_coarse) - npes_nest_tile_p, npes_nest_tile_t = setarray_Cint32(npes_nest_tile) - x_refine_p, x_refine_t = setarray_Cint32(x_refine) - y_refine_p, y_refine_t = setarray_Cint32(y_refine) + nest_level_p, nest_level_t = setarray_Cint32(nest_level_arr) + tile_fine_p, tile_fine_t = setarray_Cint32(tile_fine_arr) + tile_coarse_p, tile_coarse_t = setarray_Cint32(tile_coarse_arr) + istart_coarse_p, istart_coarse_t = setarray_Cint32(istart_coarse_arr) + icount_coarse_p, icount_coarse_t = setarray_Cint32(icount_coarse_arr) + jstart_coarse_p, jstart_coarse_t = setarray_Cint32(jstart_coarse_arr) + jcount_coarse_p, jcount_coarse_t = setarray_Cint32(jcount_coarse_arr) + npes_nest_tile_p, npes_nest_tile_t = setarray_Cint32(npes_nest_tile_arr) + x_refine_p, x_refine_t = setarray_Cint32(x_refine_arr) + y_refine_p, y_refine_t = setarray_Cint32(y_refine_arr) nest_domain_id_c, nest_domain_id_t = setscalar_Cint32(nest_domain_id) domain_id_c, domain_id_t = setscalar_Cint32(domain_id) extra_halo_c, extra_halo_t = setscalar_Cint32(extra_halo) @@ -317,7 +350,7 @@ def define_nest_domains( Returns: Boolean """ - def domain_is_initialized(self, domain_id: Optional[int] = None) -> bool: + def domain_is_initialized(self, domain_id: int = None) -> bool: _cfms_domain_is_initialized = self.cFMS.cFMS_domain_is_initialized domain_id_c, domain_id_t = setscalar_Cint32(domain_id) @@ -343,75 +376,11 @@ def domain_is_initialized(self, domain_id: Optional[int] = None) -> bool: def get_compute_domain( self, - domain_data: pyDomainData, - domain_id: Optional[int] = None, - position: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - - _cfms_get_compute_domain = self.cFMS.cFMS_get_compute_domain - - domain_id_c, domain_id_t = setscalar_Cint32(domain_id) - xbegin_c, xbegin_t = setscalar_Cint32(domain_data.xbegin) - xend_c, xend_t = setscalar_Cint32(domain_data.xend) - ybegin_c, ybegin_t = setscalar_Cint32(domain_data.ybegin) - yend_c, yend_t = setscalar_Cint32(domain_data.yend) - xsize_c, xsize_t = setscalar_Cint32(domain_data.xsize) - xmax_size_c, xmax_size_t = setscalar_Cint32(domain_data.xmax_size) - ysize_c, ysize_t = setscalar_Cint32(domain_data.ysize) - ymax_size_c, ymax_size_t = setscalar_Cint32(domain_data.ymax_size) - x_is_global_c, x_is_global_t = setscalar_Cbool(domain_data.x_is_global) - y_is_global_c, y_is_global_t = setscalar_Cbool(domain_data.y_is_global) - tile_count_c, tile_count_t = setscalar_Cint32(domain_data.tile_count) - position_c, position_t = setscalar_Cint32(position) - whalo_c, whalo_t = setscalar_Cint32(whalo) - shalo_c, shalo_t = setscalar_Cint32(shalo) - - _cfms_get_compute_domain.argtypes = [ - domain_id_t, - xbegin_t, - xend_t, - ybegin_t, - yend_t, - xsize_t, - xmax_size_t, - ysize_t, - ymax_size_t, - x_is_global_t, - y_is_global_t, - tile_count_t, - position_t, - whalo_t, - shalo_t, - ] - _cfms_get_compute_domain.restype = None - - _cfms_get_compute_domain( - domain_id_c, - xbegin_c, - xend_c, - ybegin_c, - yend_c, - xsize_c, - xmax_size_c, - ysize_c, - ymax_size_c, - x_is_global_c, - y_is_global_c, - tile_count_c, - position_c, - whalo_c, - shalo_c, - ) - - def get_compute_domain2( - self, - domain_id: int | None = None, - position: int | None = None, - tile_count: int | None = None, - whalo: int | None = None, - shalo: int | None = None, + domain_id: int = None, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None, ): _cfms_get_compute_domain = self.cFMS.cFMS_get_compute_domain @@ -519,7 +488,6 @@ def get_compute_domain2( def get_data_domain( self, - domain_data: pyDomainData, domain_id: Optional[int] = None, position: Optional[int] = None, whalo: Optional[int] = None, @@ -527,39 +495,59 @@ def get_data_domain( ): _cfms_get_data_domain = self.cFMS.cFMS_get_data_domain - domain_id_c, domain_id_t = setscalar_Cint32(domain_id) - xbegin_c, xbegin_t = setscalar_Cint32(domain_data.xbegin) - xend_c, xend_t = setscalar_Cint32(domain_data.xend) - ybegin_c, ybegin_t = setscalar_Cint32(domain_data.ybegin) - yend_c, yend_t = setscalar_Cint32(domain_data.yend) - xsize_c, xsize_t = setscalar_Cint32(domain_data.xsize) - xmax_size_c, xmax_size_t = setscalar_Cint32(domain_data.xmax_size) - ysize_c, ysize_t = setscalar_Cint32(domain_data.ysize) - ymax_size_c, ymax_size_t = setscalar_Cint32(domain_data.ymax_size) - x_is_global_c, x_is_global_t = setscalar_Cbool(domain_data.x_is_global) - y_is_global_c, y_is_global_t = setscalar_Cbool(domain_data.y_is_global) - tile_count_c, tile_count_t = setscalar_Cint32(domain_data.tile_count) - position_c, position_t = setscalar_Cint32(position) - whalo_c, whalo_t = setscalar_Cint32(whalo) - shalo_c, shalo_t = setscalar_Cint32(shalo) + default_i = 0 + default_b = False + + domain_id_t = ctypes.c_int + xbegin_t = ctypes.c_int + xend_t = ctypes.c_int + ybegin_t = ctypes.c_int + yend_t = ctypes.c_int + xsize_t = ctypes.c_int + xmax_size_t = ctypes.c_int + ysize_t = ctypes.c_int + ymax_size_t = ctypes.c_int + x_is_global_t = ctypes.c_bool + y_is_global_t = ctypes.c_bool + tile_count_t = ctypes.c_int + position_t = ctypes.c_int + whalo_t = ctypes.c_int + shalo_t = ctypes.c_int + + xbegin_c = xbegin_t(default_i) + xend_c = xend_t(default_i) + ybegin_c = ybegin_t(default_i) + yend_c = yend_t(default_i) + xsize_c = xsize_t(default_i) + xmax_size_c = xmax_size_t(default_i) + ysize_c = ysize_t(default_i) + ymax_size_c = ymax_size_t(default_i) + x_is_global_c = x_is_global_t(default_b) + y_is_global_c = y_is_global_t(default_b) + domain_id_c = domain_id_t(domain_id) if domain_id is not None else None + tile_count_c = tile_count_t(tile_count) if tile_count is not None else None + position_c = position_t(position) if tile_count is not None else None + whalo_c = whalo_t(whalo) if whalo is not None else None + shalo_c = shalo_t(shalo) if shalo is not None else None _cfms_get_data_domain.argtypes = [ - domain_id_t, - xbegin_t, - xend_t, - ybegin_t, - yend_t, - xsize_t, - xmax_size_t, - ysize_t, - ymax_size_t, - x_is_global_t, - y_is_global_t, - tile_count_t, - position_t, - whalo_t, - shalo_t, + ctypes.POINTER(domain_id_t), + ctypes.POINTER(xbegin_t), + ctypes.POINTER(xend_t), + ctypes.POINTER(ybegin_t), + ctypes.POINTER(yend_t), + ctypes.POINTER(xsize_t), + ctypes.POINTER(xmax_size_t), + ctypes.POINTER(ysize_t), + ctypes.POINTER(ymax_size_t), + ctypes.POINTER(x_is_global_t), + ctypes.POINTER(y_is_global_t), + ctypes.POINTER(tile_count_t), + ctypes.POINTER(position_t), + ctypes.POINTER(whalo_t), + ctypes.POINTER(shalo_t), ] + _cfms_get_data_domain.restype = None _cfms_get_data_domain( @@ -580,6 +568,20 @@ def get_data_domain( shalo_c, ) + return dict( + domain_id=domain_id_c.value, + xbegin=xbegin_c.value, + ybegin=ybegin_c.value, + xend=xend_c.value, + yend=yend_c.value, + xsize=xsize_c.value, + ysize=ysize_c.value, + xmax_size=xmax_size_c.value, + ymax_size=ymax_size_c.value, + x_is_global=x_is_global_c.value, + y_is_global=y_is_global_c.value, + ) + """ Subroutine: get_domain_name @@ -591,7 +593,7 @@ def get_data_domain( its value as well. """ - def get_domain_name(self, domain_id: Optional[int] = None) -> str: + def get_domain_name(self, domain_id: int = None) -> str: _cfms_get_domain_name = self.cFMS.cFMS_get_domain_name domain_name = "" @@ -614,7 +616,7 @@ def get_domain_name(self, domain_id: Optional[int] = None) -> str: Returns: NDArray with layout info """ - def get_layout(self, domain_id: Optional[int] = None) -> NDArray: + def get_layout(self, domain_id: int = None) -> list[int]: layout = np.empty(shape=2, dtype=np.int32, order="C") @@ -628,7 +630,7 @@ def get_layout(self, domain_id: Optional[int] = None) -> NDArray: _cfms_get_layout(layout_p, domain_id_c) - return layout + return layout_p """ Subroutine: get_domain_pelist @@ -651,7 +653,7 @@ def get_domain_pelist(self, domain_id: Optional[int]) -> NDArray: _cfms_get_domain_pelist(pelist_p, domain_id_c) - return pelist + return pelist_p """ Subroutine: set_compute_domain @@ -910,257 +912,18 @@ def set_global_domain( ) -class pyDomain: - def __init__( - self, - mpp_domains_obj: pyFMS_mpp_domains, - global_indices: list[int], - layout: list[int], - domain_id: Optional[int] = None, - pelist: Optional[NDArray] = None, - xflags: Optional[int] = None, - yflags: Optional[int] = None, - xhalo: Optional[int] = None, - yhalo: Optional[int] = None, - xextent: Optional[NDArray] = None, - yextent: Optional[NDArray] = None, - maskmap: Optional[NDArray[np.bool_]] = None, - name: Optional[str] = None, - symmetry: Optional[bool] = None, - memory_size: Optional[NDArray] = None, - whalo: Optional[int] = None, - ehalo: Optional[int] = None, - shalo: Optional[int] = None, - nhalo: Optional[int] = None, - is_mosaic: Optional[bool] = None, - tile_count: Optional[int] = None, - tile_id: Optional[int] = None, - complete: Optional[bool] = None, - x_cyclic_offset: Optional[int] = None, - y_cyclic_offset: Optional[int] = None, - ): - self.mpp_domains_obj = mpp_domains_obj - self.global_indices = global_indices - self.layout = layout - self.domain_id = domain_id - self.pelist = pelist - self.xflags = xflags - self.yflags = yflags - self.xhalo = xhalo - self.yhalo = yhalo - self.xextent = xextent - self.yextent = yextent - self.maskmap = maskmap - self.name = name - self.symmetry = symmetry - self.memory_size = memory_size - self.whalo = whalo - self.ehalo = ehalo - self.shalo = shalo - self.nhalo = nhalo - self.is_mosaic = is_mosaic - self.tile_count = tile_count - self.tile_id = tile_id - self.complete = complete - self.x_cyclic_offset = x_cyclic_offset - self.y_cyclic_offset = y_cyclic_offset - self.compute_domain = pyDomainData() - self.data_domain = pyDomainData() - - self.mpp_domains_obj.define_domains( - global_indices=self.global_indices, - layout=self.layout, - domain_id=self.domain_id, - pelist=self.pelist, - xflags=self.xflags, - yflags=self.yflags, - xhalo=self.xhalo, - yhalo=self.yhalo, - xextent=self.xextent, - yextent=self.yextent, - maskmap=self.maskmap, - name=self.name, - symmetry=self.symmetry, - memory_size=self.memory_size, - whalo=self.whalo, - ehalo=self.ehalo, - shalo=self.shalo, - nhalo=self.nhalo, - is_mosaic=self.is_mosaic, - tile_count=self.tile_count, - tile_id=self.tile_id, - complete=self.complete, - x_cyclic_offset=self.x_cyclic_offset, - y_cyclic_offset=self.y_cyclic_offset, - ) - self.mpp_domains_obj.get_compute_domain( - domain_data=self.compute_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - self.mpp_domains_obj.get_data_domain( - domain_data=self.data_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_compute_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_compute_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - x_is_global=x_is_global, - y_is_global=y_is_global, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - - self.mpp_domains_obj.get_compute_domain( - domain_data=self.compute_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_data_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - x_is_global: Optional[bool] = None, - y_is_global: Optional[bool] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_data_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - x_is_global=x_is_global, - y_is_global=y_is_global, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - - self.mpp_domains_obj.get_data_domain( - domain_data=self.data_domain, - domain_id=self.domain_id, - whalo=self.whalo, - shalo=self.shalo, - ) - - def set_global_domain( - self, - xbegin: Optional[int] = None, - xend: Optional[int] = None, - ybegin: Optional[int] = None, - yend: Optional[int] = None, - xsize: Optional[int] = None, - ysize: Optional[int] = None, - tile_count: Optional[int] = None, - domain_id: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, - ): - self.mpp_domains_obj.set_global_domain( - xbegin=xbegin, - xend=xend, - ybegin=ybegin, - yend=yend, - xsize=xsize, - ysize=ysize, - tile_count=tile_count, - domain_id=domain_id, - whalo=whalo, - shalo=shalo, - ) - +class pyDomain(): -class pyNestDomain: - def __init__( - self, - mpp_domains_obj: pyFMS_mpp_domains, - num_nest: int, - ntiles: int, - nest_level: NDArray, - tile_fine: NDArray, - tile_coarse: NDArray, - istart_coarse: NDArray, - icount_coarse: NDArray, - jstart_coarse: NDArray, - jcount_coarse: NDArray, - npes_nest_tile: NDArray, - x_refine: NDArray, - y_refine: NDArray, - nest_domain_id: Optional[int] = None, - domain_id: Optional[int] = None, - extra_halo: Optional[int] = None, - name: Optional[str] = None, - ): - self.mpp_domains_obj = mpp_domains_obj - self.num_nest = num_nest - self.ntiles = ntiles - self.nest_level = nest_level - self.tile_fine = tile_fine - self.tile_coarse = tile_coarse - self.istart_coarse = istart_coarse - self.icount_coarse = icount_coarse - self.jstart_coarse = jstart_coarse - self.jcount_coarse = jcount_coarse - self.npes_nest_tile = npes_nest_tile - self.x_refine = x_refine - self.y_refine = y_refine - self.nest_domain_id = nest_domain_id + def __init__(self): self.domain_id = domain_id - self.extra_halo = extra_halo - self.name = name - - self.mpp_domains_obj.define_nest_domains( - num_nest=self.num_nest, - ntiles=self.ntiles, - nest_level=self.nest_level, - tile_fine=self.tile_fine, - tile_coarse=self.tile_coarse, - istart_coarse=self.istart_coarse, - icount_coarse=self.icount_coarse, - jstart_coarse=self.jstart_coarse, - jcount_coarse=self.jcount_coarse, - npes_nest_tile=self.npes_nest_tile, - x_refine=self.x_refine, - y_refine=self.y_refine, - nest_domain_id=self.nest_domain_id, - domain_id=self.domain_id, - extra_halo=self.extra_halo, - name=self.name, - ) + self.isc + self.jsc + self.iec + self.jec + self.isd + self.jsd + self.ied + self.jed + self.tile + self.pe + self.layout From ce5efd60fed520663a33d0f58f70fd5dbcde2321 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Mon, 14 Apr 2025 12:38:20 -0400 Subject: [PATCH 11/14] working test --- pyfms/__init__.py | 2 +- pyfms/py_mpp/py_mpp.py | 34 ++++- pyfms/py_mpp/py_mpp_domains.py | 106 +++++++------- pyfms/pyfms.py | 15 -- tests/py_mpp/test_define_domains.py | 211 +++++++++++----------------- 5 files changed, 165 insertions(+), 203 deletions(-) diff --git a/pyfms/__init__.py b/pyfms/__init__.py index 612be33..538dd61 100644 --- a/pyfms/__init__.py +++ b/pyfms/__init__.py @@ -2,7 +2,7 @@ from .py_diag_manager.pyfms_diag_manager import DiagManager from .py_field_manager.py_field_manager import FieldTable from .py_horiz_interp.py_horiz_interp import HorizInterp -from .py_mpp.py_mpp import pyFMS_mpp +from .py_mpp.py_mpp import mpp from .py_mpp.py_mpp_domains import ( pyDomain, mpp_domains, diff --git a/pyfms/py_mpp/py_mpp.py b/pyfms/py_mpp/py_mpp.py index bd98520..88a5956 100644 --- a/pyfms/py_mpp/py_mpp.py +++ b/pyfms/py_mpp/py_mpp.py @@ -12,7 +12,7 @@ ) -class pyFMS_mpp: +class mpp: def __init__(self, cFMS: ctypes.CDLL = None): self.cFMS = cFMS @@ -47,13 +47,14 @@ def declare_pelist( commID = 0 - pelist_p, pelist_t = setarray_Cint32(np.array(pelist)) + pelist_p = np.array(pelist, dtype=np.int32) + pelist_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=(pelist_p.shape)) name_c, name_t = set_Cchar(name) commID_c, commID_t = setscalar_Cint32(commID) _cfms_declare_pelist.argtypes = [pelist_t, name_t, commID_t] _cfms_declare_pelist.restype = None - + _cfms_declare_pelist(pelist_p, name_c, commID_c) return commID_c.value @@ -99,6 +100,9 @@ def get_current_pelist( ) -> (NDArray, Optional[int], Optional[str]): commID = 0 if get_commID else None + name = None + #if get_name: name="NAME" + npes = ctypes.c_int.in_dll(self.cFMS, "cFMS_pelist_npes") pelist = np.empty(shape=npes.value, dtype=np.int32) @@ -166,10 +170,32 @@ def set_current_pelist( ): _cfms_set_current_pelist = self.cFMS.cFMS_set_current_pelist - pelist_p, pelist_t = setarray_Cint32(np.array(pelist)) + if pelist is not None: + pelist_p = np.array(pelist, dtype=np.int32) + pelist_t = np.ctypeslib.ndpointer(dtype=np.int32, shape=pelist_p.shape) + else: + pelist_p = None + pelist_t = ctypes.POINTER(ctypes.c_int) no_sync_c, no_sync_t = setscalar_Cbool(no_sync) _cfms_set_current_pelist.argtypes = [pelist_t, no_sync_t] _cfms_set_current_pelist.restype = None _cfms_set_current_pelist(pelist_p, no_sync_c) + + + """ + Subroutine: pyfms_set_pelist_npes + + This method is used to set a npes variable of the cFMS module it wraps + """ + + def set_pelist_npes(self, npes_in: int): + _cfms_set_npes = self.cFMS.cFMS_set_pelist_npes + + npes_in_c, npes_in_t = setscalar_Cint32(npes_in) + + _cfms_set_npes.argtypes = [npes_in_t] + _cfms_set_npes.restype = None + + _cfms_set_npes(npes_in_c) diff --git a/pyfms/py_mpp/py_mpp_domains.py b/pyfms/py_mpp/py_mpp_domains.py index e66922b..8a5692e 100644 --- a/pyfms/py_mpp/py_mpp_domains.py +++ b/pyfms/py_mpp/py_mpp_domains.py @@ -15,19 +15,29 @@ class pyDomain(): - def __init__(self): + def __init__(self, + domain_id: int = None, + isc: int = None, + jsc: int = None, + iec: int = None, + jec: int = None, + isd: int = None, + jsd: int = None, + ied: int = None, + jed: int = None, + tile: int = None, + layout: list[int] = None): self.domain_id = domain_id - self.isc - self.jsc - self.iec - self.jec - self.isd - self.jsd - self.ied - self.jed - self.tile - self.pe - self.layout + self.isc = isc + self.jsc = jsc + self.iec = iec + self.jec = jec + self.isd = isd + self.jsd = jsd + self.ied = ied + self.jed = jed + self.tile = tile + self.layout = layout def update_compute_domain(self, position: int = None, @@ -61,6 +71,9 @@ def update_data_domain(self, class mpp_domains: + + + def __init__(self, cFMS: ctypes.CDLL = None): self.cFMS = cFMS @@ -81,17 +94,17 @@ def define_domains( global_indices: list[int], layout: list[int], domain_id: int = None, - pelist: NDArray = None, + pelist: list[int] = None, xflags: int = None, yflags: int = None, xhalo: int = None, yhalo: int = None, - xextent: NDArray = None, - yextent: NDArray = None, - maskmap: NDArray[np.bool_] = None, + xextent: list[int] = None, + yextent: list[int] = None, + maskmap: list[list[np.bool_]] = None, name: str = None, symmetry: bool = None, - memory_size: NDArray = None, + memory_size: list[int] = None, whalo: int = None, ehalo: int = None, shalo: int = None, @@ -108,21 +121,26 @@ def define_domains( global_indices_arr = np.array(global_indices, dtype=np.int32) layout_arr = np.array(layout, dtype=np.int32) - + pelist_arr = np.array(pelist, dtype=np.int32) if pelist is not None else None + xextent_arr = np.array(xextent, dtype=np.int32) if xextent is not None else None + yextent_arr = np.array(yextent, dtype=np.int32) if yextent is not None else None + maskmap_arr = np.array(maskmap, dtype=np.bool_) if maskmap is not None else None + memory_size_arr = np.array(memory_size, dtype=np.int32) if memory_size is not None else None + global_indices_p, global_indices_t = setarray_Cint32(global_indices_arr) layout_p, layout_t = setarray_Cint32(layout_arr) domain_id_c, domain_id_t = setscalar_Cint32(domain_id) - pelist_p, pelist_t = setarray_Cint32(pelist) + pelist_p, pelist_t = setarray_Cint32(pelist_arr) xflags_c, xflags_t = setscalar_Cint32(xflags) yflags_c, yflags_t = setscalar_Cint32(yflags) xhalo_c, xhalo_t = setscalar_Cint32(xhalo) yhalo_c, yhalo_t = setscalar_Cint32(yhalo) - xextent_p, xextent_t = setarray_Cint32(xextent) - yextent_p, yextent_t = setarray_Cint32(yextent) - maskmap_p, maskmap_t = setarray_Cbool(maskmap) + xextent_p, xextent_t = setarray_Cint32(xextent_arr) + yextent_p, yextent_t = setarray_Cint32(yextent_arr) + maskmap_p, maskmap_t = setarray_Cbool(maskmap_arr) name_c, name_t = set_Cchar(name) symmetry_c, symmetry_t = setscalar_Cbool(symmetry) - memory_size_p, memory_size_t = setarray_Cint32(memory_size) + memory_size_p, memory_size_t = setarray_Cint32(memory_size_arr) whalo_c, whalo_t = setscalar_Cint32(whalo) ehalo_c, ehalo_t = setscalar_Cint32(ehalo) shalo_c, shalo_t = setscalar_Cint32(shalo) @@ -133,7 +151,7 @@ def define_domains( complete_c, complete_t = setscalar_Cbool(complete) x_cyclic_offset_c, x_cyclic_offset_t = setscalar_Cint32(x_cyclic_offset) y_cyclic_offset_c, y_cyclic_offset_t = setscalar_Cint32(y_cyclic_offset) - + _cfms_define_domains.argtypes = [ global_indices_t, layout_t, @@ -192,7 +210,7 @@ def define_domains( return pyDomain(domain_id=domain_id, layout=layout, - tile_id=tile_id) + tile=tile_id) """ Subroutine: define_io_domains @@ -258,16 +276,16 @@ def define_nest_domains( self, num_nest: int, ntiles: int, - nest_level: NDArray, - tile_fine: NDArray, - tile_coarse: NDArray, - istart_coarse: NDArray, - icount_coarse: NDArray, - jstart_coarse: NDArray, - jcount_coarse: NDArray, - npes_nest_tile: NDArray, - x_refine: NDArray, - y_refine: NDArray, + nest_level: list[int], + tile_fine: list[int], + tile_coarse: list[int], + istart_coarse: list[int], + icount_coarse: list[int], + jstart_coarse: list[int], + jcount_coarse: list[int], + npes_nest_tile: list[int], + x_refine: list[int], + y_refine: list[int], nest_domain_id: int = None, domain_id: int = None, extra_halo: int = None, @@ -280,6 +298,7 @@ def define_nest_domains( tile_coarse_arr = np.array(tile_coarse, dtype=np.int32) istart_coarse_arr = np.array(istart_coarse, dtype=np.int32) jstart_coarse_arr = np.array(jstart_coarse, dtype=np.int32) + icount_coarse_arr = np.array(icount_coarse, dtype=np.int32) jcount_coarse_arr = np.array(jcount_coarse, dtype=np.int32) npes_nest_tile_arr = np.array(npes_nest_tile, dtype=np.int32) x_refine_arr = np.array(x_refine, dtype=np.int32) @@ -630,7 +649,7 @@ def get_layout(self, domain_id: int = None) -> list[int]: _cfms_get_layout(layout_p, domain_id_c) - return layout_p + return layout_p.tolist() """ Subroutine: get_domain_pelist @@ -912,18 +931,3 @@ def set_global_domain( ) -class pyDomain(): - - def __init__(self): - self.domain_id = domain_id - self.isc - self.jsc - self.iec - self.jec - self.isd - self.jsd - self.ied - self.jed - self.tile - self.pe - self.layout diff --git a/pyfms/pyfms.py b/pyfms/pyfms.py index eba41a1..3a7f945 100755 --- a/pyfms/pyfms.py +++ b/pyfms/pyfms.py @@ -108,18 +108,3 @@ def pyfms_init( calendar_type_c, ) - """ - Subroutine: pyfms_set_pelist_npes - - This method is used to set a npes variable of the cFMS module it wraps - """ - - def set_pelist_npes(self, npes_in: int): - _cfms_set_npes = self.cFMS.cFMS_set_pelist_npes - - npes_in_c, npes_in_t = setscalar_Cint32(npes_in) - - _cfms_set_npes.argtypes = [npes_in_t] - _cfms_set_npes.restype = None - - _cfms_set_npes(npes_in_c) diff --git a/tests/py_mpp/test_define_domains.py b/tests/py_mpp/test_define_domains.py index 08c429f..13c6524 100644 --- a/tests/py_mpp/test_define_domains.py +++ b/tests/py_mpp/test_define_domains.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from pyfms import pyFMS, pyFMS_mpp, pyFMS_mpp_domains +from pyfms import mpp, mpp_domains, pyFMS @pytest.mark.create @@ -16,42 +16,25 @@ def test_create_input_nml(): @pytest.mark.parallel def test_define_domains(): - NX = 96 - NY = 96 - NX_FINE = 48 - NY_FINE = 48 - X_REFINE = 2 - Y_REFINE = 2 - COARSE_NPES = 4 - FINE_NPES = 4 - ndomain = 2 nnest_domain = 2 - domain_id = 1 - nest_domain_id = 1 - - coarse_global_indices = [0, NX - 1, 0, NY - 1] - coarse_npes = COARSE_NPES - coarse_pelist = np.empty(shape=COARSE_NPES, dtype=np.int32, order="C") + domain_id = 0 + nest_domain_id = 0 + + nx = 96 + ny = 96 + coarse_global_indices = [0, nx - 1, 0, ny - 1] + coarse_npes = 4 + coarse_pelist = list(range(coarse_npes)) coarse_tile_id = 0 - coarse_whalo = 2 - coarse_ehalo = 2 - coarse_shalo = 2 - coarse_nhalo = 2 - coarse_xflags = 3 - coarse_yflags = 2 - is_mosaic = False - symmetry = False - - fine_global_indices = [0, NX_FINE - 1, 0, NY_FINE - 1] - fine_npes = FINE_NPES - fine_pelist = np.empty(shape=FINE_NPES, dtype=np.int32, order="C") - fine_tile_id = 1 - fine_whalo = 2 - fine_ehalo = 2 - fine_shalo = 2 - fine_nhalo = 2 + nx_fine = 48 + ny_fine = 48 + fine_global_indices = [0, nx_fine - 1, 0, ny_fine - 1] + fine_npes = 4 + fine_pelist = list(range(fine_npes)) + fine_tile_id = 1 + cfms_path = "./cFMS/libcFMS/.libs/libcFMS.so" assert os.path.exists(cfms_path) @@ -61,146 +44,110 @@ def test_define_domains(): ndomain=ndomain, nnest_domain=nnest_domain, ) - mpp = pyFMS_mpp(cFMS=pyfms.cFMS) - mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) + mpp_obj = mpp(cFMS=pyfms.cFMS) + mpp_domains_obj = mpp_domains(cFMS=pyfms.cFMS) assert isinstance(pyfms, pyFMS) """get global pelist""" - npes = mpp.npes() - pyfms.set_pelist_npes(npes_in=npes) - global_pelist = mpp.get_current_pelist() + mpp_obj.set_pelist_npes(npes_in=mpp_obj.npes()) + global_pelist = mpp_obj.get_current_pelist() """set coarse domain as tile=0""" - for i in range(coarse_npes): - coarse_pelist[i] = global_pelist[i] - name_coarse = "test coarse pelist" - pyfms.set_pelist_npes(npes_in=coarse_npes) - mpp.declare_pelist(pelist=coarse_pelist, name=name_coarse) - - if mpp.pe() in coarse_pelist: - pyfms.set_pelist_npes(coarse_npes) - mpp.set_current_pelist(coarse_pelist) - name = "test coarse domain" - maskmap = np.full(shape=(2, 4), fill_value=True, dtype=np.bool_) - - xextent = np.zeros(shape=2, dtype=np.int32, order="C") - yextent = np.zeros(shape=2, dtype=np.int32, order="C") - is_mosaic = False - - ndivs = coarse_npes + coarse_pelist = global_pelist[:coarse_npes] + mpp_obj.set_pelist_npes(npes_in=coarse_npes) + mpp_obj.declare_pelist(pelist=coarse_pelist, name="test coarse pelist") - layout = mpp_domains.define_layout( + if mpp_obj.pe() in coarse_pelist: + mpp_obj.set_pelist_npes(coarse_npes) + mpp_obj.set_current_pelist(coarse_pelist) + + layout = mpp_domains_obj.define_layout( global_indices=coarse_global_indices, - ndivs=ndivs, + ndivs=coarse_npes, ) - - mpp_domains.define_domains( + + mpp_domains_obj.define_domains( global_indices=coarse_global_indices, layout=layout, domain_id=domain_id, pelist=coarse_pelist, - xflags=coarse_xflags, - yflags=coarse_yflags, - xextent=xextent, - yextent=yextent, - maskmap=maskmap, - name=name, - symmetry=symmetry, - whalo=coarse_whalo, - ehalo=coarse_ehalo, - shalo=coarse_shalo, - nhalo=coarse_nhalo, - is_mosaic=is_mosaic, + xflags=3, + yflags=2, + xextent=[nx/2]*4, + yextent=[ny/2]*4, + maskmap=None, #[[True,True],[True,True]], + name="test coarse domain", + symmetry=False, + whalo=2, + ehalo=2, + shalo=2, + nhalo=2, + is_mosaic=False, tile_id=coarse_tile_id, ) - mpp.set_current_pelist() + mpp_obj.set_current_pelist() """set fine domain as tile=1""" - name_fine = "test fine pelist" - for i in range(fine_npes): - fine_pelist[i] = global_pelist[COARSE_NPES + i] - pyfms.set_pelist_npes(fine_npes) - mpp.declare_pelist(pelist=fine_pelist, name=name_fine) - - if mpp.pe() in fine_pelist: - pyfms.set_pelist_npes(fine_npes) - mpp.set_current_pelist(pelist=fine_pelist) + fine_pelist = global_pelist[coarse_npes:coarse_npes+fine_npes] + mpp_obj.set_pelist_npes(fine_npes) + mpp_obj.declare_pelist(pelist=fine_pelist, name="test fine pelist") - name = "test fine domain" - ndivs = FINE_NPES + if mpp_obj.pe() in fine_pelist: + mpp_obj.set_pelist_npes(fine_npes) + mpp_obj.set_current_pelist(pelist=fine_pelist) - layout = mpp_domains.define_layout( + layout = mpp_domains_obj.define_layout( global_indices=fine_global_indices, - ndivs=ndivs, + ndivs=fine_npes, ) - mpp_domains.define_domains( + mpp_domains_obj.define_domains( global_indices=fine_global_indices, layout=layout, domain_id=domain_id, pelist=fine_pelist, - name=name, - symmetry=symmetry, - whalo=fine_whalo, - ehalo=fine_ehalo, - shalo=fine_shalo, - nhalo=fine_nhalo, - is_mosaic=is_mosaic, + name="test fine domain", + symmetry=False, + whalo=2, + ehalo=2, + shalo=2, + nhalo=2, + is_mosaic=False, tile_id=fine_tile_id, ) + assert mpp_domains_obj.domain_is_initialized(domain_id) - mpp.set_current_pelist() - - assert mpp_domains.domain_is_initialized(domain_id) + mpp_obj.set_current_pelist() """set nest domain""" - - name = "test nest domain" - num_nest = 1 - ntiles = 2 - nest_level = np.array([1], dtype=np.int32, order="C") - istart_coarse = np.array([24], dtype=np.int32, order="C") - icount_coarse = np.array([24], dtype=np.int32, order="C") - jstart_coarse = np.array([24], dtype=np.int32, order="C") - jcount_coarse = np.array([24], dtype=np.int32, order="C") - npes_nest_tile = np.array([COARSE_NPES, FINE_NPES], dtype=np.int32, order="C") - x_refine = np.array([X_REFINE], dtype=np.int32, order="C") - y_refine = np.array([Y_REFINE], dtype=np.int32, order="C") - tile_fine = np.array([fine_tile_id], dtype=np.int32, order="C") - tile_coarse = np.array([coarse_tile_id], dtype=np.int32, order="C") - nest_domain_id = nest_domain_id - domain_id = domain_id - - mpp_domains.define_nest_domains( - num_nest=num_nest, - ntiles=ntiles, - nest_level=nest_level, - tile_fine=tile_fine, - tile_coarse=tile_coarse, - istart_coarse=istart_coarse, - icount_coarse=icount_coarse, - jstart_coarse=jstart_coarse, - jcount_coarse=jcount_coarse, - npes_nest_tile=npes_nest_tile, - x_refine=x_refine, - y_refine=y_refine, + + mpp_domains_obj.define_nest_domains( + num_nest=1, + ntiles=2, + nest_level=[1], + tile_fine=[fine_tile_id], + tile_coarse=[coarse_tile_id], + istart_coarse=[24], + icount_coarse=[24], + jstart_coarse=[24], + jcount_coarse=[24], + npes_nest_tile=[coarse_npes, fine_npes], + x_refine=[2], + y_refine=[2], nest_domain_id=nest_domain_id, domain_id=domain_id, - extra_halo=None, - name=name, + name="test nest domain", ) - mpp.set_current_pelist() - + mpp_obj.set_current_pelist() + pyfms.pyfms_end() - # mpp.pyfms_error(errortype=1) - @pytest.mark.remove def test_remove_input_nml(): From e675c2818cbfe1e66eee3cd4dce562b791726ec9 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Mon, 14 Apr 2025 12:54:37 -0400 Subject: [PATCH 12/14] add parameters --- pyfms/py_mpp/py_mpp_domains.py | 45 ++++++++++++++++++++++++++++- tests/py_mpp/test_define_domains.py | 4 +-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/pyfms/py_mpp/py_mpp_domains.py b/pyfms/py_mpp/py_mpp_domains.py index 8a5692e..0b53957 100644 --- a/pyfms/py_mpp/py_mpp_domains.py +++ b/pyfms/py_mpp/py_mpp_domains.py @@ -72,10 +72,53 @@ def update_data_domain(self, class mpp_domains: + GLOBAL_DATA_DOMAIN: int = None + BGRID_NE: int = None + CGRID_NE: int = None + DGRID_NE: int = None + AGRID: int = None + FOLD_SOUTH_EDGE: int = None + FOLD_WEST_EDGE: int = None + FOLD_EAST_EDGE: int = None + CYCLIC_GLOBAL_DOMAIN: int = None + NUPDATE: int = None + EUPDATE: int = None + XUPDATE: int = None + YUPDATE: int = None + NORTH: int = None + NORTH_EAST: int = None + EAST: int = None + SOUTH_EAST: int = None + CORNER: int = None + CENTER: int = None + SOUTH: int = None + SOUTH_WEST: int = None - def __init__(self, cFMS: ctypes.CDLL = None): self.cFMS = cFMS + self.GLOBAL_DATA_DOMAIN = ctypes.c_int.in_dll(self.cFMS, "GLOBAL_DATA_DOMAIN") + self.BGRID_NE = ctypes.c_int.in_dll(self.cFMS, "BGRID_NE") + self.CGRID_NE = ctypes.c_int.in_dll(self.cFMS, "CGRID_NE") + self.DGRID_NE = ctypes.c_int.in_dll(self.cFMS, "DGRID_NE") + self.AGRID = ctypes.c_int.in_dll(self.cFMS, "AGRID") + self.FOLD_SOUTH_EDGE = ctypes.c_int.in_dll(self.cFMS, "FOLD_SOUTH_EDGE") + self.FOLD_WEST_EDGE = ctypes.c_int.in_dll(self.cFMS, "FOLD_WEST_EDGE") + self.FOLD_EAST_EDGE = ctypes.c_int.in_dll(self.cFMS, "FOLD_EAST_EDGE") + self.CYCLIC_GLOBAL_DOMAIN = ctypes.c_int.in_dll(self.cFMS, "CYCLIC_GLOBAL_DOMAIN") + self.NUPDATE = ctypes.c_int.in_dll(self.cFMS, "NUPDATE") + self.EUPDATE = ctypes.c_int.in_dll(self.cFMS, "EUPDATE") + self.XUPDATE = ctypes.c_int.in_dll(self.cFMS, "XUPDATE") + self.YUPDATE = ctypes.c_int.in_dll(self.cFMS, "YUPDATE") + self.NORTH = ctypes.c_int.in_dll(self.cFMS, "NORTH") + self.NORTH_EAST = ctypes.c_int.in_dll(self.cFMS, "NORTH_EAST") + self.EAST = ctypes.c_int.in_dll(self.cFMS, "EAST") + self.SOUTH_EAST = ctypes.c_int.in_dll(self.cFMS, "SOUTH_EAST") + self.CORNER = ctypes.c_int.in_dll(self.cFMS, "CORNER") + self.CENTER = ctypes.c_int.in_dll(self.cFMS, "CENTER") + self.SOUTH = ctypes.c_int.in_dll(self.cFMS, "SOUTH") + self.SOUTH_WEST = ctypes.c_int.in_dll(self.cFMS, "SOUTH_WEST") + self.WEST = ctypes.c_int.in_dll(self.cFMS, "WEST") + self.NORTH_WEST = ctypes.c_int.in_dll(self.cFMS, "NORTH_WEST") """ Subroutine: define_domains diff --git a/tests/py_mpp/test_define_domains.py b/tests/py_mpp/test_define_domains.py index 13c6524..9a68c22 100644 --- a/tests/py_mpp/test_define_domains.py +++ b/tests/py_mpp/test_define_domains.py @@ -74,8 +74,8 @@ def test_define_domains(): layout=layout, domain_id=domain_id, pelist=coarse_pelist, - xflags=3, - yflags=2, + xflags=mpp_domains_obj.WEST, + yflags=mpp_domains_obj.SOUTH, xextent=[nx/2]*4, yextent=[ny/2]*4, maskmap=None, #[[True,True],[True,True]], From db8a90eaf964c401ac4f4506f43fe892fafcfd4a Mon Sep 17 00:00:00 2001 From: mlee03 Date: Mon, 14 Apr 2025 13:42:07 -0400 Subject: [PATCH 13/14] updated getset test --- pyfms/py_mpp/py_mpp_domains.py | 127 +++++++++++++-------------- tests/py_mpp/test_getset_domains.py | 130 +++++++++++++--------------- 2 files changed, 126 insertions(+), 131 deletions(-) diff --git a/pyfms/py_mpp/py_mpp_domains.py b/pyfms/py_mpp/py_mpp_domains.py index 0b53957..f57dcec 100644 --- a/pyfms/py_mpp/py_mpp_domains.py +++ b/pyfms/py_mpp/py_mpp_domains.py @@ -13,63 +13,6 @@ ) -class pyDomain(): - - def __init__(self, - domain_id: int = None, - isc: int = None, - jsc: int = None, - iec: int = None, - jec: int = None, - isd: int = None, - jsd: int = None, - ied: int = None, - jed: int = None, - tile: int = None, - layout: list[int] = None): - self.domain_id = domain_id - self.isc = isc - self.jsc = jsc - self.iec = iec - self.jec = jec - self.isd = isd - self.jsd = jsd - self.ied = ied - self.jed = jed - self.tile = tile - self.layout = layout - - def update_compute_domain(self, - position: int = None, - tile_count: int = None, - whalo: int = None, - shalo: int = None): - compute = self.get_compute_domain(domain_id=self.domain_id, - tile_count=tile_count, - position = position, - whalo=whalo, - shalo=shalo) - self.isc = compute["xbegin"] - self.jsc = compute["ybegin"] - self.iec = compute["xend"] - self.iec = compute["yend"] - - def update_data_domain(self, - position: int = None, - tile_count: int = None, - whalo: int = None, - shalo: int = None): - data = self.get_data_domain(domain_id=self.domain_id, - tile_count=tile_count, - position = position, - whalo=whalo, - shalo=shalo) - self.isd = data["xbegin"] - self.jsd = data["ybegin"] - self.ied = data["xend"] - self.jed = data["yend"] - - class mpp_domains: GLOBAL_DATA_DOMAIN: int = None @@ -478,7 +421,7 @@ def get_compute_domain( y_is_global_c = y_is_global_t(default_b) domain_id_c = domain_id_t(domain_id) if domain_id is not None else None tile_count_c = tile_count_t(tile_count) if tile_count is not None else None - position_c = position_t(position) if tile_count is not None else None + position_c = position_t(position) if position is not None else None whalo_c = whalo_t(whalo) if whalo is not None else None shalo_c = shalo_t(shalo) if shalo is not None else None @@ -550,10 +493,11 @@ def get_compute_domain( def get_data_domain( self, - domain_id: Optional[int] = None, - position: Optional[int] = None, - whalo: Optional[int] = None, - shalo: Optional[int] = None, + domain_id: int = None, + position: int = None, + tile_count: int = None, + whalo: int = None, + shalo: int = None, ): _cfms_get_data_domain = self.cFMS.cFMS_get_data_domain @@ -588,7 +532,7 @@ def get_data_domain( y_is_global_c = y_is_global_t(default_b) domain_id_c = domain_id_t(domain_id) if domain_id is not None else None tile_count_c = tile_count_t(tile_count) if tile_count is not None else None - position_c = position_t(position) if tile_count is not None else None + position_c = position_t(position) if position is not None else None whalo_c = whalo_t(whalo) if whalo is not None else None shalo_c = shalo_t(shalo) if shalo is not None else None @@ -974,3 +918,60 @@ def set_global_domain( ) +class pyDomain(): + + def __init__(self, + domain_id: int = None, + isc: int = None, + jsc: int = None, + iec: int = None, + jec: int = None, + isd: int = None, + jsd: int = None, + ied: int = None, + jed: int = None, + tile: int = None, + layout: list[int] = None): + self.domain_id = domain_id + self.isc = isc + self.jsc = jsc + self.iec = iec + self.jec = jec + self.isd = isd + self.jsd = jsd + self.ied = ied + self.jed = jed + self.tile = tile + self.layout = layout + + #def update_compute_domain(self, + # position: int = None, + # tile_count: int = None, + # whalo: int = None, + # shalo: int = None): + # compute = self.get_compute_domain(domain_id=self.domain_id, + # tile_count=tile_count, + # position = position, + # whalo=whalo, + # shalo=shalo) + # self.isc = compute["xbegin"] + # self.jsc = compute["ybegin"] + # self.iec = compute["xend"] + # self.iec = compute["yend"] + + #def update_data_domain(self, + # position: int = None, + # tile_count: int = None, + # whalo: int = None, + # shalo: int = None): + # data = self.get_data_domain(domain_id=self.domain_id, + # tile_count=tile_count, + # position = position, + # whalo=whalo, + # shalo=shalo) + # self.isd = data["xbegin"] + # self.jsd = data["ybegin"] + # self.ied = data["xend"] + # self.jed = data["yend"] + + diff --git a/tests/py_mpp/test_getset_domains.py b/tests/py_mpp/test_getset_domains.py index 8438371..ac316e7 100644 --- a/tests/py_mpp/test_getset_domains.py +++ b/tests/py_mpp/test_getset_domains.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from pyfms import pyDomain, pyFMS, pyFMS_mpp, pyFMS_mpp_domains +import pyfms @pytest.mark.create @@ -15,7 +15,9 @@ def test_create_input_nml(): @pytest.mark.parallel def test_getset_domains(): + """ + copied from cFMS global domain * * * * * * * * @@ -26,8 +28,8 @@ def test_getset_domains(): * * * * * * * * """ + domain_id = 0 - ndiv = 4 global_indices = [0, 3, 0, 3] whalo = 2 ehalo = 2 @@ -35,30 +37,27 @@ def test_getset_domains(): nhalo = 2 name = "test domain" - pyfms = pyFMS(cFMS_path="./cFMS/libcFMS/.libs/libcFMS.so") - mpp = pyFMS_mpp(cFMS=pyfms.cFMS) - mpp_domains = pyFMS_mpp_domains(cFMS=pyfms.cFMS) + pyfms_obj = pyfms.pyFMS(cFMS_path="./cFMS/libcFMS/.libs/libcFMS.so") + mpp_obj = pyfms.mpp(cFMS=pyfms_obj.cFMS) + mpp_domains_obj = pyfms.mpp_domains(cFMS=pyfms_obj.cFMS) # set domain - layout = mpp_domains.define_layout(global_indices=global_indices, ndivs=ndiv) + layout = mpp_domains_obj.define_layout(global_indices=global_indices, ndivs=4) - domain = pyDomain( - global_indices=global_indices, - layout=layout, - mpp_domains_obj=mpp_domains, - domain_id=domain_id, - name=name, - whalo=whalo, - ehalo=ehalo, - shalo=shalo, - nhalo=nhalo, + domain = mpp_domains_obj.define_domains(global_indices=global_indices, + layout=layout, + domain_id=domain_id, + name=name, + whalo=whalo, + ehalo=ehalo, + shalo=shalo, + nhalo=nhalo, ) + + assert(mpp_domains_obj.domain_is_initialized(domain_id)) - if not mpp_domains.domain_is_initialized(domain_id): - mpp.pyfms_error(1, "error in setting domain") - - mpp.set_current_pelist() + mpp_obj.set_current_pelist() """ flipping the domain: @@ -68,10 +67,10 @@ def test_getset_domains(): pe 3: isc=4, iec=5, jsc=4, jec=5 --> pe 0 """ - isc = np.array([4, 2, 4, 2], dtype=np.int32, order="C") - iec = np.array([5, 3, 5, 3], dtype=np.int32, order="C") - jsc = np.array([4, 4, 2, 2], dtype=np.int32, order="C") - jec = np.array([5, 5, 3, 3], dtype=np.int32, order="C") + isc = [4, 2, 4, 2] + iec = [5, 3, 5, 3] + jsc = [4, 4, 2, 2] + jec = [5, 5, 3, 3] """ pe 0: isd=0, ied=5, jsd=0, jed=5 --> pe 3 @@ -80,77 +79,72 @@ def test_getset_domains(): pe 3: isd=2, ied=7, jsd=2, jed=7 --> pe 0 """ - isd = np.array([2, 0, 2, 0], dtype=np.int32, order="C") - ied = np.array([7, 5, 7, 5], dtype=np.int32, order="C") - jsd = np.array([2, 2, 0, 0], dtype=np.int32, order="C") - jed = np.array([7, 7, 5, 5], dtype=np.int32, order="C") + isd = [2, 0, 2, 0] + ied = [7, 5, 7, 5] + jsd = [2, 2, 0, 0] + jed = [7, 7, 5, 5] - pe = mpp.pe() + pe = mpp_obj.pe() tile_count = 0 x_is_global = False y_is_global = False # set compute and data domains - xsize = 2 - ysize = 2 - - domain.set_compute_domain( + mpp_domains_obj.set_compute_domain( domain_id=domain_id, xbegin=isc[pe], xend=iec[pe], ybegin=jsc[pe], yend=jec[pe], - xsize=xsize, - ysize=ysize, + xsize=2, + ysize=2, x_is_global=x_is_global, y_is_global=y_is_global, - tile_count=tile_count, whalo=whalo, shalo=shalo, - ) - - xsize = 6 - ysize = 6 - - domain.set_data_domain( + ) + + mpp_domains_obj.set_data_domain( domain_id=domain_id, xbegin=isd[pe], xend=ied[pe], ybegin=jsd[pe], yend=jed[pe], - xsize=xsize, - ysize=ysize, + xsize=6, + ysize=6, x_is_global=x_is_global, y_is_global=y_is_global, - tile_count=tile_count, whalo=whalo, shalo=shalo, ) - # get domain - - assert domain.compute_domain.xbegin.value == isc[pe] - assert domain.compute_domain.xend.value == iec[pe] - assert domain.compute_domain.ybegin.value == jsc[pe] - assert domain.compute_domain.yend.value == jec[pe] - assert domain.compute_domain.xsize.value == 2 - assert domain.compute_domain.ysize.value == 2 - assert domain.compute_domain.xmax_size.value == 2 - assert domain.compute_domain.ymax_size.value == 2 - assert domain.compute_domain.x_is_global.value is False - assert domain.compute_domain.y_is_global.value is False - - assert domain.data_domain.xbegin.value == isd[pe] - assert domain.data_domain.xend.value == ied[pe] - assert domain.data_domain.ybegin.value == jsd[pe] - assert domain.data_domain.yend.value == jed[pe] - assert domain.data_domain.xsize.value == 6 - assert domain.data_domain.ysize.value == 6 - assert domain.data_domain.xmax_size.value == 6 - assert domain.data_domain.ymax_size.value == 6 - - pyfms.pyfms_end() + compute = mpp_domains_obj.get_compute_domain(domain_id=domain_id, whalo=whalo, shalo=shalo) + data = mpp_domains_obj.get_data_domain(domain_id=domain_id, whalo=whalo, shalo=shalo) + + # get domain + + assert compute["xbegin"] == isc[pe] + assert compute["xend"] == iec[pe] + assert compute["ybegin"] == jsc[pe] + assert compute["yend"] == jec[pe] + assert compute["xsize"] == 2 + assert compute["ysize"] == 2 + assert compute["xmax_size"] == 2 + assert compute["ymax_size"] == 2 + assert compute["x_is_global"] is False + assert compute["y_is_global"] is False + + assert data["xbegin"] == isd[pe] + assert data["xend"] == ied[pe] + assert data["ybegin"] == jsd[pe] + assert data["yend"] == jed[pe] + assert data["xsize"] == 6 + assert data["ysize"] == 6 + assert data["xmax_size"] == 6 + assert data["ymax_size"] == 6 + + pyfms_obj.pyfms_end() @pytest.mark.remove From 52bc1ae3286c7d34b1013fb82e4dc50fc807da04 Mon Sep 17 00:00:00 2001 From: mlee03 Date: Mon, 14 Apr 2025 13:43:27 -0400 Subject: [PATCH 14/14] save before merging --- tests/py_mpp/test_getset_domains.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/py_mpp/test_getset_domains.py b/tests/py_mpp/test_getset_domains.py index e2b834e..1dfe8c8 100644 --- a/tests/py_mpp/test_getset_domains.py +++ b/tests/py_mpp/test_getset_domains.py @@ -40,7 +40,8 @@ def test_getset_domains(): # set domain layout = pyfms.mpp_domains.define_layout(global_indices=global_indices, ndivs=ndiv) - + + #domain = pyDomain( # global_indices=global_indices, # layout=layout,