Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feature/provider_m…
Browse files Browse the repository at this point in the history
…etadata
  • Loading branch information
uturuncoglu committed Dec 5, 2024
2 parents 45bbc28 + 3f8a08e commit 5ba55b0
Show file tree
Hide file tree
Showing 9 changed files with 384 additions and 406 deletions.
2 changes: 1 addition & 1 deletion src/Superstructure/State/doc/State_refdoc.ctex
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
48 changes: 35 additions & 13 deletions src/Superstructure/State/doc/State_rest.tex
Original file line number Diff line number Diff line change
@@ -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}


Expand Down
20 changes: 1 addition & 19 deletions src/Superstructure/State/doc/State_usage.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}.
2 changes: 1 addition & 1 deletion src/Superstructure/State/doc/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
212 changes: 68 additions & 144 deletions src/Superstructure/State/examples/ESMF_StateEx.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down
Loading

0 comments on commit 5ba55b0

Please sign in to comment.