The ESMF utilities are a set of tools for quickly assembling modeling applications.
The ESMF Info class enables models to be self-describing via metadata, which are instances of JSON-compatible key-value pairs.
The Time Management Library provides utilities for time and time interval representation and calculation, and higher-level utilities that control model time stepping, via clocks, as well as alarming.
The ESMF Config class provides configuration management based on NASA DAO's Inpak package, a collection of methods for accessing files containing input parameters stored in an ASCII format.
The ESMF LogErr class consists of a variety of methods for writing error, warning, and informational messages to log files. A default Log is created during ESMF initialization. Other Logs can be created later in the code by the user.
The DELayout class provides a layer of abstraction on top of the Virtual Machine (VM) layer. DELayout does this by introducing DEs (Decomposition Elements) as logical resource units. The DELayout object keeps track of the relationship between its DEs and the resources of the associated VM object. A DELayout can be shaped by the user at creation time to best match the computational problem or other design criteria.
The ESMF VM (Virtual Machine) class is a generic representation of hardware and system software resources. There is exactly one VM object per ESMF Component, providing the execution environment for the Component code. The VM class handles all resource management tasks for the Component class and provides a description of the underlying configuration of the compute resources used by a Component. In addition to resource description and management, the VM class offers the lowest level of ESMF communication methods.
The ESMF Fortran I/O utilities provide portable methods to access capabilities which are often implemented in different ways amongst different environments. Currently, two utility methods are implemented: one to find an unopened unit number, and one to flush an I/O buffer.
All ESMF base objects (i.e. Array, ArrayBundle, Field, FieldBundle, Grid, Mesh, DistGrid) contain a key-value attribute storage object called ESMF_Info. ESMF_Info objects may also be created independent of a base object. ESMF_Info supports setting and getting key-value pairs where the key is a string and the value is a scalar or a list of common data types. An ESMF_Info object may have a flat or nested data structure. The purpose of ESMF_Info is to support I/O-compatible metadata structures (i.e. netCDF), internal record-keeping for model execution (NUOPC), and provide a mechanism for custom user metadata attributes.
ESMF_Info is designed for interoperability. To achieve this goal, ESMF_Info adopted the JSON (Javascript Object Notation) specification. Internally, ESMF_Info uses JSON for Modern C++ [1] to manage its storage map. There are numerous resources for JSON on the web [11]. Quoting from the json.org site [11] when it introduces the format:
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. JSON is built on two structures:
These are universal data structures. Virtually all modern programming languages support them in one form or another. It makes sense that a data format that is interchangeable with programming languages also be based on these structures.
By adopting JSON compliance for ESMF_Info, ESMF made its core metadata capabilities explicitly interoperable with a widely used data structure. If data may be represented with JSON, then it is compatible with ESMF_Info.
There are some aspects of the ESMF_Info implementation related to JSON and JSON for Modern C++ that should be noted:
Below are examples for setting and getting an attribute using ESMF_Info and the legacy ESMF_Attribute. The ESMF_Info interfaces are not overloaded for ESMF object types but rather work off a handle retrieved via a get call.
call ESMF_AttributeSet(array, "aKey", 15, rc=rc)With ESMF_Info:
call ESMF_InfoGetFromHost(array, info, rc=rc) call ESMF_InfoSet(info, "aKey", 15, rc=rc)
Notice that the legacy ESMF_Attribute API expects the usage of what was called an "Attribute Package". This essentially corresponds to a namespace similar to what ESMF_Info provides for keys via the JSON Pointer syntax (see 40.2). In the above ESMF_AttributeSet() call, without specification of convention and purpose arguments, the resulting JSON pointer of the key is "/ESMF/General/aKey". This is important to account for when mixing deprecated ESMF_Attribute calls with the ESMF_Info API.
call ESMF_AttributeGet(array, "aKey", aKeyValue, rc=rc)With ESMF_Info:
call ESMF_InfoGetFromHost(array, info, rc=rc) call ESMF_InfoGet(info, "aKey", aKeyValue, rc=rc)
Notice again that the ESMF_Attribute API automatically prepends "/ESMF/General/" to the JSON pointer used for key in the absence of convention and purpose arguments.
Every "key" argument in the ESMF_Info class uses pathing following the JSON Pointer syntax [6]. A forward slash is prepended to string keys if it does not exist. Hence, "aKey" and "/aKey" are equivalent. Note the indexing aspect of the JSON Pointer syntax is not supported (i.e. "/my_list 1").
Some examples for valid "key" arguments:
Variable declarations:
type(ESMF_DistGrid) :: distgrid type(ESMF_Array) :: array type(ESMF_Info) :: infoh real(ESMF_KIND_R8), dimension(10,10) :: farray integer :: rc
Create an ESMF Array.
distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,10/), rc=rc)
array = ESMF_ArrayCreate(distgrid, farray, indexflag=ESMF_INDEX_DELOCAL, rc=rc)
Get the ESMF_Info handle from the object. See example 40.3.2 for additional usage examples.
call ESMF_InfoGetFromHost(array, infoh, rc=rc)
Destroy everything except the ESMF_Info object. Attempting to destroy the ESMF_Info handle will result in an error.
call ESMF_ArrayDestroy(array, rc=rc)
call ESMF_DistGridDestroy(distgrid, rc=rc)
Variable declarations:
type(ESMF_Info) :: info, infoCopy, infoFromCh type(ESMF_TypeKind_Flag) :: typekind character(len=ESMF_MAXSTR) :: ikey character(:), allocatable :: output, getCh real(ESMF_KIND_R8), dimension(4) :: realList real(ESMF_KIND_R8), dimension(:), allocatable :: realListAlloc integer(ESMF_KIND_I4) :: getInt real(ESMF_KIND_R8) :: getReal integer :: rc, infoSize, ii logical :: isPresent, isSet
Create an ESMF_Info object. This object contains an empty key-value store called a JSON object [8].
An ESMF_Info handle may also be retrieved from an ESMF object as opposed to creating a standalone ESMF_Info object. See example 40.3.1.
info = ESMF_InfoCreate(rc=rc)
Add an integer value.
call ESMF_InfoSet(info, "myIntegerKey", 54, rc=rc)
Get the integer value we just set.
call ESMF_InfoGet(info, "myIntegerKey", getInt, rc=rc)
Set a list of reals.
call ESMF_InfoSet(info, "myListOfReals", (/ 33.3, 44.4, 0.0, 99.0 /), rc=rc)
Set an index in the new list then retrieve the value.
call ESMF_InfoSet(info, "myListOfReals", 1234.0, idx=3, rc=rc)
call ESMF_InfoGet(info, "myListOfReals", getReal, idx=3, rc=rc)
Get the values from a list.
call ESMF_InfoGet(info, "myListOfReals", realList, rc=rc)
Allocatable lists may be used through a specific interface.
call ESMF_InfoGetAlloc(info, "myListOfReals", realListAlloc, rc=rc)
The storage contents may be printed directly or dumped to a character.
call ESMF_InfoPrint(info, indent=4, rc=rc)
output = ESMF_InfoDump(info, rc=rc)
print *, "the Info dump: "//output
Check if a key is present.
isPresent = ESMF_InfoIsPresent(info, "myIntegerKey", rc=rc)
if (.not. isPresent) call ESMF_Finalize(endflag=ESMF_END_ABORT)
Add a null value and check if it is set (has a non-null value).
call ESMF_InfoSetNULL(info, "aNullKey", rc=rc)
isSet = ESMF_InfoIsSet(info, "aNullKey", rc=rc)
if (isSet) call ESMF_Finalize(endflag=ESMF_END_ABORT) isSet = ESMF_InfoIsSet(info, "myIntegerKey", rc=rc)
if (.not. isSet) call ESMF_Finalize(endflag=ESMF_END_ABORT)
The force flag, when set to false, will cause an error if the key exists in the map. The force flag is set to true by default.
call ESMF_InfoSet(info, "myIntegerKey", 33, force=.false., rc=rc) if (rc .ne. ESMC_RC_CANNOT_SET) call ESMF_Finalize(endflag=ESMF_END_ABORT)
Nesting uses the JSON Pointer 40.2 syntax. All key arguments in ESMF_Info may use this syntax unless noted otherwise. When creating a nested object, objects are created if they do not exist. Hence, it is not necessary to create the individual nested elements for deep hierarchies.
call ESMF_InfoSet(info, "/Universe/Galaxy/Star/Planet", "Venus", rc=rc)
Using the get interface, it is possible to iterate over the storage contents. In the call below, we are retrieving the number of elements (key-value pairs) that exist in our root storage object. We then select the target element in root using an index and retrieve some additional metadata for the target object.
call ESMF_InfoGet(info, size=infoSize, rc=rc)
do ii=1,infoSize call ESMF_InfoGet(info, idx=ii, ikey=ikey, typekind=typekind, rc=rc)
if (localPet == 0) then print *, "ESMF_Info inquire loop: " print *, " idx= ", ii print *, " ikey= ", trim(ikey) print *, " typekind= ", typekind endif enddo
Copying the ESMF_Info object requires the copy to be destroyed/deallocated.
infoCopy = ESMF_InfoCreate(info, rc=rc)
Comparison operators = and /= are implemented for ESMF_Info objects.
if (infoCopy /= info) call ESMF_Finalize(endflag=ESMF_END_ABORT)
After removing a key from the copied ESMF_Info object, the two objects will no longer be equal.
call ESMF_InfoRemove(infoCopy, "myIntegerKey", rc=rc)
if (infoCopy == info) call ESMF_Finalize(endflag=ESMF_END_ABORT)
Destroy the copied object.
call ESMF_InfoDestroy(infoCopy, rc=rc)
An ESMF_Info object may be created from a JSON string. Note the usage of quotes is required as below.
infoFromCh = ESMF_InfoCreate('{"hello":"world"}', rc=rc)
The contents of an ESMF_Info object may be set in another ESMF_Info object.
call ESMF_InfoSet(info, "infoFromCh", infoFromCh, rc=rc)
call ESMF_InfoDestroy(infoFromCh, rc=rc)
An allocatable character get interface is available.
call ESMF_InfoGetCharAlloc(info, "/infoFromCh/hello", getCh, rc=rc)
Destroy the ESMF_Info object.
call ESMF_InfoDestroy(info, rc=rc)
INTERFACE:
interface assignment(=) info1 = info2ARGUMENTS:
type(ESMF_Info) :: info1 type(ESMF_Info) :: info2STATUS:
DESCRIPTION:
Assign info1 as an alias to the same ESMF Info object in memory as info2. If info2 is invalid, then info1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Info), intent(in) :: info1 type(ESMF_Info), intent(in) :: info2DESCRIPTION:
Test if the contents of two ESMF_Info objects are equal.
The arguments are:
INTERFACE:
interface operator(/=)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Info), intent(in) :: info1 type(ESMF_Info), intent(in) :: info2DESCRIPTION:
Test if the contents of two ESMF_Info objects are not equal.
The arguments are:
INTERFACE:
subroutine ESMF_InfoBroadcast(info, rootPet, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Broadcast an ESMF_Info object collectively across the current VM.
Users wishing to synchronize via broadcast an attribute hierarchy associated with an ESMF object should consult the ESMF_InfoSync documentation 40.4.29
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoCreate() function ESMF_InfoCreateEmpty(rc)ARGUMENTS:
integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_Info) :: ESMF_InfoCreateEmptyDESCRIPTION:
Create an ESMF_Info object. This object must be destroyed using ESMF_InfoDestroy to free its memory allocation
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoCreate() function ESMF_InfoCreateByKey(info, key, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_Info) :: ESMF_InfoCreateByKeyDESCRIPTION:
Create an ESMF_Info object from a location in info defined by key. Returned object is a deep copy. The value associated with key must be a nested object (i.e. a collection of key/value pairs).
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoCreate() function ESMF_InfoCreateFromInfo(info, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_Info) :: ESMF_InfoCreateFromInfoDESCRIPTION:
Create an ESMF_Info object from another ESMF_Info object. The returned object is a deep copy of the source object.
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoCreate() function ESMF_InfoCreateByParse(jsonString, rc)ARGUMENTS:
character(len=*), intent(in) :: jsonString -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_Info) :: ESMF_InfoCreateByParseDESCRIPTION:
Create an ESMF_Info object by parsing a JSON-formatted string.
The arguments are:
INTERFACE:
subroutine ESMF_InfoDestroy(info, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Destroy an ESMF_Info object. Destroying an ESMF_Info object created internally by an ESMF object results in an error
The arguments are:
INTERFACE:
function ESMF_InfoDump(info, key, indent, rc) result(output)ARGUMENTS:
type(ESMF_Info), intent(in) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(*), intent(in), optional :: key integer, intent(in), optional :: indent integer, intent(out), optional :: rc RESULT: character(:), allocatable :: outputDESCRIPTION:
Dump the contents of an ESMF_Info object as a JSON string.
The arguments are:
INTERFACE:
subroutine ESMF_InfoGet(info, key, value, default, idx, attnestflag, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key <value>, see below for supported value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- <default, optional> see below for supported default value integer, intent(in), optional :: idx type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag integer, intent(out), optional :: rcDESCRIPTION:
Get a value from an ESMF_Info object using a key. If the key is not found, rc will not equal ESMF_SUCCESS. The returned value is always a copy including gets with a default.
Overloaded value for the following types:
The arguments are:
INTERFACE:
subroutine ESMF_InfoGetCharAlloc(info, key, value, default, idx, attnestflag, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key character(:), allocatable, intent(out) :: value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: default integer, intent(in), optional :: idx type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag integer, intent(out), optional :: rcDESCRIPTION:
Get a value from an ESMF_Info object using a key. If the key is not found, rc will not equal ESMF_SUCCESS. The returned value is always a copy including gets with a default.
The arguments are:
INTERFACE:
subroutine ESMF_InfoGet(info, key, values, itemCount, attnestflag, scalarToArray, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key <values>, see below for supported values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: itemCount type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag logical, intent(in), optional :: scalarToArray integer, intent(out), optional :: rcDESCRIPTION:
Get a value list from an ESMF_Info object using a key. If the key is not found, rc will not equal ESMF_SUCCESS. The returned value is always a copy.
The length of values must match its length in storage.
Overloaded values for the following types:
The arguments are:
INTERFACE:
subroutine ESMF_InfoGetAlloc(info, key, values, itemCount, attnestflag, scalarToArray, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key <values>, see below for supported values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: itemCount type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag logical, intent(in), optional :: scalarToArray integer, intent(out), optional :: rcDESCRIPTION:
Get a value list from an ESMF_Info object using a key. If the key is not found, rc will not equal ESMF_SUCCESS. The returned value is always a copy.
Overloaded values for the following types:
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoGet() subroutine ESMF_InfoInquire(info, size, key, jsonType, isArray, & isDirty, idx, typekind, ikey, isPresent, isStructured, isNull, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: size character(len=*), intent(in), optional :: key character(len=*), intent(out), optional :: jsonType logical, intent(out), optional :: isArray logical, intent(out), optional :: isDirty integer, intent(in), optional :: idx type(ESMF_TypeKind_Flag), intent(out), optional :: typekind character(len=*), intent(out), optional :: ikey logical, intent(out), optional :: isPresent logical, intent(out), optional :: isStructured logical, intent(out), optional :: isNull integer, intent(out), optional :: rcDESCRIPTION:
Inquire an ESMF_Info object for metadata.
The arguments are:
INTERFACE:
subroutine ESMF_InfoGetFromHost(host, info, rc)ARGUMENTS:
type(ESMF_*), intent(inout) :: host type(ESMF_Info), intent(out) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Get an ESMF_Info object handle from a host ESMF object. The returned handle should not be destroyed.
The arguments are:
INTERFACE:
function ESMF_InfoGetTK(info, key, attnestflag, rc) result(typekind)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_TypeKind_Flag) :: typekindDESCRIPTION:
Return the ESMF TypeKind of the value associated with key. See section 54.60 for valid return values.
The arguments are:
INTERFACE:
subroutine ESMF_InfoGetArrayMeta(info, key, isArray, size, attnestflag, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key logical, intent(out) :: isArray integer(C_INT), intent(out) :: size -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag integer, intent(out), optional :: rcDESCRIPTION:
Return a value's array status and size using a key.
The arguments are:
INTERFACE:
function ESMF_InfoIsPresent(info, key, attnestflag, isPointer, rc) result(is_present)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag logical, intent(in), optional :: isPointer integer, intent(out), optional :: rcRETURN VALUE:
logical :: is_presentDESCRIPTION:
Return true if key exists in ESMF_Info's storage.
The arguments are:
INTERFACE:
function ESMF_InfoIsSet(info, key, rc) result(is_set)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: key -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
logical :: is_setDESCRIPTION:
Returns true if the target value is not null [7].
The arguments are:
INTERFACE:
subroutine ESMF_InfoPrint(info, indent, preString, unit, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(*), intent(in), optional :: preString character(*), intent(out), optional :: unit integer, intent(in), optional :: indent integer, intent(out), optional :: rcDESCRIPTION:
Print ESMF_Info contents in JSON format.
The arguments are:
INTERFACE:
function ESMF_InfoReadJSON(filename, rc) result(info_r)ARGUMENTS:
character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
type(ESMF_Info) :: info_rDESCRIPTION:
Read JSON data from a file and return a new ESMF_Info object.
The arguments are:
INTERFACE:
subroutine ESMF_InfoRemove(info, keyParent, keyChild, attnestflag, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info character(len=*), intent(in) :: keyParent -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: keyChild type(ESMF_AttNest_Flag), intent(in), optional :: attnestflag integer, intent(out), optional :: rcDESCRIPTION:
Remove a key-value pair from an ESMF_Info object.
The arguments are:
INTERFACE:
subroutine ESMF_InfoSet(info, key, value, force, idx, pkey, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info character(len=*), intent(in) :: key <value>, see below for supported value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: force integer, intent(in), optional :: idx character(len=*), intent(in), optional :: pkey integer, intent(out), optional :: rcDESCRIPTION:
Set a value in an ESMF_Info object using a key.
Overloaded value for the following types:
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoSet subroutine ESMF_InfoSetINFO(info, key, value, force, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info character(len=*), intent(in) :: key type(ESMF_Info), intent(in) :: value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: force integer, intent(out), optional :: rcDESCRIPTION:
Set a value to the contents of an ESMF_Info object. A copy of the source contents is made.
The arguments are:
INTERFACE:
! Private name; call using ESMF_InfoSet recursive subroutine ESMF_InfoSetHConfig(info, value, keyPrefix, force, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info type(ESMF_HConfig), intent(in) :: value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: keyPrefix logical, intent(in), optional :: force integer, intent(out), optional :: rcDESCRIPTION:
The provided ESMF_HConfig object is expected to be a map. An error is returned if this condition is not met. Each key-value pair held by the ESMF_HConfig object is added to the ESMF_Info object. A copy of the source contents is made.
Transfer of scalar, sequence, and map values from ESMF_HConfig to ESMF_Info are supported. Maps are treated recursively. Sequences are restricted to scalar elements of the same typekind.
The keys of any map provided by the ESMF_HConfig object must be of scalar type. Keys are interpreted as strings when transferred to the ESMF_Info object. YAML merge keys "«" are supported.
When existing keys in info are overridden by this operation, the typekind of the associated value element is allowed to change.
The arguments are:
INTERFACE:
subroutine ESMF_InfoSet(info, key, values, force, pkey, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info character(len=*), intent(in) :: key <values>, see below for supported values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: force character(len=*), intent(in), optional :: pkey integer, intent(out), optional :: rcDESCRIPTION:
Set a value list in an ESMF_Info object using a key. List values are initialized to null.
Overloaded values for the following types:
The arguments are:
INTERFACE:
subroutine ESMF_InfoSetNULL(info, key, force, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: info character(len=*), intent(in) :: key -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: force integer, intent(out), optional :: rcDESCRIPTION:
Set a value to null [7].
The arguments are:
INTERFACE:
subroutine ESMF_InfoSync(host, rootPet, vm, markClean, & rc)ARGUMENTS:
type(ESMF_*), intent(inout) :: host integer, intent(in) :: rootPet type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: markClean integer, intent(out), optional :: rcDESCRIPTION:
Synchronize ESMF_Info contents collectively across the current VM. Contents on the rootPet are set as the contents on matching objects sharing the VM. An attempt is made to optimize by only communicating updated contents (i.e. something set or modified). This subroutine will traverse the ESMF object hierarchy associated with host (i.e. Arrays in an ArrayBundle, Fields in a FieldBundle, etc.).
Users interested in broadcasting only the ESMF_Info object should consult the ESMF_InfoBroadcast documentation 40.4.4.
The arguments are:
INTERFACE:
subroutine ESMF_InfoUpdate(lhs, rhs, recursive, overwrite, rc)ARGUMENTS:
type(ESMF_Info), intent(inout) :: lhs type(ESMF_Info), intent(in) :: rhs -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: recursive logical, intent(in), optional :: overwrite integer, intent(out), optional :: rcDESCRIPTION:
Update the contents of lhs using the contents of rhs. The operation inserts or overwrites any key in lhs if it exists in rhs. Otherwise, the contents of lhs is left unaltered. See the JSON documentation for implementation details [10]. If recursive is .true. (default is .false.), nested objects will be updated by their component key/values. Otherwise, the first instance or top-level key is replaced without the child contents being updated element-by-element.
The arguments are:
INTERFACE:
subroutine ESMF_InfoWriteJSON(info, filename, rc)ARGUMENTS:
type(ESMF_Info), intent(in) :: info character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Write ESMF_Info contents to file using the JSON format.
The arguments are:
The ESMF Time Manager utility includes software for time and date representation and calculations, model time advancement, and the identification of unique and periodic events. Since multi-component geophysical applications often require synchronization across the time management schemes of the individual components, the Time Manager's standard calendars and consistent time representation promote component interoperability.
Key Features |
Drift-free timekeeping through an integer-based internal time representation. Both integers and reals can be specified at the interface. |
The ability to represent time as a rational fraction, to support exact timekeeping in applications that involve grid refinement. |
Support for many calendar kinds, including user-customized calendars. |
Support for both concurrent and sequential modes of component execution. |
Support for varying and negative time steps. |
In the remainder of this section, we briefly summarize the functionality that the Time Manager classes provide. Detailed descriptions and usage examples precede the API listing for each class.
TimeIntervals and Time instants (simply called Times) are the computational building blocks of the Time Manager utility. TimeIntervals support operations such as add, subtract, compare size, reset value, copy value, and subdivide by a scalar. Times, which are moments in time associated with specific Calendars, can be incremented or decremented by TimeIntervals, compared to determine which of two Times is later, differenced to obtain the TimeInterval between two Times, copied, reset, and manipulated in other useful ways. Times support a host of different queries, both for values of individual Time components such as year, month, day, and second, and for derived values such as day of year, middle of current month and Julian day. It is also possible to retrieve the value of the hardware realtime clock in the form of a Time. See Sections 43.1 and 44.1, respectively, for use and examples of Times and TimeIntervals.
Since climate modeling, numerical weather prediction and other Earth and space applications have widely varying time scales and require different sorts of calendars, Times and TimeIntervals must support a wide range of time specifiers, spanning nanoseconds to years. The interfaces to these time classes are defined so that the user can specify a time using a combination of units selected from the list shown in Table 41.4.
Unit | Meaning |
<yy|yy_i8> | Year. |
mm | Month of the year. |
dd | Day of the month. |
<d|d_i8|d_r8> | Julian or Modified Julian day. |
<h|h_r8> | Hour. |
<m|m_r8> | Minute. |
<s|s_i8|s_r8> | Second. |
<ms|ms_r8> | Millisecond. |
<us|us_r8> | Microsecond. |
<ns|ns_r8> | Nanosecond. |
O | Time zone offset in integer number of hours and minutes. |
<sN|sN_i8> | Numerator for times of the form s , where s is seconds and s, sN, and sD are integers. This format provides a mechanism for supporting exact behavior. |
<sD|sD_i8 | Denominator for times of the form s , where s is seconds and s, sN, and sD are integers. |
The result of this strategy is that Time Intervals and Times gain a consistent core representation of time as well a set of basic methods.
The BaseTime class can be designed with a minimum number of elements to represent any required time. The design is based on the idea used in the real-time POSIX 1003.1b-1993 standard. That is, to represent time simply as a pair of integers: one for seconds (whole) and one for nanoseconds (fractional). These can then be converted at the interface level to any desired format.
For ESMF, this idea can be modified and extended, in order to handle the requirements for a large time range (> 200,000 years) and to exactly represent any rational fraction, not just nanoseconds. To handle the large time range, a 64-bit or greater integer is used for whole seconds. Any rational fractional second is expressed using two additional integers: a numerator and a denominator. Both the whole seconds and fractional numerator are signed to handle negative time intervals and instants. For arithmetic consistency both must carry the same sign (both positive or both negative), except, of course, for zero values. The fractional seconds element (numerator) is bounded with respect to whole seconds. If the absolute value of the numerator becomes greater than or equal to the denominator, whole seconds are incremented or decremented accordingly and the numerator is reset to the remainder. Conversions are performed upon demand by interface methods within the TimeInterval and Time classes. This is done because different applications require different representations of time intervals and time instances. Floating point values as well as integers can be specified for the various time units in the interfaces, see Table 41.4. Floating point values are represented internally as integer-based rational fractions.
The BaseTime class defines increment and decrement methods for basic TimeInterval calculations between Time instants. It is done here rather than in the Calendar class because it can be done with simple second-based arithmetic that is calendar independent.
Comparison methods can also be defined in the BaseTime class. These perform equality/inequality, less than, and greater than comparisons between any two TimeIntervals or Times. These methods capture the common comparison logic between TimeIntervals and Times and hence are defined here for sharing.
The following is a simplified UML diagram showing the structure of the Time Manager utility. See Appendix A, A Brief Introduction to UML, for a translation table that lists the symbols in the diagram and their meaning.
The Calendar class represents the standard calendars used in geophysical modeling: Gregorian, Julian, Julian Day, Modified Julian Day, no-leap, 360-day, and no-calendar. It also supports a user-customized calendar. Brief descriptions are provided for each calendar below. For more information on standard calendars, see [30] and [26].
DESCRIPTION:
Supported calendar kinds.
The type of this flag is:
type(ESMF_CalKind_Flag)
The valid values are:
MJD = JD - 2400000.5
The half day is subtracted so that the day starts at midnight.
In most multi-component Earth system applications, the timekeeping in each component must refer to the same standard calendar in order for the components to properly synchronize. It therefore makes sense to create as few ESMF Calendars as possible, preferably one per application. A typical strategy would be to create a single Calendar at the start of an application, and use that Calendar in all subsequent calls that accept a Calendar, such as ESMF_TimeSet.
The following example shows how to set up an ESMF Calendar.
! !PROGRAM: ESMF_CalendarEx - Calendar creation examples ! ! !DESCRIPTION: ! ! This program shows examples of how to create different calendar kinds !----------------------------------------------------------------------------- #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! instantiate calendars type(ESMF_Calendar) :: gregorianCalendar type(ESMF_Calendar) :: julianDayCalendar type(ESMF_Calendar) :: marsCalendar ! local variables for Get methods integer :: sols integer(ESMF_KIND_I8) :: dl type(ESMF_Time) :: time, marsTime type(ESMF_TimeInterval) :: marsTimeStep ! return code integer:: rc
! initialize ESMF framework call ESMF_Initialize(defaultlogfilename="CalendarEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
This example shows how to create three ESMF_Calendars.
! create a Gregorian calendar gregorianCalendar = ESMF_CalendarCreate(ESMF_CALKIND_GREGORIAN, & name="Gregorian", rc=rc)
! create a Julian Day calendar julianDayCalendar = ESMF_CalendarCreate(ESMF_CALKIND_JULIANDAY, & name="JulianDay", rc=rc)
! create a Custom calendar for the planet Mars ! 1 Mars solar day = 24 hours, 39 minutes, 35 seconds = 88775 seconds ! 1 Mars solar year = 668.5921 Mars solar days = 668 5921/10000 sols/year ! http://www.giss.nasa.gov/research/briefs/allison_02 ! http://www.giss.nasa.gov/tools/mars24/help/notes.html marsCalendar = ESMF_CalendarCreate(secondsPerDay=88775, & daysPerYear=668, & daysPerYearDn=5921, & daysPerYearDd=10000, & name="MarsCalendar", rc=rc)
This example shows how to compare an ESMF_Calendar with a known calendar kind.
! compare calendar kind against a known type if (gregorianCalendar == ESMF_CALKIND_GREGORIAN) then print *, "gregorianCalendar is of type ESMF_CALKIND_GREGORIAN." else print *, "gregorianCalendar is not of type ESMF_CALKIND_GREGORIAN." end if
This example shows how to convert a time from one ESMF_Calendar to another.
call ESMF_TimeSet(time, yy=2004, mm=4, dd=17, & calendar=gregorianCalendar, rc=rc)
! switch time's calendar to perform conversion call ESMF_TimeSet(time, calendar=julianDayCalendar, rc=rc)
call ESMF_TimeGet(time, d_i8=dl, rc=rc) print *, "Gregorian date 2004/4/17 is ", dl, & " days in the Julian Day calendar."
This example shows how to increment a time using a custom ESMF_Calendar.
! Set a time to Mars solar year 3, sol 100 call ESMF_TimeSet(marsTime, yy=3, d=100, & calendar=marsCalendar, rc=rc)
! Set a 1 solar year time step call ESMF_TimeIntervalSet(marsTimeStep, yy=1, rc=rc)
! Perform the increment marsTime = marsTime + marsTimeStep
! Get the result in sols (2774 = (3+1)*668.5921 + 100) call ESMF_TimeGet(marsTime, d=sols, rc=rc) print *, "For Mars, 3 solar years, 100 sols + 1 solar year = ", & sols, "sols."
This example shows how to destroy three ESMF_Calendars.
call ESMF_CalendarDestroy(julianDayCalendar, rc=rc)
call ESMF_CalendarDestroy(gregorianCalendar, rc=rc)
call ESMF_CalendarDestroy(marsCalendar, rc=rc)
! finalize ESMF framework call ESMF_Finalize(rc=rc)
end program ESMF_CalendarEx
INTERFACE:
interface assignment(=) calendar1 = calendar2ARGUMENTS:
type(ESMF_Calendar) :: calendar1 type(ESMF_Calendar) :: calendar2STATUS:
DESCRIPTION:
Assign calendar1 as an alias to the same ESMF_Calendar object in memory as calendar2. If calendar2 is invalid, then calendar1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (<calendar argument 1> == <calendar argument 2>) then ... endif OR result = (<calendar argument 1> == <calendar argument 2>)RETURN VALUE:
logical :: resultARGUMENTS:
<calendar argument 1>, see below for supported values <calendar argument 2>, see below for supported valuesDESCRIPTION:
Overloads the (==) operator for the ESMF_Calendar class. Compare an ESMF_Calendar object or ESMF_CalKind_Flag with another calendar object or calendar kind for equality. Return .true. if equal, .false. otherwise. Comparison is based on calendar kind, which is a property of a calendar object.
If both arguments are ESMF_Calendar objects, and both are of type ESMF_CALKIND_CUSTOM, then all the calendar's properties, except name, are compared.
If both arguments are ESMF_Calendar objects, and either of them is not in the ESMF_INIT_CREATED status, an error will be logged. However, this does not affect the return value, which is .true. when both arguments are in the same status, and .false. otherwise.
If one argument is an ESMF_Calendar object, and the other is an ESMF_CalKind_Flag, and the calendar object is not in the ESMF_INIT_CREATED status, an error will be logged and .false. will be returned.
Supported values for <calendar argument 1> are:
The arguments are:
INTERFACE:
interface operator(/=) if (<calendar argument 1> /= <calendar argument 2>) then ... endif OR result = (<calendar argument 1> /= <calendar argument 2>)RETURN VALUE:
logical :: resultARGUMENTS:
<calendar argument 1>, see below for supported values <calendar argument 2>, see below for supported valuesDESCRIPTION:
Overloads the (/=) operator for the ESMF_Calendar class. Compare a ESMF_Calendar object or ESMF_CalKind_Flag with another calendar object or calendar kind for inequality. Return .true. if not equal, .false. otherwise. Comparison is based on calendar kind, which is a property of a calendar object.
If both arguments are ESMF_Calendar objects, and both are of type ESMF_CALKIND_CUSTOM, then all the calendar's properties, except name, are compared.
If both arguments are ESMF_Calendar objects, and either of them is not in the ESMF_INIT_CREATED status, an error will be logged. However, this does not affect the return value, which is .true. when both arguments are not in the same status, and .false. otherwise.
If one argument is an ESMF_Calendar object, and the other is an ESMF_CalKind_Flag, and the calendar object is not in the ESMF_INIT_CREATED status, an error will be logged and .true. will be returned.
Supported values for <calendar argument 1> are:
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarCreate() function ESMF_CalendarCreateBuiltIn(calkindflag, & name, rc)RETURN VALUE:
type(ESMF_Calendar) :: ESMF_CalendarCreateBuiltInARGUMENTS:
type(ESMF_CalKind_Flag), intent(in) :: calkindflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates and sets a calendar to the given built-in ESMF_CalKind_Flag.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarCreate() function ESMF_CalendarCreateCopy(calendar, rc)RETURN VALUE:
type(ESMF_Calendar) :: ESMF_CalendarCreateCopyARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates a complete (deep) copy of a given ESMF_Calendar.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarCreate() function ESMF_CalendarCreateCustom(& daysPerMonth, secondsPerDay, & daysPerYear, daysPerYearDn, daysPerYearDd, name, rc)RETURN VALUE:
type(ESMF_Calendar) :: ESMF_CalendarCreateCustomARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: daysPerMonth(:) integer(ESMF_KIND_I4), intent(in), optional :: secondsPerDay integer(ESMF_KIND_I4), intent(in), optional :: daysPerYear integer(ESMF_KIND_I4), intent(in), optional :: daysPerYearDn integer(ESMF_KIND_I4), intent(in), optional :: daysPerYearDd character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcDESCRIPTION:
Creates a custom ESMF_Calendar and sets its properties.
The arguments are:
INTERFACE:
subroutine ESMF_CalendarDestroy(calendar, rc)ARGUMENTS:
type(ESMF_Calendar), intent(inout) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Releases resources associated with this ESMF_Calendar.
The arguments are:
INTERFACE:
subroutine ESMF_CalendarGet(calendar, & name, calkindflag, daysPerMonth, monthsPerYear, & secondsPerDay, secondsPerYear, & daysPerYear, daysPerYearDn, daysPerYearDd, rc)ARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_CalKind_Flag),intent(out), optional :: calkindflag integer, intent(out), optional :: daysPerMonth(:) integer, intent(out), optional :: monthsPerYear integer(ESMF_KIND_I4), intent(out), optional :: secondsPerDay integer(ESMF_KIND_I4), intent(out), optional :: secondsPerYear integer(ESMF_KIND_I4), intent(out), optional :: daysPerYear integer(ESMF_KIND_I4), intent(out), optional :: daysPerYearDn integer(ESMF_KIND_I4), intent(out), optional :: daysPerYearDd character (len=*), intent(out), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets one or more of an ESMF_Calendar's properties.
The arguments are:
INTERFACE:
function ESMF_CalendarIsCreated(calendar, rc)RETURN VALUE:
logical :: ESMF_CalendarIsCreatedARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the calendar has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarIsLeapYear() function ESMF_CalendarIsLeapYear<kind>(calendar, yy, rc)RETURN VALUE:
logical :: ESMF_CalendarIsLeapYear<kind>ARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar integer(ESMF_KIND_<kind>), intent(in) :: yy -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns .true. if the given year is a leap year within the given calendar, and .false. otherwise. Custom calendars do not define leap years, so .false. will always be returned in this case; see Section 42.4. See also ESMF_TimeIsLeapYear().
The arguments are:
INTERFACE:
subroutine ESMF_CalendarPrint(calendar, options, rc)ARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar character (len=*), intent(in), optional :: options integer, intent(out), optional :: rcDESCRIPTION:
Prints out an ESMF_Calendar's properties to stdio,
in support of testing and debugging. The options control the
type of information and level of detail.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarSet() subroutine ESMF_CalendarSetBuiltIn(calendar, calkindflag, & name, rc)ARGUMENTS:
type(ESMF_Calendar), intent(inout) :: calendar type(ESMF_CalKind_Flag), intent(in) :: calkindflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets calendar to the given built-in ESMF_CalKind_Flag.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarSet() subroutine ESMF_CalendarSetCustom(calendar, & daysPerMonth, secondsPerDay, & daysPerYear, daysPerYearDn, daysPerYearDd, name, rc)ARGUMENTS:
type(ESMF_Calendar), intent(inout) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: daysPerMonth(:) integer(ESMF_KIND_I4),intent(in), optional :: secondsPerDay integer(ESMF_KIND_I4),intent(in), optional :: daysPerYear integer(ESMF_KIND_I4),intent(in), optional :: daysPerYearDn integer(ESMF_KIND_I4),intent(in), optional :: daysPerYearDd character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets properties in a custom ESMF_Calendar.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarSetDefault() subroutine ESMF_CalendarSetDefaultKind(calkindflag, rc)ARGUMENTS:
type(ESMF_CalKind_Flag), intent(in) :: calkindflag integer, intent(out), optional :: rcDESCRIPTION:
Sets the default calendar to the given type. Subsequent Time Manager operations requiring a calendar where one isn't specified will use the internal calendar of this type.
The arguments are:
INTERFACE:
! Private name; call using ESMF_CalendarSetDefault() subroutine ESMF_CalendarSetDefaultCal(calendar, rc)ARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar integer, intent(out), optional :: rcDESCRIPTION:
Sets the default calendar to the one given. Subsequent Time Manager operations requiring a calendar where one isn't specified will use this calendar.
The arguments are:
INTERFACE:
subroutine ESMF_CalendarValidate(calendar, rc)ARGUMENTS:
type(ESMF_Calendar), intent(in) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Checks whether a calendar is valid. Must be one of the defined calendar kinds. daysPerMonth, daysPerYear, secondsPerDay must all be greater than or equal to zero.
The arguments are:
A Time represents a specific point in time. In order to accommodate the range of time scales in Earth system applications, Times in the ESMF can be specified in many different ways, from years to nanoseconds. The Time interface is designed so that you select one or more options from a list of time units in order to specify a Time. The options for specifying a Time are shown in Table 41.4.
There are Time methods defined for setting and getting a Time, incrementing and decrementing a Time by a TimeInterval, taking the difference between two Times, and comparing Times. Special quantities such as the middle of the month and the day of the year associated with a particular Time can be retrieved. There is a method for returning the Time value as a string in the ISO 8601 format YYYY-MM-DDThh:mm:ss [24].
A Time that is specified in hours, minutes, seconds, or subsecond intervals does not need to be associated with a standard calendar; a Time whose specification includes time units of a day and greater must be. The ESMF representation of a calendar, the Calendar class, is described in Section 42.1. The ESMF_TimeSet method is used to initialize a Time as well as associate it with a Calendar. If a Time method is invoked in which a Calendar is necessary and one has not been set, the ESMF method will return an error condition.
In the ESMF the TimeInterval class is used to represent time periods. This class is frequently used in combination with the Time class. The Clock class, for example, advances model time by incrementing a Time with a TimeInterval.
Times are most frequently used to represent start, stop, and current model times. The following examples show how to create, initialize, and manipulate Time.
! !PROGRAM: ESMF_TimeEx - Time initialization and manipulation examples ! ! !DESCRIPTION: ! ! This program shows examples of Time initialization and manipulation !----------------------------------------------------------------------------- #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! instantiate two times type(ESMF_Time) :: time1, time2 type(ESMF_VM) :: vm ! instantiate a time interval type(ESMF_TimeInterval) :: timeinterval1 ! local variables for Get methods integer :: YY, MM, DD, H, M, S ! return code integer:: rc
! initialize ESMF framework call ESMF_Initialize(vm=vm, defaultCalKind=ESMF_CALKIND_GREGORIAN, & defaultlogfilename="TimeEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
This example shows how to initialize an ESMF_Time.
! initialize time1 to 2/28/2000 2:24:45 call ESMF_TimeSet(time1, yy=2000, mm=2, dd=28, h=2, m=24, s=45, rc=rc)
print *, "Time1 = " call ESMF_TimePrint(time1, options="string", rc=rc)
This example shows how to increment an ESMF_Time by an ESMF_TimeInterval.
! initialize a time interval to 2 days, 8 hours, 36 minutes, 15 seconds call ESMF_TimeIntervalSet(timeinterval1, d=2, h=8, m=36, s=15, rc=rc)
print *, "Timeinterval1 = " call ESMF_TimeIntervalPrint(timeinterval1, options="string", rc=rc)
! increment time1 with timeinterval1 time2 = time1 + timeinterval1 call ESMF_TimeGet(time2, yy=YY, mm=MM, dd=DD, h=H, m=M, s=S, rc=rc) print *, "time2 = time1 + timeinterval1 = ", YY, "/", MM, "/", DD, & " ", H, ":", M, ":", S
This example shows how to compare two ESMF_Times.
if (time2 > time1) then print *, "time2 is larger than time1" else print *, "time1 is smaller than or equal to time2" endif
! finalize ESMF framework call ESMF_Finalize(rc=rc)
end program ESMF_TimeEx
For fractional seconds, a signed 64-bit integer will handle a resolution of +/- -1, or +/- 9,223,372,036,854,775,807 parts of a second.
INTERFACE:
interface assignment(=) time1 = time2ARGUMENTS:
type(ESMF_Time) :: time1 type(ESMF_Time) :: time2STATUS:
DESCRIPTION:
Set time1 equal to time2. This is the default Fortran assignment, which creates a complete, independent copy of time2 as time1. If time2 is an invalid ESMF_Time object then time1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(+) time2 = time1 + timeintervalRETURN VALUE:
type(ESMF_Time) :: time2ARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_TimeInterval), intent(in) :: timeintervalSTATUS:
DESCRIPTION:
Overloads the (+) operator for the ESMF_Time class to increment time1 with timeinterval and return the result as an ESMF_Time.
The arguments are:
INTERFACE:
interface operator(-) time2 = time1 - timeintervalRETURN VALUE:
type(ESMF_Time) :: time2ARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_TimeInterval), intent(in) :: timeintervalSTATUS:
DESCRIPTION:
Overloads the (-) operator for the ESMF_Time class to decrement time1 with timeinterval, and return the result as an ESMF_Time.
The arguments are:
INTERFACE:
interface operator(-) timeinterval = time1 - time2RETURN VALUE:
type(ESMF_TimeInterval) :: timeintervalARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (-) operator for the ESMF_Time class to return the difference between time1 and time2 as an ESMF_TimeInterval. It is assumed that time1 is later than time2; if not, the resulting ESMF_TimeInterval will have a negative value.
The arguments are:
INTERFACE:
interface operator(==) if (time1 == time2) then ... endif OR result = (time1 == time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (==) operator for the ESMF_Time class to return .true. if time1 and time2 represent the same instant in time, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(/=) if (time1 /= time2) then ... endif OR result = (time1 /= time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (/=) operator for the ESMF_Time class to return .true. if time1 and time2 do not represent the same instant in time, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(<) if (time1 < time2) then ... endif OR result = (time1 < time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (<) operator for the ESMF_Time class to return .true. if time1 is earlier in time than time2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(<=) if (time1 <= time2) then ... endif OR result = (time1 <= time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (<=) operator for the ESMF_Time class to return .true. if time1 is earlier in time or the same time as time2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(>) if (time1 > time2) then ... endif OR result = (time1 > time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (>) operator for the ESMF_Time class to return .true. if time1 is later in time than time2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(>=) if (time1 >= time2) then ... endif OR result = (time1 >= time2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2STATUS:
DESCRIPTION:
Overloads the (>=) operator for the ESMF_Time class to return .true. if time1 is later in time or the same time as time2, and .false. otherwise.
The arguments are:
INTERFACE:
subroutine ESMF_TimeGet(time, & yy, yy_i8, & mm, dd, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & calendar, calkindflag, timeZone, & timeString, timeStringISOFrac, & dayOfWeek, midMonth, & dayOfYear, dayOfYear_r8, & dayOfYear_intvl, rc)ARGUMENTS:
type(ESMF_Time), intent(in) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(out), optional :: yy integer(ESMF_KIND_I8), intent(out), optional :: yy_i8 integer, intent(out), optional :: mm integer, intent(out), optional :: dd integer(ESMF_KIND_I4), intent(out), optional :: d integer(ESMF_KIND_I8), intent(out), optional :: d_i8 integer(ESMF_KIND_I4), intent(out), optional :: h integer(ESMF_KIND_I4), intent(out), optional :: m integer(ESMF_KIND_I4), intent(out), optional :: s integer(ESMF_KIND_I8), intent(out), optional :: s_i8 integer(ESMF_KIND_I4), intent(out), optional :: ms integer(ESMF_KIND_I4), intent(out), optional :: us integer(ESMF_KIND_I4), intent(out), optional :: ns real(ESMF_KIND_R8), intent(out), optional :: d_r8 real(ESMF_KIND_R8), intent(out), optional :: h_r8 real(ESMF_KIND_R8), intent(out), optional :: m_r8 real(ESMF_KIND_R8), intent(out), optional :: s_r8 real(ESMF_KIND_R8), intent(out), optional :: ms_r8 real(ESMF_KIND_R8), intent(out), optional :: us_r8 real(ESMF_KIND_R8), intent(out), optional :: ns_r8 integer(ESMF_KIND_I4), intent(out), optional :: sN integer(ESMF_KIND_I8), intent(out), optional :: sN_i8 integer(ESMF_KIND_I4), intent(out), optional :: sD integer(ESMF_KIND_I8), intent(out), optional :: sD_i8 type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag integer, intent(out), optional :: timeZone ! not imp character (len=*), intent(out), optional :: timeString character (len=*), intent(out), optional :: timeStringISOFrac integer, intent(out), optional :: dayOfWeek type(ESMF_Time), intent(out), optional :: midMonth integer(ESMF_KIND_I4), intent(out), optional :: dayOfYear real(ESMF_KIND_R8), intent(out), optional :: dayOfYear_r8 type(ESMF_TimeInterval), intent(out), optional :: dayOfYear_intvl integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the value of time in units specified by the user via Fortran optional arguments. See ESMF_TimeSet() above for a description of time units and calendars.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally from integers. For example, if a time value is 5 and 3/8 seconds (s=5, sN=3, sD=8), and you want to get it as floating point seconds, you would get 5.375 (s_r8=5.375).
Units are bound (normalized) by the next larger unit specified. For example, if a time is defined to be 2:00 am on February 2, 2004, then ESMF_TimeGet(dd=day, h=hours, s=seconds) would return day = 2, hours = 2, seconds = 0, whereas ESMF_TimeGet(dd = day, s=seconds) would return day = 2, seconds = 7200. Note that hours and seconds are bound by a day. If bound by a month, ESMF_TimeGet(mm=month, h=hours, s=seconds) would return month = 2, hours = 26, seconds = 0, and ESMF_TimeGet(mm = month, s=seconds) would return month = 2, seconds = 93600 (26 * 3600). Similarly, if bound to a year, ESMF_TimeGet(yy=year, h=hours, s=seconds) would return year = 2004, hours = 770 (32*24 + 2), seconds = 0, and ESMF_TimeGet(yy = year, s=seconds) would return year = 2004, seconds = 2772000 (770 * 3600).
For timeString, timeStringISOFrac, dayOfWeek,
midMonth, dayOfYear, dayOfYear_intvl, and
dayOfYear_r8 described below, valid calendars are Gregorian,
Julian, No Leap, 360 Day and Custom calendars. Not valid for
Julian Day, Modified Julian Day, or No Calendar.
For timeString and timeStringISOFrac, YYYY format returns at least 4 digits; years <= 999 are padded on the left with zeroes and years >= 10000 return the number of digits required.
For timeString, convert ESMF_Time's value into partial ISO 8601 format YYYY-MM-DDThh:mm:ss[:n/d]. See [24] and [14]. See also method ESMF_TimePrint().
For timeStringISOFrac, convert ESMF_Time's value into full ISO 8601 format YYYY-MM-DDThh:mm:ss[.f]. See [24] and [14]. See also method ESMF_TimePrint().
For dayOfWeek, gets the day of the week the given ESMF_Time instant falls on. ISO 8601 standard: Monday = 1 through Sunday = 7. See [24] and [14].
For midMonth, gets the middle time instant of the month that the given ESMF_Time instant falls on.
For dayOfYear, gets the day of the year that the given ESMF_Time instant falls on. See range discussion in argument list below. Return as an integer value.
For dayOfYear_r8, gets the day of the year the given ESMF_Time instant falls on. See range discussion in argument list below. Return as floating point value; fractional part represents the time of day.
For dayOfYear_intvl, gets the day of the year the given ESMF_Time instant falls on. Return as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
function ESMF_TimeIsLeapYear(time, rc)RETURN VALUE:
logical :: ESMF_TimeIsLeapYearARGUMENTS:
type(ESMF_Time), intent(in) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns .true. if given time is in a leap year, and .false. otherwise. See also ESMF_CalendarIsLeapYear().
The arguments are:
INTERFACE:
function ESMF_TimeIsSameCalendar(time1, time2, rc)RETURN VALUE:
logical :: ESMF_TimeIsSameCalendarARGUMENTS:
type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns .true. if the Calendars in these Times are the same, .false. otherwise.
The arguments are:
INTERFACE:
subroutine ESMF_TimePrint(time, options, preString, unit, rc)ARGUMENTS:
type(ESMF_Time), intent(in) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character (len=*), intent(in), optional :: options character(*), intent(in), optional :: preString character(*), intent(out), optional :: unit integer, intent(out), optional :: rcDESCRIPTION:
Prints out the contents of an ESMF_Time to stdout, in
support of testing and debugging. The options control the type of
information and level of detail. For options "string" and "string
isofrac", YYYY format returns at least 4 digits; years <= 999 are
padded on the left with zeroes and years >= 10000 return the number
of digits required.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeSet() subroutine ESMF_TimeSetDefault(time, & yy, yy_i8, & mm, dd, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & calendar, calkindflag, & timeZone, rc)ARGUMENTS:
type(ESMF_Time), intent(inout) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(in), optional :: yy integer(ESMF_KIND_I8), intent(in), optional :: yy_i8 integer, intent(in), optional :: mm integer, intent(in), optional :: dd integer(ESMF_KIND_I4), intent(in), optional :: d integer(ESMF_KIND_I8), intent(in), optional :: d_i8 integer(ESMF_KIND_I4), intent(in), optional :: h integer(ESMF_KIND_I4), intent(in), optional :: m integer(ESMF_KIND_I4), intent(in), optional :: s integer(ESMF_KIND_I8), intent(in), optional :: s_i8 integer(ESMF_KIND_I4), intent(in), optional :: ms integer(ESMF_KIND_I4), intent(in), optional :: us integer(ESMF_KIND_I4), intent(in), optional :: ns real(ESMF_KIND_R8), intent(in), optional :: d_r8 real(ESMF_KIND_R8), intent(in), optional :: h_r8 real(ESMF_KIND_R8), intent(in), optional :: m_r8 real(ESMF_KIND_R8), intent(in), optional :: s_r8 real(ESMF_KIND_R8), intent(in), optional :: ms_r8 real(ESMF_KIND_R8), intent(in), optional :: us_r8 real(ESMF_KIND_R8), intent(in), optional :: ns_r8 integer(ESMF_KIND_I4), intent(in), optional :: sN integer(ESMF_KIND_I8), intent(in), optional :: sN_i8 integer(ESMF_KIND_I4), intent(in), optional :: sD integer(ESMF_KIND_I8), intent(in), optional :: sD_i8 type(ESMF_Calendar), intent(in), optional :: calendar type(ESMF_CalKind_Flag), intent(in), optional :: calkindflag integer, intent(in), optional :: timeZone ! not imp integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Initializes an ESMF_Time with a set of user-specified units via Fortran optional arguments.
The range of valid values for mm and dd depend on the calendar used. For Gregorian, Julian, and No-Leap calendars, mm is [1-12] and dd is [1-28,29,30, or 31], depending on the value of mm and whether yy or yy_i8 is a leap year. For the 360-day calendar, mm is [1-12] and dd is [1-30]. For Julian Day, Modified Julian Day, and No-Calendar, yy, yy_i8, mm, and dd are invalid inputs, since these calendars do not define them. When valid, the yy and yy_i8 arguments should be fully specified, e.g. 2003 instead of 03. yy and yy_i8 ranges are only limited by machine word size, except for the Gregorian and Julian calendars, where the lowest (proleptic) date limits are 3/1/-4800 and 3/1/-4712, respectively. This is a limitation of the Gregorian date-to-Julian day and Julian date-to-Julian day conversion algorithms used to convert Gregorian and Julian dates to the internal representation of seconds. See [21] for a description of the Gregorian date-to-Julian day algorithm and [23] for a description of the Julian date-to-Julian day algorithm. The Custom calendar will have user-defined values for yy, yy_i8, mm, and dd.
The Julian day specifier, d or d_i8, can only be used with the Julian Day and Modified Julian Day calendars, and has a valid range depending on the word size. For a signed 32-bit d, the range for Julian day is [+/- 24855]. For a signed 64-bit d_i8, the valid range for Julian day is [+/- 106,751,991,167,300]. The Julian day number system adheres to the conventional standard where the reference day of d=0 corresponds to 11/24/-4713 in the proleptic Gregorian calendar and 1/1/-4712 in the proleptic Julian calendar. See [27] and [12].
The Modified Julian Day system, introduced by space scientists in the late 1950's, is defined as Julian Day - 2400000.5. See [31].
Note that d and d_i8 are not valid for the No-Calendar. To remain consistent with non-Earth calendars added to ESMF in the future, ESMF requires a calendar to be planet-specific. Hence the No-Calendar does not know what a day is; it cannot assume an Earth day of 86400 seconds.
Hours, minutes, seconds, and sub-seconds can be used with any calendar, since they are standardized units that are the same for any planet.
Time manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally to integers. Sub-second values are represented internally with an integer numerator and denominator fraction (sN/sD). The smallest required resolution is nanoseconds (denominator). For example, pi can be represented as s=3, sN=141592654, sD=1000000000. However, via sN_i8 and sD_i8, larger values can be used. If specifying a constant floating point value, be sure to provide at least 16 digits to take full advantage of double precision, for example s_r8=2.718281828459045d0 for 'e' seconds.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeSet() subroutine ESMF_TimeSetString(time, timeString, rc)ARGUMENTS:
type(ESMF_Time), intent(inout) :: time character(*), intent(in) :: timeString integer, intent(out), optional :: rcDESCRIPTION:
Initializes an ESMF_Time with a set of user-specified string.
The arguments are:
INTERFACE:
subroutine ESMF_TimeSyncToRealTime(time, rc)ARGUMENTS:
type(ESMF_Time), intent(inout) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the system real time (wall clock time), and returns it as an ESMF_Time. Accurate to the nearest second.
The arguments are:
INTERFACE:
subroutine ESMF_TimeValidate(time, options, rc)ARGUMENTS:
type(ESMF_Time), intent(in) :: time character (len=*), intent(in), optional :: options integer, intent(out), optional :: rcDESCRIPTION:
Checks whether an ESMF_Time is valid. Must be a valid date/time on a valid calendar. The options control the type of validation.
The arguments are:
There are TimeInterval methods defined for setting and getting a TimeInterval, for incrementing and decrementing a TimeInterval by another TimeInterval, and for multiplying and dividing TimeIntervals by integers, reals, fractions and other TimeIntervals. Methods are also defined to take the absolute value and negative absolute value of a TimeInterval, and for comparing the length of two TimeIntervals.
The class used to represent time instants in ESMF is Time, and this class is frequently used in operations along with TimeIntervals. For example, the difference between two Times is a TimeInterval.
When a TimeInterval is used in calculations that involve an absolute reference time, such as incrementing a Time with a TimeInterval, calendar dependencies may be introduced. The length of the time period that the TimeInterval represents will depend on the reference Time and the standard calendar that is associated with it. The calendar dependency becomes apparent when, for example, adding a TimeInterval of 1 day to the Time of February 28, 1996, at 4:00pm EST. In a 360 day calendar, the resulting date would be February 29, 1996, at 4:00pm EST. In a no-leap calendar, the result would be March 1, 1996, at 4:00pm EST.
TimeIntervals are used by other parts of the ESMF timekeeping system, such as Clocks (Section 45.1) and Alarms (Section 46.1).
A typical use for a TimeInterval in a geophysical model is representation of the time step by which the model is advanced. Some models change the size of their time step as the model run progresses; this could be done by incrementing or decrementing the original time step by another TimeInterval, or by dividing or multiplying the time step by an integer value. An example of advancing model time using a TimeInterval representation of a time step is shown in Section 45.1.
The following brief example shows how to create, initialize and manipulate TimeInterval.
! !PROGRAM: ESMF_TimeIntervalEx - Time Interval initialization and ! manipulation examples ! ! !DESCRIPTION: ! ! This program shows examples of Time Interval initialization and manipulation !----------------------------------------------------------------------------- #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! instantiate some time intervals type(ESMF_TimeInterval) :: timeinterval1, timeinterval2, timeinterval3 ! local variables integer :: d, h, m, s ! return code integer:: rc
! initialize ESMF framework call ESMF_Initialize(defaultCalKind=ESMF_CALKIND_GREGORIAN, & defaultlogfilename="TimeIntervalEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
This example shows how to initialize two ESMF_TimeIntervals.
! initialize time interval1 to 1 day call ESMF_TimeIntervalSet(timeinterval1, d=1, rc=rc)
call ESMF_TimeIntervalPrint(timeinterval1, options="string", rc=rc)
! initialize time interval2 to 4 days, 1 hour, 30 minutes, 10 seconds call ESMF_TimeIntervalSet(timeinterval2, d=4, h=1, m=30, s=10, rc=rc)
call ESMF_TimeIntervalPrint(timeinterval2, options="string", rc=rc)
This example shows how to convert ESMF_TimeIntervals into different units.
call ESMF_TimeIntervalGet(timeinterval1, s=s, rc=rc) print *, "Time Interval1 = ", s, " seconds."
call ESMF_TimeIntervalGet(timeinterval2, h=h, m=m, s=s, rc=rc) print *, "Time Interval2 = ", h, " hours, ", m, " minutes, ", & s, " seconds."
This example shows how to calculate the difference between two ESMF_TimeIntervals.
! difference between two time intervals timeinterval3 = timeinterval2 - timeinterval1 call ESMF_TimeIntervalGet(timeinterval3, d=d, h=h, m=m, s=s, rc=rc) print *, "Difference between TimeInterval2 and TimeInterval1 = ", & d, " days, ", h, " hours, ", m, " minutes, ", s, " seconds."
This example shows how to multiply an ESMF_TimeInterval.
! multiply time interval by an integer timeinterval3 = timeinterval2 * 3 call ESMF_TimeIntervalGet(timeinterval3, d=d, h=h, m=m, s=s, rc=rc) print *, "TimeInterval2 multiplied by 3 = ", d, " days, ", h, & " hours, ", m, " minutes, ", s, " seconds."
This example shows how to compare two ESMF_TimeIntervals.
! comparison if (timeinterval1 < timeinterval2) then print *, "TimeInterval1 is smaller than TimeInterval2" else print *, "TimeInterval1 is larger than or equal to TimeInterval2" end if
end program ESMF_TimeIntervalEx
For fractional seconds, a signed 64-bit integer will handle a resolution of +/- -1, or +/- 9,223,372,036,854,775,807 parts of a second.
INTERFACE:
interface assignment(=) timeinterval1 = timeinterval2ARGUMENTS:
type(ESMF_TimeInterval) :: timeinterval1 type(ESMF_TimeInterval) :: timeinterval2STATUS:
DESCRIPTION:
Set timeinterval1 equal to timeinterval2. This is the default Fortran assignment, which creates a complete, independent copy of timeinterval2 as timeinterval1. If timeinterval2 is an invalid ESMF_TimeInterval object then timeinterval1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(+) sum = timeinterval1 + timeinterval2RETURN VALUE:
type(ESMF_TimeInterval) :: sumARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (+) operator for the ESMF_TimeInterval class to add timeinterval1 to timeinterval2 and return the sum as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
interface operator(-) difference = timeinterval1 - timeinterval2RETURN VALUE:
type(ESMF_TimeInterval) :: differenceARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (-) operator for the ESMF_TimeInterval class to subtract timeinterval2 from timeinterval1 and return the difference as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
interface operator(-) timeinterval = -timeintervalRETURN VALUE:
type(ESMF_TimeInterval) :: -timeIntervalARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeintervalSTATUS:
DESCRIPTION:
Overloads the (-) operator for the ESMF_TimeInterval class to perform unary negation on timeinterval and return the result.
The arguments are:
INTERFACE:
interface operator(/) quotient = timeinterval1 / timeinterval2RETURN VALUE:
real(ESMF_KIND_R8) :: quotientARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (/) operator for the ESMF_TimeInterval class to return timeinterval1 divided by timeinterval2 as a double precision quotient.
The arguments are:
INTERFACE:
interface operator(/) quotient = timeinterval / divisorRETURN VALUE:
type(ESMF_TimeInterval) :: quotientARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval integer(ESMF_KIND_I4), intent(in) :: divisorSTATUS:
DESCRIPTION:
Overloads the (/) operator for the ESMF_TimeInterval class to divide a timeinterval by an integer divisor, and return the quotient as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
interface MOD function MOD(timeinterval1, timeinterval2)RETURN VALUE:
type(ESMF_TimeInterval) :: MODARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the Fortran intrinsic MOD() function for the ESMF_TimeInterval class to return the remainder of timeinterval1 divided by timeinterval2 as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
interface operator(*) product = timeinterval * multiplier OR product = multiplier * timeintervalRETURN VALUE:
type(ESMF_TimeInterval) :: productARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval integer(ESMF_KIND_I4), intent(in) :: multiplierSTATUS:
DESCRIPTION:
Overloads the (*) operator for the ESMF_TimeInterval class to multiply a timeinterval by an integer multiplier, and return the product as an ESMF_TimeInterval.
The arguments are:
INTERFACE:
interface operator(==) if (timeinterval1 == timeinterval2) then ... endif OR result = (timeinterval1 == timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (==) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 and timeinterval2 represent an equal duration of time, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(/=) if (timeinterval1 /= timeinterval2) then ... endif OR result = (timeinterval1 /= timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (/=) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 and timeinterval2 do not represent an equal duration of time, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(<) if (timeinterval1 < timeinterval2) then ... endif OR result = (timeinterval1 < timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (<) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 is a lesser duration of time than timeinterval2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(<=) if (timeinterval1 <= timeinterval2) then ... endif OR result = (timeinterval1 <= timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (<=) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 is a lesser or equal duration of time than timeinterval2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(>) if (timeinterval1 > timeinterval2) then ... endif OR result = (timeinterval1 > timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (>) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 is a greater duration of time than timeinterval2, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(>=) if (timeinterval1 >= timeinterval2) then ... endif OR result = (timeinterval1 >= timeinterval2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval1 type(ESMF_TimeInterval), intent(in) :: timeinterval2STATUS:
DESCRIPTION:
Overloads the (>=) operator for the ESMF_TimeInterval class to return .true. if timeinterval1 is a greater or equal duration of time than timeinterval2, and .false. otherwise.
The arguments are:
INTERFACE:
function ESMF_TimeIntervalAbsValue(timeinterval)RETURN VALUE:
type(ESMF_TimeInterval) :: ESMF_TimeIntervalAbsValueARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeintervalSTATUS:
DESCRIPTION:
Returns the absolute value of timeinterval.
The argument is:
INTERFACE:
! Private name; call using ESMF_TimeIntervalGet() subroutine ESMF_TimeIntervalGetDur(timeinterval, & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & startTime, calendar, calkindflag, & timeString, timeStringISOFrac, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(out), optional :: yy integer(ESMF_KIND_I8), intent(out), optional :: yy_i8 integer(ESMF_KIND_I4), intent(out), optional :: mm integer(ESMF_KIND_I8), intent(out), optional :: mm_i8 integer(ESMF_KIND_I4), intent(out), optional :: d integer(ESMF_KIND_I8), intent(out), optional :: d_i8 integer(ESMF_KIND_I4), intent(out), optional :: h integer(ESMF_KIND_I4), intent(out), optional :: m integer(ESMF_KIND_I4), intent(out), optional :: s integer(ESMF_KIND_I8), intent(out), optional :: s_i8 integer(ESMF_KIND_I4), intent(out), optional :: ms integer(ESMF_KIND_I4), intent(out), optional :: us integer(ESMF_KIND_I4), intent(out), optional :: ns real(ESMF_KIND_R8), intent(out), optional :: d_r8 real(ESMF_KIND_R8), intent(out), optional :: h_r8 real(ESMF_KIND_R8), intent(out), optional :: m_r8 real(ESMF_KIND_R8), intent(out), optional :: s_r8 real(ESMF_KIND_R8), intent(out), optional :: ms_r8 real(ESMF_KIND_R8), intent(out), optional :: us_r8 real(ESMF_KIND_R8), intent(out), optional :: ns_r8 integer(ESMF_KIND_I4), intent(out), optional :: sN integer(ESMF_KIND_I8), intent(out), optional :: sN_i8 integer(ESMF_KIND_I4), intent(out), optional :: sD integer(ESMF_KIND_I8), intent(out), optional :: sD_i8 type(ESMF_Time), intent(out), optional :: startTime type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag character (len=*), intent(out), optional :: timeString character (len=*), intent(out), optional :: timeStringISOFrac integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the value of timeinterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally from integers.
Units are bound (normalized) to the next larger unit specified. For example, if a time interval is defined to be one day, then ESMF_TimeIntervalGet(d = days, s = seconds) would return days = 1, seconds = 0, whereas ESMF_TimeIntervalGet(s = seconds) would return seconds = 86400.
For timeString, converts ESMF_TimeInterval's value into partial ISO 8601 format PyYmMdDThHmMs[:n/d]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
For timeStringISOFrac, converts ESMF_TimeInterval's value into full ISO 8601 format PyYmMdDThHmMs[.f]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalGet() subroutine ESMF_TimeIntervalGetDurStart(timeinterval, startTimeIn, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & startTime, & calendar, calkindflag, & timeString, timeStringISOFrac, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval type(ESMF_Time), intent(in) :: startTimeIn ! Input -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(out), optional :: yy integer(ESMF_KIND_I8), intent(out), optional :: yy_i8 integer(ESMF_KIND_I4), intent(out), optional :: mm integer(ESMF_KIND_I8), intent(out), optional :: mm_i8 integer(ESMF_KIND_I4), intent(out), optional :: d integer(ESMF_KIND_I8), intent(out), optional :: d_i8 integer(ESMF_KIND_I4), intent(out), optional :: h integer(ESMF_KIND_I4), intent(out), optional :: m integer(ESMF_KIND_I4), intent(out), optional :: s integer(ESMF_KIND_I8), intent(out), optional :: s_i8 integer(ESMF_KIND_I4), intent(out), optional :: ms integer(ESMF_KIND_I4), intent(out), optional :: us integer(ESMF_KIND_I4), intent(out), optional :: ns real(ESMF_KIND_R8), intent(out), optional :: d_r8 real(ESMF_KIND_R8), intent(out), optional :: h_r8 real(ESMF_KIND_R8), intent(out), optional :: m_r8 real(ESMF_KIND_R8), intent(out), optional :: s_r8 real(ESMF_KIND_R8), intent(out), optional :: ms_r8 real(ESMF_KIND_R8), intent(out), optional :: us_r8 real(ESMF_KIND_R8), intent(out), optional :: ns_r8 integer(ESMF_KIND_I4), intent(out), optional :: sN integer(ESMF_KIND_I8), intent(out), optional :: sN_i8 integer(ESMF_KIND_I4), intent(out), optional :: sD integer(ESMF_KIND_I8), intent(out), optional :: sD_i8 type(ESMF_Time), intent(out), optional :: startTime type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag character (len=*), intent(out), optional :: timeString character (len=*), intent(out), optional :: timeStringISOFrac integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the value of timeinterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally from integers.
Units are bound (normalized) to the next larger unit specified. For example, if a time interval is defined to be one day, then ESMF_TimeIntervalGet(d = days, s = seconds) would return days = 1, seconds = 0, whereas ESMF_TimeIntervalGet(s = seconds) would return seconds = 86400.
For timeString, converts ESMF_TimeInterval's value into partial ISO 8601 format PyYmMdDThHmMs[:n/d]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
For timeStringISOFrac, converts ESMF_TimeInterval's value into full ISO 8601 format PyYmMdDThHmMs[.f]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalGet() subroutine ESMF_TimeIntervalGetDurCal(timeinterval, calendarIn, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & startTime, & calendar, calkindflag, & timeString, timeStringISOFrac, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval type(ESMF_Calendar), intent(in) :: calendarIn ! Input -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(out), optional :: yy integer(ESMF_KIND_I8), intent(out), optional :: yy_i8 integer(ESMF_KIND_I4), intent(out), optional :: mm integer(ESMF_KIND_I8), intent(out), optional :: mm_i8 integer(ESMF_KIND_I4), intent(out), optional :: d integer(ESMF_KIND_I8), intent(out), optional :: d_i8 integer(ESMF_KIND_I4), intent(out), optional :: h integer(ESMF_KIND_I4), intent(out), optional :: m integer(ESMF_KIND_I4), intent(out), optional :: s integer(ESMF_KIND_I8), intent(out), optional :: s_i8 integer(ESMF_KIND_I4), intent(out), optional :: ms integer(ESMF_KIND_I4), intent(out), optional :: us integer(ESMF_KIND_I4), intent(out), optional :: ns real(ESMF_KIND_R8), intent(out), optional :: d_r8 real(ESMF_KIND_R8), intent(out), optional :: h_r8 real(ESMF_KIND_R8), intent(out), optional :: m_r8 real(ESMF_KIND_R8), intent(out), optional :: s_r8 real(ESMF_KIND_R8), intent(out), optional :: ms_r8 real(ESMF_KIND_R8), intent(out), optional :: us_r8 real(ESMF_KIND_R8), intent(out), optional :: ns_r8 integer(ESMF_KIND_I4), intent(out), optional :: sN integer(ESMF_KIND_I8), intent(out), optional :: sN_i8 integer(ESMF_KIND_I4), intent(out), optional :: sD integer(ESMF_KIND_I8), intent(out), optional :: sD_i8 type(ESMF_Time), intent(out), optional :: startTime type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag character (len=*), intent(out), optional :: timeString character (len=*), intent(out), optional :: timeStringISOFrac integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the value of timeinterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally from integers.
Units are bound (normalized) to the next larger unit specified. For example, if a time interval is defined to be one day, then ESMF_TimeIntervalGet(d = days, s = seconds) would return days = 1, seconds = 0, whereas ESMF_TimeIntervalGet(s = seconds) would return seconds = 86400.
For timeString, converts ESMF_TimeInterval's value into partial ISO 8601 format PyYmMdDThHmMs[:n/d]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
For timeStringISOFrac, converts ESMF_TimeInterval's value into full ISO 8601 format PyYmMdDThHmMs[.f]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalGet() subroutine ESMF_TimeIntervalGetDurCalTyp(timeinterval, calkindflagIn, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & startTime, & calendar, calkindflag, & timeString, & timeStringISOFrac, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval type(ESMF_CalKind_Flag), intent(in) :: calkindflagIn ! Input -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(out), optional :: yy integer(ESMF_KIND_I8), intent(out), optional :: yy_i8 integer(ESMF_KIND_I4), intent(out), optional :: mm integer(ESMF_KIND_I8), intent(out), optional :: mm_i8 integer(ESMF_KIND_I4), intent(out), optional :: d integer(ESMF_KIND_I8), intent(out), optional :: d_i8 integer(ESMF_KIND_I4), intent(out), optional :: h integer(ESMF_KIND_I4), intent(out), optional :: m integer(ESMF_KIND_I4), intent(out), optional :: s integer(ESMF_KIND_I8), intent(out), optional :: s_i8 integer(ESMF_KIND_I4), intent(out), optional :: ms integer(ESMF_KIND_I4), intent(out), optional :: us integer(ESMF_KIND_I4), intent(out), optional :: ns real(ESMF_KIND_R8), intent(out), optional :: d_r8 real(ESMF_KIND_R8), intent(out), optional :: h_r8 real(ESMF_KIND_R8), intent(out), optional :: m_r8 real(ESMF_KIND_R8), intent(out), optional :: s_r8 real(ESMF_KIND_R8), intent(out), optional :: ms_r8 real(ESMF_KIND_R8), intent(out), optional :: us_r8 real(ESMF_KIND_R8), intent(out), optional :: ns_r8 integer(ESMF_KIND_I4), intent(out), optional :: sN integer(ESMF_KIND_I8), intent(out), optional :: sN_i8 integer(ESMF_KIND_I4), intent(out), optional :: sD integer(ESMF_KIND_I8), intent(out), optional :: sD_i8 type(ESMF_Time), intent(out), optional :: startTime type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag character (len=*), intent(out), optional :: timeString character (len=*), intent(out), optional :: timeStringISOFrac integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the value of timeinterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally from integers.
Units are bound (normalized) to the next larger unit specified. For example, if a time interval is defined to be one day, then ESMF_TimeIntervalGet(d = days, s = seconds) would return days = 1, seconds = 0, whereas ESMF_TimeIntervalGet(s = seconds) would return seconds = 86400.
For timeString, converts ESMF_TimeInterval's value into partial ISO 8601 format PyYmMdDThHmMs[:n/d]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
For timeStringISOFrac, converts ESMF_TimeInterval's value into full ISO 8601 format PyYmMdDThHmMs[.f]S. See [24] and [14]. See also method ESMF_TimeIntervalPrint().
The arguments are:
INTERFACE:
function ESMF_TimeIntervalNegAbsValue(timeinterval)RETURN VALUE:
type(ESMF_TimeInterval) :: ESMF_TimeIntervalNegAbsValueARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeintervalSTATUS:
DESCRIPTION:
Returns the negative absolute value of timeinterval.
The argument is:
INTERFACE:
subroutine ESMF_TimeIntervalPrint(timeinterval, options, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval character (len=*), intent(in), optional :: options integer, intent(out), optional :: rcDESCRIPTION:
Prints out the contents of an ESMF_TimeInterval to stdout,
in support of testing and debugging. The options control the type of
information and level of detail.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetDur(timeinterval, & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(in), optional :: yy integer(ESMF_KIND_I8), intent(in), optional :: yy_i8 integer(ESMF_KIND_I4), intent(in), optional :: mm integer(ESMF_KIND_I8), intent(in), optional :: mm_i8 integer(ESMF_KIND_I4), intent(in), optional :: d integer(ESMF_KIND_I8), intent(in), optional :: d_i8 integer(ESMF_KIND_I4), intent(in), optional :: h integer(ESMF_KIND_I4), intent(in), optional :: m integer(ESMF_KIND_I4), intent(in), optional :: s integer(ESMF_KIND_I8), intent(in), optional :: s_i8 integer(ESMF_KIND_I4), intent(in), optional :: ms integer(ESMF_KIND_I4), intent(in), optional :: us integer(ESMF_KIND_I4), intent(in), optional :: ns real(ESMF_KIND_R8), intent(in), optional :: d_r8 real(ESMF_KIND_R8), intent(in), optional :: h_r8 real(ESMF_KIND_R8), intent(in), optional :: m_r8 real(ESMF_KIND_R8), intent(in), optional :: s_r8 real(ESMF_KIND_R8), intent(in), optional :: ms_r8 real(ESMF_KIND_R8), intent(in), optional :: us_r8 real(ESMF_KIND_R8), intent(in), optional :: ns_r8 integer(ESMF_KIND_I4), intent(in), optional :: sN integer(ESMF_KIND_I8), intent(in), optional :: sN_i8 integer(ESMF_KIND_I4), intent(in), optional :: sD integer(ESMF_KIND_I8), intent(in), optional :: sD_i8 integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets the value of the ESMF_TimeInterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally to integers.
Ranges are limited only by machine word size. Numeric defaults are 0, except for sD, which is 1.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetDurStart(timeinterval, startTime, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_Time), intent(in) :: startTime -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(in), optional :: yy integer(ESMF_KIND_I8), intent(in), optional :: yy_i8 integer(ESMF_KIND_I4), intent(in), optional :: mm integer(ESMF_KIND_I8), intent(in), optional :: mm_i8 integer(ESMF_KIND_I4), intent(in), optional :: d integer(ESMF_KIND_I8), intent(in), optional :: d_i8 integer(ESMF_KIND_I4), intent(in), optional :: h integer(ESMF_KIND_I4), intent(in), optional :: m integer(ESMF_KIND_I4), intent(in), optional :: s integer(ESMF_KIND_I8), intent(in), optional :: s_i8 integer(ESMF_KIND_I4), intent(in), optional :: ms integer(ESMF_KIND_I4), intent(in), optional :: us integer(ESMF_KIND_I4), intent(in), optional :: ns real(ESMF_KIND_R8), intent(in), optional :: d_r8 real(ESMF_KIND_R8), intent(in), optional :: h_r8 real(ESMF_KIND_R8), intent(in), optional :: m_r8 real(ESMF_KIND_R8), intent(in), optional :: s_r8 real(ESMF_KIND_R8), intent(in), optional :: ms_r8 real(ESMF_KIND_R8), intent(in), optional :: us_r8 real(ESMF_KIND_R8), intent(in), optional :: ns_r8 integer(ESMF_KIND_I4), intent(in), optional :: sN integer(ESMF_KIND_I8), intent(in), optional :: sN_i8 integer(ESMF_KIND_I4), intent(in), optional :: sD integer(ESMF_KIND_I8), intent(in), optional :: sD_i8 integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets the value of the ESMF_TimeInterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally to integers.
Ranges are limited only by machine word size. Numeric defaults are 0, except for sD, which is 1.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetDurCal(timeinterval, calendar, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_Calendar), intent(in) :: calendar -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(in), optional :: yy integer(ESMF_KIND_I8), intent(in), optional :: yy_i8 integer(ESMF_KIND_I4), intent(in), optional :: mm integer(ESMF_KIND_I8), intent(in), optional :: mm_i8 integer(ESMF_KIND_I4), intent(in), optional :: d integer(ESMF_KIND_I8), intent(in), optional :: d_i8 integer(ESMF_KIND_I4), intent(in), optional :: h integer(ESMF_KIND_I4), intent(in), optional :: m integer(ESMF_KIND_I4), intent(in), optional :: s integer(ESMF_KIND_I8), intent(in), optional :: s_i8 integer(ESMF_KIND_I4), intent(in), optional :: ms integer(ESMF_KIND_I4), intent(in), optional :: us integer(ESMF_KIND_I4), intent(in), optional :: ns real(ESMF_KIND_R8), intent(in), optional :: d_r8 real(ESMF_KIND_R8), intent(in), optional :: h_r8 real(ESMF_KIND_R8), intent(in), optional :: m_r8 real(ESMF_KIND_R8), intent(in), optional :: s_r8 real(ESMF_KIND_R8), intent(in), optional :: ms_r8 real(ESMF_KIND_R8), intent(in), optional :: us_r8 real(ESMF_KIND_R8), intent(in), optional :: ns_r8 integer(ESMF_KIND_I4), intent(in), optional :: sN integer(ESMF_KIND_I8), intent(in), optional :: sN_i8 integer(ESMF_KIND_I4), intent(in), optional :: sD integer(ESMF_KIND_I8), intent(in), optional :: sD_i8 integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets the value of the ESMF_TimeInterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally to integers.
Ranges are limited only by machine word size. Numeric defaults are 0, except for sD, which is 1.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetDurCalTyp(timeinterval, calkindflag, & & yy, yy_i8, & mm, mm_i8, & d, d_i8, & h, m, & s, s_i8, & ms, us, ns, & d_r8, h_r8, m_r8, s_r8, & ms_r8, us_r8, ns_r8, & sN, sN_i8, sD, sD_i8, & rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_CalKind_Flag), intent(in) :: calkindflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer(ESMF_KIND_I4), intent(in), optional :: yy integer(ESMF_KIND_I8), intent(in), optional :: yy_i8 integer(ESMF_KIND_I4), intent(in), optional :: mm integer(ESMF_KIND_I8), intent(in), optional :: mm_i8 integer(ESMF_KIND_I4), intent(in), optional :: d integer(ESMF_KIND_I8), intent(in), optional :: d_i8 integer(ESMF_KIND_I4), intent(in), optional :: h integer(ESMF_KIND_I4), intent(in), optional :: m integer(ESMF_KIND_I4), intent(in), optional :: s integer(ESMF_KIND_I8), intent(in), optional :: s_i8 integer(ESMF_KIND_I4), intent(in), optional :: ms integer(ESMF_KIND_I4), intent(in), optional :: us integer(ESMF_KIND_I4), intent(in), optional :: ns real(ESMF_KIND_R8), intent(in), optional :: d_r8 real(ESMF_KIND_R8), intent(in), optional :: h_r8 real(ESMF_KIND_R8), intent(in), optional :: m_r8 real(ESMF_KIND_R8), intent(in), optional :: s_r8 real(ESMF_KIND_R8), intent(in), optional :: ms_r8 real(ESMF_KIND_R8), intent(in), optional :: us_r8 real(ESMF_KIND_R8), intent(in), optional :: ns_r8 integer(ESMF_KIND_I4), intent(in), optional :: sN integer(ESMF_KIND_I8), intent(in), optional :: sN_i8 integer(ESMF_KIND_I4), intent(in), optional :: sD integer(ESMF_KIND_I8), intent(in), optional :: sD_i8 integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets the value of the ESMF_TimeInterval in units specified by the user via Fortran optional arguments.
The ESMF Time Manager represents and manipulates time internally with integers to maintain precision. Hence, user-specified floating point values are converted internally to integers.
Ranges are limited only by machine word size. Numeric defaults are 0, except for sD, which is 1.
The arguments are:
INTERFACE:
Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetStr(timeinterval, timeIntervalString, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval character(*), intent(in) :: timeIntervalString integer, intent(out), optional :: rcDESCRIPTION:
Sets the value of the ESMF_TimeInterval using a user specified string in ISO duration format P[y]Y[mm]M[d]DT[h]H[m]M[s]S. See [24] and [14] for information about the format. In ESMF's implementation the time values can have the following types:
As with the ISO format, in ESMF's implementation the specifier and value can be left out if the value is 0. For example, P1YT1H3M4S is a valid format if the number of months and days are both 0. The time part including the T can also be left off if the time values are all 0, so P1Y is a valid string if just 1 year is being specified.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetStrCal(timeinterval, calendar, & timeIntervalString, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_Calendar), intent(in) :: calendar character(*), intent(in) :: timeIntervalString integer, intent(out), optional :: rcDESCRIPTION:
Sets the value of the ESMF_TimeInterval using a user specified string in ISO duration format P[y]Y[mm]M[d]DT[h]H[m]M[s]S. See [24] and [14] for information about the format. Also, see the description for the method ESMF_TimeIntervalSetStr() 44.4.26 for the specific types supported by ESMF for the values in the duration string.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetStrCalTyp(timeinterval, calkindflag, & timeIntervalString, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_CalKind_Flag), intent(in) :: calkindflag character(*), intent(in) :: timeIntervalString integer, intent(out), optional :: rcDESCRIPTION:
Sets the value of the ESMF_TimeInterval using a user specified string in ISO duration format P[y]Y[mm]M[d]DT[h]H[m]M[s]S. See [24] and [14] for information about the format. Also, see the description for the method ESMF_TimeIntervalSetStr() 44.4.26 for the specific types supported by ESMF for the values in the duration string.
The arguments are:
INTERFACE:
! Private name; call using ESMF_TimeIntervalSet() subroutine ESMF_TimeIntervalSetStrStart(timeinterval, startTime, & timeIntervalString, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(inout) :: timeinterval type(ESMF_Time), intent(in) :: startTime character(*), intent(in) :: timeIntervalString integer, intent(out), optional :: rcDESCRIPTION:
Sets the value of the ESMF_TimeInterval using a user specified string in ISO duration format P[y]Y[mm]M[d]DT[h]H[m]M[s]S. See [24] and [14] for information about the format. Also, see the description for the method ESMF_TimeIntervalSetStr() 44.4.26 for the specific types supported by ESMF for the values in the duration string.
The arguments are:
INTERFACE:
subroutine ESMF_TimeIntervalValidate(timeinterval, rc)ARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeinterval -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Checks whether a timeinterval is valid. If fractional value, denominator must be non-zero.
The arguments are:
The Clock class advances model time and tracks its associated date on a specified Calendar. It stores start time, stop time, current time, previous time, and a time step. It can also store a reference time, typically the time instant at which a simulation originally began. For a restart run, the reference time can be different than the start time, when the application execution resumes.
A user can call the ESMF_ClockSet method and reset the time step as desired.
A Clock also stores a list of Alarms, which can be set to flag events that occur at a specified time instant or at a specified time interval. See Section 46.1 for details on how to use Alarms.
There are methods for setting and getting the Times and Alarms associated with a Clock. Methods are defined for advancing the Clock's current time, checking if the stop time has been reached, reversing direction, and synchronizing with a real clock.
DESCRIPTION:
Specifies the time-stepping direction of a clock. Use with "direction"
argument to methods ESMF_ClockSet() and ESMF_ClockGet().
Cannot be used with method ESMF_ClockCreate(), since it only
initializes a clock in the default forward mode; a clock must be advanced
(timestepped) at least once before reversing direction via
ESMF_ClockSet(). This also holds true for negative timestep clocks
which are initialized (created) with stopTime < startTime, since "forward"
means timestepping from startTime towards stopTime
(see ESMF_DIRECTION_FORWARD below).
"Forward" and "reverse" directions are distinct from positive and negative timesteps. "Forward" means timestepping in the direction established at ESMF_ClockCreate(), from startTime towards stopTime, regardless of the timestep sign. "Reverse" means timestepping in the opposite direction, back towards the clock's startTime, regardless of the timestep sign.
Clocks and alarms run in reverse in such a way that the state of a clock and its alarms after each time step is precisely replicated as it was in forward time-stepping mode. All methods which query clock and alarm state will return the same result for a given timeStep, regardless of the direction of arrival.
The type of this flag is:
type(ESMF_Direction_Flag)
The valid values are:
The following is a typical sequence for using a Clock in a geophysical model.
At initialize:
At run:
At finalize:
The following code example illustrates Clock usage.
! !PROGRAM: ESMF_ClockEx - Clock initialization and time-stepping ! ! !DESCRIPTION: ! ! This program shows an example of how to create, initialize, advance, and ! examine a basic clock !----------------------------------------------------------------------------- #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! instantiate a clock type(ESMF_Clock) :: clock ! instantiate time_step, start and stop times type(ESMF_TimeInterval) :: timeStep type(ESMF_Time) :: startTime type(ESMF_Time) :: stopTime ! local variables for Get methods type(ESMF_Time) :: currTime integer(ESMF_KIND_I8) :: advanceCount integer :: YY, MM, DD, H, M, S ! return code integer :: rc
! initialize ESMF framework call ESMF_Initialize(defaultCalKind=ESMF_CALKIND_GREGORIAN, & defaultlogfilename="ClockEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
This example shows how to create and initialize an ESMF_Clock.
! initialize time interval to 2 days, 4 hours (6 timesteps in 13 days) call ESMF_TimeIntervalSet(timeStep, d=2, h=4, rc=rc)
! initialize start time to 4/1/2003 2:24:00 ( 1/10 of a day ) call ESMF_TimeSet(startTime, yy=2003, mm=4, dd=1, h=2, m=24, rc=rc)
! initialize stop time to 4/14/2003 2:24:00 ( 1/10 of a day ) call ESMF_TimeSet(stopTime, yy=2003, mm=4, dd=14, h=2, m=24, rc=rc)
! initialize the clock with the above values clock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & name="Clock 1", rc=rc)
This example shows how to time-step an ESMF_Clock.
! time step clock from start time to stop time do while (.not.ESMF_ClockIsStopTime(clock, rc=rc))
call ESMF_ClockPrint(clock, options="currTime string", rc=rc)
call ESMF_ClockAdvance(clock, rc=rc)
end do
This example shows how to examine an ESMF_Clock.
! get the clock's final current time call ESMF_ClockGet(clock, currTime=currTime, rc=rc)
call ESMF_TimeGet(currTime, yy=YY, mm=MM, dd=DD, h=H, m=M, s=S, rc=rc) print *, "The clock's final current time is ", YY, "/", MM, "/", DD, & " ", H, ":", M, ":", S
! get the number of times the clock was advanced call ESMF_ClockGet(clock, advanceCount=advanceCount, rc=rc) print *, "The clock was advanced ", advanceCount, " times."
This example shows how to time-step an ESMF_Clock in reverse mode.
call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=rc)
! time step clock in reverse from stop time back to start time; ! note use of ESMF_ClockIsDone() rather than ESMF_ClockIsStopTime() do while (.not.ESMF_ClockIsDone(clock, rc=rc))
call ESMF_ClockPrint(clock, options="currTime string", rc=rc)
call ESMF_ClockAdvance(clock, rc=rc)
end do
This example shows how to destroy an ESMF_Clock.
! destroy clock call ESMF_ClockDestroy(clock, rc=rc)
! finalize ESMF framework call ESMF_Finalize(rc=rc)
end program ESMF_ClockEx
INTERFACE:
interface assignment(=) clock1 = clock2ARGUMENTS:
type(ESMF_Clock) :: clock1 type(ESMF_Clock) :: clock2STATUS:
DESCRIPTION:
Assign clock1 as an alias to the same ESMF_Clock object in memory as clock2. If clock2 is invalid, then clock1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (clock1 == clock2) then ... endif OR result = (clock1 == clock2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Clock), intent(in) :: clock1 type(ESMF_Clock), intent(in) :: clock2DESCRIPTION:
Overloads the (==) operator for the ESMF_Clock class. Compare two clocks for equality; return .true. if equal, .false. otherwise. Comparison is based on IDs, which are distinct for newly created clocks and identical for clocks created as copies.
If either side of the equality test is not in the ESMF_INIT_CREATED status an error will be logged. However, this does not affect the return value, which is .true. when both sides are in the same status, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(/=) if (clock1 /= clock2) then ... endif OR result = (clock1 /= clock2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Clock), intent(in) :: clock1 type(ESMF_Clock), intent(in) :: clock2DESCRIPTION:
Overloads the (/=) operator for the ESMF_Clock class. Compare two clocks for inequality; return .true. if not equal, .false. otherwise. Comparison is based on IDs, which are distinct for newly created clocks and identical for clocks created as copies.
If either side of the equality test is not in the ESMF_INIT_CREATED status an error will be logged. However, this does not affect the return value, which is .true. when both sides are not in the same status, and .false. otherwise.
The arguments are:
INTERFACE:
subroutine ESMF_ClockAdvance(clock, & timeStep, ringingAlarmList, ringingAlarmCount, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: timeStep type(ESMF_Alarm), intent(out), optional :: ringingAlarmList(:) integer, intent(out), optional :: ringingAlarmCount integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Advances the clock's current time by one time step: either the clock's, or the passed-in timeStep (see below). When the clock is in ESMF_DIRECTION_FORWARD (default), this method adds the timeStep to the clock's current time. In ESMF_DIRECTION_REVERSE, timeStep is subtracted from the current time. In either case, timeStep can be positive or negative. See the "direction" argument in method ESMF_ClockSet(). ESMF_ClockAdvance() optionally returns a list and number of ringing ESMF_Alarms. See also method ESMF_ClockGetRingingAlarms().
The arguments are:
INTERFACE:
! Private name; call using ESMF_ClockCreate() function ESMF_ClockCreateNew(timeStep, startTime, & stopTime, runDuration, runTimeStepCount, refTime, repeatDuration, name, rc)RETURN VALUE:
type(ESMF_Clock) :: ESMF_ClockCreateNewARGUMENTS:
type(ESMF_TimeInterval), intent(in) :: timeStep type(ESMF_Time), intent(in) :: startTime -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Time), intent(in), optional :: stopTime type(ESMF_TimeInterval), intent(in), optional :: runDuration integer, intent(in), optional :: runTimeStepCount type(ESMF_Time), intent(in), optional :: refTime type(ESMF_TimeInterval), intent(in), optional :: repeatDuration character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates and sets the initial values in a new ESMF_Clock.
The arguments are:
INTERFACE:
! Private name; call using ESMF_ClockCreate() function ESMF_ClockCreateCopy(clock, rc)RETURN VALUE:
type(ESMF_Clock) :: ESMF_ClockCreateCopyARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates a deep copy of a given ESMF_Clock, but does not copy its list of ESMF_Alarms (pointers), since an ESMF_Alarm can only be associated with one ESMF_Clock. Hence, the returned ESMF_Clock copy has no associated ESMF_Alarms, the same as with a newly created ESMF_Clock. If desired, new ESMF_Alarms must be created and associated with this copied ESMF_Clock via ESMF_AlarmCreate(), or existing ESMF_Alarms must be re-associated with this copied ESMF_Clock via ESMF_AlarmSet(...clock=...).
The arguments are:
INTERFACE:
subroutine ESMF_ClockDestroy(clock, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Releases resources associated with this ESMF_Clock. This releases the list of associated ESMF_Alarms (pointers), but not the ESMF_Alarms themselves; the user must explicitly call ESMF_AlarmDestroy() on each ESMF_Alarm to release its resources. ESMF_ClockDestroy() and corresponding ESMF_AlarmDestroy()s can be called in either order.
If ESMF_ClockDestroy() is called before ESMF_AlarmDestroy(), any ESMF_Alarms that were in the ESMF_Clock's list will no longer be associated with any ESMF_Clock. If desired, these "orphaned" ESMF_Alarms can be associated with a different ESMF_Clock via a call to ESMF_AlarmSet(...clock=...).
The arguments are:
INTERFACE:
subroutine ESMF_ClockGet(clock, & timeStep, startTime, stopTime, & runDuration, runTimeStepCount, refTime, currTime, prevTime, & currSimTime, prevSimTime, calendar, calkindflag, timeZone, & advanceCount, alarmCount, direction, repeatDuration, repeatCount, & name, rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(out), optional :: timeStep type(ESMF_Time), intent(out), optional :: startTime type(ESMF_Time), intent(out), optional :: stopTime type(ESMF_TimeInterval), intent(out), optional :: runDuration real(ESMF_KIND_R8), intent(out), optional :: runTimeStepCount type(ESMF_Time), intent(out), optional :: refTime type(ESMF_Time), intent(out), optional :: currTime type(ESMF_Time), intent(out), optional :: prevTime type(ESMF_TimeInterval), intent(out), optional :: currSimTime type(ESMF_TimeInterval), intent(out), optional :: prevSimTime type(ESMF_Calendar), intent(out), optional :: calendar type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag integer, intent(out), optional :: timeZone integer(ESMF_KIND_I8), intent(out), optional :: advanceCount integer, intent(out), optional :: alarmCount type(ESMF_Direction_Flag), intent(out), optional :: direction type(ESMF_TimeInterval), intent(out), optional :: repeatDuration integer(ESMF_KIND_I8), intent(out), optional :: repeatCount character (len=*), intent(out), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets one or more of the properties of an ESMF_Clock.
The arguments are:
INTERFACE:
subroutine ESMF_ClockGetAlarm(clock, alarmname, alarm, & rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock character (len=*), intent(in) :: alarmname type(ESMF_Alarm), intent(out) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the alarm whose name is the value of alarmname in the clock's ESMF_Alarm list.
The arguments are:
INTERFACE:
subroutine ESMF_ClockGetAlarmList(clock, alarmlistflag, & timeStep, alarmList, alarmCount, rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock type(ESMF_AlarmList_Flag), intent(in) :: alarmlistflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: timeStep type(ESMF_Alarm), intent(out), optional :: alarmList(:) integer, intent(out), optional :: alarmCount integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the clock's list of alarms and/or number of alarms.
The arguments are:
ESMF_ALARMLIST_ALL : Returns the ESMF_Clock's entire list of alarms.
ESMF_ALARMLIST_NEXTRINGING : Return only those alarms that will ring upon the next clock time step. Can optionally specify argument timeStep (see below) to use instead of the clock's. See also method ESMF_AlarmWillRingNext() for checking a single alarm.
ESMF_ALARMLIST_PREVRINGING : Return only those alarms that were ringing on the previous ESMF_Clock time step. See also method ESMF_AlarmWasPrevRinging() for checking a single alarm.
ESMF_ALARMLIST_RINGING : Returns only those clock alarms that are currently ringing. See also method ESMF_ClockAdvance() for getting the list of ringing alarms subsequent to a time step. See also method ESMF_AlarmIsRinging() for checking a single alarm.
INTERFACE:
subroutine ESMF_ClockGetNextTime(clock, nextTime, & timeStep, rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock type(ESMF_Time), intent(out) :: nextTime -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: timeStep integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Calculates what the next time of the clock will be, based on the clock's current time step or an optionally passed-in timeStep.
The arguments are:
INTERFACE:
function ESMF_ClockIsCreated(clock, rc)RETURN VALUE:
logical :: ESMF_ClockIsCreatedARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the clock has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
function ESMF_ClockIsDone(clock, rc)RETURN VALUE:
logical :: ESMF_ClockIsDoneARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns true if currentTime is greater than or equal to stopTime in ESMF_DIRECTION_FORWARD, or if currentTime is less than or equal to startTime in ESMF_DIRECTION_REVERSE. It returns false otherwise.
The arguments are:
INTERFACE:
function ESMF_ClockIsReverse(clock, rc)RETURN VALUE:
logical :: ESMF_ClockIsReverseARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns true if clock is in ESMF_DIRECTION_REVERSE, and false if in ESMF_DIRECTION_FORWARD. Allows convenient use in "if" and "do while" constructs. Alternative to ESMF_ClockGet(...direction=...).
The arguments are:
INTERFACE:
function ESMF_ClockIsStopTime(clock, rc)RETURN VALUE:
logical :: ESMF_ClockIsStopTimeARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns true if the clock has reached or exceeded its stop time, and false otherwise.
The arguments are:
INTERFACE:
function ESMF_ClockIsStopTimeEnabled(clock, rc)RETURN VALUE:
logical :: ESMF_ClockIsStopTimeEnabledARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns true if the clock's stop time is set and enabled, and false otherwise.
The arguments are:
INTERFACE:
subroutine ESMF_ClockPrint(clock, options, preString, unit, rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character (len=*), intent(in), optional :: options character(*), intent(in), optional :: preString character(*), intent(out), optional :: unit integer, intent(out), optional :: rcDESCRIPTION:
Prints out an ESMF_Clock's properties to stdout, in
support of testing and debugging. The options control the type of
information and level of detail.
The arguments are:
INTERFACE:
subroutine ESMF_ClockSet(clock, & timeStep, startTime, stopTime, & runDuration, runTimeStepCount, refTime, currTime, advanceCount, & direction, name, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: timeStep type(ESMF_Time), intent(in), optional :: startTime type(ESMF_Time), intent(in), optional :: stopTime type(ESMF_TimeInterval), intent(in), optional :: runDuration integer, intent(in), optional :: runTimeStepCount type(ESMF_Time), intent(in), optional :: refTime type(ESMF_Time), intent(in), optional :: currTime integer(ESMF_KIND_I8), intent(in), optional :: advanceCount type(ESMF_Direction_Flag), intent(in), optional :: direction character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets/resets one or more of the properties of an ESMF_Clock that was previously initialized via ESMF_ClockCreate().
The arguments are:
INTERFACE:
subroutine ESMF_ClockStopTimeDisable(clock, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Disables a ESMF_Clock's stop time; ESMF_ClockIsStopTime() will always return false, allowing a clock to run past its stopTime.
The arguments are:
INTERFACE:
subroutine ESMF_ClockStopTimeEnable(clock, stopTime, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Time), intent(in), optional :: stopTime integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Enables a ESMF_Clock's stop time, allowing ESMF_ClockIsStopTime() to respect the stopTime.
The arguments are:
INTERFACE:
subroutine ESMF_ClockSyncToRealTime(clock, rc)ARGUMENTS:
type(ESMF_Clock), intent(inout) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets a clock's current time to the wall clock time. It is accurate to the nearest second.
The arguments are:
INTERFACE:
subroutine ESMF_ClockValidate(clock, rc)ARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Checks whether a clock is valid. Must have a valid startTime and timeStep. If clock has a stopTime, its currTime must be within startTime to stopTime, inclusive; also startTime's and stopTime's calendars must be the same.
The arguments are:
The Alarm class identifies events that occur at specific Times or specific TimeIntervals by returning a true value at those times or subsequent times, and a false value otherwise.
DESCRIPTION:
Specifies the characteristics of Alarms that populate
a retrieved Alarm list.
The type of this flag is:
type(ESMF_AlarmList_Flag)
The valid values are:
Alarms are used in conjunction with Clocks (see Section 45.1). Multiple Alarms can be associated with a Clock. During the ESMF_ClockAdvance() method, a Clock iterates over its internal Alarms to determine if any are ringing. Alarms ring when a specified Alarm time is reached or exceeded, taking into account whether the time step is positive or negative. In ESMF_DIRECTION_REVERSE (see Section 45.1), alarms ring in reverse, i.e., they begin ringing when they originally ended, and end ringing when they originally began. On completion of the time advance call, the Clock optionally returns a list of ringing alarms.
Each ringing Alarm can then be processed using Alarm methods for identifying, turning off, disabling or resetting the Alarm.
Alarm methods are defined for obtaining the ringing state, turning the ringer on/off, enabling/disabling the Alarm, and getting/setting associated times.
The following example shows how to set and process Alarms.
! !PROGRAM: ESMF_AlarmEx - Alarm examples ! ! !DESCRIPTION: ! ! This program shows an example of how to create, initialize, and process ! alarms associated with a clock. !----------------------------------------------------------------------------- #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! instantiate time_step, start, stop, and alarm times type(ESMF_TimeInterval) :: timeStep, alarmInterval type(ESMF_Time) :: alarmTime, startTime, stopTime ! instantiate a clock type(ESMF_Clock) :: clock ! instantiate Alarm lists integer, parameter :: NUMALARMS = 2 type(ESMF_Alarm) :: alarm(NUMALARMS) ! local variables for Get methods integer :: ringingAlarmCount ! at any time step (0 to NUMALARMS) ! name, loop counter, result code character (len=ESMF_MAXSTR) :: name integer :: i, rc, result
! initialize ESMF framework call ESMF_Initialize(defaultCalKind=ESMF_CALKIND_GREGORIAN, & defaultlogfilename="AlarmEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
This example shows how to create and initialize an ESMF_Clock.
! initialize time interval to 1 day call ESMF_TimeIntervalSet(timeStep, d=1, rc=rc)
! initialize start time to 9/1/2003 call ESMF_TimeSet(startTime, yy=2003, mm=9, dd=1, rc=rc)
! initialize stop time to 9/30/2003 call ESMF_TimeSet(stopTime, yy=2003, mm=9, dd=30, rc=rc)
! create & initialize the clock with the above values clock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & name="The Clock", rc=rc)
This example shows how to create and initialize two ESMF_Alarms and associate them with the clock.
! Initialize first alarm to be a one-shot on 9/15/2003 and associate ! it with the clock call ESMF_TimeSet(alarmTime, yy=2003, mm=9, dd=15, rc=rc)
alarm(1) = ESMF_AlarmCreate(clock, & ringTime=alarmTime, name="Example alarm 1", rc=rc)
! Initialize second alarm to ring on a 1 week interval starting 9/1/2003 ! and associate it with the clock call ESMF_TimeSet(alarmTime, yy=2003, mm=9, dd=1, rc=rc)
call ESMF_TimeIntervalSet(alarmInterval, d=7, rc=rc)
! Alarm gets default name "Alarm002" alarm(2) = ESMF_AlarmCreate(clock=clock, ringTime=alarmTime, & ringInterval=alarmInterval, rc=rc)
This example shows how to advance an ESMF_Clock and process any resulting ringing alarms.
! time step clock from start time to stop time do while (.not.ESMF_ClockIsStopTime(clock, rc=rc))
! perform time step and get the number of any ringing alarms call ESMF_ClockAdvance(clock, ringingAlarmCount=ringingAlarmCount, & rc=rc)
call ESMF_ClockPrint(clock, options="currTime string", rc=rc)
! check if alarms are ringing if (ringingAlarmCount > 0) then print *, "number of ringing alarms = ", ringingAlarmCount do i = 1, NUMALARMS if (ESMF_AlarmIsRinging(alarm(i), rc=rc)) then
call ESMF_AlarmGet(alarm(i), name=name, rc=rc) print *, trim(name), " is ringing!"
! after processing alarm, turn it off call ESMF_AlarmRingerOff(alarm(i), rc=rc)
end if ! this alarm is ringing end do ! each ringing alarm endif ! ringing alarms end do ! timestep clock
This example shows how to destroy ESMF_Alarms and ESMF_Clocks.
call ESMF_AlarmDestroy(alarm(1), rc=rc)
call ESMF_AlarmDestroy(alarm(2), rc=rc)
call ESMF_ClockDestroy(clock, rc=rc)
! finalize ESMF framework call ESMF_Finalize(rc=rc)
end program ESMF_AlarmEx
The Alarm class is designed as a deep, dynamically allocatable class, based on a pointer type. This allows for both indirect and direct manipulation of alarms. Indirect alarm manipulation is where ESMF_Alarm API methods, such as ESMF_AlarmRingerOff(), are invoked on alarm references (pointers) returned from ESMF_Clock queries such as "return ringing alarms." Since the method is performed on an alarm reference, the actual alarm held by the clock is affected, not just a user's local copy. Direct alarm manipulation is the more common case where alarm API methods are invoked on the original alarm objects created by the user.
For consistency, the ESMF_Clock class is also designed as a deep, dynamically allocatable class.
An additional benefit from this approach is that Clocks and Alarms can be created and used from anywhere in a user's code without regard to the scope in which they were created. In contrast, statically created Alarms and Clocks would disappear if created within a user's routine that returns, whereas dynamically allocated Alarms and Clocks will persist until explicitly destroyed by the user.
INTERFACE:
interface assignment(=) alarm1 = alarm2ARGUMENTS:
type(ESMF_Alarm) :: alarm1 type(ESMF_Alarm) :: alarm2STATUS:
DESCRIPTION:
Assign alarm1 as an alias to the same ESMF_Alarm object in memory as alarm2. If alarm2 is invalid, then alarm1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (alarm1 == alarm2) then ... endif OR result = (alarm1 == alarm2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm1 type(ESMF_Alarm), intent(in) :: alarm2DESCRIPTION:
Overloads the (==) operator for the ESMF_Alarm class. Compare two alarms for equality; return .true. if equal, .false. otherwise. Comparison is based on IDs, which are distinct for newly created alarms and identical for alarms created as copies.
If either side of the equality test is not in the ESMF_INIT_CREATED status an error will be logged. However, this does not affect the return value, which is .true. when both sides are in the same status, and .false. otherwise.
The arguments are:
INTERFACE:
interface operator(/=) if (alarm1 /= alarm2) then ... endif OR result = (alarm1 /= alarm2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm1 type(ESMF_Alarm), intent(in) :: alarm2DESCRIPTION:
Overloads the (/=) operator for the ESMF_Alarm class. Compare two alarms for inequality; return .true. if not equal, .false. otherwise. Comparison is based on IDs, which are distinct for newly created alarms and identical for alarms created as copies.
If either side of the equality test is not in the ESMF_INIT_CREATED status an error will be logged. However, this does not affect the return value, which is .true. when both sides are not in the same status, and .false. otherwise.
The arguments are:
INTERFACE:
! Private name; call using ESMF_AlarmCreate() function ESMF_AlarmCreateNew(clock, & ringTime, ringInterval, stopTime, ringDuration, ringTimeStepCount, & refTime, enabled, sticky, name, rc)RETURN VALUE:
type(ESMF_Alarm) :: ESMF_AlarmCreateNewARGUMENTS:
type(ESMF_Clock), intent(in) :: clock -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Time), intent(in), optional :: ringTime type(ESMF_TimeInterval), intent(in), optional :: ringInterval type(ESMF_Time), intent(in), optional :: stopTime type(ESMF_TimeInterval), intent(in), optional :: ringDuration integer, intent(in), optional :: ringTimeStepCount type(ESMF_Time), intent(in), optional :: refTime logical, intent(in), optional :: enabled logical, intent(in), optional :: sticky character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates and sets the initial values in a new ESMF_Alarm.
In ESMF_DIRECTION_REVERSE (see Section 45.1), alarms ring in reverse, i.e., they begin ringing when they originally ended, and end ringing when they originally began.
The arguments are:
INTERFACE:
! Private name; call using ESMF_AlarmCreate() function ESMF_AlarmCreateCopy(alarm, rc)RETURN VALUE:
type(ESMF_Alarm) :: ESMF_AlarmCreateCopyARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Creates a complete (deep) copy of a given ESMF_Alarm. The returned ESMF_Alarm copy is associated with the same ESMF_Clock as the original ESMF_Alarm. If desired, use ESMF_AlarmSet(...clock=...) to re-associate the ESMF_Alarm copy with a different ESMF_Clock.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmDestroy(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Releases resources associated with this ESMF_Alarm. Also removes this ESMF_Alarm from its associated ESMF_Clock's list of ESMF_Alarms (removes the ESMF_Alarm pointer from the list).
The arguments are:
INTERFACE:
subroutine ESMF_AlarmDisable(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Disables an ESMF_Alarm.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmEnable(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Enables an ESMF_Alarm to function.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmGet(alarm, & clock, ringTime, prevRingTime, ringInterval, stopTime, ringDuration, & ringTimeStepCount, timeStepRingingCount, ringBegin, ringEnd, & refTime, ringing, ringingOnPrevTimeStep, enabled, sticky, name, rc)ARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Clock), intent(out), optional :: clock type(ESMF_Time), intent(out), optional :: ringTime type(ESMF_Time), intent(out), optional :: prevRingTime type(ESMF_TimeInterval), intent(out), optional :: ringInterval type(ESMF_Time), intent(out), optional :: stopTime type(ESMF_TimeInterval), intent(out), optional :: ringDuration integer, intent(out), optional :: ringTimeStepCount integer, intent(out), optional :: timeStepRingingCount type(ESMF_Time), intent(out), optional :: ringBegin type(ESMF_Time), intent(out), optional :: ringEnd type(ESMF_Time), intent(out), optional :: refTime logical, intent(out), optional :: ringing logical, intent(out), optional :: ringingOnPrevTimeStep logical, intent(out), optional :: enabled logical, intent(out), optional :: sticky character (len=*), intent(out), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets one or more of an ESMF_Alarm's properties.
The arguments are:
INTERFACE:
function ESMF_AlarmIsCreated(alarm, rc)RETURN VALUE:
logical :: ESMF_AlarmIsCreatedARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the alarm has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
function ESMF_AlarmIsEnabled(alarm, rc)RETURN VALUE:
logical :: ESMF_AlarmIsEnabledARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Check if ESMF_Alarm is enabled.
The arguments are:
INTERFACE:
function ESMF_AlarmIsRinging(alarm, rc)RETURN VALUE:
logical :: ESMF_AlarmIsRingingARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Check if ESMF_Alarm is ringing.
See also method ESMF_ClockGetAlarmList(clock, ESMF_ALARMLIST_RINGING, ...) to get a list of all ringing alarms belonging to an ESMF_Clock.
The arguments are:
INTERFACE:
function ESMF_AlarmIsSticky(alarm, rc)RETURN VALUE:
logical :: ESMF_AlarmIsStickyARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Check if alarm is sticky.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmNotSticky(alarm, & ringDuration, ringTimeStepCount, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: ringDuration integer, intent(in), optional :: ringTimeStepCount integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Unset an ESMF_Alarm's sticky flag; once alarm is ringing, it turns itself off after ringDuration.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmPrint(alarm, options, rc)ARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm character (len=*), intent(in), optional :: options integer, intent(out), optional :: rcDESCRIPTION:
Prints out an ESMF_Alarm's properties to stdout, in support
of testing and debugging. The options control the type of information
and level of detail.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmRingerOff(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Turn off an ESMF_Alarm; unsets ringing state. For a sticky alarm, this method must be called to turn off its ringing state. This is true for either ESMF_DIRECTION_FORWARD (default) or ESMF_DIRECTION_REVERSE. See Section 45.1.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmRingerOn(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Turn on an ESMF_Alarm; sets ringing state.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmSet(alarm, & clock, ringTime, ringInterval, stopTime, ringDuration, & ringTimeStepCount, refTime, ringing, enabled, sticky, name, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Clock), intent(in), optional :: clock type(ESMF_Time), intent(in), optional :: ringTime type(ESMF_TimeInterval), intent(in), optional :: ringInterval type(ESMF_Time), intent(in), optional :: stopTime type(ESMF_TimeInterval), intent(in), optional :: ringDuration integer, intent(in), optional :: ringTimeStepCount type(ESMF_Time), intent(in), optional :: refTime logical, intent(in), optional :: ringing logical, intent(in), optional :: enabled logical, intent(in), optional :: sticky character (len=*), intent(in), optional :: name integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets/resets one or more of the properties of an ESMF_Alarm that was previously initialized via ESMF_AlarmCreate().
The arguments are:
INTERFACE:
subroutine ESMF_AlarmSticky(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(inout) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Set an ESMF_Alarm's sticky flag; once alarm is ringing, it remains ringing until ESMF_AlarmRingerOff() is called. There is an implicit limitation that in order to properly reverse timestep through a ring end time in ESMF_DIRECTION_REVERSE, that time must have already been traversed in the forward direction. This is due to the fact that an ESMF_Alarm cannot predict when user code will call ESMF_AlarmRingerOff(). An error message will be logged when this limitation is not satisfied.
The arguments are:
INTERFACE:
subroutine ESMF_AlarmValidate(alarm, rc)ARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Performs a validation check on an ESMF_Alarm's properties. Must have a valid ringTime, set either directly or indirectly via ringInterval. See ESMF_AlarmCreate().
The arguments are:
INTERFACE:
function ESMF_AlarmWasPrevRinging(alarm, rc)RETURN VALUE:
logical :: ESMF_AlarmWasPrevRingingARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Check if ESMF_Alarm was ringing on the previous clock timestep.
See also method ESMF_ClockGetAlarmList(clock, ESMF_ALARMLIST_PREVRINGING, ...) get a list of all alarms belonging to a ESMF_Clock that were ringing on the previous time step.
The arguments are:
INTERFACE:
function ESMF_AlarmWillRingNext(alarm, timeStep, rc)RETURN VALUE:
logical :: ESMF_AlarmWillRingNextARGUMENTS:
type(ESMF_Alarm), intent(in) :: alarm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_TimeInterval), intent(in), optional :: timeStep integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Check if ESMF_Alarm will ring on the next clock timestep, either the current clock timestep or a passed-in timestep.
See also method ESMF_ClockGetAlarmList(clock, ESMF_ALARMLIST_NEXTRINGING, ...) to get a list of all alarms belonging to a ESMF_Clock that will ring on the next time step.
The arguments are:
ESMF Configuration Management is based on NASA DAO's
Inpak 90 package, a Fortran 90 collection of routines/functions
for accessing Resource Files in ASCII format.The package
is optimized for minimizing formatted I/O, performing all of its
string operations in memory using Fortran intrinsic functions.
The ESMF Configuration Management Package was evolved by Leonid Zaslavsky and Arlindo da Silva from Ipack90 package created by Arlindo da Silva at NASA DAO.
Back in the 70's Eli Isaacson wrote IOPACK in Fortran 66. In June of 1987 Arlindo da Silva wrote Inpak77 using Fortran 77 string functions; Inpak 77 is a vastly simplified IOPACK, but has its own goodies not found in IOPACK. Inpak 90 removes some obsolete functionality in Inpak77, and parses the whole resource file in memory for performance.
A Resource File (RF) is a text file consisting of list of label-value pairs. There is a limit of 1024 characters per line and the Resource File can contain a maximum of 200 records. Each label should be followed by some data, the value. An example Resource File follows. It is the file used in the example below.
# This is an example Resource File. # It contains a list of <label,value> pairs. # The colon after the label is required. # The values after the label can be an list. # Multiple types are authorized. my_file_names: jan87.dat jan88.dat jan89.dat # all strings constants: 3.1415 25 # float and integer my_favorite_colors: green blue 022 # Or, the data can be a list of single value pairs. # It is simplier to retrieve data in this format: radius_of_the_earth: 6.37E6 parameter_1: 89 parameter_2: 78.2 input_file_name: dummy_input.nc # Or, the data can be located in a table using the following # syntax: my_table_name:: 1000 3000 263.0 925 3000 263.0 850 3000 263.0 700 3000 269.0 500 3000 287.0 400 3000 295.8 300 3000 295.8 ::
Note that the colon after the label is required and that the double colon is required to declare tabular data.
Resource files are intended for random access (except between ::'s in a table definition). This means that order in which a particular label-value pair is retrieved is not dependent upon the original order of the pairs. The only exception to this, however, is when the same label appears multiple times within the Resource File.
This example/test code performs simple Config/Resource File routines. It does not include attaching a Config to a component. The important thing to remember there is that you can have one Config per component.
There are two methodologies for accessing data in a Resource File. This example will demonstrate both.
Note the API section contains a complete description of arguments in the methods/functions demonstrated in this example.
The following are the variable declarations used as arguments in the following code fragments. They represent the locals names for the variables listed in the Resource File (RF). Note they do not need to be the same.
character(ESMF_MAXPATHLEN) :: fname ! config file name character(ESMF_MAXPATHLEN) :: fn1, fn2, fn3, input_file ! strings to be read in integer :: rc ! error return code (0 is OK) integer :: i_n ! the first constant in the RF real :: param_1 ! the second constant in the RF real :: radius ! radius of the earth real :: table(7,3) ! an array to hold the table in the RF type(ESMF_Config) :: cf ! the Config itself type(ESMF_HConfig) :: hconfig ! HConfig variable
While there are two methodologies for accessing the data within a Resource File, there is only one way to create the initial Config and load its ASCII text into memory. This is the first step in the process.
Note that subsequent calls to ESMF_ConfigLoadFile will OVERWRITE the current Config NOT append to it. There is no means of appending to a Config.
cf = ESMF_ConfigCreate(rc=rc) ! Create the empty Config
fname = "myResourceFile.rc" ! Name the Resource File call ESMF_ConfigLoadFile(cf, fname, rc=rc) ! Load the Resource File ! into the empty Config
Remember, that the order in which a particular label/value pair is retrieved is not dependent upon the order which they exist within the Resource File.
call ESMF_ConfigGetAttribute(cf, radius, label='radius_of_the_earth:', & default=1.0, rc=rc)
Note that the colon must be included in the label string when using this methodology. It is also important to provide a default value in case the label does not exist in the file
This methodology works for all types. The following is an example of retrieving a string:
call ESMF_ConfigGetAttribute(cf, input_file, label='input_file_name:', & default="./default.nc", rc=rc)
The same code fragment can be used to demonstrate what happens when the label is not present. Note that "file_name" does not exist in the Resource File. The result of its absence is the default value provided in the call.
call ESMF_ConfigGetAttribute(cf, input_file, label='file_name:', & default="./default.nc", rc=rc)
A second reminder that the order in which a particular label/value pair is retrieved is not dependent upon the order which they exist within the Resource File. The label used in this method allows the user to skip to any point in the file.
call ESMF_ConfigFindLabel(cf, 'constants:', rc=rc) ! Step a) Find the ! label
Two constants, radius and i_n, can now be retrieved without having to specify their label or use an array. They are also different types.
call ESMF_ConfigGetAttribute(cf, param_1, rc=rc) ! Step b) read in the ! first constant in ! the sequence call ESMF_ConfigGetAttribute(cf, i_n, rc=rc) ! Step c) read in the ! second constant in ! the sequence
This methodology also works with strings.
call ESMF_ConfigFindLabel(cf, 'my_file_names:', & rc=rc) ! Step a) find the label
call ESMF_ConfigGetAttribute(cf, fn1, & rc=rc) ! Step b) retrieve the 1st filename call ESMF_ConfigGetAttribute(cf, fn2, & rc=rc) ! Step c) retrieve the 2nd filename call ESMF_ConfigGetAttribute(cf, fn3, & rc=rc) ! Step d) retrieve the 3rd filename
To access tabular data, the user must use the multi-value method.
call ESMF_ConfigFindLabel(cf, 'my_table_name::', & rc=rc) ! Step a) Set the label location to the ! beginning of the table
Subsequently, call ESMF_ConfigNextLine() is used to move the location to the next row of the table. The example table in the Resource File contains 7 rows and 3 columns (7,3).
do i = 1, 7 call ESMF_ConfigNextLine(cf, rc=rc) ! Step b) Increment the rows do j = 1, 3 ! Step c) Fill in the table call ESMF_ConfigGetAttribute(cf, table(i,j), rc=rc) enddo enddo
The work with the Config object cf is finalized by callling ESMF_ConfigDestroy().
call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
The Config class supports loading of YAML files. As before, an empty Config object is created with ESMF_ConfigCreate() and then populated via the ESMF_ConfigLoadFile() method.
cf = ESMF_ConfigCreate(rc=rc) ! Create the empty Config object
Files ending in .yaml, .yml, or any combination of upper and lower case letters that can be mapped to these two options, are interpreted as YAML files. All other names are interpreted as classic Config RFs as documented earlier.
call ESMF_ConfigLoadFile(cf, "myResourceFile.yaml", & ! Load the YAML File rc=rc) ! into the empty Config object
Here the myResourceFile.yaml contains a YAML version of the previously used myResourceFile.rc file contents:
# YAML representation of the myResourceFile.rc RF # mapping to sequences my_file_names: [jan87.dat, jan88.dat, jan89.dat] # all strings constants: [3.1415, 25] # float and integer my_favorite_colors: [green, blue, 022] # mapping to scalars radius_of_the_earth: 6.37E6 parameter_1: 89 parameter_2: 78.2 input_file_name: dummy_input.nc # represent table as mapping to sequence of sequences my_table_name: - [1000, 3000, 263.0] - [ 925, 3000, 263.0] - [ 850, 3000, 263.0] - [ 700, 3000, 269.0] - [ 500, 3000, 287.0] - [ 400, 3000, 295.8] - [ 300, 3000, 295.8]
Notice that YAML support is limited to a small subset of the full YAML language specification, allowing access through the classic Config API. Specifically, the top level in the YAML file is expected to be a mapping (dictionary) of scalar keys to any of the following three value options:
As an example, access the my_table_name element:
call ESMF_ConfigFindLabel(cf, 'my_table_name::', & rc=rc) ! Step a) Set the label location to the ! beginning of the table
When done, the resources held by the Config object are released by calling the ESMF_ConfigDestroy() method.
call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
The Config class supports creating a Config object from a HConfig object. Here the HConfig object is created from the same YAML file as used before.
! Create HConfig object hconfig = ESMF_HConfigCreate(filename="myResourceFile.yaml", rc=rc)
The myResourceFile.yaml contains the following YAML contents:
# YAML representation of the myResourceFile.rc RF # mapping to sequences my_file_names: [jan87.dat, jan88.dat, jan89.dat] # all strings constants: [3.1415, 25] # float and integer my_favorite_colors: [green, blue, 022] # mapping to scalars radius_of_the_earth: 6.37E6 parameter_1: 89 parameter_2: 78.2 input_file_name: dummy_input.nc # represent table as mapping to sequence of sequences my_table_name: - [1000, 3000, 263.0] - [ 925, 3000, 263.0] - [ 850, 3000, 263.0] - [ 700, 3000, 269.0] - [ 500, 3000, 287.0] - [ 400, 3000, 295.8] - [ 300, 3000, 295.8]
A Config object can be created from the HConfig object simply by passing hconfig into ESMF_CreateConfig() as argument.
! Create Config object from HConfig cf = ESMF_ConfigCreate(hconfig=hconfig, rc=rc)
Notice that cf uses the specified hconfig object via reference. It remains the callers responsibility to destroy the hconfig object when finished. Care must be taken to not destroy until access via cf is complete.
Here, as an example, access the my_table_name element:
call ESMF_ConfigFindLabel(cf, 'my_table_name::', & rc=rc) ! Step a) Set the label location to the ! beginning of the table
call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
As discussed above, the hconfig object requires its own destroy call for a complete release.
call ESMF_HConfigDestroy(hconfig, rc=rc) ! Destroy the HConfig object
INTERFACE:
interface assignment(=) config1 = config2ARGUMENTS:
type(ESMF_Config) :: config1 type(ESMF_Config) :: config2DESCRIPTION:
Assign config1 as an alias to the same ESMF_Config object in memory as config2. If config2 is invalid, then config1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (config1 == config2) then ... endif OR result = (config1 == config2)RETURN VALUE:
configical :: resultARGUMENTS:
type(ESMF_Config), intent(in) :: config1 type(ESMF_Config), intent(in) :: config2DESCRIPTION:
Overloads the (==) operator for the ESMF_Config class. Compare two configs for equality; return .true. if equal, .false. otherwise. Comparison is based on whether the objects are distinct, as with two newly created objects, or are simply aliases to the same object as would be the case when assignment was involved.
The arguments are:
INTERFACE:
interface operator(/=) if (config1 /= config2) then ... endif OR result = (config1 /= config2)RETURN VALUE:
configical :: resultARGUMENTS:
type(ESMF_Config), intent(in) :: config1 type(ESMF_Config), intent(in) :: config2DESCRIPTION:
Overloads the (/=) operator for the ESMF_Config class. Compare two configs for equality; return .true. if not equivalent, .false. otherwise. Comparison is based on whether the Config objects are distinct, as with two newly created objects, or are simply aliases to the same object as would be the case when assignment was involved.
The arguments are:
INTERFACE:
! Private name; call using ESMF_ConfigCreate() type(ESMF_Config) function ESMF_ConfigCreateDefault(hconfig, rc)ARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_HConfig), intent(in), optional :: hconfig integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Instantiates an ESMF_Config object. Optionally create from HConfig.
The arguments are:
INTERFACE:
! Private name; call using ESMF_ConfigCreate() type(ESMF_Config) function ESMF_ConfigCreateFromSection(config, & openlabel, closelabel, rc)ARGUMENTS:
type(ESMF_Config) :: config character(len=*), intent(in) :: openlabel, closelabel -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer,intent(out), optional :: rcDESCRIPTION:
Instantiates an ESMF_Config object from a section of an existing ESMF_Config object delimited by openlabel and closelabel. An error is returned if neither of the input labels is found in input config.
Note that a section is intended as the content of a given ESMF_Config object delimited by two distinct labels. Such content, as well as each of the surrounding labels, are still within the scope of the parent ESMF_Config object. Therefore, including in a section labels used outside that section should be done carefully to prevent parsing conflicts.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigDestroy(config, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Destroys the config object.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigFindLabel(config, label, isPresent, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config character(len=*), intent(in) :: label -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(out), optional :: isPresent integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Finds the label (key) string in the config object starting from the beginning of its content.
Since the search is done by looking for a string, possibly multi-worded, in the whole Config object, it is important to use special conventions to distinguish labels from other words. This is done in the Resource File by using the NASA/DAO convention to finish line labels with a colon (:) and table labels with a double colon (::).
The arguments are:
INTERFACE:
subroutine ESMF_ConfigFindNextLabel(config, label, isPresent, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config character(len=*), intent(in) :: label -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(out), optional :: isPresent integer, intent(out), optional :: rcDESCRIPTION:
Finds the label (key) string in the config object, starting from the current position pointer.
This method is equivalent to ESMF_ConfigFindLabel, but the search is performed starting from the current position pointer.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigGet(config, hconfig, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_HConfig), intent(out), optional :: hconfig integer, intent(out), optional :: rcDESCRIPTION:
Access Config internals.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigGetAttribute(config, <value>, & label, default, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config <value argument>, see below for supported values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: label character(len=*), intent(in), optional :: default integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets a value from the config object. When the value is a sequence of characters it will be terminated by the first white space.
Supported values for <value argument> are:
The arguments are:
INTERFACE:
subroutine ESMF_ConfigGetAttribute(config, <value list argument>, & count, label, default, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config <value list argument>, see below for values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in) optional :: count character(len=*), intent(in), optional :: label character(len=*), intent(in), optional :: default integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets a list of values from the config object.
Supported values for <value list argument> are:
The arguments are:
INTERFACE:
subroutine ESMF_ConfigGetChar(config, value, & label, default, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config character, intent(out) :: value -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: label character, intent(in), optional :: default integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets a character value from the config object.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigGetDim(config, lineCount, columnCount, & label, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config integer, intent(out) :: lineCount integer, intent(out) :: columnCount -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: label integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Returns the number of lines in the table in lineCount and the maximum number of words in a table line in columnCount.
After the call, the line pointer is positioned to the end of the table. To reset it to the beginning of the table, use ESMF_ConfigFindLabel.
The arguments are:
INTERFACE:
integer function ESMF_ConfigGetLen(config, label, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: label integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Gets the length of the line in words by counting words disregarding types. Returns the word count as an integer.
The arguments are:
INTERFACE:
function ESMF_ConfigIsCreated(config, rc)RETURN VALUE:
logical :: ESMF_ConfigIsCreatedARGUMENTS:
type(ESMF_Config), intent(in) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the config has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
subroutine ESMF_ConfigLoadFile(config, filename, & delayout, & ! DEPRECATED ARGUMENT unique, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_DELayout), intent(in), optional :: delayout ! DEPRECATED ARGUMENT logical, intent(in), optional :: unique integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
The resource file named filename is loaded into memory. Both the classic Config file format, described in this document, and the YAML file format are supported. YAML support is limited to a small subset of the full YAML language specification, allowing access through the classic Config API. Specifically, in YAML mode, the top level is expected to be a mapping (dictionary) of scalar keys to the following value options:
The arguments are:
INTERFACE:
subroutine ESMF_ConfigLog(config, raw, prefix, logMsgFlag, & log, rc)ARGUMENTS:
type(ESMF_Config), intent(in) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: raw character (len=*), intent(in), optional :: prefix type(ESMF_LogMsg_Flag), intent(in), optional :: logMsgFlag type(ESMF_Log), intent(inout), optional :: log integer, intent(out), optional :: rcDESCRIPTION:
Write content of ESMF_Config object to ESMF log.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigNextLine(config, tableEnd, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(out), optional :: tableEnd integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Selects the next line (for tables).
The arguments are:
INTERFACE:
subroutine ESMF_ConfigPrint(config, unit, rc)ARGUMENTS:
type(ESMF_Config), intent(in) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, optional, intent(in) :: unit integer, optional, intent(out) :: rcDESCRIPTION:
Write content of input ESMF_Config object to unit unit. If unit not provided, writes to standard output.
The arguments are:
INTERFACE:
subroutine ESMF_ConfigSetAttribute(config, <value argument>, & label, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config <value argument>, see below for supported values -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: label integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Sets a value in the config object.
Supported values for <value argument> are:
The arguments are:
INTERFACE:
subroutine ESMF_ConfigValidate(config, & options, rc)ARGUMENTS:
type(ESMF_Config), intent(inout) :: config -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character (len=*), intent(in), optional :: options integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Checks whether a config object is valid.
The arguments are:
The ESMF HConfig class implements a hierarchical configuration facility that is compatible with YAML Ain't Markup Language (YAMLTM). ESMF HConfig can be understood as a Fortran interface to YAML. However, no claim is made that all YAML language features are supported in their entirety.
The purpose of the HConfig class under ESMF is to provide a migration path toward more standard configuration management for ESMF applications. To this end ESMF_HConfig integrates with the traditional ESMF_Config class. Through this integration the traditional Config class API offers basic access to YAML configuration files, in addition to providing backward compatible support of the traditional config file format. This is discussed in more detail in the Config class section. For more complete YAML support, applications are encouraged to migrate to the HConfig API discussed in this section.
The following examples demonstrate how a user typically interacts with the HConfig API. The HConfig class introduces two derived types:
ESMF_HConfig objects can be created explicitly by the user, or they can be accessed from an existing ESMF_Config object, e.g. queried from a Component. They can play a number of roles when interacting with a HConfig hierarchy:
ESMF_HConfigIter objects are iterators, referencing a specific node within the hierarchy. They are created from ESMF_HConfig objects. The iterator approach allows convenient sequential traversal of a particular location in the HConfig hierarchy. There are two flavors of iterators in HConfig: sequence and map iterators. Both are represented by the same ESMF_HConfigIter derived type, and the distinction is made at run-time.
Notice that there are redundancies built into the HConfig API, where different ways are available to achieve the same goal. This is mostly done for convenience, allowing the user to pick the approach most suitable to their needs.
For instance, while it can be convenient to use iterators in some cases, in others, it might be more appropriate to access elements directly by index (for sequences) or key (for maps). Both options are available.
By default, ESMF_HConfigCreate() creates an empty HConfig object.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(rc=rc)
An empty HConfig object can be set directly from a string using YAML syntax.
call ESMF_HConfigSet(hconfig, content="[1, 2, 3, abc, b, TRUE]", rc=rc)
This sets hconfig as a sequence of six scalar members.
One way to parse the elements contained in hconfig is to use the iterator pattern known from laguages such as C++ or Python. HConfig iterators are implemented as type(ESMF_HConfigIter) objects that are initialized using one of the HConfigIter*() methods. An iterator can then be used to traverse the elements in a sequence or map by calling the ESMF_HConfigIterNext() method, taking one step forward each time the method is called.
Being a HConfig object, an iterator can be passed into any of the usual HConfig methods. The operation is applied to the element that the iterator is currently referencing.
Notice that iterators are merely references, not associated with their own deep allocation. This is reflected in the fact that iterators are not created by an assignment that has a Create() call on the right hand side. As such, HConfig iterators need not be destroyed explicitly when done.
Two special HConfig iterators are defined, referencing the beginning and the end of a HConfig sequence or map object.
! type(ESMF_HConfigIter) :: hconfigIterBegin, hconfigIterEnd hconfigIterBegin = ESMF_HConfigIterBegin(hconfig, rc=rc)
hconfigIterEnd = ESMF_HConfigIterEnd(hconfig, rc=rc)
In analogy to the C++ iterator pattern, hconfigIterBegin points to the first element in hconfig, while hconfigIterEnd points one step beyond the last element. Using these elements together, an iterator loop can be written in the following intuitive way, using hconfigIter as the loop variable.
! type(ESMF_HConfigIter) :: hconfigIter hconfigIter = hconfigIterBegin do while (hconfigIter /= hconfigIterEnd) ! Code here that uses hconfigIter ! to access the currently referenced ! element in hconfig. ....... call ESMF_HConfigIterNext(hconfigIter, rc=rc)
enddo
One major concern with the above iterator loop implementation is when Fortran cycle statements are introduced. In orde to make the above loop cycle-safe, each such cycle statement needs to be matched with its own call to ESMF_HConfigIterNext(). This needs to be done to prevent endless-loop conditions, where the exit condition of the do while is never reached.
The cycle-safe alternative implementation of the iterator loop leverages the ESMF_HConfigIterLoop() function instead of ESMF_HConfigIterNext(). This approach is more akin to the C++
for (element : container){ ... }or the Python
for element in container: ...approach. It is the preferable way to write HConfig iterator loops due to its simplicity and inherent cycle-safety.
The ESMF_HConfigIterLoop() function takes three required arguments. The first is the loop iterator, followed by the begin and end iterators. The loop iterator must enter equal to the begin iterator at the start of the loop. Each time the ESMF_HConfigIterLoop() function is called, the loop iterator is stepped forward as appropriate, and the exit condition of having reached the end iterator is checked. Having both the stepping and exit logic in one place provided by the HConfig API simplifies the usage. In addition, the approach is cycle-safe: no matter where a cycle statement is inserted in the loop body, it always brings the execution back to the top of the while loop, which in turn calls the ESMF_HConfigIterLoop() function.
! type(ESMF_HConfigIter) :: hconfigIter hconfigIter = hconfigIterBegin do while (ESMF_HConfigIterLoop(hconfigIter, hconfigIterBegin, hconfigIterEnd, rc=rc))
! Check whether the current element is a scalar. ! logical :: isScalar isScalar = ESMF_HConfigIsScalar(hconfigIter, rc=rc)
if (isScalar) then ! Any scalar can be accessed as a string. ! character(len=:), allocatable :: string string = ESMF_HConfigAsString(hconfigIter, rc=rc)
! The attempt can be made to interpret the scalar as any of the other ! supported data types. By default, if the scalar cannot be interpreted ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent ! such error condition, the optional, intent(out) argument "asOkay" can ! be provided. If asOkay == .true. is returned, the interpretation was ! successful. Otherwise asOkay == .false. is returned. ! logical :: asOkay ! integer(ESMF_KIND_I4) :: valueI4 valueI4 = ESMF_HConfigAsI4(hconfigIter, asOkay=asOkay, rc=rc)
! integer(ESMF_KIND_I8) :: valueI8 valueI8 = ESMF_HConfigAsI8(hconfigIter, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R4) :: valueR4 valueR4 = ESMF_HConfigAsR4(hconfigIter, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R8) :: valueR8 valueR8 = ESMF_HConfigAsR8(hconfigIter, asOkay=asOkay, rc=rc)
! logical :: valueL valueL = ESMF_HConfigAsLogical(hconfigIter, asOkay=asOkay, rc=rc)
else ! Possible recursive iteration over the current hconfigIter element. endif enddo
An alternative way to loop over the elements contained in hconfig, and parsing them, is to use an index variable. For this approach the size of hconfig is queried.
! integer :: size size = ESMF_HConfigGetSize(hconfig, rc=rc)
Then looping over the elements is done with a simple do loop. Index based access allows random order of access, versus the iterator approach that only supports begin to end iteration. This is demonstrated here by writing the do loop in reverse order.
! integer :: i do i=size, 1, -1 ! Check whether the current element is a scalar. ! logical :: isScalar isScalar = ESMF_HConfigIsScalar(hconfig, index=i, rc=rc)
if (isScalar) then ! Any scalar can be accessed as a string. ! character(len=:), allocatable :: string string = ESMF_HConfigAsString(hconfig, index=i, rc=rc)
! The attempt can be made to interpret the scalar as any of the other ! supported data types. By default, if the scalar cannot be interpreted ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent ! such error condition, the optional, intent(out) argument "asOkay" can ! be provided. If asOkay == .true. is returned, the interpretation was ! successful. Otherwise asOkay == .false. is returned. ! logical :: asOkay ! integer(ESMF_KIND_I4) :: valueI4 valueI4 = ESMF_HConfigAsI4(hconfig, index=i, asOkay=asOkay, rc=rc)
! integer(ESMF_KIND_I8) :: valueI8 valueI8 = ESMF_HConfigAsI8(hconfig, index=i, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R4) :: valueR4 valueR4 = ESMF_HConfigAsR4(hconfig, index=i, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R8) :: valueR8 valueR8 = ESMF_HConfigAsR8(hconfig, index=i, asOkay=asOkay, rc=rc)
! logical :: valueL valueL = ESMF_HConfigAsLogical(hconfig, index=i, asOkay=asOkay, rc=rc)
else ! Possible recursive iteration over the current index=i element. endif enddo
The above loop is safe with respect to index potentially being specified with an out-of-range value. This is because ESMF_HConfigIsScalar() returns .false. in this case. There are only four valid options of what type a valid HConfig element can be. Each has an associated Is method:
! logical :: isDefined isDefined = ESMF_HConfigIsDefined(hconfig, index=10, rc=rc)
This returns isDefined == .false. because for hconfig a value of index=10 is out of range.
When done with hconfig, it should be destroyed in the usual manner.
call ESMF_HConfigDestroy(hconfig, rc=rc)
The ESMF_HConfigCreate() method supports loading contents from string using YAML syntax directly via the optional content argument.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(content="{car: red, bike: 22, plane: TRUE}", rc=rc)
Here a map is created. In this case, all of the keys are scalars (car, bike, plane), as are all of the associated values (red, 22, TRUE).
The elements of the map contained in hconfig can be iterated over analogous to the sequence case demonstrated earlier. Again the begin and end iterator variables are defined.
! type(ESMF_HConfigIter) :: hconfigIterBegin, hconfigIterEnd hconfigIterBegin = ESMF_HConfigIterBegin(hconfig, rc=rc)
hconfigIterEnd = ESMF_HConfigIterEnd(hconfig, rc=rc)
Then iterate over the elements in hconfig using an iterator loop variable as before.
The difference of the code below, compared to the sequence case, is that all the As access methods here are either of the form As*MapKey or As*MapVal. This is necessary to selectively access the map key or map value, respectively.
! type(ESMF_HConfigIter) :: hconfigIter hconfigIter = hconfigIterBegin do while (ESMF_HConfigIterLoop(hconfigIter, hconfigIterBegin, hconfigIterEnd, rc=rc))
! Check whether the current element is a scalar both for the map key ! and the map value. ! logical :: isScalar isScalar = ESMF_HConfigIsScalarMapKey(hconfigIter, rc=rc)
isScalar = isScalar .and. ESMF_HConfigIsScalarMapVal(hconfigIter, rc=rc)
if (isScalar) then ! Any scalar can be accessed as a string. Use this for the map key. ! character(len=:), allocatable :: stringKey stringKey = ESMF_HConfigAsStringMapKey(hconfigIter, rc=rc)
! Now access the map value. Again first access as a string, which ! always works. ! character(len=:), allocatable :: string string = ESMF_HConfigAsStringMapVal(hconfigIter, rc=rc)
! The attempt can be made to interpret the scalar as any of the other ! supported data types. By default, if the scalar cannot be interpreted ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent ! such error condition, the optional, intent(out) argument "asOkay" can ! be provided. If asOkay == .true. is returned, the interpretation was ! successful. Otherwise asOkay == .false. is returned. ! logical :: asOkay ! integer(ESMF_KIND_I4) :: valueI4 valueI4 = ESMF_HConfigAsI4MapVal(hconfigIter, asOkay=asOkay, rc=rc)
! integer(ESMF_KIND_I8) :: valueI8 valueI8 = ESMF_HConfigAsI8MapVal(hconfigIter, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R4) :: valueR4 valueR4 = ESMF_HConfigAsR4MapVal(hconfigIter, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R8) :: valueR8 valueR8 = ESMF_HConfigAsR8MapVal(hconfigIter, asOkay=asOkay, rc=rc)
! logical :: valueL valueL = ESMF_HConfigAsLogicalMapVal(hconfigIter, asOkay=asOkay, rc=rc)
else ! Deal with case where either key or value are not scalars themselves. endif enddo
The map values stored in hconfig can be accessed in random order providing the map key.
To demonstrate this, a temporary array holding keys in random order is defined.
! character(5) :: keyList(3) keyList = ["bike ", "plane", "car "]
Then loop over the elements of keyList and use them as map key to access the map values in hconfig.
! integer :: i do i=1,3 ! Ensure that all white space padding is removed. ! character :: stringKey stringKey = trim(keyList(i)) ! Check whether the accessed map value is a scalar. ! logical :: isScalar isScalar = ESMF_HConfigIsScalar(hconfig, keyString=stringKey, rc=rc)
if (isScalar) then ! Access as a string always works. ! character(len=:), allocatable :: string string = ESMF_HConfigAsString(hconfig, keyString=stringKey, rc=rc)
! The attempt can be made to interpret the scalar as any of the other ! supported data types. By default, if the scalar cannot be interpreted ! as the requested data type, rc /= ESMF_SUCCESS is returned. To prevent ! such error condition, the optional, intent(out) argument "asOkay" can ! be provided. If asOkay == .true. is returned, the interpretation was ! successful. Otherwise asOkay == .false. is returned. ! logical :: asOkay ! integer(ESMF_KIND_I4) :: valueI4 valueI4 = ESMF_HConfigAsI4(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
! integer(ESMF_KIND_I8) :: valueI8 valueI8 = ESMF_HConfigAsI8(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R4) :: valueR4 valueR4 = ESMF_HConfigAsR4(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
! real(ESMF_KIND_R8) :: valueR8 valueR8 = ESMF_HConfigAsR8(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
! logical :: valueL valueL = ESMF_HConfigAsLogical(hconfig, keyString=stringKey, asOkay=asOkay, rc=rc)
else ! Deal with case where either key or value are not scalars themselves. endif enddo
The above loop is safe with respect to stringKey potentially specifying a value that is not a valid map key. This is because ESMF_HConfigIsScalar() returns .false. in this case.
The general check to see whether a map key refers to a valid element is provided by ESMF_HConfigIsDefined().
! logical :: isDefined isDefined = ESMF_HConfigIsDefined(hconfig, keyString="bad-key", rc=rc)
This returns isDefined == .false. because hconfig does not contain "bad-key" as one of its valid map keys.
Finally destroy hconfig when done.
call ESMF_HConfigDestroy(hconfig, rc=rc)
The ESMF_Config class can be queried for a HConfig object. This allows the use of the HConfig API to access information contained in a Config object.
! type(ESMF_Config) :: config ! type(ESMF_HConfig) :: hconfig call ESMF_ConfigGet(config, hconfig=hconfig, rc=rc)
The hconfig obtained this way is indistinguishable from an explicitly created HConfig instance. E.g. it can be queried for its type using the Is methods:
! logical :: isDefined isDefined = ESMF_HConfigIsDefined(hconfig, rc=rc)
! logical :: isNull isNull = ESMF_HConfigIsNull(hconfig, rc=rc)
! logical :: isSequence isSequence = ESMF_HConfigIsSequence(hconfig, rc=rc)
! logical :: isMap isMap = ESMF_HConfigIsMap(hconfig, rc=rc)
Once done with hconfig it must not be destroyed explicitly by the user. The hconfig is still owned by the config object, and will be destroyed automatically when the config object is destroyed. This follows the simple rule that a user only owns those objects created explicitly by calling a Create() method.
One option to load a YAML file is to first create an empty HConfig object, followed by calling ESMF_HConfigFileLoad().
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(rc=rc)
call ESMF_HConfigFileLoad(hconfig, filename="example.yaml", rc=rc)
! When done destroy as usual. call ESMF_HConfigDestroy(hconfig, rc=rc)
The alternative option is to create and load the HConfig object in a single call to ESMF_HConfigCreate() using the optional filename argument to specify the YAML file.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
! And again destroy hconfig when done with it. call ESMF_HConfigDestroy(hconfig, rc=rc)
A HConfig object can be saved to a YAML file by calling the ESMF_HConfigFileSave() method. To demonstrate this, a YAML file containing:
# An example of YAML configuration file simple_list: [1, 2, 3, abc, b, TRUE] simple_map: car: red [bike, {p1: 10, p2: 20}]: [bmx, mountain, street] plane: [TRUE, FALSE]
is loaded to create the hconfig object:
hconfig = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
Now the hconfig object can be saved to file using the ESMF_HConfigFileSave() method.
call ESMF_HConfigFileSave(hconfig, filename="saveMe.yml", rc=rc)
Notice that the resulting contents of file saveMe.yml does not contain the comments of the original file. The YAML structure is saved.
simple_list: [1, 2, 3, abc, b, TRUE] simple_map: car: red [bike, {p1: 10, p2: 20}]: [bmx, mountain, street] plane: [TRUE, FALSE]
The object specified in ESMF_HConfigFileSave() can be a regular node (of any type) or a sequence iterator. In either case the file written represents the YAML hierarchy with the specified object as the root node.
In the case of a map iterator, it is necessary to first create an appropriate root node utilizing the appropriate CreateAt method. This allows saving either the map key or map value node at the current iterator. This is demonstrated below.
In the current example, where hconfig is a map with two elements, a map iterator can be set to the beginning using the following call.
! type(ESMF_HConfigIter) :: hconfigIter hconfigIter = ESMF_HConfigIterBegin(hconfig, rc=rc)
Here hconfigIter cannot be saved to file directly. To write the key node, first create a HConfig object for it using method ESMF_HConfigCreateAtMapKey().
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAtMapKey(hconfigIter, rc=rc)
Then save it.
call ESMF_HConfigFileSave(hconfigTemp, filename="mapKeyBegin.yaml", rc=rc)
And finally destroy hconfigTemp again.
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
Similarly, to write the value node to file, first create a HConfig object for it using method ESMF_HConfigCreateAtMapVal().
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAtMapVal(hconfigIter, rc=rc)
Then save it.
call ESMF_HConfigFileSave(hconfigTemp, filename="mapValBegin.yaml", rc=rc)
And destroy it.
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
Since hconfig is a map node, it is also possible to directly create a value node by calling ESMF_HConfigCreateAt() on it, using the desired key.
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAt(hconfig, keyString="simple_map", rc=rc)
Now hconfigTemp points to the value node, that is associated with the "simple_map" key, which is in turn a map:
car: red [bike, {p1: 10, p2: 20}]: [bmx, mountain, street] plane: [TRUE, FALSE]It can be saved to file as usual.
call ESMF_HConfigFileSave(hconfigTemp, filename="mapValAtKey.yaml", rc=rc)
Any of the value nodes of hconfigTemp can be accessed through recursive usage of the ESMF_HConfigCreateAt() method. For example, the following call accesses the value node that is associated with keyString="[bike, p1: 10, p2: 20]". Here the keyString is interpreted as YAML syntax, for which an internal HConfig representation is created, and finally the map held by hconfigTemp is searched for a matching key.
! type(ESMF_HConfig) :: hconfigTemp2 hconfigTemp2 = ESMF_HConfigCreateAt(hconfigTemp, & keyString="[bike, {p1: 10, p2: 20}]", rc=rc)
Now hconfigTemp2 points to the sequence node with contents [bmx, mountain, street]. It, too, can be saved to file.
call ESMF_HConfigFileSave(hconfigTemp2, filename="mapValRecursive.yaml", rc=rc)
Finally hconfigTemp2, hconfigTemp and hconfig should be destroyed.
call ESMF_HConfigDestroy(hconfigTemp2, rc=rc)
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
call ESMF_HConfigDestroy(hconfig, rc=rc)
The HConfig class implements tags to identify a node's data type according to the YAML standard. The combination of a set of defined tags and a mechanism to resolve non-specific tags is called a schema under YAML. The HConfig class implements the YAML Core schema, which is an extension of the JSON schema.
This example starts with an empty HConfig object.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(rc=rc)
Method ESMF_HConfigGetTag() is used to query the tag.
! character(len=:), allocatable :: tag tag = ESMF_HConfigGetTag(hconfig, rc=rc)
Next, file exampleWithTags.yaml is loaded.
call ESMF_HConfigFileLoad(hconfig, filename="exampleWithTags.yaml", rc=rc)
The file contains the following YAML:
value_one: {word1: this, word2: is, word3: a, word4: map} value_two: [this, is, a, list] value_three: 123 value_four: !!float 123 value_five: 2.5 value_six: !!str 2.5 value_seven: False value_eight: !!str true value_nine: 0x234 value_ten: Null value_eleven: value_twelve: !myStuff xyz
The value associated with map key "value_ten" is explicitly set to Null. The associated tag for this node can be obtained directly by supplying the keyString argument.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_ten", rc=rc)
The resolved Core schema tag is again tag:yaml.org,2002:null. There are four special values that resolve to this tag: null, Null, NULL, and . In addition to those special values, an empty value, as demonstrated by key "value_eleven", also automatically resolves to tag:yaml.org,2002:null.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_eleven", rc=rc)
tag = ESMF_HConfigGetTag(hconfig, rc=rc)
results in the Core schema tag of tag:yaml.org,2002:map.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_two", rc=rc)
The resolved Core schema tag for a sequence is tag:yaml.org,2002:seq.
! type(ESMF_HConfigIter) :: hconfigIter hconfigIter = ESMF_HConfigIterBegin(hconfig, rc=rc)
Now the ESMF_HConfigGetTagMapKey() method can be used to obtain the tag for the first key node.
tag = ESMF_HConfigGetTagMapKey(hconfigIter, rc=rc)
Here the Core schema tag resolves to tag:yaml.org,2002:str.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_three", rc=rc)
The Core schema tag resolves to tag:yaml.org,2002:int.
The value associated with map key "value_nine" in the current hconfig object is an integer number in hex. The tag for this node can be obtained as before by directly supplying the keyString argument.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_nine", rc=rc)
The Core schema tag resolves to tag:yaml.org,2002:int.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_five", rc=rc)
The Core schema tag resolves to tag:yaml.org,2002:float.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_seven", rc=rc)
The Core schema tag resolves to tag:yaml.org,2002:bool. The supported boolean values are true, True, TRUE, false, False, and FALSE.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_four", rc=rc)
tag = ESMF_HConfigGetTag(hconfig, keyString="value_six", rc=rc)
tag = ESMF_HConfigGetTag(hconfig, keyString="value_eight", rc=rc)
The default resolution of these three keys would be tag:yaml.org,2002:int, tag:yaml.org,2002:float, and tag:yaml.org,2002:bool, respectively. However, with the explict tags in place, they are resolved to tag:yaml.org,2002:float, tag:yaml.org,2002:str, tag:yaml.org,2002:str, instead.
The value associated with map key "value_twelve" in the current hconfig object has a custom tag. The tag for this node can be obtained as before by directly supplying the keyString argument.
tag = ESMF_HConfigGetTag(hconfig, keyString="value_twelve", rc=rc)
The returned tag is !myStuff.
Finally clean up hconfig.
! Destroy hconfig when done with it. call ESMF_HConfigDestroy(hconfig, rc=rc)
After creating a HConfig object without specifying content or filename, it is empty.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(rc=rc)
Now the ESMF_HConfigAdd() method can be used to add new elements to an existing HConfig object. The Add() interfaces are heavily overloaded, each specific entry point featuring a number of optional arguments. The two fundamentally different ways of using Add() are: (1) adding an element at the end of a sequence or (2) adding an element to a map. Here, where hconfig is empty, either option is possible. The way the first element is added determines whether hconfig is a sequence or a map.
The following call adds an element to hconfig without specifying the addKey or addKeyString argument. This indicates that a sequence element is added to the end, and as a consequence rendering hconfig a sequence.
call ESMF_HConfigAdd(hconfig, "first added item", rc=rc)
Additional elements can be added at the end of hconfig.
call ESMF_HConfigAdd(hconfig, 12.57_ESMF_KIND_R8, rc=rc)
At this point, the content of hconfig is a sequence with two elements.
- first added item - 12.5700000000
It is also possible to add an entire HConfig structure as an item to the existing sequence. One way to do this is to use standar YAML syntax when adding the element. Here a map is added to the end of hconfig.
call ESMF_HConfigAdd(hconfig, "{k1: 7, k2: 25}", rc=rc)
This results in the following content, where the third element of the sequence is the map that was just added.
- first added item - 12.5700000000 - {k1: 7, k2: 25}
A HConfig structure can even be loaded from file and added to the end of hconfig. This requires a temporary HConfig object.
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreate(filename="example.yaml", rc=rc)
call ESMF_HConfigAdd(hconfig, hconfigTemp, rc=rc)
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
The result is the following content for hconfig.
- first added item - 12.5700000000 - {k1: 7, k2: 25} - simple_list: [1, 2, 3, abc, b, TRUE] simple_map: car: red [bike, {p1: 10, p2: 20}]: [bmx, mountain, street] plane: [TRUE, FALSE]
Using the CreateAt() method, it is easy to gain access to any specific element in hconfig. Since hconfig is a sequence, the proper access is by index.
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=3, rc=rc)
This creates a temporary HConfig object that references the 3rd element of the sequence stored by hconfig. If hconfigTemp were to be saved to file, it would have the following content.
{k1: 7, k2: 25}
Using the Set() methods, contents in hconfigTemp, and thus in the 3rd element of hconfig can be modified. The content of hconfigTemp is a map, and the proper access is by map key. Here key "k2" is being modified.
call ESMF_HConfigSet(hconfigTemp, 12.5, keyString="k2", rc=rc)
The hconfigTemp is a reference to a map, and new elements can be added using the addKeyString argument.
call ESMF_HConfigAdd(hconfigTemp, .true., addKeyString="k3", rc=rc)
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
After these operations, the content of hconfig has changed to
- first added item - 12.5700000000 - {k1: 7, k2: 12.5000000000, k3: True} - simple_list: [1, 2, 3, abc, b, TRUE] simple_map: car: red [bike, {p1: 10, p2: 20}]: [bmx, mountain, street] plane: [TRUE, FALSE]Notice that while hconfigTemp should be destroyed explicitly, as in the example above, doing so does not affect the referenced node inside the hconfig object. In other words, hconfigTemp was a reference, and not a deep copy of the node! There is some allocated memory associated with the hconfigTemp reference that gets cleaned up with the Destroy() call, but it does not affect the reference itself.
The Set() method can also be used to edit the element referenced itself. Here the 4th element in the hconfig sequence is set to be a simple scalar string value using this approach.
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=4, rc=rc)
call ESMF_HConfigSet(hconfigTemp, "Simple scalar string value", rc=rc)
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
The content of hconfig has been updated as below.
- first added item - 12.5700000000 - {k1: 7, k2: 12.5000000000, k3: True} - Simple scalar string value
There is a simpler alternative for direct element editing in an HConfig object via the Set() method. Using the index or keyString argument, a sequence or map element, respectively, can be edited directly. For instance,
call ESMF_HConfigSet(hconfig, "[a, b, c]", index=4, rc=rc)
sets the 4th element of hconfig directly, without the need of a temporary HConfig variable. This updates the content to:
- first added item - 12.5700000000 - {k1: 7, k2: 12.5000000000, k3: True} - [a, b, c]
Elements can be deleted from a HConfig object holding a sequence or map using the Remove() method, specifying the index or map key, respectively. Here the 2nd element of the sequence held by hconfig is removed.
call ESMF_HConfigRemove(hconfig, index=2, rc=rc)
The result is a sequence with only three remaining elements.
- first added item - {k1: 7, k2: 12.5000000000, k3: True} - [a, b, c]
To demonstrate removal of an element from a map, the second hconfig element is referenced by a temporary HConfig object. The element with key "k2" is then removed using the respective Remove() method.
! type(ESMF_HConfig) :: hconfigTemp hconfigTemp = ESMF_HConfigCreateAt(hconfig, index=2, rc=rc)
call ESMF_HConfigRemove(hconfigTemp, keyString="k2", rc=rc)
call ESMF_HConfigDestroy(hconfigTemp, rc=rc)
The resulting hconfig content is as expected.
- first added item - {k1: 7, k3: True} - [a, b, c]
Finally the entire contents of hconfig can be deleted by setting the node itself to one of the special NULL values.
call ESMF_HConfigSet(hconfig, "NULL", rc=rc)
If saved to file, the contents of hconfig shows up as a simple tilde character, indicating its NULL value.
~
At this point hconfig is neither a sequence nor a map. It is NULL. Adding a map element, i.e. an element with a key, turns hconfig into a map.
call ESMF_HConfigAdd(hconfig, "first added item", addKeyString="item1", rc=rc)
The contents of hconfig now is a map with a single entry: character, indicating its NULL value.
item1: first added item
As in other contexts before, the content as well as the specified addKeyString can be of any legal YAML syntax. This is demonstrated in the following Add() calls.
! Add YAML sequence content with simple scalar key. call ESMF_HConfigAdd(hconfig, "[2, added, item]", addKeyString="item2", rc=rc)
! Add simple scalar content with a YAML map as key. call ESMF_HConfigAdd(hconfig, "third added item", addKeyString="{item: 3}", & rc=rc)
! Add complex YAML content with YAML sequence as key. call ESMF_HConfigAdd(hconfig, "{4th: item, 5th: [true, false]}", & addKeyString="[1, 2, 3, 4]", rc=rc)
Resulting in the final contents of hconfig:
item1: first added item item2: [2, added, item] {item: 3}: third added item [1, 2, 3, 4]: {4th: item, 5th: [true, false]}Finally clean up hconfig.
! Destroy hconfig when done with it. call ESMF_HConfigDestroy(hconfig, rc=rc)
The YAML standard supports multiple documents in a single file by separating each document with a line containing three dashes (--). Optionally the end of each document may be indicated by three periods (...). For example, the following YAML file contains three documents (notice the optional usage of the document end marker):
--- - This - is - the - first document. ... --- - And - a second document. --- - And - finally a - third document.All of the documents contained in a YAML file can be loaded into a single HConfig object all at once.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(filename="multiDoc.yaml", rc=rc)
The number of documents held by hconfig can be queried.
! integer :: docCount docCount = ESMF_HConfigGetDocCount(hconfig, rc=rc)
When saving hconfig, a multi-document YAML file will be written.
call ESMF_HConfigFileSave(hconfig, filename="multi_00.yaml", rc=rc)
The ESMF_HConfigFileSave() method implements strict usage of both document markers when saving a multi-document HConfig object.
--- - This - is - the - first document. ... --- - And - a second document. ... --- - And - finally a - third document. ...
The optional doc argument can be specified when saving the multi-document hconfig to file. Only the specified document, by index, is written to file.
call ESMF_HConfigFileSave(hconfig, filename="multi_01.yaml", doc=2, rc=rc)
This operation results in a single document file:
- And - a second document.The ESMF_HConfigFileLoad() method also accepts the optional doc argument. When specified, the result is a single-document hconfig object, holding the content of the indicated document within the loaded file.
call ESMF_HConfigFileLoad(hconfig, filename="multiDoc.yaml", doc=3, rc=rc)
Saving hconfig to file shows the expected situation.
call ESMF_HConfigFileSave(hconfig, filename="multi_02.yaml", rc=rc)
Resulting in:
- And - finally a - third document.
Most HConfig methods provide the optional doc argument. If present, the method applies to the specified document. The default for when the doc argument is not present, for most methods is to use the first document in the object. The exceptions to this rule are the ESMF_HConfigFileSave() and ESMF_HConfigFileLoad() methods. Here the default is to apply the operation to all documents.
When done, clean up hconfig as usual.
! Destroy hconfig when done with it. call ESMF_HConfigDestroy(hconfig, rc=rc)
The HConfig class offers shortcut methods for the sake of convenience when working with sequences where all elements are of the same typekind. In these cases a sequence can be represented as a one-dimensional Fortran array. The interfaces are overloaded for one-dimensional string, logical, I4, I8, R4, and R8 typekinds.
Using a Fortran array constructor for the actual argument, a sequence of I4 data is created.
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate([1,2,3], rc=rc)
The content of hconfig can be accessed in the usual manner, via iterators or indexed access. Alternatively, the sequence of I4 elements can be retrieved in a single call using a one-dimensional allocatable Fortran array of the appropriate typekind.
! integer(ESMF_KIND_I4), allocatable :: valueI4Seq(:) valueI4Seq = ESMF_HConfigAsI4Seq(hconfig, rc=rc)
The optional, intent(out) argument asOkay is available as in the scalar access methods. If specified, errors triggered by unsupported typekind conversion exceptions are suppressed, and instead asOkay == .false. is returned by the call.
Here an attempt is made to access the content of hconfig as a sequence of logicals. This is not supported, and will be flagged in the return value of asOkay.
! logical, allocatable :: valueLSeq(:) valueLSeq = ESMF_HConfigAsLogicalSeq(hconfig, asOkay=asOkay, rc=rc)
Finally the content of hconfig is accessed as a sequence of strings. This is always supported since every typekind can be represented in string form.
! character(len=:), allocatable :: valueSSeq(:) valueSSeq = ESMF_HConfigAsStringSeq(hconfig, stringLen=10, asOkay=asOkay, rc=rc)
Next hconfig is cleaned up before re-creating it as an empty HConfig object.
! Clean up hconfig. call ESMF_HConfigDestroy(hconfig, rc=rc)
! type(ESMF_HConfig) :: hconfig hconfig = ESMF_HConfigCreate(rc=rc)
Sequences can be added to hconfig conveniently using the overloaded Add() interfaces that accept one-dimensional Fortran arrays. Here a sequence of strings is added as the value of a map entry with key string "k1".
call ESMF_HConfigAdd(hconfig, ["aaa","bbb","ccc"], addKeyString="k1", rc=rc)
Next a sequence of R4 values is added to the map held by hconfig, under key string "k2".
call ESMF_HConfigAdd(hconfig, [1.0,1.25,1.5], addKeyString="k2", rc=rc)
At this point hconfig contains the following information:
k1: - aaa - bbb - ccc k2: - 1 - 1.25 - 1.5
The Set() interfaces are also overloaded to accept one-dimensional Fortran arrays as input. This makes it easy to set any node to a sequence that is available as Fortran array. Here the value associated with key "k1" is changed to a list of two logicals.
call ESMF_HConfigSet(hconfig, [.true.,.false.], keyString="k1", rc=rc)
This changes the content of hconfig as expected.
k1: - True - False k2: - 1 - 1.25 - 1.5
Finally clean up hconfig as usual.
! Destroy hconfig when done with it. call ESMF_HConfigDestroy(hconfig, rc=rc)
The ESMF HConfig class is implemented on top of YAML-CPP (https://github.com/jbeder/yaml-cpp). A copy of YAML-CPP is included in the ESMF source tree under ./src/prologue/yaml-cpp. It is used by a number of ESMF/NUOPC functions, including HConfig.
INTERFACE:
interface operator(==) if (hconfig1 == hconfig2) then ... endif OR result = (hconfig1 == hconfig2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig1 type(ESMF_HConfig), intent(in) :: hconfig2DESCRIPTION:
Test whether hconfig1 and hconfig2 are valid aliases to the same ESMF HConfig object in memory. For a more general comparison of two ESMF HConfigs, going beyond the simple alias test, the ESMF_HConfigMatch() function (not yet fully implemented) must be used.
The arguments are:
INTERFACE:
interface operator(/=) if (hconfig1 /= hconfig2) then ... endif OR result = (hconfig1 /= hconfig2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig1 type(ESMF_HConfig), intent(in) :: hconfig2DESCRIPTION:
Test whether hconfig1 and hconfig2 are not valid aliases to the same ESMF HConfig object in memory. For a more general comparison of two ESMF HConfigs, going beyond the simple alias test, the ESMF_HConfigMatch() function (not yet fully implemented) must be used.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigAdd(hconfig, content, & addKey, addKeyString, index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_HConfig), intent(in), optional :: addKey character(*), intent(in), optional :: addKeyString integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Add the content of type <Type> to the hconfig, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
If either addKey or addKeyString (mutually exclusive!) is specified, then add a new map element with the respective key. Otherwise add a new list element at the end of the list. Error checking is implemented to ensure respective conditions are met.
The supported <Type> options are:
The arguments are:
INTERFACE:
subroutine ESMF_HConfigAddMapKey(hconfig, content, & addKey, addKeyString, index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_HConfig), intent(in), optional :: addKey character(*), intent(in), optional :: addKeyString integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Add the content of type <Type> to the hconfig map key, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
If either addKey or addKeyString (mutually exclusive!) is specified, then add a new map element with the respective key. Otherwise add a new list element at the end of the list. Error checking is implemented to ensure respective conditions are met.
The supported <Type> options are:
The arguments are:
INTERFACE:
subroutine ESMF_HConfigAddMapVal(hconfig, content, & addKey, addKeyString, index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_HConfig), intent(in), optional :: addKey character(*), intent(in), optional :: addKeyString integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Add the content of type <Type> to the hconfig map value, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
If either addKey or addKeyString (mutually exclusive!) is specified, then add a new map element with the respective key. Otherwise add a new list element at the end of the list. Error checking is implemented to ensure respective conditions are met.
The supported <Type> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type> :: ESMF_HConfigAs<TypeSpec>ARGUMENTS:
type(ESMF_HConfig[Iter]) , intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the value of item hconfig interpreted as <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>MapKey(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type> :: ESMF_HConfigAs<TypeSpec>MapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the map key of item hconfig interpreted as <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>MapVal(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type> :: ESMF_HConfigAs<TypeSpec>MapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the map value of item hconfig interpreted as <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>Seq(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type>, allocatable :: ESMF_HConfigAs<TypeSpec>Seq(:)ARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the value of item hconfig interpreted as sequence of <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
An extra non-optional argument stringLen must be provided for the String option. This argument specifies the number of characters in each of the output strings. Longer actual string values are tuncated, while shorter actual string values are padded with white space.
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>SeqMapKey(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type>, allocatable :: ESMF_HConfigAs<TypeSpec>SeqMapKey(:)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the map key of item hconfig interpreted as sequence of <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
An extra non-optional argument stringLen must be provided for the String option. This argument specifies the number of characters in each of the output strings. Longer actual string values are tuncated, while shorter actual string values are padded with white space.
The arguments are:
INTERFACE:
function ESMF_HConfigAs<TypeSpec>SeqMapVal(hconfig, index, keyString, & doc, asOkay, rc)RETURN VALUE:
<Type>, allocatable :: ESMF_HConfigAs<TypeSpec>SeqMapVal(:)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc logical, intent(out), optional :: asOkay integer, intent(out), optional :: rcDESCRIPTION:
Return the map value of item hconfig interpreted as sequence of <Type>. The returned value is only valid if rc == ESMF_SUCCESS, and, if provided, asOkay == .true..
The supported <Type> / <TypeSpec> options are:
An extra non-optional argument stringLen must be provided for the String option. This argument specifies the number of characters in each of the output strings. Longer actual string values are tuncated, while shorter actual string values are padded with white space.
The arguments are:
INTERFACE:
! Private name; call using ESMF_HConfigCreate() function ESMF_HConfigCreateDefault(content, filename, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateDefaultARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: content character(len=*), intent(in), optional :: filename integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object. The object is empty unless either the content or filename argument is specified.
The arguments are:
INTERFACE:
! Private name; call using ESMF_HConfigCreate() function ESMF_HConfigCreateHConfig(content, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateHConfigARGUMENTS:
type(ESMF_HConfig), intent(in) :: content -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object from existing HConfig object as a deep copy.
The arguments are:
INTERFACE:
function ESMF_HConfigCreate(content, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateARGUMENTS:
<Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object from content of type <Type>. All <Type> options support the sequence array variant (:) in addition to the scalar variant.
The supported <Type> options are:
The arguments are:
INTERFACE:
! Private name; call using ESMF_HConfigCreate() function ESMF_HConfigCreateStringSeq(content, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateStringSeqARGUMENTS:
character(len=*), intent(in) :: content(:) -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object.
The arguments are:
INTERFACE:
function ESMF_HConfigCreateAt(hconfig, index, key, & keyString, doc, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateAtARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index type(ESMF_HConfig), intent(in), optional :: key character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object at the current iteration, or as specified by index, key or keyString. The hconfig must not be a map iterator.
The arguments are:
INTERFACE:
function ESMF_HConfigCreateAtMapKey(hconfig, index, key, & keyString, doc, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateAtMapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index type(ESMF_HConfig), intent(in), optional :: key character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object for a map key at the current iteration, or as specified by index, key or keyString. The hconfig must be a map iterator.
The arguments are:
INTERFACE:
function ESMF_HConfigCreateAtMapVal(hconfig, index, key, & keyString, doc, rc)RETURN VALUE:
type(ESMF_HConfig) :: ESMF_HConfigCreateAtMapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index type(ESMF_HConfig), intent(in), optional :: key character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Create a new HConfig object for a map value at the current iteration, or as specified by index, key or keyString. The hconfig must be a map iterator.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigDestroy(hconfig, rc)ARGUMENTS:
type(ESMF_HConfig), intent(inout) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Destroys an ESMF_HConfig, releasing the resources associated with the object.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigFileLoad(hconfig, filename, doc, rc)ARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Load YAML file into hconfig.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigFileSave(hconfig, filename, doc, rc)ARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Save HConfig into YAML file. Only localPet == 0 does the writing. The hconfig must not be a map iterator.
The arguments are:
INTERFACE:
function ESMF_HConfigGetDocCount(hconfig, rc)RETURN VALUE:
integer :: ESMF_HConfigGetDocCountARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return the number of documents held by hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigGetSize(hconfig, index, keyString, doc, rc)RETURN VALUE:
integer :: ESMF_HConfigGetSizeARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return the number of elements in collection hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigGetSizeMapKey(hconfig, index, keyString, & doc, rc)RETURN VALUE:
integer :: ESMF_HConfigGetSizeMapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return size of the hconfig node.
The arguments are:
INTERFACE:
function ESMF_HConfigGetSizeMapVal(hconfig, index, keyString, & doc, rc)RETURN VALUE:
integer :: ESMF_HConfigGetSizeMapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return size of the hconfig node.
The arguments are:
INTERFACE:
function ESMF_HConfigGetTag(hconfig, index, keyString, doc, rc)RETURN VALUE:
character(len=:), allocatable :: ESMF_HConfigGetTagARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return tag string of the hconfig node.
The arguments are:
INTERFACE:
function ESMF_HConfigGetTagMapKey(hconfig, index, keyString, & doc, rc)RETURN VALUE:
character(len=:), allocatable :: ESMF_HConfigGetTagMapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return tag string of map key of the hconfig node.
The arguments are:
INTERFACE:
function ESMF_HConfigGetTagMapVal(hconfig, index, keyString, & doc, rc)RETURN VALUE:
character(len=:), allocatable :: ESMF_HConfigGetTagMapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return tag string of map key of the hconfig node.
The arguments are:
INTERFACE:
function ESMF_HConfigIs<NodeType>(hconfig, index, keyString, & doc, rc)RETURN VALUE:
logical :: ESMF_HConfigIs<NodeType>ARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the hconfig node is of node type <NodeType>. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will be .false..
The supported <NodeType> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigIs<NodeType>MapKey(hconfig, index, keyString, & doc, rc)RETURN VALUE:
logical :: ESMF_HConfigIs<NodeType>MapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the hconfig MapKey node is of node type <NodeType>. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will be .false..
The supported <NodeType> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigIs<NodeType>MapVal(hconfig, index, keyString, & doc, rc)RETURN VALUE:
logical :: ESMF_HConfigIs<NodeType>MapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the hconfig MapVal node is of node type <NodeType>. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will be .false..
The supported <NodeType> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigIterBegin(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterBeginARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to the first item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterBeginMapKey(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterBeginMapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to the first item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterBeginMapVal(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterBeginMapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to the first item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterEnd(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterEndARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to one past the last item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterEndMapKey(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterEndMapKeyARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to one past the last item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterEndMapVal(hconfig, rc)RETURN VALUE:
type(ESMF_HConfigIter) :: ESMF_HConfigIterEndMapValARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return an iterator that points to one past the last item in hconfig.
The arguments are:
INTERFACE:
function ESMF_HConfigIterIsMap(hconfig, rc)RETURN VALUE:
logical :: ESMF_HConfigIterIsMapARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the hconfig node is Null. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
function ESMF_HConfigIterIsSequence(hconfig, rc)RETURN VALUE:
logical :: ESMF_HConfigIterIsSequenceARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the hconfig node is Null. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
function ESMF_HConfigIterLoop(hconfig, hconfigBegin, hconfigEnd, rc)RETURN VALUE:
logical :: ESMF_HConfigIterLoopARGUMENTS:
type(ESMF_HConfigIter), intent(inout) :: hconfig type(ESMF_HConfigIter), intent(in) :: hconfigBegin type(ESMF_HConfigIter), intent(in) :: hconfigEnd -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Step the iterator hconfig forward. starting at hconfigBegin until hconfigEnd is reached. Returns .true. as long as hconfig has not reached hconfigEnd. Once this condition has been reached, returns .false..
The intended usage of ESMF_HConfigIterLoop() is as the conditional in a do while loop, iterating over the elements of a HConfig object.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigIterNext(hconfig, rc)ARGUMENTS:
type(ESMF_HConfigIter), intent(inout) :: hconfig -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Step the iterator hconfig one step forward.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigRemove(hconfig, index, keyString, rc)ARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfigIter -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(out), optional :: rcDESCRIPTION:
Remove an element from a squence or map HConfig object. Either index (for sequence) or keyString (for map) must be provided. An error is flagged if neither optional argument is specified.
The arguments are:
INTERFACE:
subroutine ESMF_HConfigSet(hconfig, content, & index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfig[Iter]), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Set the content of type <Type> to hconfig, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
The supported <Type> options are:
The arguments are:
INTERFACE:
subroutine ESMF_HConfigSet(hconfig, content, & index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Set the content of type <Type> to the hconfig map key, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
The supported <Type> options are:
The arguments are:
INTERFACE:
subroutine ESMF_HConfigSet(hconfig, content, & index, keyString, doc, rc)ARGUMENTS:
type(ESMF_HConfigIter), intent(in) :: hconfig <Type>, intent(in) :: content[(:)] -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: index character(*), intent(in), optional :: keyString integer, intent(in), optional :: doc integer, intent(out), optional :: rcDESCRIPTION:
Set the content of type <Type> to the hconfig map value, at the current location, or as specified by index or keyString (mutually exclusive!). Most <Type> options support the sequence array variant (:) in addition to the scalar variant.
The supported <Type> options are:
The arguments are:
INTERFACE:
function ESMF_HConfigValidateMapKeys(hconfig, vocabulary, & badKey, rc)RETURN VALUE:
logical :: ESMF_HConfigValidateMapKeysARGUMENTS:
type(ESMF_HConfig), intent(in) :: hconfig character(len=*), intent(in) :: vocabulary(:) -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(:), allocatable, intent(out), optional :: badKey integer, intent(out), optional :: rcDESCRIPTION:
Validate that the map held in hconfig only uses keys that are listed in vocabulary.
The arguments are:
The Log class consists of a variety of methods for writing error, warning, and informational messages to files. A default Log is created at ESMF initialization. Other Logs can be created later in the code by the user. Most Log methods take a Log as an optional argument and apply to the default Log when another Log is not specified. A set of standard return codes and associated messages are provided for error handling.
Log provides capabilities to store message entries in a buffer, which is flushed to a file, either when the buffer is full, or when the user calls an ESMF_LogFlush() method. Currently, the default is for the Log to flush after every ten entries. This can easily be changed by using the ESMF_LogSet() method and setting the maxElements property to another value. The ESMF_LogFlush() method is automatically called when the program exits by any means (program completion, halt on error, or when the Log is closed).
The user has the capability to abort the program on conditions such as an error or on a warning by using the ESMF_LogSet() method with the logmsgAbort argument. For example if the logmsgAbort array is set to (ESMF_LOGMSG_ERROR,ESMF_LOGMSG_WARNING), the program will stop on any and all warning or errors. When the logmsgAbort argument is set to ESMF_LOGMSG_ERROR, the program will only abort on errors. Lastly, the user can choose to never abort by using ESMF_LOGMSG_NONE; this is the default.
Log will automatically put the PET number into the Log. Also, the user can either specify ESMF_LOGKIND_SINGLE which writes all the entries to a single Log or ESMF_LOGKIND_MULTI which writes entries to multiple Logs according to the PET number. To distinguish Logs from each other when using ESMF_LOGKIND_MULTI, the PET number (in the format PETx.) will be prepended to the file name where x is the PET number.
Opening multiple log files and writing log messages from all the processors may affect the application performance while running on a large number of processors. For that reason, ESMF_LOGKIND_NONE is provided to switch off the Log capability. All the Log methods have no effect in the ESMF_LOGKIND_NONE mode.
A tracing capability may be enabled by setting the trace flag by using the ESMF_LogSet() method. When tracing is enabled, calls to methods such as ESMF_LogFoundError, ESMF_LogFoundAllocError, and ESMF_LogFoundDeallocError are logged in the default log file. This can result in voluminous output. It is typically used only around areas of code which are being debugged.
Other options that are planned for Log are to adjust the verbosity of output, and to optionally write to stdout instead of file(s).
The valid values are:
DESCRIPTION:
Specifies a single log file, multiple log files (one per PET), or no log files.
The type of this flag is:
type(ESMF_LogKind_Flag)
The valid values are:
DESCRIPTION:
Specifies a message level
The type of this flag is:
type(ESMF_LogMsg_Flag)
The valid values are:
Valid predefined named array constant values are:
By default ESMF_Initialize() opens a default Log in ESMF_LOGKIND_MULTI mode. ESMF handles the initialization and finalization of the default Log so the user can immediately start using it. If additional Log objects are desired, they must be explicitly created or opened using ESMF_LogOpen().
ESMF_LogOpen() requires a Log object and filename argument. Additionally, the user can specify single or multi Logs by setting the logkindflag property to ESMF_LOGKIND_SINGLE or ESMF_LOGKIND_MULTI. This is useful as the PET numbers are automatically added to the Log entries. A single Log will put all entries, regardless of PET number, into a single log while a multi Log will create multiple Logs with the PET number prepended to the filename and all entries will be written to their corresponding Log by their PET number.
By default, the Log file is not truncated at the start of a new run; it just gets appended each time. Future functionality may include an option to either truncate or append to the Log file.
In all cases where a Log is opened, a Fortran unit number is assigned to a specific Log. A Log is assigned an unused unit number using the algorithm described in the ESMF_IOUnitGet() method.
The user can then set or get options on how the Log should be used with the ESMF_LogSet() and ESMF_LogGet() methods. These are partially implemented at this time.
Depending on how the options are set, ESMF_LogWrite() either writes user messages directly to a Log file or writes to a buffer that can be flushed when full or by using the ESMF_LogFlush() method. The default is to flush after every ten entries because maxElements is initialized to ten (which means the buffer reaches its full state after every ten writes and then flushes).
A message filtering option may be set with ESMF_LogSet() so that only selected message types are actually written to the log. One key use of this feature is to allow placing informational log write requests into the code for debugging or tracing. Then, when the informational entries are not needed, the messages at that level may be turned off -- leaving only warning and error messages in the logs.
For every ESMF_LogWrite(), a time and date stamp is prepended to the Log entry. The time is given in microsecond precision. The user can call other methods to write to the Log. In every case, all methods eventually make a call implicitly to ESMF_LogWrite() even though the user may never explicitly call it.
When calling ESMF_LogWrite(), the user can supply an optional line, file and method. These arguments can be passed in explicitly or with the help of cpp macros. In the latter case, a define for an ESMF_FILENAME must be placed at the beginning of a file and a define for ESMF_METHOD must be placed at the beginning of each method. The user can then use the ESMF_CONTEXT cpp macro in place of line, file and method to insert the parameters into the method. The user does not have to specify line number as it is a value supplied by cpp.
An example of Log output is given below running with logkindflag property set to ESMF_LOGKIND_MULTI (default) using the default Log:
(Log file PET0.ESMF_LogFile)
20041105 163418.472210 INFO PET0 Running with ESMF Version 2.2.1
(Log file PET1.ESMF_LogFile)
20041105 163419.186153 ERROR PET1 ESMF_Field.F90 812 ESMF_FieldGet No Grid or Bad Grid attached to Field
The first entry shows date and time stamp. The time is given in microsecond precision. The next item shown is the type of message (INFO in this case). Next, the PET number is added. Lastly, the content is written.
The second entry shows something slightly different. In this case, we have an ERROR. The method name (ESMF_Field.F90) is automatically provided from the cpp macros as well as the line number (812). Then the content of the message is written.
When done writing messages, the default Log is closed by calling ESMF_LogFinalize() or ESMF_LogClose() for user created Logs. Both methods will release the assigned unit number.
! !PROGRAM: ESMF_LogErrEx - Log Error examples ! ! !DESCRIPTION: ! ! This program shows examples of Log Error writing !-----------------------------------------------------------------------------
! Macros for cpp usage ! File define #define ESMF_FILENAME "ESMF_LogErrEx.F90" ! Method define #define ESMF_METHOD "program ESMF_LogErrEx" #include "ESMF_LogMacros.inc" ! ESMF Framework module use ESMF use ESMF_TestMod implicit none ! return variables integer :: rc1, rc2, rc3, rcToTest, allocRcToTest, result type(ESMF_LOG) :: alog ! a log object that is not the default log type(ESMF_LogKind_Flag) :: logkindflag type(ESMF_Time) :: time type(ESMF_VM) :: vm integer, pointer :: intptr(:)
This example shows how to use the default Log. This example does not use cpp macros but does use multi Logs. A separate Log will be created for each PET.
! Initialize ESMF to initialize the default Log call ESMF_Initialize(vm=vm, defaultlogfilename="LogErrEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc1)
! LogWrite call ESMF_LogWrite("Log Write 2", ESMF_LOGMSG_INFO, rc=rc2)
! LogMsgSetError call ESMF_LogSetError(ESMF_RC_OBJ_BAD, msg="Convergence failure", & rcToReturn=rc2)
! LogMsgFoundError call ESMF_TimeSet(time, calkindflag=ESMF_CALKIND_NOCALENDAR) call ESMF_TimeSyncToRealTime(time, rc=rcToTest) if (ESMF_LogFoundError(rcToTest, msg="getting wall clock time", & rcToReturn=rc2)) then ! Error getting time. The previous call will have printed the error ! already into the log file. Add any additional error handling here. ! (This call is expected to provoke an error from the Time Manager.) endif ! LogMsgFoundAllocError allocate(intptr(10), stat=allocRcToTest) if (ESMF_LogFoundAllocError(allocRcToTest, msg="integer array", & rcToReturn=rc2)) then ! Error during allocation. The previous call will have logged already ! an error message into the log. endif deallocate(intptr)
! Open a Log named "Testlog.txt" associated with alog. call ESMF_LogOpen(alog, "TestLog.txt", rc=rc1)
%///////////////////////////////////////////////////////////// \begin{verbatim} ! LogWrite call ESMF_LogWrite("Log Write 2", ESMF_LOGMSG_INFO, & line=__LINE__, file=ESMF_FILENAME, & method=ESMF_METHOD, log=alog, rc=rc2)
! LogMsgSetError call ESMF_LogSetError(ESMF_RC_OBJ_BAD, msg="Interpolation Failure", & line=__LINE__, file=ESMF_FILENAME, & method=ESMF_METHOD, rcToReturn=rc2, log=alog)
! This is an example showing a query of the default Log. Please note that ! no Log is passed in the argument list, so the default Log will be used. call ESMF_LogGet(logkindflag=logkindflag, rc=rc3)
! This is an example setting a property of a Log that is not the default. ! It was opened in a previous example, and the handle for it must be ! passed in the argument list. call ESMF_LogSet(log=alog, logmsgAbort=(/ESMF_LOGMSG_ERROR/), rc=rc2)
! Close the user log. call ESMF_LogClose(alog, rc=rc3)
! Finalize ESMF to close the default log call ESMF_Finalize(rc=rc1)
The properties for a Log are set with the ESMF_LogSet() method and retrieved with the ESMF_LogGet() method.
Additionally, buffering is enabled. Buffering allows ESMF to manage output data streams in a desired way. Writing to the buffer is transparent to the user because all the Log entries are handled automatically by the ESMF_LogWrite() method. All the user has to do is specify the buffer size (the default is ten) by setting the maxElements property. Every time the ESMF_LogWrite() method is called, a LogEntry element is populated with the ESMF_LogWrite() information. When the buffer is full (i.e., when all the LogEntry elements are populated), the buffer will be flushed and all the contents will be written to file. If buffering is not needed, that is maxElements=1 or flushImmediately=ESMF_TRUE, the ESMF_LogWrite() method will immediately write to the Log file(s).
The following is a simplified UML diagram showing the structure of the Log class. See Appendix A, A Brief Introduction to UML, for a translation table that lists the symbols in the diagram and their meaning.
INTERFACE:
interface assignment(=) log1 = log2ARGUMENTS:
type(ESMF_Log) :: log1 type(ESMF_Log) :: log2DESCRIPTION:
Assign log1 as an alias to the same ESMF_Log object in memory as log2. If log2 is invalid, then log1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (log1 == log2) then ... endif OR result = (log1 == log2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Log), intent(in) :: log1 type(ESMF_Log), intent(in) :: log2DESCRIPTION:
Overloads the (==) operator for the ESMF_Log class. Compare two logs for equality; return .true. if equal, .false. otherwise. Comparison is based on whether the objects are distinct, as with two newly created logs, or are simply aliases to the same log as would be the case when assignment was involved.
The arguments are:
INTERFACE:
interface operator(/=) if (log1 /= log2) then ... endif OR result = (log1 /= log2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_Log), intent(in) :: log1 type(ESMF_Log), intent(in) :: log2DESCRIPTION:
Overloads the (/=) operator for the ESMF_Log class. Compare two logs for inequality; return .true. if equal, .false. otherwise. Comparison is based on whether the objects are distinct, as with two newly created logs, or are simply aliases to the same log as would be the case when assignment was involved.
The arguments are:
INTERFACE:
subroutine ESMF_LogClose(log, rc)ARGUMENTS:
type(ESMF_Log), intent(inout), optional :: log -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This routine closes the log file(s) associated with log. If the log is not explicitly closed, it will be closed by ESMF_Finalize.
The arguments are:
INTERFACE:
subroutine ESMF_LogFlush(log, rc)ARGUMENTS:
type(ESMF_Log), intent(inout), optional :: log -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This subroutine flushes the file buffer associated with log.
The arguments are:
INTERFACE:
function ESMF_LogFoundAllocError(statusToCheck, & msg,line,file, & method,rcToReturn,log)RETURN VALUE:
logical :: ESMF_LogFoundAllocErrorARGUMENTS:
integer, intent(in) :: statusToCheck -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: msg integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method integer, intent(inout), optional :: rcToReturn type(ESMF_Log), intent(inout), optional :: logSTATUS:
DESCRIPTION:
This function returns .true. when statusToCheck indicates an allocation error, otherwise it returns .false.. The status value is typically returned from a Fortran ALLOCATE statement. If an error is indicated, a ESMF memory allocation error message will be written to the ESMF_Log along with a user added msg, line, file and method.
The arguments are:
INTERFACE:
function ESMF_LogFoundDeallocError(statusToCheck, & msg,line,file, & method,rcToReturn,log)RETURN VALUE:
logical ::ESMF_LogFoundDeallocErrorARGUMENTS:
integer, intent(in) :: statusToCheck -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: msg integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method integer, intent(inout), optional :: rcToReturn type(ESMF_Log), intent(inout), optional :: logSTATUS:
DESCRIPTION:
This function returns .true. when statusToCheck indicates a deallocation error, otherwise it returns .false.. The status value is typically returned from a Fortran DEALLOCATE statement. If an error is indicated, a ESMF memory allocation error message will be written to the ESMF_Log along with a user added msg, line, file and method.
The arguments are:
INTERFACE:
recursive function ESMF_LogFoundError(rcToCheck, & msg, line, file, method, & rcToReturn, log) result (LogFoundError)RETURN VALUE:
logical :: LogFoundErrorARGUMENTS:
integer, intent(in), optional :: rcToCheck -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: msg integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method integer, intent(inout), optional :: rcToReturn type(ESMF_Log), intent(inout), optional :: logSTATUS:
DESCRIPTION:
This function returns .true. when rcToCheck indicates an return code other than ESMF_SUCCESS, otherwise it returns .false.. If an error is indicated, a ESMF predefined error message will be written to the ESMF_Log along with a user added msg, line, file and method.
The arguments are:
INTERFACE:
function ESMF_LogFoundNetCDFError(ncerrToCheck, msg, line, & file, method, rcToReturn, log) #if defined ESMF_NETCDF use netcdf #elif defined ESMF_PNETCDF use pnetcdf #endifRETURN VALUE:
logical :: ESMF_LogFoundNetCDFErrorARGUMENTS:
integer, intent(in) :: ncerrToCheck -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: msg integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method integer, intent(inout), optional :: rcToReturn type(ESMF_Log), intent(inout), optional :: logDESCRIPTION:
This function returns .true. when ncerrToCheck indicates an return code other than 0 (the success code from NetCDF Fortran) or NF_NOERR (the success code for PNetCDF). Otherwise it returns .false.. If an error is indicated, a predefined ESMF error message will be written to the ESMF_Log along with a user added msg, line, file and method. The NetCDF string error representation will also be logged.
The arguments are:
INTERFACE:
subroutine ESMF_LogGet(log, & flush, & logmsgAbort, logkindflag, & maxElements, trace, fileName, & highResTimestampFlag, indentCount, & noPrefix, rc)ARGUMENTS:
type(ESMF_Log), intent(in), optional :: log -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(out), optional :: flush type(ESMF_LogMsg_Flag), pointer, optional :: logmsgAbort(:) type(ESMF_LogKind_Flag), intent(out), optional :: logkindflag integer, intent(out), optional :: maxElements logical, intent(out), optional :: trace character(*), intent(out), optional :: fileName logical, intent(out), optional :: highResTimestampFlag integer, intent(out), optional :: indentCount logical, intent(out), optional :: noPrefix integer, intent(out), optional :: rcDESCRIPTION:
This subroutine returns properties about a Log object.
The arguments are:
INTERFACE:
subroutine ESMF_LogOpen(log, filename, & appendflag, logkindflag, noPrefix, rc)ARGUMENTS:
type(ESMF_Log), intent(inout) :: log character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: appendFlag type(ESMF_LogKind_Flag), intent(in), optional :: logkindFlag logical, intent(in), optional :: noPrefix integer, intent(out), optional :: rcDESCRIPTION:
This routine opens a file named filename and associates it with the ESMF_Log. When logkindflag is set to ESMF_LOGKIND_MULTI or ESMF_LOGKIND_MULTI_ON_ERROR the file name is prepended with PET number identification. If the incoming log is already open, an error is returned.
The arguments are:
INTERFACE:
! Private name; call using ESMF_LogOpen () subroutine ESMF_LogOpenDefault (filename, & appendflag, logkindflag, rc)ARGUMENTS:
character(len=*), intent(in) :: filename -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: appendflag type(ESMF_LogKind_Flag), intent(in), optional :: logkindflag integer, intent(out), optional :: rcDESCRIPTION:
This routine opens a file named filename and associates it with the default log. When logkindflag is set to ESMF_LOGKIND_MULTI the file name is prepended with PET number identification. If the incoming default log is already open, an error is returned.
The arguments are:
INTERFACE:
subroutine ESMF_LogSet(log, & flush, & logmsgAbort, maxElements, logmsgList, & errorMask, trace, highResTimestampFlag, indentCount, & noPrefix, rc)ARGUMENTS:
type(ESMF_Log), intent(inout), optional :: log -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: flush type(ESMF_LogMsg_Flag), intent(in), optional :: logmsgAbort(:) integer, intent(in), optional :: maxElements type(ESMF_LogMsg_Flag), intent(in), optional :: logmsgList(:) integer, intent(in), optional :: errorMask(:) logical, intent(in), optional :: trace logical, intent(in), optional :: highResTimestampFlag integer, intent(in), optional :: indentCount logical, intent(in), optional :: noPrefix integer, intent(out), optional :: rcDESCRIPTION:
This subroutine sets the properties for the Log object.
The arguments are:
INTERFACE:
subroutine ESMF_LogSetError(rcToCheck, & msg, line, file, method, & rcToReturn, log)ARGUMENTS:
integer, intent(in) :: rcToCheck -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: msg integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method integer, intent(out), optional :: rcToReturn type(ESMF_Log), intent(inout), optional :: logSTATUS:
DESCRIPTION:
This subroutine sets the rcToReturn value to rcToCheck if rcToReturn is present and writes this error code to the ESMF_Log if an error is generated. A predefined error message will added to the ESMF_Log along with a user added msg, line, file and method.
The arguments are:
INTERFACE:
recursive subroutine ESMF_LogWrite(msg, logmsgFlag, & logmsgList, & ! DEPRECATED ARGUMENT line, file, method, log, rc)ARGUMENTS:
character(len=*), intent(in) :: msg type(ESMF_LogMsg_Flag),intent(in),optional :: logmsgFlag type(ESMF_LogMsg_Flag),intent(in),optional::logmsgList ! DEPRECATED ARG -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: line character(len=*), intent(in), optional :: file character(len=*), intent(in), optional :: method type(ESMF_Log), intent(inout),optional :: log integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This subroutine writes to the file associated with an ESMF_Log. A message is passed in along with the logmsgFlag, line, file and method. If the write to the ESMF_Log is successful, the function will return a logical true. This function is the base function used by all the other ESMF_Log writing methods.
The arguments are:
The DELayout class provides an additional layer of abstraction on top of the Virtual Machine (VM) layer. DELayout does this by introducing DEs (Decomposition Elements) as logical resource units. The DELayout object keeps track of the relationship between its DEs and the resources of the associated VM object.
The relationship between DEs and VM resources (PETs (Persistent Execution Threads) and VASs (Virtual Address Spaces)) contained in a DELayout object is defined during its creation and cannot be changed thereafter. There are, however, a number of hint and specification arguments that can be used to shape the DELayout during its creation.
Contrary to the number of PETs and VASs contained in a VM object, which are fixed by the available resources, the number of DEs contained in a DELayout can be chosen freely to best match the computational problem or other design criteria. Creating a DELayout with less DEs than there are PETs in the associated VM object can be used to share resources between decomposed objects within an ESMF component. Creating a DELayout with more DEs than there are PETs in the associated VM object can be used to evenly partition the computation over the available resources.
The simplest case, however, is where the DELayout contains the same number of DEs as there are PETs in the associated VM context. In this case the DELayout may be used to re-label the hardware and operating system resources held by the VM. For instance, it is possible to order the resources so that specific DEs have best available communication paths. The DELayout will map the DEs to the PETs of the VM according to the resource details provided by the VM instance.
Furthermore, general DE to PET mapping can be used to offer computational resources with finer granularity than the VM does. The DELayout can be queried for computational and communication capacities of DEs and DE pairs, respectively. This information can be used to best utilize the DE resources when partitioning the computational problem. In combination with other ESMF classes, general DE to PET mapping can be used to realize cache blocking, communication hiding and dynamic load balancing.
Finally, the DELayout layer offers primitives that allow a work queue style dynamic load balancing between DEs.
DESCRIPTION:
Specifies which VM resource DEs are pinned to (PETs, VASs, SSIs).
The type of this flag is:
type(ESMF_Pin_Flag)
The valid values are:
DESCRIPTION:
Reply when a PET offers to service a DE.
The type of this flag is:
type(ESMF_ServiceReply_Flag)
The valid values are:
The following examples demonstrate how to create, use and destroy DELayout objects.
Without specifying any of the optional parameters the created ESMF_DELayout defaults into having as many DEs as there are PETs in the associated VM object. Consequently the resulting DELayout describes a simple 1-to-1 DE to PET mapping.
delayout = ESMF_DELayoutCreate(rc=rc)
The default DE to PET mapping is simply:
DE 0 -> PET 0 DE 1 -> PET 1 ...
DELayout objects that are not used any longer should be destroyed.
call ESMF_DELayoutDestroy(delayout, rc=rc)
The optional vm argument can be provided to DELayoutCreate() to lower the method's overhead by the amount it takes to determine the current VM.
delayout = ESMF_DELayoutCreate(vm=vm, rc=rc)
By default all PETs of the associated VM will be considered. However, if the optional argument petList is present DEs will only be mapped against the PETs contained in the list. When the following example is executed on four PETs it creates a DELayout with four DEs by default that are mapped to the provided PETs in their given order. It is erroneous to specify PETs that are not part of the VM context on which the DELayout is defined.
delayout = ESMF_DELayoutCreate(petList=(/(i,i=petCount-1,1,-1)/), rc=rc)
Once the end of the petList has been reached the DE to PET mapping continues from the beginning of the list. For a 4 PET VM the above created DELayout will end up with the following DE to PET mapping:
DE 0 -> PET 3 DE 1 -> PET 2 DE 2 -> PET 1 DE 2 -> PET 3
The deCount argument can be used to specify the number of DEs. In this example a DELayout is created that contains four times as many DEs as there are PETs in the VM.
delayout = ESMF_DELayoutCreate(deCount=4*petCount, rc=rc)
Cyclic DE to PET mapping is the default. For 4 PETs this means:
DE 0, 4, 8, 12 -> PET 0 DE 1, 5, 9, 13 -> PET 1 DE 2, 6, 10, 14 -> PET 2 DE 3, 7, 11, 15 -> PET 3The default DE to PET mapping can be overridden by providing the deGrouping argument. This argument provides a positive integer group number for each DE in the DELayout. All of the DEs of a group will be mapped against the same PET. The actual group index is arbitrary (but must be positive) and its value is of no consequence.
delayout = ESMF_DELayoutCreate(deCount=4*petCount, & deGrouping=(/(i/4,i=0,4*petCount-1)/), rc=rc)
This will achieve blocked DE to PET mapping. For 4 PETs this means:
DE 0, 1, 2, 3 -> PET 0 DE 4, 5, 6, 7 -> PET 1 DE 8, 9, 10, 11 -> PET 2 DE 12, 13, 14, 15 -> PET 3
The quality of the partitioning expressed by the DE to PET mapping depends on the amount and quality of information provided during DELayout creation. In the following example the compWeights argument is used to specify relative computational weights for all DEs and communication weights for DE pairs are provided by the commWeights argument. The example assumes four DEs.
allocate(compWeights(4)) allocate(commWeights(4, 4)) ! setup compWeights and commWeights according to computational problem delayout = ESMF_DELayoutCreate(deCount=4, compWeights=compWeights, & commWeights=commWeights, rc=rc) deallocate(compWeights, commWeights)
The resulting DE to PET mapping depends on the specifics of the VM object and the provided compWeights and commWeights arrays.
Full control over the DE to PET mapping is provided via the petMap argument. This example maps the DEs to PETs in reverse order. In the 4-PET case this will result in the following mapping:
DE 0 -> PET 3 DE 1 -> PET 2 DE 2 -> PET 1 DE 3 -> PET 0
delayout = ESMF_DELayoutCreate(petMap=(/(i,i=petCount-1,0,-1)/), rc=rc)
The petMap argument gives full control over DE to PET mapping. The following example run on 4 or more PETs maps DEs to PETs according to the following table:
DE 0 -> PET 3 DE 1 -> PET 3 DE 2 -> PET 1 DE 3 -> PET 0 DE 4 -> PET 2 DE 5 -> PET 1 DE 6 -> PET 3 DE 7 -> PET 1
delayout = ESMF_DELayoutCreate(petMap=(/3, 3, 1, 0, 2, 1, 3, 1/), rc=rc)
The simplest case is a DELayout where there is exactly one DE for every PET. Of course this implies that the number of DEs equals the number of PETs. This special 1-to-1 DE-to-PET mapping is very common and many applications assume it. The following example shows how a DELayout can be queried about its mapping.
First a default DELayout is created where the number of DEs equals the number of PETs, and are associated 1-to-1.
delayout = ESMF_DELayoutCreate(rc=rc)
Next the DELayout is queried for the oneToOneFlag, and the user code makes a decision based on its value.
call ESMF_DELayoutGet(delayout, oneToOneFlag=oneToOneFlag, rc=rc) if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) if (.not. oneToOneFlag) then ! handle the unexpected case of not dealing with a 1-to-1 mapping else
1-to-1 mapping is guaranteed in this branch and the following code can work under the simplifying assumption that every PET holds exactly one DE:
allocate(localDeToDeMap(1)) call ESMF_DELayoutGet(delayout, localDeToDeMap=localDeToDeMap, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc myDe = localDeToDeMap(1) deallocate(localDeToDeMap) if (finalrc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) endif
In general a DELayout may map any number (including zero) of DEs against a single PET. The exact situation can be detected by querying the DELayout for the oneToOneFlag. If this flag comes back as .true. then the DELayout maps exactly one DE against each PET, but if it comes back as .false. the DELayout describes a more general DE-to-PET layout. The following example shows how code can be be written to work for a general DELayout.
First a DELayout is created with two more DEs than there are PETs. The DELayout will consequently map some DEs to the same PET.
delayout = ESMF_DELayoutCreate(deCount=petCount+2, rc=rc)
The first piece of information needed on each PET is the localDeCount. This number may be different on each PET and indicates how many DEs are mapped against the local PET.
call ESMF_DELayoutGet(delayout, localDeCount=localDeCount, rc=rc)
The DELayout can further be queried for a list of DEs that are held by the local PET. This information is provided by the localDeToDeMap argument. In ESMF a localDe is an index that enumerates the DEs that are associated with the local PET. In many cases the exact bounds of the localDe index range, e.g. , or does not matter, since it only affects how user code indexes into variables the user allocated, and therefore set the specific bounds. However, there are a few Array and Field level calls that take localDe input arguments. In all those cases where the localDe index variable is passed into an ESMF call as an input argument, it must be defined with a range starting at zero, i.e. .
For consistency with Array and Field, the following code uses a range for the localDe index variable, although it is not strictly necessary here:
allocate(localDeToDeMap(0:localDeCount-1)) call ESMF_DELayoutGet(delayout, localDeToDeMap=localDeToDeMap, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc do localDe=0, localDeCount-1 workDe = localDeToDeMap(localDe) ! print *, "I am PET", localPET, " and I am working on DE ", workDe enddo deallocate(localDeToDeMap) if (finalrc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
The DELayout API includes two calls that can be used to easily implement work queue dynamic load balancing. The workload is broken up into DEs (more than there are PETs) and processed by the PETs. Load balancing is only possible for ESMF multi-threaded VMs and requires that DEs are pinned to VASs instead of the PETs (default). The following example will run for any VM and DELayout, however, load balancing will only occur under the mentioned conditions.
delayout = ESMF_DELayoutCreate(deCount=petCount+2, & pinflag=ESMF_PIN_DE_TO_VAS, rc=rc)
call ESMF_DELayoutGet(delayout, vasLocalDeCount=localDeCount, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc allocate(localDeToDeMap(localDeCount)) call ESMF_DELayoutGet(delayout, vasLocalDeToDeMap=localDeToDeMap, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc do i=1, localDeCount workDe = localDeToDeMap(i) print *, "I am PET", localPET, & " and I am offering service for DE ", workDe reply = ESMF_DELayoutServiceOffer(delayout, de=workDe, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc if (reply == ESMF_SERVICEREPLY_ACCEPT) then ! process work associated with workDe print *, "I am PET", localPET, ", service offer for DE ", workDe, & " was accepted." call ESMF_DELayoutServiceComplete(delayout, de=workDe, rc=rc) if (rc /= ESMF_SUCCESS) finalrc=rc endif enddo deallocate(localDeToDeMap) if (finalrc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
The DELayout class is a light weight object. It stores the DE to PET and VAS mapping for all DEs within all PET instances and a list of local DEs for each PET instance. The DELayout does not store the computational and communication weights optionally provided as arguments to the create method. These hints are only used during create while they are available in user owned arrays.
INTERFACE:
interface assignment(=) delayout1 = delayout2ARGUMENTS:
type(ESMF_DELayout) :: delayout1 type(ESMF_DELayout) :: delayout2STATUS:
DESCRIPTION:
Assign delayout1 as an alias to the same ESMF DELayout object in memory as delayout2. If delayout2 is invalid, then delayout1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (delayout1 == delayout2) then ... endif OR result = (delayout1 == delayout2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout1 type(ESMF_DELayout), intent(in) :: delayout2STATUS:
DESCRIPTION:
Test whether delayout1 and delayout2 are valid aliases to the same ESMF DELayout object in memory. For a more general comparison of two ESMF DELayouts, going beyond the simple alias test, the ESMF_DELayoutMatch() function (not yet implemented) must be used.
The arguments are:
INTERFACE:
interface operator(/=) if (delayout1 /= delayout2) then ... endif OR result = (delayout1 /= delayout2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout1 type(ESMF_DELayout), intent(in) :: delayout2STATUS:
DESCRIPTION:
Test whether delayout1 and delayout2 are not valid aliases to the same ESMF DELayout object in memory. For a more general comparison of two ESMF DELayouts, going beyond the simple alias test, the ESMF_DELayoutMatch() function (not yet implemented) must be used.
The arguments are:
INTERFACE:
! Private name; call using ESMF_DELayoutCreate() recursive function ESMF_DELayoutCreateDefault(deCount, & deGrouping, pinflag, petList, vm, rc)RETURN VALUE:
type(ESMF_DELayout) :: ESMF_DELayoutCreateDefaultARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: deCount integer, target, intent(in), optional :: deGrouping(:) type(ESMF_Pin_Flag), intent(in), optional :: pinflag integer, target, intent(in), optional :: petList(:) type(ESMF_VM), intent(in), optional :: vm integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Create an ESMF_DELayout object on the basis of optionally provided restrictions. By default a DELayout with deCount equal to petCount will be created, each DE mapped to a single PET. However, the number of DEs as well grouping of DEs and PETs can be specified via the optional arguments.
The arguments are:
INTERFACE:
! Private name; call using ESMF_DELayoutCreate() recursive function ESMF_DELayoutCreateFromPetMap(petMap, & pinflag, vm, rc)RETURN VALUE:
type(ESMF_DELayout) :: ESMF_DELayoutCreateFromPetMapARGUMENTS:
integer, intent(in) :: petMap(:) -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Pin_Flag), intent(in), optional :: pinflag type(ESMF_VM), intent(in), optional :: vm integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Create an ESMF_DELayout with exactly specified DE to PET mapping.
This ESMF method must be called in unison by all PETs of the VM. Calling this method from a PET not part of the VM or not calling it from a PET that is part of the VM will result in undefined behavior. ESMF does not guard against violation of the unison requirement. The call is not collective, there is no communication between PETs.
The arguments are:
INTERFACE:
recursive subroutine ESMF_DELayoutDestroy(delayout, noGarbage, rc)ARGUMENTS:
type(ESMF_DELayout), intent(inout) :: delayout -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: noGarbage integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Destroy an ESMF_DELayout object, releasing the resources associated with the object.
By default a small remnant of the object is kept in memory in order to prevent problems with dangling aliases. The default garbage collection mechanism can be overridden with the noGarbage argument.
The arguments are:
It is generally recommended to leave the noGarbage argument set to .FALSE. (the default), and to take advantage of the ESMF garbage collection system which will prevent problems with dangling aliases or incorrect sequences of destroy calls. However this level of support requires that a small remnant of the object is kept in memory past the destroy call. This can lead to an unexpected increase in memory consumption over the course of execution in applications that use temporary ESMF objects. For situations where the repeated creation and destruction of temporary objects leads to memory issues, it is recommended to call with noGarbage set to .TRUE., fully removing the entire temporary object from memory.
INTERFACE:
recursive subroutine ESMF_DELayoutGet(delayout, vm, deCount,& petMap, vasMap, oneToOneFlag, pinflag, localDeCount, localDeToDeMap, & localDeList, & ! DEPRECATED ARGUMENT vasLocalDeCount, vasLocalDeToDeMap, & vasLocalDeList, & ! DEPRECATED ARGUMENT rc)ARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_VM), intent(out), optional :: vm integer, intent(out), optional :: deCount integer, target, intent(out), optional :: petMap(:) integer, target, intent(out), optional :: vasMap(:) logical, intent(out), optional :: oneToOneFlag type(ESMF_Pin_Flag), intent(out), optional :: pinflag integer, intent(out), optional :: localDeCount integer, target, intent(out), optional :: localDeToDeMap(:) integer, target, intent(out), optional :: localDeList(:) !DEPRECATED ARG integer, intent(out), optional :: vasLocalDeCount integer, target, intent(out), optional :: vasLocalDeToDeMap(:) integer, target, intent(out), optional :: vasLocalDeList(:) !DEPRECATED ARG integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Access to DELayout information.
The arguments are:
INTERFACE:
function ESMF_DELayoutIsCreated(delayout, rc)RETURN VALUE:
logical :: ESMF_DELayoutIsCreatedARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the delayout has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
subroutine ESMF_DELayoutPrint(delayout, rc)ARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Prints internal information about the specified ESMF_DELayout
object to stdout.
The arguments are:
INTERFACE:
recursive subroutine ESMF_DELayoutServiceComplete(delayout, de, rc)ARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout integer, intent(in) :: de -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
The PET who's service offer was accepted for de must use ESMF_DELayoutServiceComplete to close the service window.
The arguments are:
INTERFACE:
recursive function ESMF_DELayoutServiceOffer(delayout, de, rc)RETURN VALUE:
type(ESMF_ServiceReply_Flag) :: ESMF_DELayoutServiceOfferARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout integer, intent(in) :: de -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Offer service for a DE in the ESMF_DELayout object. This call together with ESMF_DELayoutServiceComplete() provides the synchronization primitives between the PETs of an ESMF multi-threaded VM necessary for dynamic load balancing via a work queue approach.
The calling PET will either receive ESMF_SERVICEREPLY_ACCEPT if the service offer has been accepted by DELayout or ESMF_SERVICEREPLY_DENY if the service offer was denied. The service offer paradigm is different from a simple mutex approach in that the DELayout keeps track of the number of service offers issued for each DE by each PET and accepts only one PET's offer for each offer increment. This requires that all PETs use ESMF_DELayoutServiceOffer() in unison. See section 50.2.2 for the potential return values.
The arguments are:
INTERFACE:
subroutine ESMF_DELayoutValidate(delayout, rc)ARGUMENTS:
type(ESMF_DELayout), intent(in) :: delayout -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Validates that the delayout is internally consistent. The method returns an error code if problems are found.
The arguments are:
The ESMF VM (Virtual Machine) class is a generic representation of hardware and system software resources. There is exactly one VM object per ESMF Component, providing the execution environment for the Component code. The VM class handles all resource management tasks for the Component class and provides a description of the underlying configuration of the compute resources used by a Component.
In addition to resource description and management, the VM class offers the lowest level of ESMF communication methods. The VM communication calls are very similar to MPI. Data references in VM communication calls must be provided as raw, language-specific, one-dimensional, contiguous data arrays. The similarity between VM and MPI communication calls is striking and there are many equivalent point-to-point and collective communication calls. However, unlike MPI, the VM communication calls support communication between threaded PETs in a completely transparent fashion.
Many ESMF applications do not interact with the VM class directly very much. The resource management aspect is wrapped completely transparent into the ESMF Component concept. Often the only reason that user code queries a Component object for the associated VM object is to inquire about resource information, such as the localPet or the petCount. Further, for most applications the use of higher level communication APIs, such as provided by Array and Field, are much more convenient than using the low level VM communication calls.
The basic elements of a VM are called PETs, which stands for Persistent Execution Threads. These are equivalent to OS threads with a lifetime of at least that of the associated component. All VM functionality is expressed in terms of PETs. In the simplest, and most common case, a PET is equivalent to an MPI process. However, ESMF also supports multi-threading, where multiple PETs run as Pthreads inside the same virtual address space (VAS).
The resource management functions of the VM class become visible when a component, or the driver code, creates sub-components. Section 16.4.8 discusses this aspect from the Superstructure perspective and provides links to the relevant Component examples in the documentation.
There are two parts to resource management, the parent and the child. When the parent component creates a child component, the parent VM object provides the resources on which the child is created with ESMF_GridCompCreate() or ESMF_CplCompCreate(). The optional petList argument to these calls limits the resources that the parent gives to a specific child. The child component, may specify - during its optional ESMF_<Grid/Cpl>CompSetVM() method - how it wants to arrange the inherited resources in its own VM. After this, all standard ESMF methods of the Component, including ESMF_<Grid/Cpl>CompSetServices(), will execute in the child VM. Notice that the ESMF_<Grid/Cpl>CompSetVM() routine, although part of the child Component, must execute before the child VM has been started up. It runs in the parent VM context. The child VM is created and started up just before the user-written set services routine, specified as an argument to ESMF_<Grid/Cpl>CompSetServices(), is entered.
DESCRIPTION:
Specifies the kind of VM Epoch being entered.
The type of this flag is:
type(ESMF_VMEpoch_Flag)
The valid values are:
The concept of the ESMF Virtual Machine (VM) is so fundamental to the framework that every ESMF application uses it. However, for many user applications the VM class is transparently hidden behind the ESMF Component concept and higher data classes (e.g. Array, Field). The interaction between user code and VM is often only indirect. The following examples provide an overview of where the VM class can come into play in user code.
This complete example program demonstrates the simplest ESMF application, consisting of only a main program without any Components. The global VM, which is automatically created during the ESMF_Initialize() call, is obtained using two different methods. First the global VM will be returned by ESMF_Initialize() if the optional vm argument is specified. The example uses the VM object obtained this way to call the VM print method. Second, the global VM can be obtained anywhere in the user application using the ESMF_VMGetGlobal() call. The identical VM is returned and several VM query methods are called to inquire about the associated resources.
program ESMF_VMDefaultBasicsEx #include "ESMF.h" use ESMF use ESMF_TestMod implicit none ! local variables integer:: rc type(ESMF_VM):: vm integer:: localPet, petCount, peCount, ssiId, vas
call ESMF_Initialize(vm=vm, defaultlogfilename="VMDefaultBasicsEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc) ! Providing the optional vm argument to ESMF_Initialize() is one way of ! obtaining the global VM.
call ESMF_VMPrint(vm, rc=rc)
call ESMF_VMGetGlobal(vm=vm, rc=rc) ! Calling ESMF_VMGetGlobal() anywhere in the user application is the other ! way to obtain the global VM object.
call ESMF_VMGet(vm, localPet=localPet, petCount=petCount, peCount=peCount, & rc=rc) ! The VM object contains information about the associated resources. If the ! user code requires this information it must query the VM object.
print *, "This PET is localPet: ", localPet print *, "of a total of ",petCount," PETs in this VM." print *, "There are ", peCount," PEs referenced by this VM" call ESMF_VMGet(vm, localPet, peCount=peCount, ssiId=ssiId, vas=vas, rc=rc)
print *, "This PET is executing in virtual address space (VAS) ", vas print *, "located on single system image (SSI) ", ssiId print *, "and is associated with ", peCount, " PEs."
end program
The following example shows the role that the VM plays in connection with ESMF Components. A single Component is created in the main program. Through the optional petList argument the driver code specifies that only resources associated with PET 0 are given to the gcomp object.
When the Component code is invoked through the standard ESMF Component methods Initialize, Run, or Finalize the Component's VM is automatically entered. Inside of the user-written Component code the Component VM can be obtained by querying the Component object. The VM object will indicate that only a single PET is executing the Component code.
module ESMF_VMComponentEx_gcomp_mod
recursive subroutine mygcomp_init(gcomp, istate, estate, clock, rc) type(ESMF_GridComp) :: gcomp type(ESMF_State) :: istate, estate type(ESMF_Clock) :: clock integer, intent(out) :: rc ! local variables type(ESMF_VM):: vm ! get this Component's vm call ESMF_GridCompGet(gcomp, vm=vm) ! the VM object contains information about the execution environment of ! the Component call ESMF_VMPrint(vm, rc=rc) rc = 0 end subroutine !-------------------------------------------------------------- recursive subroutine mygcomp_run(gcomp, istate, estate, clock, rc) type(ESMF_GridComp) :: gcomp type(ESMF_State) :: istate, estate type(ESMF_Clock) :: clock integer, intent(out) :: rc ! local variables type(ESMF_VM):: vm ! get this Component's vm call ESMF_GridCompGet(gcomp, vm=vm) ! the VM object contains information about the execution environment of ! the Component call ESMF_VMPrint(vm, rc=rc) rc = 0 end subroutine !-------------------------------------------------------------- recursive subroutine mygcomp_final(gcomp, istate, estate, clock, rc) type(ESMF_GridComp) :: gcomp type(ESMF_State) :: istate, estate type(ESMF_Clock) :: clock integer, intent(out) :: rc ! local variables type(ESMF_VM):: vm ! get this Component's vm call ESMF_GridCompGet(gcomp, vm=vm) ! the VM object contains information about the execution environment of ! the Component call ESMF_VMPrint(vm, rc=rc) rc = 0 end subroutine !-------------------------------------------------------------- end module
program ESMF_VMComponentEx #include "ESMF.h" use ESMF use ESMF_TestMod use ESMF_VMComponentEx_gcomp_mod implicit none ! local variables
gcomp = ESMF_GridCompCreate(petList=(/0/), rc=rc)
call ESMF_GridCompSetServices(gcomp, userRoutine=mygcomp_register, rc=rc)
call ESMF_GridCompInitialize(gcomp, rc=rc)
call ESMF_GridCompRun(gcomp, rc=rc)
call ESMF_GridCompFinalize(gcomp, rc=rc)
call ESMF_GridCompDestroy(gcomp, rc=rc)
call ESMF_Finalize(rc=rc)
end program
Sometimes user code requires access to the MPI communicator, e.g. to support legacy code that contains explict MPI communication calls. The correct way of wrapping such code into ESMF is to obtain the MPI intra-communicator out of the VM object. In order not to interfere with ESMF communications it is advisable to duplicate the communicator before using it in user-level MPI calls. In this example the duplicated communicator is used for a user controlled MPI_Barrier().
integer:: mpic
integer:: mpic2
call ESMF_VMGet(vm, mpiCommunicator=mpic, rc=rc) ! The returned MPI communicator spans the same MPI processes that the VM ! is defined on.
call MPI_Comm_dup(mpic, mpic2, ierr) ! Duplicate the MPI communicator not to interfere with ESMF communications. ! The duplicate MPI communicator can be used in any MPI call in the user ! code. Here the MPI_Barrier() routine is called. call MPI_Barrier(mpic2, ierr)
The Fortran 2008 MPI language binding defines type MPI_Comm to represent the MPI communicator. The following example demonstrates how the MPI communicator queried from the VM object can be used with the Fortran 2008 MPI binding.
use mpi_f08
integer :: int_mpic type(MPI_Comm):: mpic
type(MPI_Comm):: mpic2
call ESMF_VMGet(vm, mpiCommunicator=int_mpic, rc=rc) ! The returned MPI communicator spans the same MPI processes that the VM ! is defined on.
mpic%mpi_val = int_mpic ! integer version of communicator -> type(MPI_Comm) ! Now mpic can be used in the Fortran 2008 MPI binding interfaces call MPI_Comm_dup(mpic, mpic2, ierr) ! Duplicate the MPI communicator not to interfere with ESMF communications. ! The duplicate MPI communicator can be used in any MPI call in the user ! code. Here the MPI_Barrier() routine is called. call MPI_Barrier(mpic2, ierr)
It is possible to nest an ESMF application inside a user application that explicitly calls MPI_Init() and MPI_Finalize(). The ESMF_Initialize() call automatically checks whether MPI has already been initialized, and if so does not call MPI_Init() internally. On the finalize side, ESMF_Finalize() can be instructed to not call MPI_Finalize(), making it the responsibility of the outer code to finalize MPI.
! For cases where ESMF resource management is desired (e.g. for threading), ! ESMF_InitializePreMPI() must be called before MPI_Init(). call ESMF_InitializePreMPI(rc=rc)
! User code initializes MPI. call MPI_Init(ierr)
! ESMF_Initialize() does not call MPI_Init() if it finds MPI initialized. call ESMF_Initialize(defaultlogfilename="VMUserMpiEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! Use ESMF here...
! Calling ESMF_Finalize() with endflag=ESMF_END_KEEPMPI instructs ESMF ! to keep MPI active. call ESMF_Finalize(endflag=ESMF_END_KEEPMPI, rc=rc)
! It is the responsibility of the outer user code to finalize MPI. call MPI_Finalize(ierr)
The previous example demonstrated that it is possible to nest an ESMF application, i.e. ESMF_Initialize()...ESMF_Finalize() inside MPI_Init()...MPI_Finalize(). It is not necessary that all MPI ranks enter the ESMF application. The following example shows how the user code can pass an MPI communicator to ESMF_Initialize(), and enter the ESMF application on a subset of MPI ranks.
! User code initializes MPI. call MPI_Init(ierr)
! User code determines the local rank. call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
! User code prepares MPI communicator "esmfComm", that allows rank 0 and 1 ! to be grouped together. if (rank < 2) then ! first communicator split with color=0 call MPI_Comm_split(MPI_COMM_WORLD, 0, 0, esmfComm, ierr) else ! second communicator split with color=1 call MPI_Comm_split(MPI_COMM_WORLD, 1, 0, esmfComm, ierr) endif
if (rank < 2) then ! Only call ESMF_Initialize() on rank 0 and 1, passing the prepared MPI ! communicator that spans these ranks. call ESMF_Initialize(mpiCommunicator=esmfComm, & defaultlogfilename="VMUserMpiCommEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! Use ESMF here...
! Calling ESMF_Finalize() with endflag=ESMF_END_KEEPMPI instructs ESMF ! to keep MPI active. call ESMF_Finalize(endflag=ESMF_END_KEEPMPI, rc=rc)
else ! Ranks 2 and above do non-ESMF work...
endif
! Free the MPI communicator before finalizing MPI. call MPI_Comm_free(esmfComm, ierr) ! It is the responsibility of the outer user code to finalize MPI. call MPI_Finalize(ierr)
Multiple instances of ESMF can run concurrently under the same user main program on separate MPI communicators. The user program first splits MPI_COMM_WORLD into separate MPI communicators. Each communicator is then used to run a separate ESMF instance by passing it into ESMF_Initialize() on the appropriate MPI ranks.
Care must be taken to set the defaultlogfilename to be unique on each ESMF instances. This prevents concurrent ESMF instances from writing to the same log file. Further, each ESMF instances must call ESMF_Finalize() with the endflag=ESMF_END_KEEPMPI option in order to hand MPI control back to the user program. The outer user program is ultimately responsible for destroying the MPI communicators and to cleanly shut down MPI.
! User code initializes MPI. call MPI_Init(ierr)
! User code determines the local rank and overall size of MPI_COMM_WORLD call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr) call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
! User code prepares different MPI communicators. ! Here a single MPI_Comm_split() call is used to split MPI_COMM_WORLD ! into two non-overlapping communicators: ! One communicator for ranks 0 and 1, and the other for ranks 2 and above. if (rank < 2) then ! first communicator split with color=0 call MPI_Comm_split(MPI_COMM_WORLD, 0, 0, esmfComm, ierr) else ! second communicator split with color=1 call MPI_Comm_split(MPI_COMM_WORLD, 1, 0, esmfComm, ierr) endif
if (rank < 2) then ! Ranks 0 and 1 enter ESMF_Initialize() with the prepared communicator. ! Care is taken to set a unique log file name. call ESMF_Initialize(mpiCommunicator=esmfComm, & defaultlogfilename="VMUserMpiCommMultiEx1.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! Use ESMF here...
! Finalize ESMF without finalizing MPI. The user application will call ! MPI_Finalize() on all ranks. call ESMF_Finalize(endflag=ESMF_END_KEEPMPI, rc=rc)
else ! Ranks 2 and above enter ESMF_Initialize() with the prepared communicator. ! Care is taken to set a unique log file name. call ESMF_Initialize(mpiCommunicator=esmfComm, & defaultlogfilename="VMUserMpiCommMultiEx2.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! Use ESMF here...
! Finalize ESMF without finalizing MPI. The user application will call ! MPI_Finalize() on all ranks. call ESMF_Finalize(endflag=ESMF_END_KEEPMPI, rc=rc)
endif
! Free the MPI communicator(s) before finalizing MPI. call MPI_Comm_free(esmfComm, ierr) ! It is the responsibility of the outer user code to finalize MPI. call MPI_Finalize(ierr)
The VM layer provides MPI-like point-to-point communication. Use ESMF_VMSend() and ESMF_VMRecv() to pass data between two PETs. The following code sends data from PET 'src' and receives it on PET 'dst'. Both PETs must be part of the same VM.
Set up the localData array.
count = 10 allocate(localData(count)) do i=1, count localData(i) = localPet*100 + i enddo
Carry out the data transfer between src PET and dst PET.
if (localPet==src) then call ESMF_VMSend(vm, sendData=localData, count=count, dstPet=dst, rc=rc) endif
if (localPet==dst) then call ESMF_VMRecv(vm, recvData=localData, count=count, srcPet=src, rc=rc) endif
Finally, on dst PET, test the received data for correctness.
if (localPet==dst) then do i=1, count if (localData(i) /= src*100 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
The VM layer provides MPI-like collective communication. ESMF_VMScatter() scatters data located on root PET across all the PETs of the VM. ESMF_VMGather() provides the opposite operation, gathering data from all the PETs of the VM onto root PET.
integer, allocatable:: array1(:), array2(:)
! allocate data arrays nsize = 2 nlen = nsize * petCount allocate(array1(nlen)) allocate(array2(nsize)) ! prepare data array1 do i=1, nlen array1(i) = localPet * 100 + i enddo
call ESMF_VMScatter(vm, sendData=array1, recvData=array2, count=nsize, & rootPet=scatterRoot, rc=rc)
call ESMF_VMGather(vm, sendData=array2, recvData=array1, count=nsize, & rootPet=gatherRoot, rc=rc)
Use ESMF_VMAllReduce() to reduce data distributed across the PETs of a VM into a result vector, returned on all the PETs. Further, use ESMF_VMAllFullReduce() to reduce the data into a single scalar returned on all PETs.
integer, allocatable:: array1(:), array2(:)
! allocate data arrays nsize = 2 allocate(array1(nsize)) allocate(array2(nsize)) ! prepare data array1 do i=1, nsize array1(i) = localPet * 100 + i enddo
call ESMF_VMAllReduce(vm, sendData=array1, recvData=array2, count=nsize, & reduceflag=ESMF_REDUCE_SUM, rc=rc) ! Reduce distributed sendData, element by element into recvData and ! return it on all the PETs.
call ESMF_VMAllFullReduce(vm, sendData=array1, recvData=result, & count=nsize, reduceflag=ESMF_REDUCE_SUM, rc=rc) ! Fully reduce the distributed sendData into a single scalar and ! return it in recvData on all PETs.
The separation of initiation and completion of the data transfer provides the opportunity for the underlying communication system to progress concurrently with other operations on the same PET. This can be leveraged to have profound impact on the performance of an algorithm that requires both computation and communication.
Another critical application of the non-blocking communication mode is the prevention of deadlocks. In the default blocking mode, a receiving method will not return until the data transfer has completed. Sending methods may also not return, especially if the message being sent is above the implementation dependent internal buffer size. This behavior makes it often hard, if not impossible, to write safe algorithms that guarantee to not deadlock when communicating between a group of PETs. Using the communication calls in non-blocking mode simplifies this problem immensely.
The following code shows how ESMF_VMSend() and ESMF_VMRecv() are used in non-blocking mode by passing in the ESMF_SYNC_NONBLOCKING argument.
Set up the localData array.
do i=1, count localData(i) = localPet*100 + i enddo
Initiate the data transfer between src PET and dst PET.
if (localPet==src) then call ESMF_VMSend(vm, sendData=localData, count=count, dstPet=dst, & syncflag=ESMF_SYNC_NONBLOCKING, rc=rc) endif
if (localPet==dst) then call ESMF_VMRecv(vm, recvData=localData, count=count, srcPet=src, & syncflag=ESMF_SYNC_NONBLOCKING, rc=rc) endif
There is no garantee at this point that the data transfer has actually started, let along completed. For this reason it is unsafe to overwrite the data in the localData array on src PET, or to access the localData array on dst PET. However both PETs are free to engage in other work while the data transfer may proceed concurrently.
! local computational work here, or other communications
Wait for the completion of all outstanding non-blocking communication calls by issuing the ESMF_VMCommWaitAll() call.
call ESMF_VMCommWaitAll(vm, rc=rc)
Finally, on dst PET, test the received data for correctness.
if (localPet==dst) then do i=1, count if (localData(i) /= src*100 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
Sometimes it is necessary to wait for individual outstanding communications specifically. This can be accomplished by using ESMF_CommHandle objects. To demonstrate this, first re-initialize the localData array.
do i=1, count localData(i) = localPet*100 + i localData2(i) = localPet*1000 + i enddo
Initiate the data transfer between src PET and dst PET, but this time also pass the commhandle variable of type ESMF_CommHandle. Here send two message between src and dst in order to have different outstanding messages to wait for.
if (localPet==src) then call ESMF_VMSend(vm, sendData=localData, count=count, dstPet=dst, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(1), rc=rc) call ESMF_VMSend(vm, sendData=localData2, count=count, dstPet=dst, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(2), rc=rc) endif
if (localPet==dst) then call ESMF_VMRecv(vm, recvData=localData, count=count, srcPet=src, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(1), rc=rc) call ESMF_VMRecv(vm, recvData=localData2, count=count, srcPet=src, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(2), rc=rc) endif
Now it is possible to specifically wait for the first data transfer, e.g. on the dst PET.
if (localPet==dst) then call ESMF_VMCommWait(vm, commhandle=commhandle(1), rc=rc) endif
At this point there are still 2 outstanding communications on the src PET, and one outstanding communication on the dst PET. However, having returned from the specific ESMF_VMCommWait() call guarantees that the first communication on the dst PET has completed, i.e. the data has been received from the src PET, and can now be accessed in the localData array.
if (localPet==dst) then do i=1, count if (localData(i) /= src*100 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
Before accessing data from the second transfer, it is necessary to wait on the associated commhandle for completion.
if (localPet==dst) then call ESMF_VMCommWait(vm, commhandle=commhandle(2), rc=rc) endif
if (localPet==dst) then do i=1, count if (localData2(i) /= src*1000 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
Finally the commhandle elements on the src side need to be cleared by waiting for them. This could be done using specific ESMF_VMCommWait() calls, similar to the dst side, or simply by waiting for all/any outstanding communications using ESMF_VMCommWaitAll() as in the previous example. This call can be issued without commhandle on all of the PETs.
call ESMF_VMCommWaitAll(vm, rc=rc)
For cases where multiple messages are being sent between the same src-dst pairs using non-blocking communications, performance can often be improved by aggregating individual messages. An extra buffer is needed to hold the collected messages. The result is a single data transfer for each PET pair. In many cases this can significantly reduce the time spent in communications. The ESMF VM class provides access to such a buffering technique through the ESMF_VMEpoch API.
The ESMF_VMEpoch API consists of two interfaces: ESMF_VMEpochEnter() and ESMF_VMEpochExit(). When entering an epoch, the user specifies the type of epoch that is to be entered. Currently only ESMF_VMEPOCH_BUFFER is available. Inside this epoch, non-blocking communication calls are aggregated and data transfers on the src side are not issued until the epoch is exited. On the dst side a single data transfer is received, and then divided over the actual non-blocking receive calls.
The following code repeates the previous example with two messages between src and dst. It is important that every PET only must act either as sender or receiver. A sending PET can send to many different PETs, and a receiving PET can receive from many PETs, but no PET must send and receive within the same epoch!
First re-initialize the localData array.
do i=1, count localData(i) = localPet*100 + i localData2(i) = localPet*1000 + i enddo
Enter the ESMF_VMEPOCH_BUFFER.
call ESMF_VMEpochEnter(epoch=ESMF_VMEPOCH_BUFFER, rc=rc)
Now issue non-blocking send and receive calls as usual.
if (localPet==src) then call ESMF_VMSend(vm, sendData=localData, count=count, dstPet=dst, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(1), rc=rc)
call ESMF_VMSend(vm, sendData=localData2, count=count, dstPet=dst, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(2), rc=rc)
endif if (localPet==dst) then call ESMF_VMRecv(vm, recvData=localData, count=count, srcPet=src, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(1), rc=rc)
call ESMF_VMRecv(vm, recvData=localData2, count=count, srcPet=src, & syncflag=ESMF_SYNC_NONBLOCKING, commhandle=commhandle(2), rc=rc)
endif
No data transfer has been initiated at this point due to the fact that this code is inside the ESMF_VMEPOCH_BUFFER. On the dst side the same methods are used to wait for the data transfer. However, it is not until the exit of the epoch on the src side that data is transferred to the dst side.
if (localPet==dst) then call ESMF_VMCommWait(vm, commhandle=commhandle(1), rc=rc)
endif
if (localPet==dst) then do i=1, count if (localData(i) /= src*100 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
if (localPet==dst) then call ESMF_VMCommWait(vm, commhandle=commhandle(2), rc=rc)
endif
if (localPet==dst) then do i=1, count if (localData2(i) /= src*1000 + i) then finalrc = ESMF_RC_VAL_WRONG endif enddo endif
Now exit the epoch, to trigger the data transfer on the src side.
call ESMF_VMEpochExit(rc=rc)
Finally clear the outstanding communication handles on the src side. This needs to happen first inside the next ESMF_VMEPOCH_BUFFER. As before, waits could be issued either for the specific commhandle elements not yet explicitly cleared, or a general call to ESMF_VMCommWaitAll() can be used for simplicity.
call ESMF_VMEpochEnter(epoch=ESMF_VMEPOCH_BUFFER, rc=rc)
call ESMF_VMCommWaitAll(vm, rc=rc)
call ESMF_VMEpochExit(rc=rc)
In the current implementation of the VM communication methods all the data array arguments are declared as assumed shape dummy arrays of rank one. The assumed shape flavor was chosen in order to minimize the chance of copy in/out problems, associated with the other options for declaring the dummy data arguments. However, currently the interfaces are not overloaded for higher ranks. This restriction requires that users that need to communicate data arrays with rank greater than one, must only pass the first dimension of the data array into the VM communication calls. Specifying the full size of the data arrays (considering all dimensions) ensure that the complete data is transferred in or out of the contiguous array memory.
integer, allocatable:: sendData(:,:) integer, allocatable:: recvData(:,:,:,:)
count1 = 5 count2 = 8 allocate(sendData(count1,count2)) ! 5 x 8 = 40 elements do j=1, count2 do i=1, count1 sendData(i,j) = localPet*100 + i + (j-1)*count1 enddo enddo count1 = 2 count2 = 5 count3 = 1 count4 = 4 allocate(recvData(count1,count2,count3,count4)) ! 2 x 5 x 1 x 4 = 40 elements do l=1, count4 do k=1, count3 do j=1, count2 do i=1, count1 recvData(i,j,k,l) = 0 enddo enddo enddo enddo
if (localPet==src) then call ESMF_VMSend(vm, & sendData=sendData(:,1), & ! 1st dimension as contiguous array section count=count1*count2, & ! total count of elements dstPet=dst, rc=rc) endif
if (localPet==dst) then call ESMF_VMRecv(vm, & recvData=recvData(:,1,1,1), & ! 1st dimension as contiguous array section count=count1*count2*count3*count4, & ! total count of elements srcPet=src, rc=rc) endif
The VM class provides an additional layer of abstraction on top of the POSIX machine model, making it suitable for HPC applications. There are four key aspects the VM class deals with.
Definition of terms used in the diagram
The POSIX machine abstraction, while a very powerful concept, needs augmentation when applied to HPC applications. Key elements of the POSIX abstraction are processes, which provide virtually unlimited resources (memory, I/O, sockets, ...) to possibly multiple threads of execution. Similarly POSIX threads create the illusion that there is virtually unlimited processing power available to each POSIX process. While the POSIX abstraction is very suitable for many multi-user/multi-tasking applications that need to share limited physical resources, it does not directly fit the HPC workload where over-subscription of resources is one of the most expensive modes of operation.
ESMF's virtual machine abstraction is based on the POSIX machine model but holds additional information about the available physical processing units in terms of Processing Elements (PEs). A PE is the smallest physical processing unit and encapsulates the hardware details (Cores, CPUs and SSIs).
There is exactly one physical machine layout for each application, and all VM instances have access to this information. The PE is the smallest processing unit which, in today's microprocessor technology, corresponds to a single Core. Cores are arranged in CPUs which in turn are arranged in SSIs. The setup of the physical machine layout is part of the ESMF initialization process.
On top of the PE concept the key abstraction provided by the VM is the PET. All user code is executed by PETs while OS and hardware details are hidden. The VM class contains a number of methods which allow the user to prescribe how the PETs of a desired virtual machine should be instantiated on the OS level and how they should map onto the hardware. This prescription is kept in a private virtual machine plan object which is created at the same time the associated component is being created. Each time component code is entered through one of the component's registered top-level methods (Initialize/Run/Finalize), the virtual machine plan along with a pointer to the respective user function is used to instantiate the user code on the PETs of the associated VM in form of single- or multi-threaded POSIX processes.
The process of starting, entering, exiting and shutting down a VM is very transparent, all spawning and joining of threads is handled by VM methods "behind the scenes". Furthermore, fundamental synchronization and communication primitives are provided on the PET level through a uniform API, hiding details related to the actual instantiation of the participating PETs.
Within a VM object each PE of the physical machine maps to 0 or 1 PETs. Allowing unassigned PEs provides a means to prevent over-subscription between multiple concurrently running virtual machines. Similarly a maximum of one PET per PE prevents over-subscription within a single VM instance. However, over-subscription is possible by subscribing PETs from different virtual machines to the same PE. This type of over-subscription can be desirable for PETs associated with I/O workloads expected to be used infrequently and to block often on I/O requests.
On the OS level each PET of a VM object is represented by a POSIX thread (Pthread) either belonging to a single- or multi-threaded process and maps to at least 1 PE of the physical machine, ensuring its execution. Mapping a single PET to multiple PEs provides resources for user-level multi-threading, in which case the user code inquires how many PEs are associated with its PET and if there are multiple PEs available the user code can spawn an equal number of threads (e.g. OpenMP) without risking over-subscription. Typically these user spawned threads are short-lived and used for fine-grained parallelization in form of TETs. All PEs mapped against a single PET must be part of a unique SSI in order to allow user-level multi-threading!
In addition to discovering the physical machine the ESMF initialization process sets up the default global virtual machine. This VM object, which is the ultimate parent of all VMs created during the course of execution, contains as many PETs as there are PEs in the physical machine. All of its PETs are instantiated in form of single-threaded MPI processes and a 1:1 mapping of PETs to PEs is used for the default global VM.
The VM design and implementation is based on the POSIX process and thread model as well as the MPI-1.2 standard. As a consequence of the latter standard the number of processes is static during the course of execution and is determined at start-up. The VM implementation further requires that the user starts up the ESMF application with as many MPI processes as there are PEs in the available physical machine using the platform dependent mechanism to ensure proper process placement.
All MPI processes participating in a VM are grouped together by means of an MPI_Group object and their context is defined via an MPI_Comm object (MPI intra-communicator). The PET local process id within each virtual machine is equal to the MPI_Comm_rank in the local MPI_Comm context whereas the PET process id is equal to the MPI_Comm_rank in MPI_COMM_WORLD. The PET process id is used within the VM methods to determine the virtual memory space a PET is operating in.
In order to provide a migration path for legacy MPI-applications the VM offers accessor functions to its MPI_Comm object. Once obtained this object may be used in explicit user-code MPI calls within the same context.
INTERFACE:
interface assignment(=) vm1 = vm2ARGUMENTS:
type(ESMF_VM) :: vm1 type(ESMF_VM) :: vm2STATUS:
DESCRIPTION:
Assign vm1 as an alias to the same ESMF VM object in memory as vm2. If vm2 is invalid, then vm1 will be equally invalid after the assignment.
The arguments are:
INTERFACE:
interface operator(==) if (vm1 == vm2) then ... endif OR result = (vm1 == vm2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_VM), intent(in) :: vm1 type(ESMF_VM), intent(in) :: vm2STATUS:
DESCRIPTION:
Test whether vm1 and vm2 are valid aliases to the same ESMF VM object in memory. For a more general comparison of two ESMF VMs, going beyond the simple alias test, the ESMF_VMMatch() function (not yet implemented) must be used.
The arguments are:
INTERFACE:
interface operator(/=) if (vm1 /= vm2) then ... endif OR result = (vm1 /= vm2)RETURN VALUE:
logical :: resultARGUMENTS:
type(ESMF_VM), intent(in) :: vm1 type(ESMF_VM), intent(in) :: vm2STATUS:
DESCRIPTION:
Test whether vm1 and vm2 are not valid aliases to the same ESMF VM object in memory. For a more general comparison of two ESMF VMs, going beyond the simple alias test, the ESMF_VMMatch() function (not yet implemented) must be used.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllFullReduce(vm, sendData, recvData, & count, reduceflag, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), intent(out) :: recvData integer, intent(in) :: count type(ESMF_Reduce_Flag), intent(in) :: reduceflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that reduces a contiguous data array of <type><kind> across the ESMF_VM object into a single value of the same <type><kind>. The result is returned on all PETs. Different reduction operations can be specified.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllGather(vm, sendData, recvData, count, & syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that gathers contiguous data of <type><kind> from all PETs of an ESMF_VM object into an array on each PET. The data received in recvData is identical across all PETs. The count elements sent from the sendData array on PET i are stored contiguously in the recvData array starting at position i count 1.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllGatherV(vm, sendData, sendCount, & recvData, recvCounts, recvOffsets, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCount <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCounts(:) integer, intent(in) :: recvOffsets(:) -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that gathers contiguous data of <type><kind> from all PETs of an ESMF_VM object into an array on each PET. The data received in recvData is identical across all PETs. The sendCount elements sent from the sendData array on PET i are stored contiguously in the recvData array starting at position recvOffsets(i).
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllReduce(vm, sendData, recvData, count, & reduceflag, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count type(ESMF_Reduce_Flag), intent(in) :: reduceflag -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that reduces a contiguous data array across the ESMF_VM object into a contiguous data array of the same <type><kind>. The result array is returned on all PETs. Different reduction operations can be specified.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllToAll(vm, sendData, sendCount, & recvData, recvCount, syncflag, & commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCount <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCount -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that performs a total exchange operation on the contiguous data of <type><kind>. PET i sends contiguous sendCount elements of its sendData array to every PET, including itself. The sendCount elements sent to PET j are those starting at position j sendCount 1, and are stored in recvData on PET in position i recvCount 1.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMAllToAllV(vm, sendData, sendCounts, & sendOffsets, recvData, recvCounts, recvOffsets, syncflag, & commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCounts(:) integer, intent(in) :: sendOffsets(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCounts(:) integer, intent(in) :: recvOffsets(:) -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that performs a total exchange operation on the contiguous data of <type><kind>. PET i sends contiguous elements of its sendData array to all PETs, including itself. The sendCount(j) elements sent to PET j are those starting at position sendOffsets(j), and are stored in recvData on PET in position recvOffsets(i).
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMBarrier(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(in), optional :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that blocks calling PET until all PETs of the VM context have issued the call.
The arguments are:
INTERFACE:
subroutine ESMF_VMBroadcast(vm, bcstData, count, rootPet, & syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(inout) :: bcstData(:) integer, intent(in) :: count integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that broadcasts a contiguous data array of <type><kind> from rootPet to all other PETs of the ESMF_VM object. When the call returns, the bcstData array on all PETs contains the same data as on rootPet.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL, ESMF_TYPEKIND_CHARACTER.
The arguments are:
INTERFACE:
subroutine ESMF_VMCommWait(vm, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm type(ESMF_CommHandle), intent(in) :: commhandle -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Wait for non-blocking VM communication specified by the commhandle to complete.
The arguments are:
INTERFACE:
subroutine ESMF_VMCommWaitAll(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Wait for all pending non-blocking VM communication within the specified VM context to complete.
The arguments are:
INTERFACE:
subroutine ESMF_VMEpochEnter(vm, epoch, keepAlloc, throttle, rc)ARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_VM), intent(in), optional :: vm type(ESMF_VMEpoch_Flag), intent(in), optional :: epoch logical, intent(in), optional :: keepAlloc integer, intent(in), optional :: throttle integer, intent(out), optional :: rcDESCRIPTION:
Enter a specific VM epoch. VM epochs change low level communication behavior which can have significant performance implications. It is an error to call ESMF_VMEpochEnter() again before exiting a previous epoch with ESMF_VMEpochExit().
The arguments are:
INTERFACE:
subroutine ESMF_VMEpochExit(vm, keepAlloc, rc)ARGUMENTS:
-- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_VM), intent(in), optional :: vm logical, intent(in), optional :: keepAlloc integer, intent(out), optional :: rcDESCRIPTION:
Exit the current VM epoch.
The arguments are:
INTERFACE:
subroutine ESMF_VMGather(vm, sendData, recvData, count, rootPet, & syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that gathers contiguous data of <type><kind> from all PETs of an ESMF_VM object (including the rootPet itself) into an array on rootPet. The count elements sent from the sendData array on PET i are stored contiguously in the recvData array on rootPet starting at position i count 1.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL.
The arguments are:
INTERFACE:
subroutine ESMF_VMGatherV(vm, sendData, sendCount, recvData, & recvCounts, recvOffsets, rootPet, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCount <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCounts(:) integer, intent(in) :: recvOffsets(:) integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that gathers contiguous data of <type><kind> from all PETs of an ESMF_VM object (including the rootPet itself) into an array on rootPet. The sendCount elements sent from the sendData array on PET i are stored contiguously in the recvData array on rootPet starting at position recvOffsets(i).
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
! Private name; call using ESMF_VMGet() recursive subroutine ESMF_VMGetDefault(vm, localPet, & currentSsiPe, petCount, peCount, ssiCount, ssiMap, ssiMinPetCount, ssiMaxPetCount, & ssiLocalPetCount, ssiLocalPet, ssiLocalDevCount, ssiLocalDevList, mpiCommunicator, & pthreadsEnabledFlag, openMPEnabledFlag, ssiSharedMemoryEnabledFlag, esmfComm, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: localPet integer, intent(out), optional :: currentSsiPe integer, intent(out), optional :: petCount integer, intent(out), optional :: peCount integer, intent(out), optional :: ssiCount integer, allocatable, intent(out), optional :: ssiMap(:) integer, intent(out), optional :: ssiMinPetCount integer, intent(out), optional :: ssiMaxPetCount integer, intent(out), optional :: ssiLocalPetCount integer, intent(out), optional :: ssiLocalPet integer, intent(out), optional :: ssiLocalDevCount integer, allocatable, intent(out), optional :: ssiLocalDevList(:) integer, intent(out), optional :: mpiCommunicator logical, intent(out), optional :: pthreadsEnabledFlag logical, intent(out), optional :: openMPEnabledFlag logical, intent(out), optional :: ssiSharedMemoryEnabledFlag character(:), allocatable, intent(out), optional :: esmfComm integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get internal information about the specified ESMF_VM object.
The arguments are:
INTERFACE:
! Private name; call using ESMF_VMGet() subroutine ESMF_VMGetPetSpecific(vm, pet, peCount, & accDeviceCount, & ! DEPRECATED ARGUMENT ssiId, threadCount, threadId, vas, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm integer, intent(in) :: pet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: peCount integer, intent(out), optional :: accDeviceCount ! DEPRECATED ARGUMENT integer, intent(out), optional :: ssiId integer, intent(out), optional :: threadCount integer, intent(out), optional :: threadId integer, intent(out), optional :: vas integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get internal information about a specific PET within an ESMF_VM object.
The arguments are:
INTERFACE:
subroutine ESMF_VMGetGlobal(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(out) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get the global ESMF_VM object. This is the VM object that is created during ESMF_Initialize() and is the ultimate parent of all VM objects in an ESMF application. It is identical to the VM object returned by ESMF_Initialize(..., vm=vm, ...).
The ESMF_VMGetGlobal() call provides access to information about the global execution context via the global VM. This call is necessary because ESMF does not created a global ESMF Component during ESMF_Initialize() that could be queried for information about the global execution context of an ESMF application.
Usage of ESMF_VMGetGlobal() from within Component code is strongly discouraged. ESMF Components should only access their own VM objects through Component methods. Global information, if required by the Component user code, should be passed down to the Component from the driver through the Component calling interface.
The arguments are:
INTERFACE:
subroutine ESMF_VMGetCurrent(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(out) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get the ESMF_VM object of the current execution context. Calling ESMF_VMGetCurrent() within an ESMF Component, will return the same VM object as ESMF_GridCompGet(..., vm=vm, ...) or ESMF_CplCompGet(..., vm=vm, ...).
The main purpose of providing ESMF_VMGetCurrent() is to simplify ESMF adoption in legacy code. Specifically, code that uses MPI_COMM_WORLD deep within its calling tree can easily be modified to use the correct MPI communicator of the current ESMF execution context. The advantage is that these modifications are very local, and do not require wide reaching interface changes in the legacy code to pass down the ESMF component object, or the MPI communicator.
The use of ESMF_VMGetCurrent() is strongly discouraged in newly written Component code. Instead, the ESMF Component object should be used as the appropriate container of ESMF context information. This object should be passed between the subroutines of a Component, and be queried for any Component specific information.
Outside of a Component context, i.e. within the driver context, the call to ESMF_VMGetCurrent() is identical to ESMF_VMGetGlobal().
The arguments are:
INTERFACE:
function ESMF_VMIsCreated(vm, rc)RETURN VALUE:
logical :: ESMF_VMIsCreatedARGUMENTS:
type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return .true. if the vm has been created. Otherwise return .false.. If an error occurs, i.e. rc /= ESMF_SUCCESS is returned, the return value of the function will also be .false..
The arguments are:
INTERFACE:
subroutine ESMF_VMLog(vm, prefix, logMsgFlag, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm character(len=*), intent(in), optional :: prefix type(ESMF_LogMsg_Flag), intent(in), optional :: logMsgFlag integer, intent(out), optional :: rcDESCRIPTION:
Log the VM.
The arguments are:
INTERFACE:
subroutine ESMF_VMLogSystem(prefix, logMsgFlag, rc)ARGUMENTS:
character(len=*), intent(in), optional :: prefix type(ESMF_LogMsg_Flag), intent(in), optional :: logMsgFlag integer, intent(out), optional :: rcDESCRIPTION:
Log the VM.
The arguments are:
INTERFACE:
subroutine ESMF_VMPrint(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Print internal information about the specified ESMF_VM to
stdout.
The arguments are:
INTERFACE:
subroutine ESMF_VMRecv(vm, recvData, count, srcPet, & syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count integer, intent(in) :: srcPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Receive contiguous data from srcPet within the same ESMF_VM object.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL, ESMF_TYPEKIND_CHARACTER.
The arguments are:
INTERFACE:
subroutine ESMF_VMReduce(vm, sendData, recvData, count, & reduceflag, rootPet, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count type(ESMF_Reduce_Flag), intent(in) :: reduceflag integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that reduces a contiguous data array across the ESMF_VM object into a contiguous data array of the same <type><kind>. The result array is returned on rootPet. Different reduction operations can be specified.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
TODO: The current version of this method does not provide an implementation of the non-blocking feature. When calling this method with syncflag = ESMF_SYNC_NONBLOCKING, error code ESMF_RC_NOT_IMPL will be returned and an error will be logged.
The arguments are:
INTERFACE:
subroutine ESMF_VMScatter(vm, sendData, recvData, count, & rootPet, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: count integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that scatters contiguous data of <type><kind> from rootPet across all the PETs of an ESMF_VM object. Every PET, including rootPet, receives a portion of the data. The count number of elements received by PET i originate from the sendData array on rootPet, starting at position i count 1. Each PET stores the received contiguous data portion at the start of its recvData array.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL.
The arguments are:
INTERFACE:
subroutine ESMF_VMScatterV(vm, sendData, sendCounts, & sendOffsets, recvData, recvCount, rootPet, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCounts(:) integer, intent(in) :: sendOffsets(:) <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCount integer, intent(in) :: rootPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Collective ESMF_VM communication call that scatters contiguous data of <type><kind> from rootPet across all the PETs of an ESMF_VM object. Every PET, including rootPet, receives a portion of the data. The recvCount number of elements received by PET i originate from the sendData array on rootPet, starting at position sendOffsets(i). Each PET stores the received contiguous data portion at the start of its recvData array.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.
The arguments are:
INTERFACE:
subroutine ESMF_VMSend(vm, sendData, count, dstPet, & syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: count integer, intent(in) :: dstPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Send contiguous data to dstPet within the same ESMF_VM object.
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL, ESMF_TYPEKIND_CHARACTER.
The arguments are:
INTERFACE:
subroutine ESMF_VMSendRecv(vm, sendData, sendCount, dstPet, & recvData, recvCount, srcPet, syncflag, commhandle, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm <type>(ESMF_KIND_<kind>), target, intent(in) :: sendData(:) integer, intent(in) :: sendCount integer, intent(in) :: dstPet <type>(ESMF_KIND_<kind>), target, intent(out) :: recvData(:) integer, intent(in) :: recvCount integer, intent(in) :: srcPet -- The following arguments require argument keyword syntax (e.g. rc=rc). -- type(ESMF_Sync_Flag), intent(in), optional :: syncflag type(ESMF_CommHandle), intent(out), optional :: commhandle integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Send contiguous data to dstPet within the same ESMF_VM object while receiving contiguous data from srcPet within the same ESMF_VM object. The sendData and recvData arrays must be disjoint!
This method is overloaded for: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8, ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8, ESMF_TYPEKIND_LOGICAL, ESMF_TYPEKIND_CHARACTER.
The arguments are:
INTERFACE:
subroutine ESMF_VMValidate(vm, rc)ARGUMENTS:
type(ESMF_VM), intent(in) :: vm -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Validates that the vm is internally consistent. The method returns an error code if problems are found.
The arguments are:
INTERFACE:
subroutine ESMF_VMWtime(time, rc)ARGUMENTS:
real(ESMF_KIND_R8), intent(out) :: time -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get floating-point number of seconds of elapsed wall-clock time since the beginning of execution of the application.
The arguments are:
INTERFACE:
recursive subroutine ESMF_VMWtimeDelay(delay, rc)ARGUMENTS:
real(ESMF_KIND_R8), intent(in) :: delay -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Delay execution for amount of seconds.
The arguments are:
INTERFACE:
subroutine ESMF_VMWtimePrec(prec, rc)ARGUMENTS:
real(ESMF_KIND_R8), intent(out) :: prec -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Get a run-time estimate of the timer precision as floating-point number of seconds. This is a relatively expensive call since the timer precision is measured several times before the maximum is returned as the estimate. The returned value is PET-specific and may differ across the VM context.
The arguments are:
ESMF's built in profiling capability collects runtime statistics of an executing ESMF application through both automatic and manual code instrumentation. Timing information for all phases of all ESMF components executing in an application can be automatically collected using the ESMF_RUNTIME_PROFILE environment variable (see below for settings). Additionally, arbitrary user-defined code regions can be timed by manually instrumenting code with special API calls. Timing profiles of component phases and user-defined regions can be output in several different formats:
The following table lists important environment variables that control aspects of ESMF profiling.
Environment Variable | Description | Example Values | Default |
ESMF_RUNTIME_PROFILE | Enable/disables all profiling functions | ON or OFF | OFF |
ESMF_RUNTIME_PROFILE_PETLIST | Limits profiling to an explicit list of PETs | “0-9 50 99” | profile all PETs |
ESMF_RUNTIME_PROFILE_OUTPUT | Controls output format of profiles; multiple can be specified in a space separated list | TEXT, SUMMARY, BINARY | TEXT |
Whereas profiling collects summary information from an application, tracing records a more detailed set of events for later analysis. Trace analysis can be used to understand what happened during a program's execution and is often used for diagnosing problems, debugging, and performance analysis.
ESMF has a built-in tracing capability that records events into special binary log files. Unlike log files written by the ESMF_Log class, which are primarily for human consumption (see Section 49.1), the trace output files are recorded in a compact binary representation and are processed by tools to produce various analyses. ESMF event streams are recorded in the Common Trace Format (CTF). CTF traces include one or more event streams, as well as a metadata file describing the events in the streams.
Several tools are available for reading in the CTF traces output by ESMF. Of the tools listed below, the first one is designed specifically for analyzing ESMF applications and the second two are general purpose tools for working with all CTF traces.
Events that can be captured by the ESMF tracer include the following. Events are recorded with a high-precision timestamp to allow timing analyses.
The following table lists important environment variables that control aspects of ESMF tracing.
Environment Variable | Description | Example Values | Default |
ESMF_RUNTIME_TRACE | Enable/disables all tracing functions | ON or OFF | OFF |
ESMF_RUNTIME_TRACE_CLOCK | Sets the type of clock for timestamping events (see Section 52.2.6). | REALTIME or MONOTONIC or MONOTONIC_SYNC | REALTIME |
ESMF_RUNTIME_TRACE_PETLIST | Limits tracing to an explicit list of PETs | “0-9 50 99” | trace all PETs |
ESMF_RUNTIME_TRACE_COMPONENT | Enables/disable tracing of Component phase_enter and phase_exit events | ON or OFF | ON |
ESMF_RUNTIME_TRACE_FLUSH | Controls frequency of event stream flushing to file | DEFAULT or EAGER | DEFAULT |
ESMF profiling is disabled by default. To profile an application, set the ESMF_RUNTIME_PROFILE variable to ON prior to executing the application. You do not need to recompile your code to enable profiling.
# csh shell $ setenv ESMF_RUNTIME_PROFILE ON # bash shell $ export ESMF_RUNTIME_PROFILE=ON # (from now on, only the csh shell version will be shown)
Then execute the application in the usual way. At the end of the run the profile information will be available at the end of each PET log (if ESMF Logs are turned on) or in a set of separate files, one per PET, with names ESMF_Profile.XXX where XXX is the PET number. Below is an example timing profile. Some regions are left out for brevity.
Region Count Total (s) Self (s) Mean (s) Min (s) Max (s) [esm] Init 1 1 4.0878 0.0341 4.0878 4.0878 4.0878 [OCN-TO-ATM] IPDv05p6b 1 2.6007 2.6007 2.6007 2.6007 2.6007 [ATM-TO-OCN] IPDv05p6b 1 1.4333 1.4333 1.4333 1.4333 1.4333 [ATM] IPDv00p2 1 0.0055 0.0055 0.0055 0.0055 0.0055 [OCN] IPDv00p2 1 0.0023 0.0023 0.0023 0.0023 0.0023 [ATM] IPDv00p1 1 0.0011 0.0011 0.0011 0.0011 0.0011 [OCN] IPDv00p1 1 0.0009 0.0009 0.0009 0.0009 0.0009 [ATM-TO-OCN] IPDv05p3 1 0.0008 0.0008 0.0008 0.0008 0.0008 [ATM-TO-OCN] IPDv05p1 1 0.0008 0.0008 0.0008 0.0008 0.0008 [ATM-TO-OCN] IPDv05p2b 1 0.0007 0.0007 0.0007 0.0007 0.0007 [ATM-TO-OCN] IPDv05p4 1 0.0007 0.0007 0.0007 0.0007 0.0007 [ATM-TO-OCN] IPDv05p2a 1 0.0007 0.0007 0.0007 0.0007 0.0007 [ATM-TO-OCN] IPDv05p5 1 0.0007 0.0007 0.0007 0.0007 0.0007 [OCN-TO-ATM] IPDv05p3 1 0.0006 0.0006 0.0006 0.0006 0.0006 [OCN-TO-ATM] IPDv05p4 1 0.0006 0.0006 0.0006 0.0006 0.0006 [OCN-TO-ATM] IPDv05p2b 1 0.0006 0.0006 0.0006 0.0006 0.0006 [OCN-TO-ATM] IPDv05p2a 1 0.0006 0.0006 0.0006 0.0006 0.0006 [OCN-TO-ATM] IPDv05p5 1 0.0006 0.0006 0.0006 0.0006 0.0006 [OCN-TO-ATM] IPDv05p1 1 0.0005 0.0005 0.0005 0.0005 0.0005 [esm] RunPhase1 1 2.7423 0.9432 2.7423 2.7423 2.7423 [OCN-TO-ATM] RunPhase1 864 0.6094 0.6094 0.0007 0.0006 0.0179 [ATM] RunPhase1 864 0.5296 0.2274 0.0006 0.0005 0.0011 ATM:ModelAdvance 864 0.3022 0.3022 0.0003 0.0003 0.0005 [ATM-TO-OCN] RunPhase1 864 0.3345 0.3345 0.0004 0.0002 0.0299 [OCN] RunPhase1 864 0.3256 0.3256 0.0004 0.0003 0.0010 [esm] FinalizePhase1 1 0.0029 0.0020 0.0029 0.0029 0.0029 [OCN-TO-ATM] FinalizePhase1 1 0.0006 0.0006 0.0006 0.0006 0.0006 [ATM-TO-OCN] FinalizePhase1 1 0.0002 0.0002 0.0002 0.0002 0.0002 [OCN] FinalizePhase1 1 0.0001 0.0001 0.0001 0.0001 0.0001 [ATM] FinalizePhase1 1 0.0000 0.0000 0.0000 0.0000 0.0000
A timed region is either an ESMF component phase (e.g., initialize, run, or finalize) or a user-defined region of code surrounded by calls to ESMF_TraceRegionEnter() and ESMF_TraceRegionExit(). (See section 52.2.8 for more information on instrumenting user-defined regions.) Regions are organized hierarchically with sub-regions nested. For example, in the profile above, the [OCN] RunPhase1 is a sub-region of [esm] RunPhase1 and is entirely contained inside that region. Regions with the same name may appear at multiple places in the hierarchy, and so would appear in multiple rows in the table. The statistics in that row apply to that region at that location in the hierarchy. Component names appear in square brackets, e.g., [ATM], [OCN], and [ATM-TO-OCN]. By default, timings are based on elapsed wall clock time and are collected on a per-PET basis. Therefore, regions timings may differ across PETs. Regions are sorted with the most expensive regions appearing at the top. The following describes the meaning of the statistics in each column:
Count | the number of times the region is executed |
Total | the aggregate time spent in the region, inclusive of all sub-regions |
Self | the aggregate time spend in the region, exclusive of all sub-regions |
Mean | the average amount of time for one execution of the region |
Min | time of the fastest execution of the region |
Max | time of the slowest execution of the region |
By default, separate timing profiles are generated for each PET in the application. The per-PET profiles can be aggregated together and output to a single file, ESMF_Profile.summary, by setting the ESMF_RUNTIME_PROFILE_OUTPUT environment variable as follows:
$ setenv ESMF_RUNTIME_PROFILE ON # turn on profiling $ setenv ESMF_RUNTIME_PROFILE_OUTPUT SUMMARY # specify summary output
Note the ESMF_RUNTIME_PROFILE environment variable must also be set to ON since this controls all profiling capabilities. The ESMF_Profile.summary file will contain a tree of timed regions, but aggregated across all PETs. For example:
Region PETs PEs Count Mean (s) Min (s) Min PET Max (s) Max PET [esm] Init 1 4 4 1 4.0880 4.0878 2 4.0883 1 [OCN-TO-ATM] IPDv05p6b 4 4 1 2.6007 2.6007 2 2.6007 3 [ATM-TO-OCN] IPDv05p6b 4 4 1 1.4335 1.4333 0 1.4337 3 [ATM-TO-OCN] IPDv05p4 4 4 1 0.0037 0.0007 0 0.0060 1 [ATM] IPDv00p2 4 4 1 0.0034 0.0020 1 0.0055 0 [ATM-TO-OCN] IPDv05p1 4 4 1 0.0020 0.0007 2 0.0033 3 [OCN] IPDv00p2 4 4 1 0.0019 0.0015 3 0.0024 2 [ATM-TO-OCN] IPDv05p3 4 4 1 0.0010 0.0008 0 0.0013 1 [ATM-TO-OCN] IPDv05p2a 4 4 1 0.0009 0.0007 0 0.0012 3 [ATM] IPDv00p1 4 4 1 0.0009 0.0007 3 0.0011 0 [ATM-TO-OCN] IPDv05p2b 4 4 1 0.0008 0.0007 0 0.0010 3 [ATM-TO-OCN] IPDv05p5 4 4 1 0.0008 0.0007 0 0.0010 3 [ATM-TO-OCN] IPDv05p6a 4 4 1 0.0008 0.0005 2 0.0012 3 [OCN-TO-ATM] IPDv05p3 4 4 1 0.0008 0.0006 2 0.0010 3 [OCN-TO-ATM] IPDv05p4 4 4 1 0.0008 0.0006 0 0.0009 3 [OCN-TO-ATM] IPDv05p2b 4 4 1 0.0007 0.0006 2 0.0009 3 [OCN] IPDv00p1 4 4 1 0.0007 0.0005 1 0.0009 2 [OCN-TO-ATM] IPDv05p2a 4 4 1 0.0007 0.0006 2 0.0009 1 [OCN-TO-ATM] IPDv05p5 4 4 1 0.0007 0.0006 0 0.0009 3 [OCN-TO-ATM] IPDv05p1 4 4 1 0.0006 0.0005 0 0.0008 1 [OCN-TO-ATM] IPDv05p6a 4 4 1 0.0006 0.0004 2 0.0007 1 [esm] RunPhase1 4 4 1 2.7444 2.7423 0 2.7454 1 [OCN-TO-ATM] RunPhase1 4 4 864 0.6123 0.6004 2 0.6244 1 [ATM] RunPhase1 4 4 864 0.5386 0.5296 0 0.5530 1 ATM:ModelAdvance 4 4 864 0.3038 0.3022 0 0.3065 1 [OCN] RunPhase1 4 4 864 0.3471 0.3256 0 0.3824 1 [ATM-TO-OCN] RunPhase1 4 4 864 0.2843 0.1956 1 0.3345 0 [esm] FinalizePhase1 4 4 1 0.0029 0.0029 1 0.0030 2 [OCN-TO-ATM] FinalizePhase1 4 4 1 0.0007 0.0006 0 0.0008 3 [ATM-TO-OCN] FinalizePhase1 4 4 1 0.0002 0.0001 3 0.0002 1 [OCN] FinalizePhase1 4 4 1 0.0001 0.0001 3 0.0001 0 [ATM] FinalizePhase1 4 4 1 0.0001 0.0000 0 0.0001 2
The meaning of the statistics in each column in as follows:
PETs | the number of reporting PETs that executed the region |
PEs | the number of PEs associated with the reporting PETs that executed the region |
Count | the number of times each reporting PET executed the region or “MULTIPLE” if not all PETs executed the region the same number of times |
Mean | the mean across all reporting PETs of the total time spent in the region |
Min | the minimum across all reporting PETs of the total time spent in the region |
Min PET | the PET that reported the minimum time |
Max | the maximum across all reporting PETs of the total time spent in the region |
Max PET | the PET that reported the maximum time |
Note that setting the ESMF_RUNTIME_PROFILE_PETLIST environment variable (described below) may reduce the number of reporting PETs. Only reporting PETs are included in the summary profile. To output both the per-PET and summary timing profiles, set the ESMF_RUNTIME_PROFILE_OUTPUT environment variable as follows:
$ setenv ESMF_RUNTIME_PROFILE_OUTPUT "TEXT SUMMARY"
By default, all PETs in an application are profiled. It may be desirable to only profile a subset of PETs to reduce the amount of output. An explicit list of PETs can be specified by setting the ESMF_RUNTIME_PROFILE_PETLIST environment variable. The syntax of this environment variable is to list PET numbers separated by spaces. PET ranges are also supported using the “X-Y” syntax where X < Y. For example:
# only profile PETs 0, 20, and 35 through 39 $ setenv ESMF_RUNTIME_PROFILE_PETLIST "0 20 35-39"
When used in conjunction with the SUMMARY option above, the summarized profile will only aggregate over the specified set of PETs. The one exception is that PET 0 is always profiled if ESMF_RUNTIME_PROFILE=ON, regardless of the ESMF_RUNTIME_TRACE_PETLIST setting.
MPI functions can be included in the timing profile to indicate how much time is spent inside communication calls. This can also help to determine load imbalance in the system, since large times spent inside MPI may indicate that communication between PETs is not tightly synchronized. This option includes all MPI calls in the application, whether or not they originate from the ESMF library. Here is a partial example summary profile that contains MPI times:
Region PETs Count Mean (s) Min (s) Min PET Max (s) Max PET [esm] RunPhase1 8 1 4.9307 4.6867 0 4.9656 1 [OCN] RunPhase1 8 1824 0.8344 0.8164 0 0.8652 1 [MED] RunPhase1 8 1824 0.8203 0.7900 5 0.8584 1 [ATM] RunPhase1 8 1824 0.6387 0.6212 5 0.6610 1 [ATM-TO-MED] RunPhase1 8 1824 0.5975 0.5317 0 0.6583 5 MPI_Bcast 8 1824 0.0443 0.0025 4 0.1231 5 MPI_Wait 8 MULTIPLE 0.0421 0.0032 0 0.0998 2 [MED-TO-OCN] RunPhase1 8 1824 0.4879 0.4497 0 0.5362 4 MPI_Wait 8 MULTIPLE 0.0234 0.0030 0 0.0821 4 MPI_Bcast 8 1824 0.0111 0.0024 4 0.0273 5 [OCN-TO-MED] RunPhase1 8 1824 0.4541 0.4075 0 0.4918 4 MPI_Wait 8 MULTIPLE 0.0339 0.0017 0 0.0824 4 MPI_Bcast 8 1824 0.0194 0.0026 4 0.0452 6 [MED-TO-ATM] RunPhase1 8 1824 0.4487 0.4005 0 0.4911 5 MPI_Bcast 8 1824 0.0338 0.0026 4 0.0942 5 MPI_Wait 8 MULTIPLE 0.0241 0.0022 1 0.0817 2 [esm] Init 1 8 1 0.6287 0.6287 1 0.6287 4 [ATM-TO-MED] IPDv05p6b 8 1 0.1501 0.1500 1 0.1501 2 MPI_Barrier 8 242 0.0082 0.0006 3 0.0157 7 MPI_Wait 8 MULTIPLE 0.0034 0.0010 0 0.0053 7 MPI_Allreduce 8 62 0.0030 0.0003 3 0.0063 7 MPI_Alltoall 8 6 0.0015 0.0000 1 0.0022 5 MPI_Allgather 8 21 0.0010 0.0002 1 0.0017 7 MPI_Waitall 8 MULTIPLE 0.0006 0.0001 3 0.0015 7 MPI_Send 8 MULTIPLE 0.0004 0.0001 7 0.0008 6 MPI_Allgatherv 8 6 0.0001 0.0001 4 0.0001 0 MPI_Scatter 8 5 0.0000 0.0000 0 0.0000 7 MPI_Reduce 8 5 0.0000 0.0000 1 0.0000 0 MPI_Recv 8 MULTIPLE 0.0000 0.0000 0 0.0000 3 MPI_Bcast 8 1 0.0000 0.0000 0 0.0000 7
The procedure for including MPI functions in the timing profile depends on whether the application is dynamically or statically linked. Most applications are dynamically linked, however on some systems (such as Cray), static linking may be used. Note that for either option, ESMF must be built with ESMF_TRACE_LIB_BUILD=ON, which is the default.
In dynamically linked applications, the LD_PRELOAD (Linux) or DYLD_INSERT_LIBRARIES (Darwin) environment variable must be used when executing the MPI application. This instructs the dynamic loader to interpose certain MPI symbols so they can be captured by the ESMF profiler. To simplify this process, a script is provided at $(ESMF_INSTALL_LIBDIR)/preload.sh that sets the appropriate variable.
For example, if you typically execute your application as as follows:
$ mpirun -np 8 ./myApp
then you should add the preload.sh script in front of the executable when starting the application as follows:
# replace $(ESMF_INSTALL_LIBDIR) with absolute path # ... to the ESMF installation lib directory $ mpirun -np 8 $(ESMF_INSTALL_LIBDIR)/preload.sh ./myApp
An advantage of this approach is that your application does not need to be recompiled. The MPI timing information will be included in the per-PET profiles and/or the summary profile, depending on the setting of environment variable ESMF_RUNTIME_PROFILE_OUTPUT.
Notice that an additional step is required for dynamically linked applications on Darwin systems with System Integrity Protection (SIP) enabled! In addition to using the $(ESMF_INSTALL_LIBDIR)/preload.sh script during launching of the executable as shown above, the executable must also be linked against the dynamic ESMF trace preload library. This must happen during the link step of the executable. It is most easily accomplished by using variable $(ESMF_F90ESMFPRELOADLINKLIBS) instead of the typical $(ESMF_F90ESMFLINKLIBS) variable for the final link command. Both variables are defined in the esmf.mk file that should be imported by the application Makefile. For example:
# import esmf.mk include $(ESMFMKFILE) # other makefile targets here... # example final link command, with $(ESMF_F90ESMFPRELOADLINKLIBS) myApp: myApp.o driver.o model.o $(ESMF_F90LINKER) $(ESMF_F90LINKOPTS) $(ESMF_F90LINKPATHS) \ $(ESMF_F90LINKRPATHS) -o $@ $^ $(ESMF_F90ESMFPRELOADLINKLIBS)
In statically linked applications, the application must be re-linked with specific options provided to the linker. These options instruct the linker to wrap the MPI symbols with the ESMF profiling functions. The linking flags that must be provided are included in the esmf.mk Makefile fragment that is part of the ESMF installation. These link flags should be imported into your application Makefile, and included in the final link command. To do this, first import the esmf.mk file into your application Makefile. The path to this file is typically stored in the ESMFMKFILE environment variable. Then, pass the variables $(ESMF_TRACE_STATICLINKOPTS) and $(ESMF_TRACE_STATICLINKLIBS) to the final linking command. For example:
# import esmf.mk include $(ESMFMKFILE) # other makefile targets here... # example final link command, with $(ESMF_TRACE_STATICLINKOPTS) # ... and $(ESMF_TRACE_STATICLINKLIBS) added myApp: myApp.o driver.o model.o $(ESMF_F90LINKER) $(ESMF_F90LINKOPTS) $(ESMF_F90LINKPATHS) \ $(ESMF_F90LINKRPATHS) -o $@ $^ $(ESMF_F90ESMFLINKLIBS) \ $(ESMF_TRACE_STATICLINKOPTS) $(ESMF_TRACE_STATICLINKLIBS)
This option will statically wrap all of the MPI functions and include them in the profile output. Execute the application in the normal way with the environment variable ESMF_RUNTIME_PROFILE set to ON. You will see the MPI functions included in the timing profile.
ESMF tracing is disabled by default. To enable tracing, set the ESMF_RUNTIME_TRACE environment variable to ON. You do not need to recompile your code to enable tracing.
# csh shell $ setenv ESMF_RUNTIME_TRACE ON # bash shell $ export ESMF_RUNTIME_TRACE=ON
When enabled, the default behavior is to trace all PETs of the ESMF application. Although the ESMF tracer is designed to write events in a compact form, tracing can produce an extremely large number of events depending on the total number of PETs and the length of the run. To reduce output, it is possible to restrict the PETs that produce trace output by setting the ESMF_RUNTIME_TRACE_PETLIST environment variable. For example, this setting:
$ setenv ESMF_RUNTIME_TRACE_PETLIST "0 101 192-196"
will instruct the tracer to only trace PETs 0, 101, and 192 through 196 (inclusive). The syntax of this environment variable is to list PET numbers separated by spaces. PET ranges are also supported using the “X-Y” syntax where X < Y. For PET counts greater than 100, it is recommended to set this environment variable. The one exception is that PET 0 is always traced, regardless of the ESMF_RUNTIME_TRACE_PETLIST setting.
ESMF's profiling and tracing options can be used together. A typical use would be to set ESMF_RUNTIME_PROFILE=ON for all PETs to capture summary timings, and set ESMF_RUNTIME_TRACE=ON and ESMF_RUNTIME_TRACE_PETLIST to a subset of of PETs, such as the root PET of each ESMF component. This helps to keep trace sizes small while still providing timing summaries over all PETs.
When tracing is enabled, phase_enter and phase_exit events will automatically be recorded for all initialize, run, and finalize phases of all Components in the application. To trace only user-instrumented regions (via the ESMF_TraceRegionEnter() and ESMF_TraceRegionExit() calls), Component-level tracing can be turned off by setting:
$ setenv ESMF_RUNTIME_TRACE_COMPONENT OFF
After running an ESMF application with tracing enabled, a directory called traceout will be created in the run directory and it will contain a metadata file and an event stream file esmf_stream_XXXX for each PET with tracing enabled. Together these files form a valid CTF trace which may be analyzed with any of the tools listed above.
Trace events are flushed to file at a regular interval. If the application crashes, some of the most recent events may not be flushed to file. To maximize the number of events appearing in the trace, an option is available to flush events to file more frequently. Because this option may have negative performance implications due to increased file I/O, it is not recommended unless needed. To turn on eager flushing use:
$ setenv ESMF_RUNTIME_TRACE_FLUSH EAGER
There are three options for the kind of clock to use to timestamp events when profiling/tracing an application. These options are controlled by setting the environment variable ESMF_RUNTIME_TRACE_CLOCK.
REALTIME | The REALTIME clock timestamps events with the current time on the system. This is the default clock if the above environment variable is not set. This setting can be useful when tracing PETs that span multiple physical computing nodes assuming that the system clocks on each node are adequately synchronized. On most HPC systems, system clocks are periodically updated to stay in sync. A disadvantage of this clock is that periodic adjustments mean the clock is not monotonically increasing so some timings may be inaccurate if the system clock jumps forward or backward significantly. Testing has shown that this is not typically an issue on most systems. |
MONOTONIC | The MONOTONIC clock is guaranteed to be monotonically increasing and does not suffer from periodic adjustments. The timestamps represent an amount of time since some arbitrary point in the past. There is no guarantee that these timestamps will be synchronized across physical computing nodes, so this option should only be used for tracing a set of PETs running on a single physical machine. |
MONOTONIC_SYNC | The MONOTONIC_SYNC clock is similar to the MONOTONIC clock in that it is guaranteed to be monotonically increasing. In addition, at application startup, all PET clocks are synchronized to a common time by determining a PET-local offset to be applied to timestamps. Therefore this option can be used to compare trace streams across physical nodes. |
This example illustrates how to trace a simple ESMF application and print the event stream using Babeltrace. The first part of the code is a module representing a trivial ESMF Gridded Component. The second part is a main program that creates and executes the component.
module SimpleComp use ESMF implicit none private public SetServices contains subroutine SetServices(gcomp, rc) type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & userRoutine=Init, rc=rc) call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_RUN, & userRoutine=Run, rc=rc) call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_FINALIZE, & userRoutine=Finalize, rc=rc) rc = ESMF_SUCCESS end subroutine SetServices subroutine Init(gcomp, istate, estate, clock, rc) type(ESMF_GridComp):: gcomp type(ESMF_State):: istate, estate type(ESMF_Clock):: clock integer, intent(out):: rc print *, "Inside Init" end subroutine Init subroutine Run(gcomp, istate, estate, clock, rc) type(ESMF_GridComp):: gcomp type(ESMF_State):: istate, estate type(ESMF_Clock):: clock integer, intent(out):: rc print *, "Inside Run" end subroutine Run subroutine Finalize(gcomp, istate, estate, clock, rc) type(ESMF_GridComp):: gcomp type(ESMF_State):: istate, estate type(ESMF_Clock):: clock integer, intent(out):: rc print *, "Inside Finalize" end subroutine Finalize end module SimpleComp
program ESMF_TraceEx
! Use ESMF framework module use ESMF use SimpleComp, only: SetServices
implicit none ! Local variables integer :: rc, finalrc, i type(ESMF_GridComp) :: gridcomp
! initialize ESMF finalrc = ESMF_SUCCESS call ESMF_Initialize(vm=vm, defaultlogfilename="TraceEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! create the component and then execute ! initialize, run, and finalize routines gridcomp = ESMF_GridCompCreate(name="test", rc=rc)
call ESMF_GridCompSetServices(gridcomp, userRoutine=SetServices, rc=rc)
call ESMF_GridCompInitialize(gridcomp, rc=rc)
do i=1, 5 call ESMF_GridCompRun(gridcomp, rc=rc) enddo
call ESMF_GridCompFinalize(gridcomp, rc=rc)
call ESMF_GridCompDestroy(gridcomp, rc=rc)
call ESMF_Finalize(rc=rc)
end program ESMF_TraceEx
Assuming the code above is executed on four PETs with the environment variable ESMF_RUNTIME_TRACE set to ON, then a folder will be created in the run directory called traceout containing a metadata file and four event stream files named esmf_stream_XXXX where XXXX is the PET number. If Babeltrace is available on the system, the list of events can be printed by executing the following from the run directory:
$ babeltrace ./traceoutFor details about iterating over trace events and performing analyses on CTF traces, see the corresponding documentation in the tools listed in Section 52.1.2.
This example illustrates how to manually instrument code with entry and exit points for user-defined code regions. Note that the API calls ESMF_TraceRegionEnter and ESMF_TraceRegionExit should always appear in pairs, wrapping a particular section of code. The environment variable ESMF_RUNTIME_TRACE or ESMF_RUNTIME_PROFILE must be set to ON to enable these regions. If not at least one is set, the calls to ESMF_TraceRegionEnter and ESMF_TraceRegionExit will simply return immediately. For this reason, it is safe to leave this instrumentation in application code, even when not being profiled.
! Use ESMF framework module use ESMF
implicit none ! Local variables integer :: rc, finalrc integer :: i, j, tmp
! initialize ESMF finalrc = ESMF_SUCCESS call ESMF_Initialize(vm=vm, defaultlogfilename="TraceUserEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
! record entrance into "outer_region" call ESMF_TraceRegionEnter("outer_region", rc=rc) tmp = 0 do i=1, 10 ! record entrance into "inner_region_1" call ESMF_TraceRegionEnter("inner_region_1", rc=rc) ! arbitrary computation do j=1,10000 tmp=tmp+j+i enddo ! record exit from "inner_region_1" call ESMF_TraceRegionExit("inner_region_1", rc=rc) tmp = 0 ! record entrance into "inner_region_2" call ESMF_TraceRegionEnter("inner_region_2", rc=rc) ! arbitrary computation do j=1,5000 tmp=tmp+j+i enddo ! record exit from "inner_region_2" call ESMF_TraceRegionExit("inner_region_2", rc=rc) enddo ! record exit from "outer_region" call ESMF_TraceRegionExit("outer_region", rc=rc)
call ESMF_Finalize(rc=rc)
INTERFACE:
subroutine ESMF_TraceRegionEnter(name, rc)ARGUMENTS:
character(len=*), intent(in) :: name integer, intent(out), optional :: rcDESCRIPTION:
Record an event in the trace for this PET indicating entry into a user-defined region with the given name. This call must be paired with a call to ESMF_TraceRegionExit() with a matching name parameter. User-defined regions may be nested. If tracing is disabled on the calling PET or for the application as a whole, no event will be recorded and the call will return immediately.
The arguments are:
INTERFACE:
subroutine ESMF_TraceRegionExit(name, rc)ARGUMENTS:
character(len=*), intent(in) :: name integer, intent(out), optional :: rcDESCRIPTION:
Record an event in the trace for this PET indicating exit from a user-defined region with the given name. This call must appear after a call to ESMF_TraceRegionEnter() with a matching name parameter. If tracing is disabled on the calling PET or for the application as a whole, no event will be recorded and the call will return immediately.
The arguments are:
The ESMF Fortran I/O and System utilities provide portable methods to access capabilities which are often implemented in different ways amongst different environments. These utility methods are divided into three groups: command line access, Fortran I/O, and sorting.
Command line arguments may be accessed using three methods: ESMF_UtilGetArg() returns a given command line argument, ESMF_UtilGetArgC() returns a count of the number of command line arguments available. Finally, the ESMF_UtilGetArgIndex() method returns the index of a desired argument value, given its keyword name.
Two I/O methods are implemented: ESMF_IOUnitGet(), to obtain an unopened Fortran unit number within the range of unit numbers that ESMF is allowed to use, and ESMF_IOUnitFlush() to flush the I/O buffer associated with a specific Fortran unit.
Finally, the ESMF_UtilSort() method sorts integer, floating point, and character string data types in either ascending or descending order.
call ESMF_UtilIOUnitGet (unit=grid_unit, rc=rc) open (unit=grid_unit, file='grid_data.dat', status='old', action='read')
By default, unit numbers between 50 and 99 are scanned to find an unopened unit number.
Internally, ESMF also uses ESMF_UtilIOUnitGet() when it needs to open Fortran unit numbers for file I/O. By using the same API for both user and ESMF code, unit number collisions can be avoided.
When integrating ESMF into an application where there are conflicts with other uses of the same unit number range, such as when hard-coded unit number values are used, an alternative unit number range can be specified. The ESMF_Initialize() optional arguments IOUnitLower and IOUnitUpper may be set as needed. Note that IOUnitUpper must be set to a value higher than IOUnitLower, and that both must be non-negative. Otherwise ESMF_Initialize will return a return code of ESMF_FAILURE. ESMF itself does not typically need more than about five units for internal use.
call ESMF_Initialize (..., IOUnitLower=120, IOUnitUpper=140)
All current Fortran environments have preconnected unit numbers, such as units 5 and 6 for standard input and output, in the single digit range. So it is recommended that the unit number range is chosen to begin at unit 10 or higher to avoid these preconnected units.
Fortran run-time libraries generally use buffering techniques to improve I/O performance. However output buffering can be problematic when output is needed, but is “trapped” in the buffer because it is not full. This is a common occurrance when debugging a program, and inserting WRITE statements to track down the bad area of code. If the program crashes before the output buffer has been flushed, the desired debugging output may never be seen -- giving a misleading indication of where the problem occurred. It would be desirable to ensure that the output buffer is flushed at predictable points in the program in order to get the needed results. Likewise, in parallel code, predictable flushing of output buffers is a common requirement, often in conjunction with ESMF_VMBarrier() calls.
The ESMF_UtilIOUnitFlush() API is provided to flush a unit as desired. Here is an example of code which prints debug values, and serializes the output to a terminal in PET order:
type(ESMF_VM) :: vm integer :: tty_unit integer :: me, npets call ESMF_Initialize (vm=vm, rc=rc) call ESMF_VMGet (vm, localPet=me, petCount=npes) call ESMF_UtilIOUnitGet (unit=tty_unit) open (unit=tty_unit, file='/dev/tty', status='old', action='write') ... call ESMF_VMBarrier (vm=vm) do, i=0, npets-1 if (i == me) then write (tty_unit, *) 'PET: ', i, ', values are: ', a, b, c call ESMF_UtilIOUnitFlush (unit=tty_unit) end if call ESMF_VMBarrier (vm=vm) end do
When ESMF needs to open a Fortran I/O unit, it calls ESMF_IOUnitGet() to find an unopened unit number. As delivered, the range of unit numbers that are searched are between ESMF_LOG_FORTRAN_UNIT_NUMBER (normally set to 50), and ESMF_LOG_UPPER (normally set to 99.) Unopened unit numbers are found by using the Fortran INQUIRE statement.
When integrating ESMF into an application where there are conflicts with other uses of the same unit number range, an alternative range can be specified in the ESMF_Initialize() call by setting the IOUnitLower and IOUnitUpper arguments as needed. ESMF_IOUnitGet() will then search the alternate range of unit numbers. Note that IOUnitUpper must be set to a value higher than IOUnitLower, and that both must be non-negative. Otherwise ESMF_Initialize will return a return code of ESMF_FAILURE.
Fortran unit numbers are not standardized in the Fortran 90 Standard. The standard only requires that they be non-negative integers. But other than that, it is up to the compiler writers and application developers to provide and use units which work with the particular implementation. For example, units 5 and 6 are a defacto standard for “standard input” and “standard output” -- even though this is not specified in the actual Fortran standard. The Fortran standard also does not specify which unit numbers can be used, nor does it specify how many can be open simultaneously.
Since all current compilers have preconnected unit numbers, and these are typically found on units lower than 10, it is recommended that applications use unit numbers 10 and higher.
When ESMF needs to flush a Fortran unit, the ESMF_IOUnitFlush() API is used to centralize the file flushing capability, because Fortran has not historically had a standard mechanism for flushing output buffers. Most compilers run-time libraries support various library extensions to provide this functionality -- though, being non-standard, the spelling and number of arguments vary between implementations. Fortran 2003 also provides for a FLUSH statement which is built into the language. When possible, ESMF_IOUnitFlush() uses the F2003 FLUSH statement. With older compilers, the appropriate library call is made.
The ESMF_UtilSort() algorithms are the same as those in the LAPACK sorting procedures SLASRT() and DLASRT(). Two algorithms are used. For small sorts, arrays with 20 or fewer elements, a simple Insertion sort is used. For larger sorts, a Quicksort algorithm is used.
Compared to the original LAPACK code, a full Fortran 90 style interface is supported for ease of use and enhanced compile time checking. Additional support is also provided for integer and character string data types.
INTERFACE:
subroutine ESMF_UtilGetArg(argindex, argvalue, arglength, rc)ARGUMENTS:
integer, intent(in) :: argindex -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(*), intent(out), optional :: argvalue integer, intent(out), optional :: arglength integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This method returns a copy of a command line argument specified when the process was started. This argument is the same as an equivalent C++ program would find in the argv array.
Some MPI implementations do not consistently provide command line arguments on PETs other than PET 0. It is therefore recommended that PET 0 call this method and broadcast the results to the other PETs by using the ESMF_VMBroadcast() method.
The arguments are:
INTERFACE:
subroutine ESMF_UtilGetArgC(count, rc)ARGUMENTS:
integer, intent(out) :: count -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This method returns the number of command line arguments specified when the process was started.
The number of arguments returned does not include the name of the command itself - which is typically returned as argument zero.
Some MPI implementations do not consistently provide command line arguments on PETs other than PET 0. It is therefore recommended that PET 0 call this method and broadcast the results to the other PETs by using the ESMF_VMBroadcast() method.
The arguments are:
INTERFACE:
subroutine ESMF_UtilGetArgIndex(argvalue, argindex, rc)ARGUMENTS:
character(*), intent(in) :: argvalue -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: argindex integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
This method searches for, and returns the index of a desired command line argument. An example might be to find a specific keyword (e.g., -esmf_path) so that its associated value argument could be obtained by adding 1 to the argindex and calling ESMF_UtilGetArg().
Some MPI implementations do not consistently provide command line arguments on PETs other than PET 0. It is therefore recommended that PET 0 call this method and broadcast the results to the other PETs by using the ESMF_VMBroadcast() method.
The arguments are:
INTERFACE:
subroutine ESMF_UtilIOGetCWD (pathName, rc)PARAMETERS:
character(*), intent(out) :: pathName -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Call the system-dependent routine to get the current directory from the file system.
The arguments are:
INTERFACE:
subroutine ESMF_UtilIOMkDir (pathName, & mode, relaxedFlag, & rc)PARAMETERS:
character(*), intent(in) :: pathName -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(in), optional :: mode logical, intent(in), optional :: relaxedFlag integer, intent(out), optional :: rcDESCRIPTION:
Call the system-dependent routine to create a directory in the file system.
The arguments are:
INTERFACE:
subroutine ESMF_UtilIORmDir (pathName, & relaxedFlag, rc)PARAMETERS:
character(*), intent(in) :: pathName -- The following arguments require argument keyword syntax (e.g. rc=rc). -- logical, intent(in), optional :: relaxedFlag integer, intent(out), optional :: rcDESCRIPTION:
Call the system-dependent routine to remove a directory from the file system. Note that the directory must be empty in order to be successfully removed.
The arguments are:
INTERFACE:
function ESMF_UtilString2Double(string, rc)RETURN VALUE:
real(ESMF_KIND_R8) :: ESMF_UtilString2DoubleARGUMENTS:
character(len=*), intent(in) :: string -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return the numerical real value represented by the string.
Leading and trailing blanks in string are ignored when directly converting into integers.
This procedure may fail when used in an expression in a write statement with some older, pre-Fortran 2003, compiler environments that do not support re-entrant I/O calls.
The arguments are:
INTERFACE:
function ESMF_UtilString2Int(string, & specialStringList, specialValueList, rc)RETURN VALUE:
integer :: ESMF_UtilString2IntARGUMENTS:
character(len=*), intent(in) :: string -- The following arguments require argument keyword syntax (e.g. rc=rc). -- character(len=*), intent(in), optional :: specialStringList(:) integer, intent(in), optional :: specialValueList(:) integer, intent(out), optional :: rcDESCRIPTION:
Return the numerical integer value represented by the string. If string matches a string in the optional specialStringList, the corresponding special value will be returned instead.
If special strings are to be taken into account, both specialStringList and specialValueList arguments must be present and of same size.
An error is returned, and return value set to 0, if string is not found in specialStringList, and does not convert into an integer value.
Leading and trailing blanks in string are ignored when directly converting into integers.
This procedure may fail when used in an expression in a write statement with some older, pre-Fortran 2003, compiler environments that do not support re-entrant I/O calls.
The arguments are:
INTERFACE:
function ESMF_UtilString2Real(string, rc)RETURN VALUE:
real :: ESMF_UtilString2RealARGUMENTS:
character(len=*), intent(in) :: string -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcDESCRIPTION:
Return the numerical real value represented by the string.
Leading and trailing blanks in string are ignored when directly converting into integers.
This procedure may fail when used in an expression in a write statement with some older, pre-Fortran 2003, compiler environments that do not support re-entrant I/O calls.
The arguments are:
INTERFACE:
function ESMF_UtilStringInt2String (i, rc)ARGUMENTS:
integer, intent(in) :: i -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
character(int2str_len (i)) :: ESMF_UtilStringInt2StringDESCRIPTION:
Converts given an integer to string representation. The returned string is sized such that it does not contain leading or trailing blanks.
This procedure may fail when used in an expression in a write statement with some older, pre-Fortran 2003, compiler environments that do not support re-entrant I/O calls.
The arguments are:
INTERFACE:
function ESMF_UtilStringLowerCase(string, rc)ARGUMENTS:
character(len=*), intent(in) :: string -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
character(len (string)) :: ESMF_UtilStringLowerCaseDESCRIPTION:
Converts given string to lowercase.
The arguments are:
INTERFACE:
function ESMF_UtilStringUpperCase(string, rc)ARGUMENTS:
character(len=*), intent(in) :: string -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcRETURN VALUE:
character(len (string)) :: ESMF_UtilStringUpperCaseDESCRIPTION:
Converts given string to uppercase.
The arguments are:
INTERFACE:
subroutine ESMF_UtilIOUnitFlush(unit, rc)PARAMETERS:
integer, intent(in) :: unit -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Call the system-dependent routine to force output on a specific Fortran unit number.
The arguments are:
INTERFACE:
subroutine ESMF_UtilIOUnitGet(unit, rc)ARGUMENTS:
integer, intent(out) :: unit -- The following arguments require argument keyword syntax (e.g. rc=rc). -- integer, intent(out), optional :: rcSTATUS:
DESCRIPTION:
Scan for, and return, a free Fortran I/O unit number. By default, the range of unit numbers returned is between 50 and 99 (parameters ESMF_LOG_FORTRAN_UNIT_NUMBER and ESMF_LOG_UPPER respectively.) When integrating ESMF into an application where these values conflict with other usages, the range of values may be moved by setting the optional IOUnitLower and IOUnitUpper arguments in the initial ESMF_Initialize() call with values in a safe, alternate, range.
The Fortran unit number which is returned is not reserved in any way. Successive calls without intervening OPEN or CLOSE statements (or other means of connecting to units), might not return a unique unit number. It is recommended that an OPEN statement immediately follow the call to ESMF_IOUnitGet() to activate the unit.
The arguments are:
INTERFACE:
subroutine ESMF_UtilSort (list, direction, rc)ARGUMENTS:
<list>, see below for supported values type(ESMF_SortFlag), intent(in) :: direction integer, intent(out), optional :: rcDESCRIPTION:
Supported values for <list> are:
Use Quick Sort, reverting to Insertion sort on lists of size <= 20.
This is an ESMFized version of SLASRT from LAPACK version 3.1. Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd. November 2006
The arguments are:
esmf_support@ucar.edu