Skip to content

Commit 366ef99

Browse files
committed
Merge branch 'feature/hconfig-extras' into develop
2 parents 525822c + eb8bb37 commit 366ef99

28 files changed

+1911
-292
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
% $Id$
2+
3+
% Earth System Modeling Framework
4+
% Copyright (c) 2002-2024, University Corporation for Atmospheric Research,
5+
% Massachusetts Institute of Technology, Geophysical Fluid Dynamics
6+
% Laboratory, University of Michigan, National Centers for Environmental
7+
% Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
8+
% NASA Goddard Space Flight Center.
9+
% Licensed under the University of Illinois-NCSA License.
10+
11+
\subsubsection{ESMF\_HCONFIGMATCH}
12+
\label{const:hconfigmatch}
13+
14+
{\sf DESCRIPTION:\\}
15+
Indicates the level to which two HConfig variables match.
16+
17+
The type of this flag is:
18+
19+
{\tt type(ESMF\_HConfigMatch\_Flag)}
20+
21+
The valid values in ascending order are:
22+
\begin{description}
23+
\item [ESMF\_HCONFIGMATCH\_INVALID:] Indicates a non-valid matching level. One
24+
or both HConfig objects are invalid.
25+
\item [ESMF\_HCONFIGMATCH\_NONE:] The lowest valid level of HConfig matching.
26+
This indicates that the HConfig objects are valid, but their YAML
27+
representation does not match.
28+
\item [ESMF\_HCONFIGMATCH\_EXACT:] There is an exact match between the YAML
29+
representation of both HConfig objects. They may or may not be aliases to
30+
the same object in memory.
31+
\item [ESMF\_HCONFIGMATCH\_ALIAS:] Both HConfig variables are aliases to the
32+
exact same HConfig object in memory.
33+
\end{description}

src/Infrastructure/HConfig/doc/HConfig_refdoc.ctex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@
6666
\input{../Infrastructure/HConfig/doc/HConfig_desc}
6767
#endif
6868

69+
\subsection{Constants}
70+
#ifdef STANDALONE
71+
\input{HConfig_options}
72+
#elif defined(CONSTITUENT)
73+
\input{../Infrastructure/HConfig/doc/HConfig_options}
74+
#endif
75+
6976
\subsection{Use and Examples}
7077
#ifdef STANDALONE
7178
\input{HConfig_usage}

src/Infrastructure/HConfig/doc/makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ TEXFILES_TO_MAKE += $(addsuffix _fapi.tex, $(basename $(notdir $(wildcard ../exa
3030
# These lists almost certainly will not be an exhaustive list of
3131
# all of the dependent files, but even a partial listing will be helpful.
3232
#
33-
REFDOC_DEP_FILES = $(TEXFILES_TO_MAKE) HConfig_desc.tex HConfig_usage.tex HConfig_rest.tex HConfig_implnotes.tex
33+
REFDOC_DEP_FILES = $(TEXFILES_TO_MAKE) HConfig_desc.tex HConfig_options.tex HConfig_usage.tex HConfig_rest.tex HConfig_implnotes.tex
3434

3535

3636
include $(ESMF_DIR)/makefile

src/Infrastructure/HConfig/examples/ESMF_HConfigEx.F90

Lines changed: 235 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ program ESMF_HConfigEx
2727
type(ESMF_HConfig) :: hconfig, hconfigTemp, hconfigTemp2
2828
type(ESMF_HConfigIter) :: hconfigIter, hconfigIterBegin, hconfigIterEnd
2929
type(ESMF_Config) :: config
30+
type(ESMF_HConfigMatch_Flag) :: match
3031
logical :: asOkay, valueL, isDefined
3132
logical :: isNull, isScalar, isSequence, isMap
33+
logical :: isAlias, isNotAlias, isExact, isMatch
34+
logical :: isNone
3235
logical, allocatable :: valueLSeq(:)
3336
character(len=:), allocatable :: string, stringKey, tag
3437
character(len=:), allocatable :: valueSSeq(:)
@@ -966,6 +969,8 @@ program ESMF_HConfigEx
966969
call ESMF_HConfigFileLoad(hconfig, filename="exampleWithTags.yaml", rc=rc)
967970
!EOC
968971
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
972+
call ESMF_HConfigLog(hconfig, prefix="WithTagsStart: ", rc=rc)
973+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
969974
!BOE
970975
! The file contains the following YAML:
971976
! \begin{verbatim}
@@ -981,6 +986,8 @@ program ESMF_HConfigEx
981986
! value_ten: Null
982987
! value_eleven:
983988
! value_twelve: !myStuff xyz
989+
! value_thirteen: NO
990+
! value_fourteen: "NO"
984991
! \end{verbatim}
985992
!
986993
! The value associated with {\em map key} "value\_ten" is explicitly set to
@@ -1120,9 +1127,72 @@ program ESMF_HConfigEx
11201127
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
11211128
!BOE
11221129
! The Core schema tag resolves to {\tt{\bf tag:yaml.org,2002:bool}}. The
1123-
! supported boolean values are {\tt true}, {\tt True}, {\tt TRUE},
1124-
! {\tt false}, {\tt False}, and {\tt FALSE}.
1130+
! supported boolean values are:
1131+
! \begin{verbatim}
1132+
! true | false
1133+
! True | False
1134+
! TRUE | FALSE
1135+
! \end{verbatim}
11251136
!
1137+
! \paragraph{Additional Boolean values and the "Norway problem"}
1138+
! The YAMLCPP backend used by {\tt ESMF\_HConfig} interprets all of the values
1139+
! recognized as such under \htmladdnormallink{YAML 1.1}
1140+
! {https://yaml.org/type/bool.html} as boolean. This extends the above list with
1141+
! additional options:
1142+
! \begin{verbatim}
1143+
! yes | no
1144+
! Yes | No
1145+
! YES | NO
1146+
! y | n
1147+
! Y | N
1148+
! on | off
1149+
! On | Off
1150+
! ON | OFF
1151+
! \end{verbatim}
1152+
! The interpretation of value {\tt NO} as a boolean, instead of a literal
1153+
! string, can be problematic. It leads to the so-called {\em "Norway problem"},
1154+
! because the same string is often used as country code instead. The underlying
1155+
! problem is the misinterpretation of values by YAML.
1156+
!EOE
1157+
tag = ESMF_HConfigGetTag(hconfig, keyString="value_thirteen", rc=rc)
1158+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1159+
write (msgString, '("value_thirteen HConfig tag: ", A30)') tag
1160+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1161+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1162+
!BOE
1163+
! Strictly speaking this is not a YAML problem, but instead a schema specific
1164+
! issue. Fortunately there are two simple solutions to ensure the correct and
1165+
! intended interpretation of values by {\tt ESMF\_HConfig}:
1166+
!
1167+
! \begin{enumerate}
1168+
! \item Explicit quotation of strings: See for instance the {\em map value}
1169+
! for {\tt value\_fourteen} in the current example. Using explicit quotes for
1170+
! {\tt "NO"}, the entry is safely interpreted as a literal string, and if
1171+
! queried for its tag, will return {\tt tag:yaml.org,2002:str}.
1172+
!
1173+
! \item Explicit standard tags: This option allows explicit specificaiton of any
1174+
! tag, e.g. the standard short-hand tag {\tt !str} for literal strings. This
1175+
! approach is discussed in more detal below.
1176+
! \end{enumerate}
1177+
!EOE
1178+
tag = ESMF_HConfigGetTag(hconfig, keyString="value_fourteen", rc=rc)
1179+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1180+
write (msgString, '("value_fourteen HConfig tag: ", A30)') tag
1181+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1182+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1183+
1184+
call ESMF_HConfigAdd(hconfig, addKeyString="value_added",content="'NO'",rc=rc)
1185+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1186+
1187+
tag = ESMF_HConfigGetTag(hconfig, keyString="value_added", rc=rc)
1188+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1189+
write (msgString, '("value_added HConfig tag: ", A30)') tag
1190+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1191+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1192+
1193+
call ESMF_HConfigLog(hconfig, prefix="WithTagsFinish: ", rc=rc)
1194+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1195+
!BOE
11261196
! \paragraph{Explicit standard tags}
11271197
! Standard short-hand tags can be specified to change the default resolution.
11281198
! This is demonstrated for {\em map keys} "value\_four", "value\_six", and
@@ -1184,6 +1254,159 @@ program ESMF_HConfigEx
11841254
!EOC
11851255
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
11861256

1257+
!-------------------------------------------------------------------------------
1258+
!BOE
1259+
! \subsubsection{Comparing HConfig objects}
1260+
!
1261+
! The HConfig class follows the standard behavior of ESMF deep classes as
1262+
! described in section \ref{assignment_equality_copy_compare}. To demonstrate
1263+
! the operations of assignment, equality, and comparison based on content, we
1264+
! start by creating a simple HConfig object.
1265+
!EOE
1266+
!BOC
1267+
! type(ESMF_HConfig) :: hconfig
1268+
hconfig = ESMF_HConfigCreate(content="{car: red, bike: 22, plane: TRUE}", rc=rc)
1269+
!EOC
1270+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1271+
!BOE
1272+
! A simple assignment results in an alias to the same deep HConfig object.
1273+
!EOE
1274+
!BOC
1275+
! type(ESMF_HConfig) :: hconfigTemp
1276+
hconfigTemp = hconfig
1277+
!EOC
1278+
!BOE
1279+
! The equality {\tt (==)} and inequality {\tt (/=)} operators are
1280+
! overloaded to check for the alias condition when used between two
1281+
! HConfig objects.
1282+
!EOE
1283+
!BOC
1284+
! logical :: isAlias
1285+
isAlias = (hconfigTemp == hconfig)
1286+
!EOC
1287+
write (msgString, '("isAlias: ", l2)') isAlias
1288+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1289+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1290+
!BOC
1291+
! logical :: isNotAlias
1292+
isNotAlias = (hconfigTemp /= hconfig)
1293+
!EOC
1294+
write (msgString, '("isNotAlias: ", l2)') isNotAlias
1295+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1296+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1297+
!BOE
1298+
! Alias equality can also be tested by using the {\tt ESMF\_HConfigMatch()}
1299+
! function. The return value of this function is of type
1300+
! {\tt ESMF\_HConfigMatch\_Flag}, which allows for a wider range of possible
1301+
! comparison results. See section~\ref{const:hconfigmatch} for all the
1302+
! implemented return values.
1303+
!EOE
1304+
!BOC
1305+
! type(ESMF_HConfigMatch_Flag) :: match
1306+
match = ESMF_HConfigMatch(hconfig, hconfigTemp, rc=rc)
1307+
!EOC
1308+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1309+
!BOE
1310+
! For the case of an alias match, the value of {\tt ESMF\_HCONFIGMATCH\_ALIAS}
1311+
! is returned.
1312+
!EOE
1313+
!BOC
1314+
isAlias = (match == ESMF_HCONFIGMATCH_ALIAS)
1315+
!EOC
1316+
write (msgString, '("isAlias from match: ", l2)') isAlias
1317+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1318+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1319+
!BOE
1320+
! To demonstrate content matching for HConfig objects that are not aliases, we
1321+
! create a separate object with the same content as {\tt hconfig}.
1322+
!EOE
1323+
!BOC
1324+
! type(ESMF_HConfig) :: hconfigTemp
1325+
hconfigTemp = ESMF_HConfigCreate(content="{car: red, bike: 22, plane: TRUE}", rc=rc)
1326+
!EOC
1327+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1328+
!BOE
1329+
! The simple alias check now returns {\tt .false.}.
1330+
!EOE
1331+
!BOC
1332+
! logical :: isAlias
1333+
isAlias = (hconfigTemp == hconfig)
1334+
!EOC
1335+
write (msgString, '("isAlias for diff objects: ", l2)') isAlias
1336+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1337+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1338+
!BOE
1339+
! However, for two separate HConfig objects that have exactly matching
1340+
! content, as is the case for {\tt hconfig} and {\tt hconfigTemp}, function
1341+
! {\tt ESMF\_HConfigMatch()} returns value {\tt ESMF\_HCONFIGMATCH\_EXACT}.
1342+
!EOE
1343+
!BOC
1344+
! type(ESMF_HConfigMatch_Flag) :: match
1345+
match = ESMF_HConfigMatch(hconfig, hconfigTemp, rc=rc)
1346+
!EOC
1347+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1348+
!BOC
1349+
! logical :: isExact
1350+
isExact = (match == ESMF_HCONFIGMATCH_EXACT)
1351+
!EOC
1352+
write (msgString, '("isExact: ", l2)') isExact
1353+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1354+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1355+
!BOE
1356+
! The values returned by {\tt ESMF\_HConfigMatch()} are constructed in
1357+
! a monotonically increasing manner to simplify general comparisons that
1358+
! ensure two objects are either aliases of each other {\em or} their content
1359+
! matches exactly. This common case is demonstrated in the following code that
1360+
! sets {\tt isMatch} to {\tt .true.} for the alias or exact match condition,
1361+
! and {\tt .false.} otherwise, using {\tt (>=)} logic.
1362+
!EOE
1363+
!BOC
1364+
! logical :: isMatch
1365+
isMatch = (match >= ESMF_HCONFIGMATCH_EXACT)
1366+
!EOC
1367+
write (msgString, '("isMatch: ", l2)') isMatch
1368+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1369+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1370+
!BOE
1371+
! While there is an exact match of the content of {\tt hconfig} and
1372+
! {\tt hconfigTemp}, they are distinct objects in memory, which can be modified
1373+
! independent of each other. E.g. another key-value pair can be added to
1374+
! {\tt hconfigTemp} without affecting the content of {\tt hconfig}.
1375+
!EOE
1376+
!BOC
1377+
call ESMF_HConfigAdd(hconfigTemp, addKeyString="kNew", content=7, rc=rc)
1378+
!EOC
1379+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1380+
!BOE
1381+
! Now that the content of {\tt hconfig} and {\tt hconfigTemp} differs, function
1382+
! {\tt ESMF\_HConfigMatch()} returns value {\tt ESMF\_HCONFIGMATCH\_NONE}.
1383+
!EOE
1384+
!BOC
1385+
! type(ESMF_HConfigMatch_Flag) :: match
1386+
match = ESMF_HConfigMatch(hconfig, hconfigTemp, rc=rc)
1387+
!EOC
1388+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1389+
!BOC
1390+
! logical :: isNone
1391+
isNone = (match == ESMF_HCONFIGMATCH_NONE)
1392+
!EOC
1393+
write (msgString, '("isNone: ", l2)') isNone
1394+
call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc)
1395+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1396+
!BOE
1397+
! Finally clean up both HConfig objects.
1398+
!EOE
1399+
!BOC
1400+
! Destroy hconfig when done with it.
1401+
call ESMF_HConfigDestroy(hconfig, rc=rc)
1402+
!EOC
1403+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1404+
!BOC
1405+
! Destroy hconfigTemp when done with it.
1406+
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
1407+
!EOC
1408+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1409+
11871410
!-------------------------------------------------------------------------------
11881411
!BOE
11891412
! \subsubsection{Adding, Setting, and Removing elements from HConfig object}
@@ -1597,9 +1820,16 @@ program ESMF_HConfigEx
15971820
! ...
15981821
! \end{verbatim}
15991822
!
1600-
! The optional {\tt doc} argument can be specified when saving the
1601-
! multi-document {\tt hconfig} to file. Only the specified document, by index,
1602-
! is written to file.
1823+
! The content of the {\tt hconfig} object can be written to the ESMF log file
1824+
! as usual.
1825+
!EOE
1826+
!BOC
1827+
call ESMF_HConfigLog(hconfig, prefix="my-multi-doc: ", rc=rc)
1828+
!EOC
1829+
if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
1830+
!BOE
1831+
! The optional {\tt doc} argument can be specified to save or log a specific
1832+
! document of the multi-document {\tt hconfig} object.
16031833
!EOE
16041834
!BOC
16051835
call ESMF_HConfigFileSave(hconfig, filename="multi_01.yaml", doc=2, rc=rc)

src/Infrastructure/HConfig/examples/exampleWithTags.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ value_nine: 0x234
1010
value_ten: Null
1111
value_eleven:
1212
value_twelve: !myStuff xyz
13+
value_thirteen: NO
14+
value_fourteen: "NO"

src/Infrastructure/HConfig/include/ESMCI_HConfig.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ namespace ESMCI {
4848

4949
namespace ESMCI {
5050

51+
// constants and enums
52+
53+
enum HConfigMatch_Flag {HCONFIGMATCH_INVALID=0, HCONFIGMATCH_NONE,
54+
HCONFIGMATCH_EXACT, HCONFIGMATCH_ALIAS};
55+
5156
// classes and structs
5257

5358
class HConfig{
@@ -130,6 +135,11 @@ namespace ESMCI {
130135
HConfig iterEndMapVal(int *rc=NULL);
131136
int iterNext();
132137

138+
void log(std::string prefix,
139+
ESMC_LogMsgType_Flag msgType=ESMC_LOGMSG_INFO, int *docIndex=NULL)const;
140+
static HConfigMatch_Flag match(HConfig *hconfig1, HConfig *hconfig2,
141+
int *rc=NULL);
142+
133143
template<typename T> T as(bool *asOkay, int *rc=NULL);
134144
template<typename T> T asMapKey(bool *asOkay, int *rc=NULL);
135145
template<typename T> T asMapVal(bool *asOkay, int *rc=NULL);

0 commit comments

Comments
 (0)