Skip to content

Commit

Permalink
Merge pull request #241 from esmf-org/feature/provider_metadata
Browse files Browse the repository at this point in the history
Implements the `FieldTransferPolicy="transferAllWithNamespace"` option.
  • Loading branch information
theurich authored Dec 10, 2024
2 parents 338cd06 + 323578c commit 523ca69
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 32 deletions.
68 changes: 67 additions & 1 deletion src/Infrastructure/Base/interface/ESMF_Info.F90
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ module ESMF_InfoMod
public ESMF_InfoSetDirty
public ESMF_InfoIsSet
public ESMF_InfoIsPresent
public ESMF_InfoLog
public ESMF_InfoPrint
public ESMF_InfoDump
public ESMF_InfoUpdate
Expand Down Expand Up @@ -2495,6 +2496,71 @@ end function ESMF_InfoIsSet

!------------------------------------------------------------------------------

#undef ESMF_METHOD
#define ESMF_METHOD "ESMF_InfoLog()"
!BOP
! !IROUTINE: ESMF_InfoLog - Log contents of an Info object
!
! !INTERFACE:
subroutine ESMF_InfoLog(info, keywordEnforcer, prefix, logMsgFlag, rc)
! !ARGUMENTS:
type(ESMF_Info), intent(in) :: info
type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
character(len=*), intent(in), optional :: prefix
type(ESMF_LogMsg_Flag), intent(in), optional :: logMsgFlag
integer, intent(out), optional :: rc
!
! !DESCRIPTION:
! Write information about {\tt info} object to the ESMF default Log.
!
! The arguments are:
! \begin{description}
! \item[info]
! {\tt ESMF\_Info} 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[{[rc]}]
! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOP
!------------------------------------------------------------------------------
integer :: localrc
character(:), allocatable :: output, local_preString

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

!TODO: This should really be implemented on the C++ side where we could
!TODO: correctly deal with line breaks and prepend the prefix string on
!TODO: each line, much like for ESMF_HConfigLog().
!TODO: For now implemented quickly on the Fortran side to make available.

if (present(prefix)) then
local_preString = prefix
else
local_preString = ""
endif

output = ESMF_InfoDump(info, indent=2, rc=localrc)
if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return

call ESMF_LogWrite(local_preString//output, logMsgFlag, 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_InfoLog

!------------------------------------------------------------------------------

#undef ESMF_METHOD
#define ESMF_METHOD "ESMF_InfoPrint()"
!BOP
Expand Down Expand Up @@ -3929,4 +3995,4 @@ subroutine ESMF_InfoWriteJSON(info, filename, keywordEnforcer, rc)
if (present(rc)) rc = ESMF_SUCCESS
end subroutine ESMF_InfoWriteJSON

end module ESMF_InfoMod !=====================================================
end module ESMF_InfoMod !=====================================================
16 changes: 16 additions & 0 deletions src/Superstructure/State/src/ESMF_StateAPI.cppF90
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ module ESMF_StateAPIMod
use ESMF_IOUtilMod
use ESMF_UtilMod
use ESMF_UtilStringMod
use ESMF_InfoMod

implicit none

Expand Down Expand Up @@ -1852,6 +1853,21 @@ type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return

#if 0
!TODO: need a way to indicate from calling side that info should be logged
block
type(ESMF_Info) :: info
call ESMF_InfoGetFromBase(stateR%statep%base, info=info, rc=localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
call ESMF_InfoLog(info, prefix=prefix, rc=localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
end block
#endif

if (itemCount > 0) then
allocate(itemNameList(itemCount))
allocate(itemTypeList(itemCount))
Expand Down
10 changes: 6 additions & 4 deletions src/addon/NUOPC/doc/NUOPC_FieldMirror.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

\label{FieldMirror}

In some cases it is helpful for a NUOPC component to automatically mirror or match the set of fields advertised by another component. One purpose of this is to automatically resolve the import data dependencies of a component, by setting up a component that exactly provides all of the needed fields. This is currently used in the NUOPC Component Explorer: when driving a child NUOPC Model with required import fields, the Component Explorer uses the field mirroring capability to advertise in the driver-self export State the exact set of fields advertised in the child NUOPC Model. This ensures that the entire Initialize Phase Sequence will complete (because all dependencies are satisfied) and all phases can be exercised by the Component Explorer.
In some cases it is useful for a NUOPC component to match the set of fields advertised by another component, e.g. in order to connect to every field. NUOPC provides the concept of {\em field mirroring} that allows automatic matching by "mirroring" the fields of another component in their import- or exportState into their own States. One purpose of this is to automatically resolve the import data dependencies of a component, by setting up a component that exactly provides all of the needed fields.

The field mirror capability is also useful with NUOPC Mediators since these components often exactly reflect, in separate States, the sets of fields of each of the connected components. The field mirroring capability, therefore, can be used to ensure that a Mediator is always capable of accepting fields from connected components, and removes the need to specify field lists in multiple places, i.e., both within a set of Model components connected to a Mediator and within the Mediator itself.

To access the field mirror capability, a component sets the {\tt FieldTransferPolicy} attribute during {\tt label\_Advertise}. The attribute is set on the Import- and/or Export- States to trigger field mirroring for each state, respectively. The default value of "TransferNone" indicates that no fields should be mirrored. The other option, "TransferAll", indicates that fields should be mirrored in the State of a connected component.
To access the field mirror capability, a component sets the {\tt FieldTransferPolicy} attribute during {\tt label\_Advertise}. The attribute is set on the Import- and/or Export- States to trigger field mirroring for each state, respectively. The default value of "transferNone" indicates that no fields should be mirrored. The other available options are "transferAll" and "transferAllWithNamespace". Both options mirror transfer all of the fields from all of the connected States into the State that carries the attribute. The "transferAll" option results in flat structure with all of the mirrored fields added directly to the acceptor State. A flat structure like this is typically the preferred situation for an ExportState, where the same fields might be connected to multiple consumer components. The "transferAllWithNamespace" option also mirrors all of the field from the connected State, but creates separate Namespaces for each connection, placing the associated mirrored fields into the respective nested State. A nested structure like this useful for an ImportState where connections are being made with multiple producer components. In this case the consumer component can query the "Namespace" attribute of each nested State to infer the component label of the associated producer components.

Each Connector consider the {\tt FieldTransferPolicy} Attribute on both its import and export States. If {\em both} States have a {\tt FieldTransferPolicy} of "TransferAll", then fields are transferred between the States in both directions (i.e., import to export and export to import). The transfer process works as follows: First, the {\tt TransferOfferGoemObject} attribute is reversed between the providing side and accepting side. Intuitively, if a field from the providing component is to be mirrored and it can provide its own geometric object, then the mirrored field on the accepting side should be set to accept a geometric object. Then, the field to be mirrored is advertised in the accepting State using a call to {\tt NUOPC\_Advertise()} such that the mirrored field shares the same Standard Name.
Each Connector considers the {\tt FieldTransferPolicy} attribute on both its import and export States. Each State that has the {\tt FieldTransferPolicy} attribute set to "transferAll" or "transferAllWithNamespace", will have then fields of the respecive other State mirror transferred. If {\em both} States have the {\tt FieldTransferPolicy} attribute set to trigger the mirror transfer, then fields are mirrored in both directions (i.e. import to export and export to import).

Components have the opportunity, using specialiozation point {\tt label\_ModifyAdvertised}, to modify any of the mirrored Fields in their Import/ExportState. After this the initialization sequence continues as usual. Since fields to be mirrored have been advertised with matching Standard Names, the field pairing algorithm will now match them in the usual way thereby establishing a connection between the original and mirrored fields.
The transfer process works as follows: First, the {\tt TransferOfferGoemObject} attribute is reversed between the providing side and accepting side. This is because if a field from the providing component is to be mirrored and it {\em can} provide its own geometric object, then the mirrored field on the accepting side should be set to {\em accept} a geometric object. The mirrored field is advertised in the accepting State using a call to {\tt NUOPC\_Advertise()} such that the mirrored field shares the same StandardName.

Components have the opportunity to modify or remove any of the mirrored Fields in their Import/ExportState by using the {\tt label\_ModifyAdvertised} specialization point. After this point the initialization sequence continues as usual. Since the mirrored fields have been advertised with matching StandardName attribute, the field pairing algorithm now matches them in the usual manner, thereby establishing a connection between the original and the mirrored fields.
2 changes: 1 addition & 1 deletion src/addon/NUOPC/doc/NUOPC_Field_metadata.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using the JSON Pointer "/NUOPC/Instance/" prefix followed by the "Attribute name"
as per the table below. E.g. "StandardName" is accessed using {\tt key="/NUOPC/Instance/StandardName"}.

\begin{longtable}{|p{.22\textwidth}|p{.6\textwidth}|p{.2\textwidth}|}
\begin{longtable}{|p{.3\textwidth}|p{.4\textwidth}|p{.3\textwidth}|}
\hline\hline
{\bf Attribute name} & {\bf Definition} & {\bf Controlled vocabulary}\\
\hline\hline
Expand Down
4 changes: 2 additions & 2 deletions src/addon/NUOPC/doc/NUOPC_State_metadata.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
using the JSON Pointer "/NUOPC/Instance/" prefix followed by the "Attribute name"
as per the table below. E.g. "Namespace" is accessed using {\tt key="/NUOPC/Instance/Namespace"}.

\begin{longtable}{|p{.22\textwidth}|p{.6\textwidth}|p{.2\textwidth}|}
\begin{longtable}{|p{.3\textwidth}|p{.4\textwidth}|p{.3\textwidth}|}
\hline\hline
{\bf Attribute name} & {\bf Definition} & {\bf Controlled vocabulary}\\
\hline\hline
{\tt Namespace} & String value holding the namespace of all the objects contained in the State.& {\em no restriction}\\ \hline
{\tt FieldTransferPolicy} & String value indicating to Connector to transfer/mirror Fields. & transferNone,\newline transferAll\\ \hline
{\tt FieldTransferPolicy} & String value indicating to Connector to transfer/mirror Fields. & transferNone,\newline transferAll,\newline transferAllWithNamespace\\ \hline
\hline
\end{longtable}
50 changes: 32 additions & 18 deletions src/addon/NUOPC/src/NUOPC_Base.F90
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,13 @@ module NUOPC_Base
! !IROUTINE: NUOPC_AddNamespace - Add a nested state with Namespace to a State
! !INTERFACE:
subroutine NUOPC_AddNamespace(state, Namespace, nestedStateName, &
nestedState, rc)
nestedState, vm, rc)
! !ARGUMENTS:
type(ESMF_State), intent(inout) :: state
character(len=*), intent(in) :: Namespace
character(len=*), intent(in), optional :: nestedStateName
type(ESMF_State), intent(out), optional :: nestedState
type(ESMF_VM), intent(in), optional :: vm
integer, intent(out), optional :: rc
! !DESCRIPTION:
! Add a Namespace to {\tt state}. Namespaces are implemented via nested
Expand All @@ -178,6 +179,10 @@ subroutine NUOPC_AddNamespace(state, Namespace, nestedStateName, &
! Name of the nested state. Defaults to {\tt Namespace}.
! \item[{[nestedState]}]
! Optional return of the newly created nested state.
! \item[{[vm]}]
! If present, the nested State created to hold the namespace is created on
! the specified {\tt ESMF\_VM} object. The default is to create the nested
! State on the VM of the current component context.
! \item[{[rc]}]
! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
Expand All @@ -189,9 +194,10 @@ subroutine NUOPC_AddNamespace(state, Namespace, nestedStateName, &
type(ESMF_State) :: nestedS
character(len=80) :: nestedSName
type(ESMF_StateIntent_Flag) :: stateIntent

logical :: stateIsCreated

if (present(rc)) rc = ESMF_SUCCESS

call ESMF_StateGet(state, stateIntent=stateIntent, rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out
Expand All @@ -201,31 +207,39 @@ subroutine NUOPC_AddNamespace(state, Namespace, nestedStateName, &
else
nestedSName = trim(Namespace)
endif

nestedS = ESMF_StateCreate(name=nestedSName, stateIntent=stateIntent, &
rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

call NUOPC_InitAttributes(nestedS, rc=localrc)
vm=vm, rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

call NUOPC_SetAttribute(nestedS, name="Namespace", &
value=trim(Namespace), rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

call ESMF_StateAdd(state, (/nestedS/), rc=localrc)
stateIsCreated = ESMF_StateIsCreated(nestedS, rc=rc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

if (stateIsCreated) then

call NUOPC_InitAttributes(nestedS, rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

call NUOPC_SetAttribute(nestedS, name="Namespace", &
value=trim(Namespace), rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

call ESMF_StateAdd(state, (/nestedS/), rc=localrc)
if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
line=__LINE__, file=FILENAME, rcToReturn=rc)) return ! bail out

endif

if (present(nestedState)) &
nestedState = nestedS

end subroutine
!---------------------------------------------------------------------
!-----------------------------------------------------------------------------

!-----------------------------------------------------------------------------
!BOP
! !IROUTINE: NUOPC_AddNestedState - Add a nested state to a state with NUOPC attributes
Expand Down
Loading

0 comments on commit 523ca69

Please sign in to comment.