ESMF_StateReconcile Subroutine

public subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc)

Arguments

Type IntentOptional Attributes Name
type(ESMF_State), intent(inout) :: state
type(ESMF_KeywordEnforcer), optional :: keywordEnforcer
type(ESMF_VM), intent(in), optional :: vm
logical, intent(in), optional :: checkflag
integer, intent(out), optional :: rc

Calls

proc~~esmf_statereconcile~~CallsGraph proc~esmf_statereconcile ESMF_StateReconcile destroy destroy proc~esmf_statereconcile->destroy initialize initialize proc~esmf_statereconcile->initialize interface~esmf_vmbroadcast ESMF_VMBroadcast proc~esmf_statereconcile->interface~esmf_vmbroadcast interface~esmf_vmget ESMF_VMGet proc~esmf_statereconcile->interface~esmf_vmget proc~esmf_imerr ESMF_IMErr proc~esmf_statereconcile->proc~esmf_imerr proc~esmf_infodump ESMF_InfoDump proc~esmf_statereconcile->proc~esmf_infodump proc~esmf_logfounderror ESMF_LogFoundError proc~esmf_statereconcile->proc~esmf_logfounderror proc~esmf_logseterror ESMF_LogSetError proc~esmf_statereconcile->proc~esmf_logseterror proc~esmf_stategetinit ESMF_StateGetInit proc~esmf_statereconcile->proc~esmf_stategetinit proc~esmf_statereconcile_driver ESMF_StateReconcile_driver proc~esmf_statereconcile->proc~esmf_statereconcile_driver proc~esmf_statereconcileisnoop ESMF_StateReconcileIsNoop proc~esmf_statereconcile->proc~esmf_statereconcileisnoop proc~esmf_traceregionenter ESMF_TraceRegionEnter proc~esmf_statereconcile->proc~esmf_traceregionenter proc~esmf_traceregionexit ESMF_TraceRegionExit proc~esmf_statereconcile->proc~esmf_traceregionexit proc~esmf_utilstringdiffmatch ESMF_UtilStringDiffMatch proc~esmf_statereconcile->proc~esmf_utilstringdiffmatch proc~esmf_vmgetcurrent ESMF_VMGetCurrent proc~esmf_statereconcile->proc~esmf_vmgetcurrent proc~esmf_vmgetinit ESMF_VMGetInit proc~esmf_statereconcile->proc~esmf_vmgetinit update update proc~esmf_statereconcile->update

Called by

compInitwESMF_StateReconcile
w
compInit1w
w
compInit2w
w
ESMF_ArraySharedDeSSISTestw
w
ESMF_FieldSharedDeSSISTestw
w
ESMF_RHandleFromRHandleExw
w
ESMF_RouteHandleAdvancedUTestw
w
ESMF_StateReconcileExw
w
ESMF_StateReconcileProxyUTestw
w
ESMF_StateReconcileUTestw
w
NUOPC_Reconcilew
w
ShareFieldWithGridw
w
ShareFieldWithMeshw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initw
w
user_initP1w
w
user_initP1w
w
user_initP2w
w
user_initP2w
w
user_initP3w
w
user_initP3w
w
usercpl1_initw
w
usercpl2_initw
w
usercpl_initw
w
usercpl_initw
w
usercpl_initw
w

Source Code

  subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc)
!
! !ARGUMENTS:
    type(ESMF_State),            intent(inout)         :: state
type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
    type(ESMF_VM),               intent(in),  optional :: vm
    logical,                     intent(in),  optional :: checkflag
    integer,                     intent(out), optional :: rc
!
! !DESCRIPTION:
!
!   Must be called for any {\tt ESMF\_State} which contains ESMF objects
!   that have not been created on all the PETs of {\tt vm}.
!   For example, if a coupler component is operating on objects
!   which were created by another component that ran on only a subset
!   of the coupler PETs, the coupler must make this call first
!   before operating with any of the objects held by the {\tt ESMF\_State}.
!   After calling {\tt ESMF\_StateReconcile()} all PETs will have
!   a common view of all objects contained in this {\tt ESMF\_State}.
!
!   The Info metadata keys of reconciled objects are also reconciled. This
!   means that after reconciliation, every object in {\tt state} holds a
!   consistent set of Info {\em keys} across all the PETs of {\tt vm}.
!   Notice however, that no guarantee is made with respect to the Info
!   {\em value} that is associated with reconciled Info keys.
!
!   The Info metadata keys of the {\tt state} object itself are also reconciled
!   for most common cases. The only exception is for the case where Info keys
!   were added to {\tt state} under a component that is executing on a subset
!   of PETs, and no actual object created under such component was added to
!   {\tt state}.
!
!   This call is collective across the specified VM.
!
!   The arguments are:
!   \begin{description}
!   \item[state]
!     {\tt ESMF\_State} to reconcile.
!   \item[{[vm]}]
!     {\tt ESMF\_VM} across which to reconcile. The default is the current VM.
!   \item [{[checkflag]}]
!     If set to {\tt .TRUE.} the reconciled State object is checked for
!     consistency across PETs before returning. Any detected issues are
!     indicated in {\tt rc}. Set {\tt checkflag} to {\tt .FALSE.} in order
!     to achieve highest performance. The default is {\tt .FALSE.}.
!   \item[{[rc]}]
!     Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!   \end{description}
!EOP

    integer                     :: localrc
    type(ESMF_VM)               :: localvm
    logical                     :: isNoop, isFlag, localCheckFlag

    logical, parameter :: profile = .false.

    ! check input variables
    ESMF_INIT_CHECK_DEEP(ESMF_StateGetInit,state,rc)
    ESMF_INIT_CHECK_DEEP(ESMF_VMGetInit,vm,rc)

    ! Initialize return code; assume routine not implemented
    if (present(rc)) rc = ESMF_RC_NOT_IMPL
    localrc = ESMF_RC_NOT_IMPL

    localCheckFlag = .false.  ! default
#if 0
    ! Activate this when working on StateReoncile, so default is to check result
    localCheckFlag = .true. ! force checking by default
#endif
    if (present(checkFlag)) localCheckFlag = checkFlag

    if (present (vm)) then
      localvm = vm
    else
      call ESMF_VMGetCurrent(vm=localvm, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
    end if

#ifdef RECONCILE_LOG_on
    block
      character(ESMF_MAXSTR)  :: stateName
      call ESMF_StateGet(state, name=stateName, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
      call ESMF_LogWrite("StateReconcile() for State: "//trim(stateName), &
        ESMF_LOGMSG_DEBUG, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
    end block
#endif

#if 0
    block
      type(ESMF_InfoDescribe)   :: idesc
      ! Log a JSON State representation -----------------------------------------
      call idesc%Initialize(createInfo=.true., addObjectInfo=.true., rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
      call idesc%Update(state, "", rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
      call ESMF_LogWrite("state_json_before_reconcile="// &
        ESMF_InfoDump(idesc%info, indent=2), ESMF_LOGMSG_DEBUG, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
      call idesc%Destroy(rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
    end block
#endif

#if 0
    ! cleaner timings below, eliminating issue due to different times PETs enter
    ! BUT: only enable this for testing purposes
    call ESMF_VMBarrier(localvm, rc=localrc)
#endif

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ! Determine whether there is anything to be Reconciled at all. !
    ! If not then return as quickly as possible.                   !
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    if (profile) then
      call ESMF_TraceRegionEnter("ESMF_StateReconcileIsNoop", rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
    endif

    call ESMF_StateReconcileIsNoop(state, vm=localvm, isNoop=isNoop, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
      rcToReturn=rc)) return

    if (profile) then
      call ESMF_TraceRegionExit("ESMF_StateReconcileIsNoop", rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
    endif

#ifdef RECONCILE_LOG_on
    block
      character(160):: msgStr
      write(msgStr,*) "StateReconcile() isNoop: ", isNoop
      call ESMF_LogWrite(msgStr, ESMF_LOGMSG_DEBUG, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return
    end block
#endif

    if (isNoop) then

      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      ! Quick exit for Noop, but still must reconcile State level Info !
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

      !TODO: Only need to do the State level Info reconcile here for a very
      !TODO: specific Noop case where no objects were added under a sub context,
      !TODO: but top level State Attributes were set under the sub context.
      !TODO: This is tricky to detect here, and to figure out which PET(s)
      !TODO: to use for correct rootPets!!
      !TODO: Luckily this is a very special edge case... and for now get away
      !TODO: not handling it... but it could some day cause an issue!!!

    else

      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      ! Go on to reconcile the State !
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

      if (profile) then
        call ESMF_TraceRegionEnter("ESMF_StateReconcile_driver", rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
          rcToReturn=rc)) return
      endif

      call ESMF_StateReconcile_driver(state, vm=localvm, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
        rcToReturn=rc)) return

      if (profile) then
        call ESMF_TraceRegionExit("ESMF_StateReconcile_driver", rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
          rcToReturn=rc)) return
      endif
    endif

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ! Conditionally check the reconciled State for consistency across PETs !
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    if (localCheckFlag) then
      if (profile) then
        call ESMF_TraceRegionEnter("JSON cross PET check", rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
          rcToReturn=rc)) return
      endif
      block
        type(ESMF_InfoDescribe)   :: idesc
        character(:), allocatable :: jsonStr, testStr
        integer                   :: size(1), localPet
        ! Log a JSON State representation -----------------------------------------
        call idesc%Initialize(createInfo=.true., addObjectInfo=.true., rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
        call idesc%Update(state, "", rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
        jsonStr = "state_json_after_reassemble="//&
          ESMF_InfoDump(idesc%info, indent=2, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
#ifdef RECONCILE_LOG_on
        call ESMF_LogWrite(jsonStr, ESMF_LOGMSG_DEBUG, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
#endif
        call idesc%Destroy(rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
#if 1
        ! check match across all PETs of VM
        size(1) = len(jsonStr)
        call ESMF_VMBroadcast(localvm, size, count=1, rootPet=0, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
        call ESMF_VMGet(localvm, localPet=localPet, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
        if (localPet==0) then
          call ESMF_VMBroadcast(localvm, jsonStr, count=size(1), rootPet=0, rc=localrc)
          if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
        else
          allocate(character(len=size(1))::testStr)
          call ESMF_VMBroadcast(localvm, testStr, count=size(1), rootPet=0, rc=localrc)
          if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, rcToReturn=rc)) return
          if (testStr/=jsonStr) then
            ! not a perfect match -> see if the differences are acceptable
            ! these are differences in the values of attributes, which show up in
            ! the bundled esmf and nuopc test cases... these diffs are begnin.
            isFlag = ESMF_UtilStringDiffMatch(jsonStr, testStr, &
              minusStringList = ["None        ", &
                                 "All         ", &
                                 "1           ", &
                                 "2           ", &
                                 "            ", &
                                 "            ", &
                                 "M           ", &
                                 "DEF         ", &
                                 "UL          ", &
                                 "            ", &
                                 "driverChild "  &
                                 ], &
              plusStringList  = ["All    ", &
                                 "None   ", &
                                 "2      ", &
                                 "1      ", &
                                 "DEF    ", &
                                 "UL     ", &
                                 "       ", &
                                 "       ", &
                                 "       ", &
                                 "M      ", &
                                 "DEFAULT"  &
                                 ], rc=localrc)
            if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
              rcToReturn=rc)) return
            if (.not.isFlag) then
              ! found unexpected/unacceptable differences
              call ESMF_LogSetError(ESMF_RC_INTNRL_INCONS, &
                msg="StateReconcile() failed!! Not all PETs hold same content!!", &
                ESMF_CONTEXT, rcToReturn=rc)
              return
            endif
          endif
        endif
#endif
      end block
      if (profile) then
        call ESMF_TraceRegionExit("JSON cross PET check", rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, &
          rcToReturn=rc)) return
      endif
    endif

    if (present(rc)) rc = ESMF_SUCCESS

  end subroutine ESMF_StateReconcile