ESMX is the Earth System Model eXecutable layer.
The ESMX layer is built on top of the ESMF and NUOPC APIs.
The idea behind ESMX is to make it as simple as possible for a user to build, run, and test NUOPC based systems. The approach implemented is the same whether applied to a single component, or a fully coupled system of NUOPC-compliant components. ESMX user interfaces are implemented through configuration files.
Major objectives of ESMX are:
- Simplification of standing up new NUOPC-based systems.
- Promotion of hierarchical model component testing.
- Reduction of maintenance cost for established NUOPC-based systems.
- Improved alignment and interoperability between different NUOPC-based systems. (Configuration files, build procedures, etc.)
- Faster and more coordinated roll-out and adoption of new NUOPC/ESMF features.
ESMX unifies, provides, and maintains those parts of NUOPC-based modeling systems that are common across most such implementations. This includes the top level application and driver code, parts of the build infrastructure, and tools to manage run configurations.
One of the main pieces provided by ESMX is the unified driver executable. A good starting point to explore this feature is the ESMX_AtmOcnProto example under the NUOPC prototype repository.
The name of the unified driver executable created by ESMX is all lower case esmx
. This name will be used for the remainder of this section to refer to the unfied driver executable.
ESMX is CMake based. The following two commands, executed from anywhere in your terminal, will build the esmx
executable under a local build
sub-drirectory:
cmake -H$ESMF_ESMXDIR -Bbuild
cmake --build ./build
Here shell variable ESMF_ESMXDIR
is assumed to be set according to your ESMF installation. The correct value for ESMF_ESMXDIR
can be looked up in the esmf.mk
file, which should be accessible via shell variable ESMFMKFILE
. (E.g. cat $ESMFMKFILE
.)
For a successful build, the ESMX build system expects to find a configuration file called esmxBuild.yaml
in the directory from which the above commands are executed. Details of this file are discussed next.
The ESMX build system depends on file esmxBuild.yaml
. This is a YAML file with a very simple format. An example is given here:
components:
tawas:
cmake_config: TaWaS/tawas.cmake
fort_module: tawas
lumo:
cmake_config: Lumo/lumo.cmake
In this example two components are built into esmx
explicitly. (Read about dynamic loading of components from shared objects at run-time later.)
Each component is given a name, here tawas
and lumo
, respectively. Components will be referenced by this component-name in the run-time configuration (esmxRun.config) discussed below.
Each component must define the cmake_config
key, specifying a CMake configuration file that can be included by the CMake based ESMX build system to access the respective component.
A component CMake configuration file must provide the following three standard CMake elements:
add_library(component-name ... )
set_target_properties(component-name ... )
target_link_libraries(esmx_driver PUBLIC component-name)
Here component-name must correspond to the name under which the component was defined in the esmxBuild.yaml
file. For the example this would be tawas
or lumo
.
In addition to the required cmake_config
key, a component can optionally provide the fort_module
key in its esmxBuild.yaml
section. This allows explicit specification of the Fortran module name that provides the entry points into the respective NUOPC component. By default the component-name is used as the Fortran module name.
It can be convenient (and in many cases necessary) to integrate the above outlined ESMX CMake procedure into a project's existing build system. This is particularily true when using ESMX in the context of hierarchical testing, where each test might specify a custom esmxBuild.yaml
configuration. In this case each test will need to build a separate esmx
executable when it is triggered.
Integration e.g. into a GNU Makefile is very straight forward:
include $(ESMFMKFILE)
esmx: esmxBuild.yaml
cmake -H$(ESMF_ESMXDIR) -Bbuild
cmake --build ./build
Inluding the esmf.mk
file via the environment variable ESMFMKFILE
automatically sets the ESMF_ESMXDIR
variable needed to find the corresponding ESMX CMake build files.
The esmx
target indicates a dependency on configuration file esmxBuild.yaml
to ensure rebuilding of the esmx
executable each time the build configuration changes. The build rule for esmx
simply executes the two standard CMake commands introduced earlier.
A successful execution of the esmx
target will result in the creation of the unfied driver executable as build/esmx
under the local directory.
The esmx
executable is launched the same way any other ESMF or NUOPC application is launched. Typically this means starting it through the system specific MPI launch facility (mpirun, mpiexec, srun, ...).
At startup, the esmx
executable expects to find a file named esmxRun.config
in the run directory from which it is launched. This run-time configuration file specifies a few global ESMF and ESMX level settings, the list of components accessed during this run, details about the components, and finally the run sequence.
logKindFlag: ESMF_LOGKIND_MULTI
globalResourceControl: .true.
ESMX_log_flush: .true.
ESMX_field_dictionary: ./fd.yaml
ESMX_component_list: ATM OCN
ESMX_attributes::
Verbosity = high
::
ATM_model: tawas
ATM_omp_num_threads: 4
ATM_attributes::
Verbosity = high
::
OCN_model: lumo
OCN_petlist: 1 3
OCN_attributes::
Verbosity = high
::
startTime: 2012-10-24T18:00:00
stopTime: 2012-10-24T19:00:00
runSeq::
@900
ATM -> OCN
OCN -> ATM
ATM
OCN
@
::
The first two fields, logKindFlag
and globalResourceControl
, are examples of ESMF level configuration options. They are ingested by the ESMF_Initialize() method (called by esmx
) as documented in the ESMF Reference Manual.
Fields starting with ESMX_
are defined by the ESMX unified driver executable. Most important on this level is ESMX_component_list
. This field defines the generic components participating in the execution. There is no restriction what labels can be used for the generic components, however, ATM
and OCN
are typical labels for "atmosphere" and "ocean", respectively. Note that the run sequence under runSeq
, toward the end of the file, is defined in terms of the generic component labels introduced by ESMX_component_list
.
Each generic component label must be associated with an actual component model through the XXX_model
field, where XXX
is replaced by the actual generic component label, e.g. ATM
, OCN
, etc. The association is made by specifying the component-name used in the esmxBuild.yaml
file discussed earlier. The options in the example are tawas
and lumo
.
Finally the startTime
and stopTime
fields set the start and stop time of the run, respectively. The runSeq
field defines the run sequence. The default time step of the outer run sequence loop, i.e. if using the @*
syntax, is set to stopTime - startTime
.
There are two options recognized when specifying the value of the XXX_model
field for a component in the esmxRun.config
file:
- First, if the value specified is recognized as a component-name provided by any of the components built into
esmx
during build-time, as specified byesmxBuild.yaml
, the respective component is accessed via its Fortran module. - Second, if the value does not match a build-time dependency, it is assumed to correspond to a shared object. In that case the attempt is made to load the specified shared object at run-time, and to associate with the generic component label.
The ESMX layer provides access to the ESMX_Driver
via the public NUOPC Driver API. This means that ESMX_Driver
can be plugged into a larger NUOPC application as a standard NUOPC component, or alternatively be accessed through the External NUOPC Interface.
A good starting point to explore this feature is the ESMX_ExternalDriverAPIProto under the NUOPC prototype repository.
The typical situation where ESMX_Driver
comes into play is where a user application needs to access a NUOPC based system that uses the unified ESMX driver. Assuming the user application uses CMake, integration of ESMX is straight forward. All that is required is add_subdirectory()
in the application's CMakeLists.txt
file to add the ${ESMF_ESMXDIR}/Driver
directory, and make the application dependent on target esmx_driver
. An example for a very simple application is shown:
cmake_minimum_required(VERSION 3.5.2)
enable_language(Fortran)
add_subdirectory(${ESMF_ESMXDIR}/Driver ./ESMX_Driver)
# Specific project settings
project(ExternalDriverAPIProto VERSION 0.1.0)
add_executable(externalApp externalApp.F90)
target_include_directories(externalApp PUBLIC ${PROJECT_BINARY_DIR})
target_link_libraries(externalApp PUBLIC esmx_driver)
The applcation can then be built as typically via cmake commands, only requiring that the ESMF_ESMXDIR
variable is passed in. It can be convenient to wrap the cmake commands into a GNU Makefile, accessing the ESMF_ESMXDIR
variable through the ESMFMKFILE
mechanism.
include $(ESMFMKFILE)
build/externalApp: externalApp.F90 esmxBuild.yaml
cmake -H. -Bbuild -DESMF_ESMXDIR=$(ESMF_ESMXDIR)
cmake --build ./build
The esmx_driver
target defined by the add_subdirectory(${ESMF_ESMXDIR}/Driver ./ESMX_Driver)
has a build-time dependency on the esmxBuild.yaml
file already discussed under the unfied driver executable section. The identical file can be used when working on the ESMX_Driver
level.
The run-time configuration needed by ESMX_Driver
can either be supplied by the user application, or alternatively default to esmxRun.config
. The following rules apply:
ESMX_Driver
, at the beginning of itsSetModelServices()
method checks whether the parent level has provided anESMF_Config
object by setting theconfig
member on theESMX_Driver
component. If so, the providedconfig
object is used. OtherwiseESMX_Driver
itself createsconfig
from fileesmxRun.config
.- For the case where the
config
object was provided by the parent layer,ESMX_Driver
does not ingest attributes fromconfig
. Instead the assumption is made that the parent layer sets the desired attributes onESMX_Driver
. - For the case where the
config
object was loaded fromesmxRun.config
byESMX_Driver
, the driver ingests attributes fromconfig
, potentially overriding parent level settings. - The
ESMX_component_list
, child component, and run sequence information is ingested fromconfig
as described under the unfied driver executable section. - If the parent level passes an
ESMF_Clock
object toESMX_Driver
during initialize, the driver uses it instead of looking forstartTime
andstopTime
inconfig
. - For the case where a clock is provided by the parent layer, its
timeStep
is used as the default time step of the outer run sequence loop when using the@*
syntax. If a specific time step is set in the run sequence with@DT
, thenDT
must be a divisor of thetimeStep
provided by the parent clock.
The ESMX layer has the following dependencies:
- ESMF Library: The ESMX layer is part of the ESMF repository. In order to use ESMX as described above, the ESMF library first needs to be built following the instructions for Building ESMF.
- CMake: v3.5.2 or greater.
- Python: v3.5 or greater.
python3
must be in$PATH
.PyYaml
must be installed in the Python environment.
There are many ways to provide a suitable Python environment. One portable way based on venv is shown below.
python3 -m venv ESMXenv
source ESMXenv/bin/activate (for Bash) or source ESMXenv/bin/activate.csh (for Csh)
pip install pyyaml
... Environment ready for ESMX ...
deactivate