diff --git a/src/Superstructure/State/doc/State_refdoc.ctex b/src/Superstructure/State/doc/State_refdoc.ctex index 3c83f42351..e14294dce7 100644 --- a/src/Superstructure/State/doc/State_refdoc.ctex +++ b/src/Superstructure/State/doc/State_refdoc.ctex @@ -21,7 +21,7 @@ \textheight 8.5in \addtolength{\oddsidemargin}{-.75in} \newcommand{\mytitle}{State Reference Manual} -\newcommand{\myauthors}{Walter Spector, Ben Koziol} +\newcommand{\myauthors}{Walter Spector, Ben Koziol, Gerhard Theurich} % these are temporary patches until something more % permanent is done to the protex script. \newlength{\oldparskip} diff --git a/src/Superstructure/State/doc/State_rest.tex b/src/Superstructure/State/doc/State_rest.tex index 1df0a3807a..f66a3a926a 100644 --- a/src/Superstructure/State/doc/State_rest.tex +++ b/src/Superstructure/State/doc/State_rest.tex @@ -1,27 +1,49 @@ % $Id$ % % Earth System Modeling Framework -% Copyright (c) 2002-2024, 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, +% Copyright (c) 2002-2024, 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. -%\subsubsection{Restrictions and Future Work} - \begin{enumerate} -\item{\bf No synchronization of object IDs at object create time.} + +\item{\bf No synchronization of object IDs at object create time - Unison Rule:} Object IDs are used during the reconcile process to identify objects which are unknown to some subset of the PETs in the currently running VM. -Object IDs are assigned in sequential order at object create time. - -One important request by the user community during the ESMF object design was -that there be no communication overhead or synchronization when creating -distributed ESMF objects. As a consequence it is required to create these -objects in {\bf unison} across all PETs in order to keep the ESMF object +Object IDs are assigned in sequential order at object create time across the +context of the current VM without communication. This design was requested by +the user community during ESMF object design to reduce communication and +synchronization overhead when creating distributed ESMF objects. +As a consequence it is required to create distributed ESMF objects in +{\bf unison} across all PETs of the current VM in order to keep the ESMF object identification in sync. +Violation of the unison rule will lead to undefined behavior when reconciling +a State that contains objects with inconsistent object IDs. + +\item{\bf Info keys on top level State not reconciled without actual objects +present from the relevant sub-context.} One of the actions of the +{\tt ESMF\_StateReconcile()} method is to reconcile the Info keys of the +State object itself. The endresult is that the reconciled State has the +same Info {\em keys} on all of the PETs of the VM across which it was +reconciled -- albeit with potentially different values across PETs +(see the {\tt ESMF\_StateReconcile()} API doc for more details). An edge case +for which {\tt ESMF\_StateReconcile()} does {\bf not} provide Info key +reconcilation is when keys were added under a component executing on a subset +of PETs (compared to the reconciling VM), but no actual object +(Field, FieldBundle, Array, ArrayBundle, or nested State) was added under the +VM of that sub-context. + +The situation of unreconciled Info keys across PETs for an ESMF State is not an +error condition per-se, however, it can lead to unexpected behavior in +downstream code. Specifically if such code expects to find consistent Info keys +across all PETs. If this is the case, care should be taken to ensure actual +objects are added to the top level State on the sub-context PETs where new Info +keys are added. + \end{enumerate} diff --git a/src/Superstructure/State/doc/State_usage.tex b/src/Superstructure/State/doc/State_usage.tex index 167fdc4e51..5d73a51d15 100644 --- a/src/Superstructure/State/doc/State_usage.tex +++ b/src/Superstructure/State/doc/State_usage.tex @@ -8,8 +8,6 @@ % NASA Goddard Space Flight Center. % Licensed under the University of Illinois-NCSA License. -%\subsection{Use and Examples} - A Gridded Component generally has one associated import State and one export State. Generally the States associated with a Gridded Component will be created by @@ -41,7 +39,7 @@ is passed out through the argument list into a Coupler Component's run method. We recommend the convention that it enters the Coupler Component as the Coupler Component's -import State. Here is it transformed into a form +import State. Here the data is transformed into a form that another Gridded Component requires, and passed out of the Coupler Component as its export State. It can then be passed into the run method of a recipient Gridded Component @@ -78,19 +76,3 @@ qualities of the original object plus enough information for it to be a data source or destination for a regrid or data redistribution operation. - -\subsubsection{State create and destroy} - -States can be created and destroyed at any time during -application execution. The {\tt ESMF\_StateCreate()} routine -can take many different combinations of optional arguments. Refer -to the API description for all possible methods of creating a State. -An empty State can be created by providing only a name and type for -the intended State: - -{\tt state = ESMF\_StateCreate(name, stateintent=ESMF\_STATEINTENT\_IMPORT, rc=rc)} - -When finished with an {\tt ESMF\_State}, the {\tt ESMF\_StateDestroy} method -removes it. However, the objects inside the {\tt ESMF\_State} -created externally should be destroyed separately, -since objects can be added to more than one {\tt ESMF\_State}. diff --git a/src/Superstructure/State/doc/makefile b/src/Superstructure/State/doc/makefile index d0405746cc..58da8a06fa 100644 --- a/src/Superstructure/State/doc/makefile +++ b/src/Superstructure/State/doc/makefile @@ -31,7 +31,7 @@ TEXFILES_TO_MAKE += $(addsuffix _fapi.tex, $(basename $(notdir $(wildcard ../exa # These lists almost certainly will not be an exhastive list of # all of the dependent files, but even a partial listing will be helpfull. # -REFDOC_DEP_FILES = $(TEXFILES_TO_MAKE) +REFDOC_DEP_FILES = $(TEXFILES_TO_MAKE) State_desc.tex State_options.tex State_usage.tex State_rest.tex State_implnotes.tex State_obj.tex include $(ESMF_DIR)/makefile diff --git a/src/Superstructure/State/examples/ESMF_StateEx.F90 b/src/Superstructure/State/examples/ESMF_StateEx.F90 index 6ba1fc057d..5c4401a74c 100644 --- a/src/Superstructure/State/examples/ESMF_StateEx.F90 +++ b/src/Superstructure/State/examples/ESMF_StateEx.F90 @@ -22,19 +22,15 @@ program ESMF_StateEx use ESMF_TestMod implicit none -#define ESMF_ENABLESTATENEEDED - ! Local variables - integer :: rc - character(ESMF_MAXSTR) :: statename, bundlename, dataname - !type(ESMF_Field) :: field1 - type(ESMF_FieldBundle) :: bundle1, bundle2 - type(ESMF_State) :: state1, state2, state3 - integer :: finalrc - logical :: neededFlag - integer :: result = 0 ! all pass - character(ESMF_MAXSTR) :: testname - character(ESMF_MAXSTR) :: failMsg + integer :: rc + type(ESMF_State) :: state + type(ESMF_FieldBundle) :: bundle + type(ESMF_Field) :: field, field1, field2 + integer :: finalrc + integer :: result = 0 ! all pass + character(ESMF_MAXSTR) :: testname + character(ESMF_MAXSTR) :: failMsg finalrc = ESMF_SUCCESS @@ -47,191 +43,119 @@ program ESMF_StateEx !------------------------------------------------------------------------- !------------------------------------------------------------------------- - - call ESMF_Initialize(defaultlogfilename="StateEx.Log", & - logkindflag=ESMF_LOGKIND_MULTI, rc=rc) - -!------------------------------------------------------------------------- - print *, "State Example 1: Import State" - - ! This will probably be called from inside the Component Init code - statename = "Atmosphere" - state1 = ESMF_StateCreate(name=statename, & - stateintent=ESMF_STATEINTENT_IMPORT, rc=rc) - print *, "State Create returned, name = ", trim(statename) - - ! Data would be added here and the State reused inside the run - ! routine of a sequential application. - - print *, "State Example 1 finished" - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE + logkindflag=ESMF_LOGKIND_MULTI, rc=rc) !------------------------------------------------------------------------- !BOE -!\subsubsection{Add items to a State} -! -! Creation of an empty {\tt ESMF\_State}, and adding an {\tt ESMF\_FieldBundle} -! to it. Note that the {\tt ESMF\_FieldBundle} does not get destroyed when -! the {\tt ESMF\_State} is destroyed; the {\tt ESMF\_State} only contains -! a reference to the objects it contains. It also does not make a copy; -! the original objects can be updated and code accessing them by using -! the {\tt ESMF\_State} will see the updated version. +!\subsubsection{Create a State and add items} +! +! Creation of an empty {\tt ESMF\_State}. Then adding an {\tt ESMF\_FieldBundle} +! to it. Note that the {\tt ESMF\_FieldBundle} is empty. +! The {\tt ESMF\_State} only contains a reference to the objects it contains. +! It does not make a copy; the original objects can be updated and code +! accessing them by using the {\tt ESMF\_State} will see the updated version. !EOE - - - ! Example 2: - ! - ! Create, Add Data, Query, then Destroy a State. - - print *, "State Example 2: Export State" - !BOC - statename = "Ocean" - state2 = ESMF_StateCreate(name=statename, & - stateintent=ESMF_STATEINTENT_EXPORT, rc=rc) + state = ESMF_StateCreate(name="Ocean", & + stateintent=ESMF_STATEINTENT_EXPORT, rc=rc) !EOC - - print *, "State Create returned, name = ", trim(statename) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - bundlename = "Temperature" - bundle1 = ESMF_FieldBundleCreate(name=bundlename, rc=rc) - print *, "FieldBundle Create returned", rc + bundle = ESMF_FieldBundleCreate(name="Surface Fields", rc=rc) !EOC if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - call ESMF_StateAdd(state2, (/bundle1/), rc=rc) - print *, "StateAdd returned", rc + call ESMF_StateAdd(state, [bundle], rc=rc) !EOC if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE - ! Loop here, updating FieldBundle contents each time step - +!------------------------------------------------------------------------- +!BOE +!\subsubsection{Query a State for items and add more items} +! +! The objects contained in a State can be queried by name. +!EOE !BOC - call ESMF_StateDestroy(state2, rc=rc) + call ESMF_StateGet(state, itemName="Surface Fields", fieldbundle=bundle, & + rc=rc) !EOC - print *, "State Destroy returned", rc if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! More objects can be created and added to the State. Here an empty Field is +! created and added to the State. +!EOE !BOC - call ESMF_FieldBundleDestroy(bundle1, rc=rc) + field = ESMF_FieldEmptyCreate(name="MyField", rc=rc) +!EOC + if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOC + call ESMF_StateAdd(state, [field], rc=rc) !EOC - print *, "FieldBundle Destroy returned", rc - print *, "State Example 2 finished" if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE - -!------------------------------------------------------------------------- !BOE -!\subsubsection{Add placeholders to a State} -! -! If a component could potentially produce a large number of optional -! items, one strategy is to add the names only of those objects to the -! {\tt ESMF\_State}. Other components can call framework routines to -! set the {\tt ESMF\_NEEDED} flag to indicate they require that data. -! The original component can query this flag and then produce only the -! data that is required by another component. +! Multiple objects of the same type can be added to the State at the same time. !EOE - - print *, "State Example 3: Export State with Placeholder" - - ! The producing Component creates the menu of data items available. !BOC - statename = "Ocean" - state3 = ESMF_StateCreate(name=statename, & - stateintent=ESMF_STATEINTENT_EXPORT, rc=rc) + field1 = ESMF_FieldEmptyCreate(name="field1", rc=rc) !EOC - print *, "State Create returned", rc, " name = ", trim(statename) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - dataname = "Downward wind:needed" - call ESMF_AttributeSet (state3, dataname, .false., rc=rc) + field2 = ESMF_FieldEmptyCreate(name="field2", rc=rc) !EOC - print *, "AttributeSet returned", rc, " name = ", trim(dataname) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - dataname = "Humidity:needed" - call ESMF_AttributeSet (state3, dataname, .false., rc=rc) + call ESMF_StateAdd(state, [field1, field2], rc=rc) !EOC - print *, "AttributeSet returned", rc, " name = ", trim(dataname) - - ! See next example for how this is used. - - print *, "State Example 3 finished" if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !------------------------------------------------------------------------- -#if defined (ESMF_ENABLESTATENEEDED) !BOE -!\subsubsection{Mark an item {\tt NEEDED}} -! -! How to set the {\tt NEEDED} state of an item. +!\subsubsection{Removing items from a State} +! +! Objects contained in a State can be removed using the item name. !EOE - - print *, "State Example 4: Get/Set Needed flags in Export State" - - ! Given state3 from the previous example, the Coupler or Application - ! is given an opportunity to mark which data items are needed. - !BOC - dataname = "Downward wind:needed" - call ESMF_AttributeSet (state3, name=dataname, value=.true., rc=rc) + call ESMF_StateRemove(state, ["field1"], rc=rc) +!EOC + if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! Notice that objects removed from a State are {\em not} destroyed by the +! {\tt ESMF\_StateRemove()} call. They must be destroyed explicitly when no +! longer needed. +!BOC + call ESMF_FieldDestroy(field1, rc=rc) !EOC - print *, "AttributeSet returned", rc if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !------------------------------------------------------------------------- !BOE -!\subsubsection{Create a {\tt NEEDED} item} -! -! Query an item for the {\tt NEEDED} status, and creating an item on demand. -! Similar flags exist for "Ready", "Valid", and "Required for Restart", -! to mark each data item as ready, having been validated, or needed if the -! application is to be checkpointed and restarted. The flags are supported -! to help coordinate the data exchange between components. +!\subsubsection{Destroy a State} +! +! Once an {\tt ESMF\_State} is not longer needed, it should be destroyed. !EOE - - ! Query Needed flags, and add FieldBundle data - - print *, "State Example 5: Get/Set Needed flags in Export State, continued" - - ! Given state3 from the previous examples, the producing Component - ! can check the state to see what data items are required. - !BOC - dataname = "Downward wind:needed" - call ESMF_AttributeGet (state3, dataname, value=neededFlag, rc=rc) + call ESMF_StateDestroy(state, rc=rc) !EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE + if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! Notice that objects contained in a State are {\em not} destroyed by the +! {\tt ESMF\_StateDestroy()} call. They must be destroyed explicitly when no +! longer needed. !BOC - if (rc == ESMF_SUCCESS .and. neededFlag) then - bundlename = dataname - bundle2 = ESMF_FieldBundleCreate(name=bundlename, rc=rc) + call ESMF_FieldBundleDestroy(bundle, rc=rc) !EOC - print *, "FieldBundle Create returned", rc, "name = ", trim(bundlename) - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE + if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - call ESMF_StateAdd(state3, (/bundle2/), rc=rc) + call ESMF_FieldDestroy(field, rc=rc) !EOC - print *, "StateAdd returned", rc - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE + if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - else - print *, "Data not marked as needed", trim(dataname) - endif + call ESMF_FieldDestroy(field2, rc=rc) !EOC - print *, "State Example 5 finished" -#endif - call ESMF_StateDestroy(state3, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE - print *, "State Destroy returned", rc - -!------------------------------------------------------------------------- -! ! Similar flags exist for "Ready" and for "Valid" to mark each data -! ! item as ready or having been validated, to help synchronize data -! ! exchange between Components and Couplers. Also "Required for -! ! Restart". -!------------------------------------------------------------------------- +!=============================================================================== ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log ! file that the scripts grep for. call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE) diff --git a/src/Superstructure/StateReconcile/examples/ESMF_StateReconcileEx.F90 b/src/Superstructure/StateReconcile/examples/ESMF_StateReconcileEx.F90 index 0e30c9fad1..3d87ba28bf 100644 --- a/src/Superstructure/StateReconcile/examples/ESMF_StateReconcileEx.F90 +++ b/src/Superstructure/StateReconcile/examples/ESMF_StateReconcileEx.F90 @@ -9,85 +9,98 @@ ! Licensed under the University of Illinois-NCSA License. ! !============================================================================== -! + +!============================================================================== +!ESMF_MULTI_PROC_EXAMPLE String used by test script to count examples. +!============================================================================== module ESMF_StateReconcileEx_Mod -use ESMF + use ESMF -contains + contains !BOE -!\subsubsection{{\tt ESMF\_StateReconcile()} usage} -! -! The set services routines are used to tell ESMF which routine -! hold the user code for the initialize, run, and finalize -! blocks of user level Components. -! These are the separate subroutines called by the code below. +!\subsubsection{Reconcile a State} +! +! An {\tt ESMF\_State} object must be reconciled if it contains objects that +! were created and added to the State on a subset of the PETs from which the +! objects are now accessed and operated on. A typical case of this is when +! a State object is passed to a component that runs on a subset of PETs, and +! that component creates objects that are added to the State. After the +! component passes control back to the larger calling context (a parent +! component or the main program), the State object is not consistent across +! PETs. The {\tt ESMF\_StateReconcile()} method is used to reconcilce the State +! across all PETs. +! +! In order to demonstrate State reconciliation we need to set up at least +! one component that can be run on a subset of PETs. To this end an external +! routine is created that adds a few emtpy Fields into its {\tt exportState}. +! !EOE - !BOC -! Initialize routine which creates "field1" on PETs 0 and 1 -subroutine comp1_init(gcomp, istate, ostate, clock, rc) + subroutine init(gcomp, importState, exportState, clock, rc) + ! Abide to ESMF-prescribed Fortran interface type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: istate, ostate + type(ESMF_State) :: importState, exportState type(ESMF_Clock) :: clock integer, intent(out) :: rc - type(ESMF_Field) :: field1 - integer :: localrc - - print *, "i am comp1_init" - - field1 = ESMF_FieldEmptyCreate(name="Comp1 Field", rc=localrc) - - call ESMF_StateAdd(istate, (/field1/), rc=localrc) - - rc = localrc + type(ESMF_Field) :: field1, field2, field3 -end subroutine comp1_init + rc = ESMF_SUCCESS ! indicate success... unless error is found -! Initialize routine which creates "field2" on PETs 2 and 3 -subroutine comp2_init(gcomp, istate, ostate, clock, rc) - type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: istate, ostate - type(ESMF_Clock) :: clock - integer, intent(out) :: rc + field1 = ESMF_FieldEmptyCreate(name="Field1", rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) return - type(ESMF_Field) :: field2 - integer :: localrc + field2 = ESMF_FieldEmptyCreate(name="Field2", rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) return - print *, "i am comp2_init" + field3 = ESMF_FieldEmptyCreate(name="Field3", rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) return - field2 = ESMF_FieldEmptyCreate(name="Comp2 Field", rc=localrc) - - call ESMF_StateAdd(istate, (/field2/), rc=localrc) + call ESMF_StateAdd(exportState, [field1, field2, field3], rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) return - rc = localrc - -end subroutine comp2_init + end subroutine init +!EOC -subroutine comp_dummy(gcomp, rc) +!BOE +! The standard way to register ESMF component routines is in the +! {\tt SetServices} routine. +!EOE +!BOC + subroutine SetServices(gcomp, rc) + ! Abide to ESMF-prescribed Fortran interface type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc - rc = ESMF_SUCCESS -end subroutine comp_dummy -!EOC - -end module ESMF_StateReconcileEx_Mod - - + rc = ESMF_SUCCESS ! indicate success... unless error is found + ! register 'init' as component initialization method + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=init, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) return + end subroutine SetServices +!EOC +end module ESMF_StateReconcileEx_Mod - program ESMF_StateReconcileEx +!BOE +! A component can now be created in the main program that uses these routines. +!EOE +!BOC + program ESMF_StateReconcileEx +!EOC -!------------------------------------------------------------------------------ -!ESMF_EXAMPLE String used by test script to count examples. !============================================================================== -!BOC +! ! !PROGRAM: ESMF_StateReconcileEx - State reconciliation ! ! !DESCRIPTION: @@ -103,13 +116,14 @@ program ESMF_StateReconcileEx implicit none ! Local variables - integer :: rc, petCount - type(ESMF_State) :: state1 - type(ESMF_GridComp) :: comp1, comp2 - type(ESMF_VM) :: vm - character(len=ESMF_MAXSTR) :: comp1name, comp2name, statename - + integer :: rc, petCount + type(ESMF_State) :: state +!BOC +! ... other local variables ... + type(ESMF_GridComp) :: comp !EOC + type(ESMF_VM) :: vm + integer :: finalrc, result character(ESMF_MAXSTR) :: testname character(ESMF_MAXSTR) :: failMsg @@ -120,180 +134,104 @@ program ESMF_StateReconcileEx write(failMsg, *) "Example failure" write(testname, *) "Example ESMF_StateReconcileEx" - ! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------ finalrc = ESMF_SUCCESS - call ESMF_Initialize(vm=vm, defaultlogfilename="StateReconcileEx.Log", & - logkindflag=ESMF_LOGKIND_MULTI, rc=rc) - + logkindflag=ESMF_LOGKIND_MULTI, rc=rc) + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) + ! verify that this example can run on the given petCount call ESMF_VMGet(vm, petCount=petCount, rc=rc) - if (rc .ne. ESMF_SUCCESS) goto 20 + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) if (petCount<4) then print *, "This test must run on at least 4 PETs." + finalrc = ESMF_FAILURE goto 20 endif - -!------------------------------------------------------------------------- -!BOE -! -! A Component can be created which will run only on a subset of the -! current PET list. -!EOE - - print *, "State Reconcile Example 1: Component Creation" - -!BOC - ! Get the global VM for this job. - call ESMF_VMGetGlobal(vm=vm, rc=rc) - - comp1name = "Atmosphere" - comp1 = ESMF_GridCompCreate(name=comp1name, petList=(/ 0, 1 /), rc=rc) - print *, "GridComp Create returned, name = ", trim(comp1name) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - - comp2name = "Ocean" - comp2 = ESMF_GridCompCreate(name=comp2name, petList=(/ 2, 3 /), rc=rc) - print *, "GridComp Create returned, name = ", trim(comp2name) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC - - statename = "Ocn2Atm" - state1 = ESMF_StateCreate(name=statename, rc=rc) + comp = ESMF_GridCompCreate(name="MyComp", petList=[0,1], rc=rc) !EOC - print *, "State Create returned, name = ", trim(statename) + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - print *, "State Example 1 finished" - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE - -!------------------------------------------------------------------------- !BOE -! -! Here we register the subroutines which should be called for initialization. -! Then we call ESMF\_GridCompInitialize() on all PETs, but the code runs -! only on the PETs given in the petList when the Component was created. -! -! Because this example is so short, we call the entry point code -! directly instead of the normal procedure of nesting it in a separate -! SetServices() subroutine. +! Here {\tt comp} is created to execute on two PETs: 0 and 1. ! +! Next the Component {\tt SetServices} method is called to register the +! custom component method(s). !EOE - !BOC - ! This is where the VM for each component is initialized. - ! Normally you would call SetEntryPoint inside set services, - ! but to make this example very short, they are called inline below. - ! This is o.k. because the SetServices routine must execute from within - ! the parent component VM. - call ESMF_GridCompSetVM(comp1, comp_dummy, rc=rc) + call ESMF_GridCompSetServices(comp, userRoutine=SetServices, rc=rc) !EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - call ESMF_GridCompSetVM(comp2, comp_dummy, rc=rc) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC +!BOE +! Now a State is created that can be passed in when the registered Component +! method is called. +!EOE - call ESMF_GridCompSetServices(comp1, userRoutine=comp_dummy, rc=rc) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !BOC - - call ESMF_GridCompSetServices(comp2, userRoutine=comp_dummy, rc=rc) + state = ESMF_StateCreate(rc=rc) !EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - print *, "ready to set entry point 1" - call ESMF_GridCompSetEntryPoint(comp1, ESMF_METHOD_INITIALIZE, & - comp1_init, rc=rc) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! The {\tt state} object is used as the Component's {\tt exportState}. +!EOE !BOC - - - print *, "ready to set entry point 2" - call ESMF_GridCompSetEntryPoint(comp2, ESMF_METHOD_INITIALIZE, & - comp2_init, rc=rc) + call ESMF_GridCompInitialize(comp, exportState=state, rc=rc) !EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - - print *, "ready to call init for comp 1" - call ESMF_GridCompInitialize(comp1, exportState=state1, rc=rc) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! Once control of execution has returned from the pevious +! {\tt ESMF\_GridCompInitialize()} call, the {\tt state} object is in an +! inconsistent state across the PETs of the current (main program) context. +! This is because Fields were added on PETs 0 and 1, but not on the remaining +! PETs (2 and 3). This situation can easliy be observed by writing the current +! {\tt state} to the ESMF log. +!EOE !BOC - - print *, "ready to call init for comp 2" - call ESMF_GridCompInitialize(comp2, exportState=state1, rc=rc) + call ESMF_StateLog(state, prefix="Before Reconcile:", rc=rc) !EOC + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - print *, "State Example 2 finished" - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE - -!------------------------------------------------------------------------- !BOE -! -! Now we have {\tt state1} containing {\tt field1} on PETs 0 and 1, and -! {\tt state1} containing {\tt field2} on PETs 2 and 3. For the code -! to have a rational view of the data, we call {\tt ESMF\_StateReconcile} -! which determines which objects are missing from any PET, and communicates -! information about the object. After the call to reconcile, all -! {\tt ESMF\_State} objects now have a consistent view of the data. +! To reconcile {\tt state} across all of the PETs, use the +! {\tt ESMF\_StateReconcile()} method. !EOE - !BOC - print *, "State before calling StateReconcile()" - call ESMF_StatePrint(state1, rc=rc) + call ESMF_StateReconcile(state, rc=rc) !EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE -!BOC - + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - call ESMF_StateReconcile(state1, vm=vm, rc=rc) -!EOC - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE +!BOE +! The output of {\tt state} to the ESMF log shows that the object is now +! consistent across all PETs. I.e. {\tt state} contains identical items on +! all of the PETs. +!EOE !BOC - - - print *, "State after calling StateReconcile()" - call ESMF_StatePrint(state1, rc=rc) + call ESMF_StateLog(state, prefix="After Reconcile:", rc=rc) !EOC - - print *, "State Example 3 finished" - if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) !------------------------------------------------------------------------- - call ESMF_StateDestroy (state1, rc=rc) - if (rc /= ESMF_SUCCESS) finalrc = ESMF_FAILURE - - call ESMF_GridCompDestroy (comp2, rc=rc) - if (rc /= ESMF_SUCCESS) finalrc = ESMF_FAILURE + call ESMF_StateDestroy (state, rc=rc) + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) - call ESMF_GridCompDestroy (comp1, rc=rc) - if (rc /= ESMF_SUCCESS) finalrc = ESMF_FAILURE + call ESMF_GridCompDestroy (comp, rc=rc) + if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) 20 continue ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log ! file that the scripts grep for. call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE) - call ESMF_Finalize(rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE diff --git a/src/Superstructure/StateReconcile/examples/makefile b/src/Superstructure/StateReconcile/examples/makefile index b806f1aec1..b83da87cee 100644 --- a/src/Superstructure/StateReconcile/examples/makefile +++ b/src/Superstructure/StateReconcile/examples/makefile @@ -11,7 +11,7 @@ EXAMPLES_BUILD = $(ESMF_EXDIR)/ESMF_StateReconcileEx EXAMPLES_RUN = run_ESMF_StateReconcileEx -EXAMPLES_RUN_UNI = run_ESMF_StateReconcileEx_uni +EXAMPLES_RUN_UNI = include $(ESMF_DIR)/makefile @@ -27,6 +27,3 @@ DIRS = # run_ESMF_StateReconcileEx: $(MAKE) EXNAME=StateReconcile NP=4 exfrun - -run_ESMF_StateReconcileEx_uni: - $(MAKE) EXNAME=StateReconcile NP=1 exfrun diff --git a/src/Superstructure/StateReconcile/src/ESMF_StateReconcile.F90 b/src/Superstructure/StateReconcile/src/ESMF_StateReconcile.F90 index 0db8c80fb0..9158c7719b 100644 --- a/src/Superstructure/StateReconcile/src/ESMF_StateReconcile.F90 +++ b/src/Superstructure/StateReconcile/src/ESMF_StateReconcile.F90 @@ -152,14 +152,26 @@ subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc) ! !DESCRIPTION: ! ! Must be called for any {\tt ESMF\_State} which contains ESMF objects -! that have not been created on all the {\tt PET}s of the current VM. -! For example, if a coupler component is operating on data -! which was created by another component that ran on only a subset -! of the coupler {\tt PET}s, the coupler must make this call first +! 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 {\tt PET}s will have +! 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: @@ -193,12 +205,11 @@ subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc) localrc = ESMF_RC_NOT_IMPL localCheckFlag = .false. ! default - if (present(checkFlag)) localCheckFlag = checkFlag - #if 0 - ! Activate this when working on StateReoncile, so all tests validate! - localCheckFlag = .true. ! force checking + ! 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 @@ -229,7 +240,8 @@ subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc) 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), ESMF_LOGMSG_DEBUG, rc=localrc) + 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 @@ -274,34 +286,45 @@ subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc) #endif if (isNoop) then - ! successful early return because of NOOP condition - if (present(rc)) rc = ESMF_SUCCESS - return ! NOOP -> EARLY RETURN - endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! Go on to reconcile the State ! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! Quick exit for Noop, but still must reconcile State level Info ! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (profile) then - call ESMF_TraceRegionEnter("ESMF_StateReconcile_driver", rc=localrc) - if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & - rcToReturn=rc)) return - endif + !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!!! - call ESMF_StateReconcile_driver(state, vm=localvm, rc=localrc) - if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & - rcToReturn=rc)) return + else - if (profile) then - call ESMF_TraceRegionExit("ESMF_StateReconcile_driver", rc=localrc) + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! 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 - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! Conditinally check the reconciled State for consistency across PETs ! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! Conditionally check the reconciled State for consistency across PETs ! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (localCheckFlag) then if (profile) then @@ -318,7 +341,9 @@ subroutine ESMF_StateReconcile(state, keywordEnforcer, vm, checkflag, rc) 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) + 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 @@ -702,8 +727,6 @@ subroutine ESMF_StateReconcile_driver(state, vm, rc) ! {\tt ESMF\_VM} will exchange information about objects which might ! only be known to one or more PETs, and ensure all PETs in this VM ! have a consistent view of the object list in this {\tt ESMF\_State}. -! \item[{[attreconflag]}] -! Flag to tell if Attribute reconciliation is to be done as well as data reconciliation ! \item[{[rc]}] ! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors. ! \end{description} @@ -877,7 +900,8 @@ subroutine ESMF_StateReconcile_driver(state, vm, rc) 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_after_vmid="//ESMF_InfoDump(idesc%info), ESMF_LOGMSG_DEBUG, rc=localrc) + call ESMF_LogWrite("state_json_after_vmid="// & + 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 @@ -925,7 +949,8 @@ subroutine ESMF_StateReconcile_driver(state, vm, rc) 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_after_set_field_meta="//ESMF_InfoDump(idesc%info), ESMF_LOGMSG_DEBUG, rc=localrc) + call ESMF_LogWrite("state_json_after_set_field_meta="// & + 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 @@ -1385,6 +1410,8 @@ end subroutine ESMF_ReconcileSingleCompCase !BOPI ! !IROUTINE: ESMF_ReconcileSerializeAll ! +!TODO: This routine looks almost redundant to ESMF_StateSerialize()!!!!!!!!!! +! ! !INTERFACE: subroutine ESMF_ReconcileSerializeAll(state, itemList, itemCount, & attreconflag, siwrap, buffer, rc) @@ -1598,6 +1625,24 @@ subroutine ESMF_ReconcileSerializeAll(state, itemList, itemCount, & sizeBuffer = sizeBuffer + itemSize enddo + ! Size of the State's Base itself + call ESMF_BaseSerialize(state%statep%base, fakeBuffer, itemSize, & + attreconflag=attreconflag, inquireflag=inqflag, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return +#ifdef RECONCILE_LOG_on + block + character(160) :: msgStr + write(msgStr,*) "Serialize top State Base itself, size=", itemSize + call ESMF_LogWrite(msgStr, ESMF_LOGMSG_DEBUG, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + end block +#endif + + ! Update buffer size by itemSize + sizeBuffer = sizeBuffer + itemSize + ! Get rid of fakeBuffer deallocate(fakeBuffer) @@ -1685,6 +1730,12 @@ subroutine ESMF_ReconcileSerializeAll(state, itemList, itemCount, & end select enddo + ! Serialize of the State's Base itself + call ESMF_BaseSerialize(state%statep%base, buffer, posBuffer, & + attreconflag=attreconflag, inquireflag=inqflag, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + ! Return success rc = ESMF_SUCCESS @@ -1699,6 +1750,8 @@ end subroutine ESMF_ReconcileSerializeAll ! !INTERFACE: subroutine ESMF_ReconcileDeserializeAll(state, vm, attreconflag, buffer, rc) ! +!TODO: This routine looks almost redundant to ESMF_StateDeserialize()!!!!!!!!!! +! ! !ARGUMENTS: type (ESMF_State), intent(inout) :: state type (ESMF_VM), intent(in) :: vm @@ -1726,7 +1779,6 @@ subroutine ESMF_ReconcileDeserializeAll(state, vm, attreconflag, buffer, rc) !EOPI integer :: localrc - integer :: memstat type(ESMF_FieldBundle) :: fieldbundle type(ESMF_Field) :: field @@ -1737,7 +1789,6 @@ subroutine ESMF_ReconcileDeserializeAll(state, vm, attreconflag, buffer, rc) integer :: stateitem_type character(ESMF_MAXSTR) :: errstring character(ESMF_MAXSTR) :: name - integer :: localPet integer :: item, numNewItems integer :: itemType @@ -1750,11 +1801,6 @@ subroutine ESMF_ReconcileDeserializeAll(state, vm, attreconflag, buffer, rc) rcToReturn=rc)) return #endif - ! VM information for debug output - call ESMF_VMGet (vm, localPet=localPet, rc=localrc) - if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & - rcToReturn=rc)) return - ! Set start position of buffer posBuffer = 0 @@ -1906,6 +1952,48 @@ subroutine ESMF_ReconcileDeserializeAll(state, vm, attreconflag, buffer, rc) enddo + ! Deserialize the received State's Base itself and add to local top State + block + type(ESMF_Base) :: base_temp + type(ESMF_Info) :: base_info, base_temp_info + +#ifdef RECONCILE_LOG_on + block + character(160) :: msgStr + write(msgStr,*) "deserializing top State Base itself, pos =", posBuffer + call ESMF_LogWrite(msgStr, ESMF_LOGMSG_DEBUG, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + end block +#endif + + base_temp = ESMF_BaseDeserializeWoGarbage(buffer, & + offset=posBuffer, attreconflag=attreconflag, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + + call ESMF_BaseSetInitCreated(base_temp, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + + call ESMF_InfoGetFromBase(base_temp, base_temp_info, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + + call ESMF_InfoGetFromBase(state%statep%base, base_info, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + + call ESMF_InfoUpdate(base_info, base_temp_info, recursive=.true., & + rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + + call ESMF_BaseDestroyWoGarbage(base_temp, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + end block + ! Return success rc = ESMF_SUCCESS @@ -2174,6 +2262,30 @@ subroutine ESMF_ReconcileBruteForce(state, vm, attreconflag, siwrap, & ! ------------------------------------------------------------------------- if (meminfo) call ESMF_VMLogMemInfo ("after (8) Deserialize received objects and create proxies") + ! ------------------------------------------------------------------------- + ! (9) Attributes on the State itself + ! ------------------------------------------------------------------------- + if (profile) then + call ESMF_TraceRegionEnter("(9) Attributes on the State itself", rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + endif + ! ------------------------------------------------------------------------- + if (attreconflag == ESMF_ATTRECONCILE_ON) then + call ESMF_ReconcileExchgAttributes (state, vm, rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, & + rcToReturn=rc)) return + end if + ! ------------------------------------------------------------------------- + if (profile) then + call ESMF_TraceRegionExit("(9) Attributes on the State itself", rc=localrc) + if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, ESMF_CONTEXT, & + rcToReturn=rc)) return + endif + ! ------------------------------------------------------------------------- + if (meminfo) call ESMF_VMLogMemInfo ("after (9) Attributes on the State itself") + ! Clean up if (associated (buffer_recv)) then diff --git a/src/Superstructure/StateReconcile/tests/ESMF_StateReconcileUTest.F90 b/src/Superstructure/StateReconcile/tests/ESMF_StateReconcileUTest.F90 index 44fc076f81..d9e2db52cd 100644 --- a/src/Superstructure/StateReconcile/tests/ESMF_StateReconcileUTest.F90 +++ b/src/Superstructure/StateReconcile/tests/ESMF_StateReconcileUTest.F90 @@ -1508,7 +1508,10 @@ program ESMF_StateReconcileUTest !NEX_UTest_Multi_Proc_Only write(failMsg, *) "Did not return ESMF_SUCCESS" write(name, *) "Reconciling state with Base attribute test" - call ESMF_StateReconcile (state_attr, checkflag=.true., rc=rc) + ! use explicit checkflag=.false, because state Info values will not be + ! consistent across PETs... and in case we force default .true. for + ! development, make sure this is explicitly set to .false. here + call ESMF_StateReconcile (state_attr, checkflag=.false., rc=rc) call ESMF_Test((rc == ESMF_SUCCESS), name, failMsg, result, ESMF_SRCLINE) !-------------------------------------------------------------------------