! $Id$ ! ! Earth System Modeling Framework ! Copyright (c) 2002-2025, University Corporation for Atmospheric Research, ! Massachusetts Institute of Technology, Geophysical Fluid Dynamics ! Laboratory, University of Michigan, National Centers for Environmental ! Prediction, Los Alamos National Laboratory, Argonne National Laboratory, ! NASA Goddard Space Flight Center. ! Licensed under the University of Illinois-NCSA License. ! !============================================================================== #define ESMF_FILENAME "ESMF_FieldHalo.F90" !============================================================================== ! ! ESMF Field Halo Module module ESMF_FieldHaloMod ! !============================================================================== ! ! This file contains the Fortran implementation of Field Halo methods. ! !------------------------------------------------------------------------------ ! INCLUDES #include "ESMF.h" !============================================================================== !BOPI ! !MODULE: ESMF_FieldHaloMod ! ! Fortran API of Field Halo ! !------------------------------------------------------------------------------ ! !USES: use ESMF_UtilTypesMod ! ESMF utility types use ESMF_InitMacrosMod ! ESMF initializer macros use ESMF_BaseMod ! ESMF base class use ESMF_LogErrMod ! ESMF error handling use ESMF_ArrayMod use ESMF_FieldMod use ESMF_FieldGetMod use ESMF_VMMod use ESMF_DELayoutMod use ESMF_RHandleMod use ESMF_UtilMod implicit none !------------------------------------------------------------------------------ ! !PRIVATE TYPES: private !------------------------------------------------------------------------------ ! !PUBLIC TYPES: !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! ! !PUBLIC MEMBER FUNCTIONS: ! - ESMF-public methods: public ESMF_FieldHalo public ESMF_FieldHaloRelease public ESMF_FieldHaloStore public ESMF_FieldIsCreated ! Check if a Field object is created public ESMF_FieldLog !EOPI !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! The following line turns the CVS identifier string into a printable variable. character(*), parameter, private :: version = & '$Id$' !============================================================================== ! ! INTERFACE BLOCKS ! !============================================================================== !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! contains !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !==================== communication calls =========================== !------------------------------------------------------------------------------ #undef ESMF_METHOD #define ESMF_METHOD "ESMF_FieldHalo()" !BOP ! !IROUTINE: ESMF_FieldHalo - Execute a FieldHalo operation ! ! !INTERFACE: subroutine ESMF_FieldHalo(field, routehandle, keywordEnforcer, & routesyncflag, finishedflag, checkflag, rc) ! ! !ARGUMENTS: type(ESMF_Field), intent(inout) :: field type(ESMF_RouteHandle), intent(inout) :: routehandle type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords for the below type(ESMF_RouteSync_Flag), intent(in), optional :: routesyncflag logical, intent(out), optional :: finishedflag logical, intent(in), optional :: checkflag integer, intent(out), optional :: rc ! ! ! !STATUS: ! \begin{itemize} ! \item\apiStatusCompatibleVersion{5.2.0r} ! \end{itemize} ! ! !DESCRIPTION: ! Execute a precomputed Field halo operation for {\tt field}. ! The {\tt field} argument must match the Field used during ! {\tt ESMF\_FieldHaloStore()} in {\em type}, {\em kind}, and ! memory layout of the {\em gridded} dimensions. However, the size, number, ! and index order of {\em ungridded} dimensions may be different. See section ! \ref{RH:Reusability} for a more detailed discussion of RouteHandle ! reusability. ! ! See {\tt ESMF\_FieldHaloStore()} on how to precompute {\tt routehandle}. ! ! This call is {\em collective} across the current VM. ! ! \begin{description} ! \item [field] ! {\tt ESMF\_Field} containing data to be haloed. ! \item [routehandle] ! Handle to the precomputed Route. ! \item [{[routesyncflag]}] ! Indicate communication option. Default is {\tt ESMF\_ROUTESYNC\_BLOCKING}, ! resulting in a blocking operation. ! See section \ref{const:routesync} for a complete list of valid settings. ! \item [{[finishedflag]}] ! \begin{sloppypar} ! Used in combination with {\tt routesyncflag = ESMF\_ROUTESYNC\_NBTESTFINISH}. ! Returned {\tt finishedflag} equal to {\tt .true.} indicates that all ! operations have finished. A value of {\tt .false.} indicates that there ! are still unfinished operations that require additional calls with ! {\tt routesyncflag = ESMF\_ROUTESYNC\_NBTESTFINISH}, or a final call with ! {\tt routesyncflag = ESMF\_ROUTESYNC\_NBWAITFINISH}. For all other {\tt routesyncflag} ! settings the returned value in {\tt finishedflag} is always {\tt .true.}. ! \end{sloppypar} ! \item [{[checkflag]}] ! If set to {\tt .TRUE.} the input Field pair will be checked for ! consistency with the precomputed operation provided by {\tt routehandle}. ! If set to {\tt .FALSE.} {\em (default)} only a very basic input check ! will be performed, leaving many inconsistencies undetected. Set ! {\tt checkflag} to {\tt .FALSE.} to achieve highest performance. ! \item [{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} ! !EOP !------------------------------------------------------------------------------ integer :: localrc ! local return code ! local variables type(ESMF_Array) :: array ! initialize return code; assume routine not implemented localrc = ESMF_RC_NOT_IMPL if (present(rc)) rc = ESMF_RC_NOT_IMPL ! Check init status of arguments ESMF_INIT_CHECK_DEEP(ESMF_FieldGetInit, field, rc) ESMF_INIT_CHECK_DEEP(ESMF_RouteHandleGetInit, routehandle, rc) call ESMF_FieldGet(field, array=array, rc=localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! Call into the Array interface, which will sort out optional arguments call ESMF_ArrayHalo(array, routehandle=routehandle, routesyncflag=routesyncflag, & finishedflag=finishedflag, checkflag=checkflag, rc=localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! return successfully if (present(rc)) rc = ESMF_SUCCESS end subroutine ESMF_FieldHalo !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ #undef ESMF_METHOD #define ESMF_METHOD "ESMF_FieldHaloRelease()" !BOP ! !IROUTINE: ESMF_FieldHaloRelease - Release resources associated with a Field halo operation ! ! !INTERFACE: subroutine ESMF_FieldHaloRelease(routehandle, keywordEnforcer, noGarbage, rc) ! ! !ARGUMENTS: type(ESMF_RouteHandle), intent(inout) :: routehandle type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below logical, intent(in), optional :: noGarbage integer, intent(out), optional :: rc ! ! ! !STATUS: ! \begin{itemize} ! \item\apiStatusCompatibleVersion{5.2.0r} ! \item\apiStatusModifiedSinceVersion{5.2.0r} ! \begin{description} ! \item[8.0.0] Added argument {\tt noGarbage}. ! The argument provides a mechanism to override the default garbage collection ! mechanism when destroying an ESMF object. ! \end{description} ! \end{itemize} ! ! !DESCRIPTION: ! Release resources associated with a Field halo operation. ! After this call {\tt routehandle} becomes invalid. ! ! \begin{description} ! \item [routehandle] ! Handle to the precomputed Route. ! \item[{[noGarbage]}] ! If set to {\tt .TRUE.} the object will be fully destroyed and removed ! from the ESMF garbage collection system. Note however that under this ! condition ESMF cannot protect against accessing the destroyed object ! through dangling aliases -- a situation which may lead to hard to debug ! application crashes. ! ! It is generally recommended to leave the {\tt noGarbage} argument ! set to {\tt .FALSE.} (the default), and to take advantage of the ESMF ! garbage collection system which will prevent problems with dangling ! aliases or incorrect sequences of destroy calls. However this level of ! support requires that a small remnant of the object is kept in memory ! past the destroy call. This can lead to an unexpected increase in memory ! consumption over the course of execution in applications that use ! temporary ESMF objects. For situations where the repeated creation and ! destruction of temporary objects leads to memory issues, it is ! recommended to call with {\tt noGarbage} set to {\tt .TRUE.}, fully ! removing the entire temporary object from memory. ! \item [{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} ! !EOP !------------------------------------------------------------------------------ integer :: localrc ! local return code ! initialize return code; assume routine not implemented localrc = ESMF_RC_NOT_IMPL if (present(rc)) rc = ESMF_RC_NOT_IMPL ! Check init status of arguments, deal with optional Array args ESMF_INIT_CHECK_DEEP(ESMF_RouteHandleGetInit, routehandle, rc) ! Call into the RouteHandle code call ESMF_RouteHandleRelease(routehandle, noGarbage=noGarbage, rc=localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! return successfully if (present(rc)) rc = ESMF_SUCCESS end subroutine ESMF_FieldHaloRelease !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ #undef ESMF_METHOD #define ESMF_METHOD "ESMF_FieldHaloStore()" !BOP ! !IROUTINE: ESMF_FieldHaloStore - Store a FieldHalo operation ! ! !INTERFACE: subroutine ESMF_FieldHaloStore(field, routehandle, keywordEnforcer, & startregion, haloLDepth, haloUDepth, rc) ! ! !ARGUMENTS: type(ESMF_Field), intent(inout) :: field type(ESMF_RouteHandle), intent(inout) :: routehandle type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below type(ESMF_StartRegion_Flag), intent(in), optional :: startregion integer, intent(in), optional :: haloLDepth(:) integer, intent(in), optional :: haloUDepth(:) integer, intent(out), optional :: rc ! ! ! !STATUS: ! \begin{itemize} ! \item\apiStatusCompatibleVersion{5.2.0r} ! \end{itemize} ! ! !DESCRIPTION: ! Store a Field halo operation over the data in {\tt field}. By default, ! i.e. without specifying {\tt startregion}, {\tt haloLDepth} and ! {\tt haloUDepth}, all elements in the total Field region that lie outside ! the exclusive region will be considered potential destination elements for ! halo. However, only those elements that have a corresponding halo source ! element, i.e. an exclusive element on one of the DEs, will be updated under ! the halo operation. Elements that have no associated source remain ! unchanged under halo. ! ! Specifying {\tt startregion} allows to change the shape of the ! effective halo region from the inside. Setting this flag to ! {\tt ESMF\_STARTREGION\_COMPUTATIONAL} means that only elements outside ! the computational region of the Field are considered for potential ! destination elements for the halo operation. The default is {\tt ESMF\_STARTREGION\_EXCLUSIVE}. ! ! The {\tt haloLDepth} and {\tt haloUDepth} arguments allow to reduce ! the extent of the effective halo region. Starting at the region specified ! by {\tt startregion}, the {\tt haloLDepth} and {\tt haloUDepth} ! define a halo depth in each direction. Note that the maximum halo region is ! limited by the total Field region, independent of the actual ! {\tt haloLDepth} and {\tt haloUDepth} setting. The total Field region is ! local DE specific. The {\tt haloLDepth} and {\tt haloUDepth} are interpreted ! as the maximum desired extent, reducing the potentially larger region ! available for the halo operation. ! ! The routine returns an {\tt ESMF\_RouteHandle} that can be used to call ! {\tt ESMF\_FieldHalo()} on any Field that matches ! {\tt field} in {\em type}, {\em kind}, and ! memory layout of the {\em gridded} dimensions. However, the size, number, ! and index order of {\em ungridded} dimensions may be different. See section ! \ref{RH:Reusability} for a more detailed discussion of RouteHandle ! reusability. ! ! This call is {\em collective} across the current VM. ! ! \begin{description} ! \item [field] ! {\tt ESMF\_Field} containing data to be haloed. The data in this Field may be ! destroyed by this call. ! \item [routehandle] ! Handle to the precomputed Route. ! \item [{[startregion]}] ! \begin{sloppypar} ! The start of the effective halo region on every DE. The default ! setting is {\tt ESMF\_STARTREGION\_EXCLUSIVE}, rendering all non-exclusive ! elements potential halo destination elements. ! See section \ref{const:startregion} for a complete list of ! valid settings. ! \end{sloppypar} ! \item[{[haloLDepth]}] ! This vector specifies the lower corner of the effective halo ! region with respect to the lower corner of {\tt startregion}. ! The size of {\tt haloLDepth} must equal the number of distributed Array ! dimensions. ! \item[{[haloUDepth]}] ! This vector specifies the upper corner of the effective halo ! region with respect to the upper corner of {\tt startregion}. ! The size of {\tt haloUDepth} must equal the number of distributed Array ! dimensions. ! \item [{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} ! !EOP !------------------------------------------------------------------------------ integer :: localrc ! local return code ! local variables type(ESMF_Array) :: array ! initialize return code; assume routine not implemented localrc = ESMF_RC_NOT_IMPL if (present(rc)) rc = ESMF_RC_NOT_IMPL ! Check init status of arguments ESMF_INIT_CHECK_DEEP(ESMF_FieldGetInit, field, rc) ! query the field for its internal array call ESMF_FieldGet(field, array=array, rc=localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! Call into the Array interface, which will sort out optional arguments call ESMF_ArrayHaloStore(array, routehandle=routehandle, & startregion=startregion, haloLDepth=haloLDepth, & haloUDepth=haloUDepth, rc=localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! return successfully if (present(rc)) rc = ESMF_SUCCESS end subroutine ESMF_FieldHaloStore !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ #undef ESMF_METHOD #define ESMF_METHOD "ESMF_FieldIsCreated()" !BOP ! !IROUTINE: ESMF_FieldIsCreated - Check whether a Field object has been created ! !INTERFACE: function ESMF_FieldIsCreated(field, keywordEnforcer, rc) ! !RETURN VALUE: logical :: ESMF_FieldIsCreated ! ! !ARGUMENTS: type(ESMF_Field), intent(in) :: field type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below integer, intent(out), optional :: rc ! !DESCRIPTION: ! Return {\tt .true.} if the {\tt field} has been created. Otherwise return ! {\tt .false.}. If an error occurs, i.e. {\tt rc /= ESMF\_SUCCESS} is ! returned, the return value of the function will also be {\tt .false.}. ! ! The arguments are: ! \begin{description} ! \item[field] ! {\tt ESMF\_Field} queried. ! \item[{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} ! !EOP !------------------------------------------------------------------------------ ESMF_FieldIsCreated = .false. ! initialize if (present(rc)) rc = ESMF_SUCCESS if (ESMF_FieldGetInit(field)==ESMF_INIT_CREATED) & ESMF_FieldIsCreated = .true. end function !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ #undef ESMF_METHOD #define ESMF_METHOD "ESMF_FieldLog()" !BOP ! !IROUTINE: ESMF_FieldLog - Log Field information ! !INTERFACE: subroutine ESMF_FieldLog(field, keywordEnforcer, prefix, logMsgFlag, deepFlag, rc) ! ! !ARGUMENTS: type(ESMF_Field), intent(in) :: field type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below character(len=*), intent(in), optional :: prefix type(ESMF_LogMsg_Flag), intent(in), optional :: logMsgFlag logical, intent(in), optional :: deepFlag integer, intent(out), optional :: rc ! ! !DESCRIPTION: ! Write information about {\tt field} to the ESMF default Log. ! ! The arguments are: ! \begin{description} ! \item[field] ! The {\tt ESMF\_Field} object logged. ! \item [{[prefix]}] ! String to prefix the log message. Default is no prefix. ! \item [{[logMsgFlag]}] ! Type of log message generated. See section \ref{const:logmsgflag} for ! a list of valid message types. Default is {\tt ESMF\_LOGMSG\_INFO}. ! \item[{[deepFlag]}] ! When set to {\tt .false.} (default), only log top level information about ! the Field. ! When set to {\tt .true.}, additionally log deep information. ! \item[{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} ! !EOP !------------------------------------------------------------------------------ integer :: localrc ! local return code type(ESMF_LogMsg_Flag) :: logMsg character(len=:), allocatable :: prefixStr logical :: deepLog type(ESMF_FieldStatus_Flag) :: fieldStatus type(ESMF_TypeKind_Flag) :: typekind integer :: rank, dimCount character(ESMF_MAXSTR) :: name, tempString character(800) :: msgString type(ESMF_Array) :: array ! initialize return code; assume routine not implemented localrc = ESMF_RC_NOT_IMPL if (present(rc)) rc = ESMF_RC_NOT_IMPL ! optional prefix if (present(prefix)) then prefixStr = trim(prefix) else prefixStr = "" endif ! deal with optional logMsgFlag logMsg = ESMF_LOGMSG_INFO ! default if (present(logMsgFlag)) logMsg = logMsgFlag ! deal with optional deepFlag deepLog = .false. ! default if (present(deepFlag)) deepLog = deepFlag call ESMF_LogWrite(ESMF_StringConcat(trim(prefixStr), & "--- FieldLog() start -----------------"), logMsg, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return if (.not. ESMF_FieldIsCreated(field)) then call ESMF_LogWrite(ESMF_StringConcat(prefix, & "Field object is invalid! Not created or deleted!"), & logMsg, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return else ! query call ESMF_FieldGet(field, name=name, status=fieldStatus, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return if (fieldStatus==ESMF_FIELDSTATUS_EMPTY) then tempString = "ESMF_FIELDSTATUS_EMPTY" else if (fieldStatus==ESMF_FIELDSTATUS_GRIDSET) then tempString = "ESMF_FIELDSTATUS_GRIDSET" else if (fieldStatus==ESMF_FIELDSTATUS_COMPLETE) then tempString = "ESMF_FIELDSTATUS_COMPLETE" else tempString = "Out or range FIELDSTATUS!!!" endif write (msgString,'(A,A,A,A,A,A)') & prefix, "<name: ", trim(name), "> <fieldStatus: ", trim(tempString), ">" call ESMF_LogWrite(trim(msgString), logMsg, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return call c_esmc_vmlogpointer(field, prefix, logMsg) if (fieldStatus == ESMF_FIELDSTATUS_COMPLETE) then call ESMF_FieldGet(field, typekind=typekind, rank=rank, & dimCount=dimCount, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return call ESMF_TypeKindString(typekind, string=tempString, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return write (msgString,'(A,A,A,A,A,I4,A,A,I4,A)') & prefix, "<typekind: ", trim(tempString), ">", & " <rank: ", rank, ">", " <dimCount: ", dimCount, ">" call ESMF_LogWrite(trim(msgString), logMsg, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return if (deepLog) then call ESMF_FieldGet(field, array=array, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return call ESMF_ArrayLog(array, & prefix=ESMF_StringConcat(prefix, "! "), & logMsgFlag=logMsg, deepFlag=deepLog, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return endif endif endif call ESMF_LogWrite(ESMF_StringConcat(trim(prefixStr), & "--- FieldLog() end -------------------"), logMsg, rc=localrc) if (ESMF_LogFoundError(localrc, & ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return ! return successfully if (present(rc)) rc = ESMF_SUCCESS end subroutine ESMF_FieldLog !------------------------------------------------------------------------------ end module ESMF_FieldHaloMod