ESMF_ConfigOverviewEx.F90 Source File


Source Code

!
! Earth System Modeling Framework
! Copyright (c) 2002-2023, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the University of Illinois-NCSA License.
!
!==============================================================================
!
      program ESMF_ConfigOverviewEx

!-------------------------------------------------------------------------
!ESMF_EXAMPLE        String used by test script to count examples.
!==============================================================================
!
! !DESCRIPTION:
!BOE
! 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.
!EOE 
#include "ESMF.h"

      ! ESMF Framework module
      use ESMF
      use ESMF_TestMod
      implicit none

      ! Local variables
      integer             :: i, j, result
      type(ESMF_VM)       :: vm

      character(ESMF_MAXSTR) :: testname
      character(ESMF_MAXSTR) :: failMsg

!BOE
!\subsubsection{Variable declarations}

! 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.
!EOE

!BOC
      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
!EOC

!--------------------------------------------------------
! Set up the status messages and initialize the program
!--------------------------------------------------------
      integer :: finalrc
      finalrc = ESMF_SUCCESS                      ! Establish initial success

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

      write(failMsg, *) "Example failure"
      write(testname, *) "Example ESMF_ConfigOverviewEx"

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


  
      call ESMF_Initialize(defaultlogfilename="ConfigOverviewEx.Log", &
                    logkindflag=ESMF_LOGKIND_MULTI, rc=rc)                 ! Initialize

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_Initialize' failed"
      endif
  
      call ESMF_VMGetGlobal(vm, rc=rc)               ! Establish the VM

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call to ESMF_VMGetGlobal' failed"
      endif

!-------------------------------------------------------------------------
!  Begin the Example
!------------------------------------------------------------------------

!BOE
!\subsubsection{Creation of a Config}

! 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 {\tt ESMF\_ConfigLoadFile} will OVERWRITE the current
! Config NOT append to it. There is no means of appending to a Config. 
!
!EOE

!BOC
      cf = ESMF_ConfigCreate(rc=rc)             ! Create the empty Config
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigCreate' failed"
      endif

!BOC
      fname = "myResourceFile.rc"                ! Name the Resource File
      call ESMF_ConfigLoadFile(cf, fname, rc=rc) ! Load the Resource File 
                                                 ! into the empty Config
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigLoadFile' failed"
      endif

!----------------------------------------------------------------
! First Method of Retrieval
!----------------------------------------------------------------
!BOE
!\subsubsection{How to retrieve a label with a single value}
! The first method for retrieving information from the 
! Resource File takes advantage of the <label,value> relationship
! within the file and access the data in a dictionary-like manner. This is the
! simplest methodology, but it does imply the use of only one value per label
! in the Resource File.  
! 
! 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. 
!EOE

!BOC 
    call ESMF_ConfigGetAttribute(cf, radius, label='radius_of_the_earth:', &
                                 default=1.0, rc=rc)
!EOC


    if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute' for radius failed"
    else
        print*, "---------------------------------------------------------------"
        print*, "Results from using the dictionary-like method of data retrieval"
        print*, "The radius of the earth was retrieved from the Resource File"
        print*, "Its value is: ", radius
        print*, "---------------------------------------------------------------"
    endif

    if(radius .ne. 6.37E6)then
      finalrc = ESMF_FAILURE
      print*, "******** Radius not retrieved correctly"
      print*, trim (input_file)
    endif


!BOE
! 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
!EOE


!BOE
! This methodology works for all types. The following is an example of retrieving a 
! string:
!EOE

!BOC 
    call ESMF_ConfigGetAttribute(cf, input_file, label='input_file_name:', &
                                 default="./default.nc", rc=rc)
!EOC


    if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute'  for input_file failed"
    else
        print*, "Results from using the dictionary-like method of data retrieval of a string"
        print*, "The input file name (a string) was retrieved from the Resource File"
        print*, "Its value is: ", trim (input_file)
        print*, "---------------------------------------------------------------"
    endif

    if(input_file .ne. "dummy_input.nc")then
       finalrc = ESMF_FAILURE
       print*, "******* input_file not retrieved correctly"
       print*, trim (input_file)
    endif

!BOE
! 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.
!EOE

!BOC 
    call ESMF_ConfigGetAttribute(cf, input_file, label='file_name:', &
                                 default="./default.nc", rc=rc)
!EOC

    if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute'  for input_file failed"
    else
        print*, "Results when the label in the call does not exist in the Resource File"
        print*, "The default value is returned."
        print*, "Its value is: ", trim (input_file)
        print*, "---------------------------------------------------------------"
    endif

    if (input_file .ne. "./default.nc") then
      finalrc = ESMF_FAILURE
      print*, "****** Demonstration of default value (input_file) not working correctly"
      print*, trim (input_file)
    endif
!----------------------------------------------------------------
! Second Method of Retrieval
!----------------------------------------------------------------
!BOE
!\subsubsection{How to retrieve a label with multiple values}
! When there are multiple, mixed-typed values associated with a label, the 
! values can be retrieved in two steps:  1) Use ESMF\_ConfigFindLabel() 
! to find the label in the Config class; 2) use
! ESMF\_ConfigGetAttribute() without the optional 'label' argument to 
! retrieve the values one at a time, reading from left to right in
! the record. 
!
! 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. 
!EOE

!BOC
      call ESMF_ConfigFindLabel(cf, 'constants:', rc=rc) ! Step a) Find the 
                                                         ! label 
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigFindLabel' failed"
      endif 

!BOE
! 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.
!EOE

!BOC
      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
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute' failed"
      else
        print*, "Results from retrieving multiple values:"
        print*, "The first constant was was retrieved from the Resource File"
        print*, "Its value is: ", param_1
        print*, "The second constant was was retrieved from the Resource File"
        print*, "Its value is: ", i_n
        print*, "---------------------------------------------------------------"
      endif

      if (param_1 .ne. 3.1415 .or. i_n .ne. 25) then
        finalrc = ESMF_FAILURE
        print*, "*****The constants param_1 and i_n did not retrieve correctly from the file"
      endif

!BOE
! This methodology also works with strings.
!EOE

!BOC
       call ESMF_ConfigFindLabel(cf, 'my_file_names:', &
               rc=rc)                       ! Step a) find the label
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigFindLabel' failed"
      endif

!BOC
       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
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute' for multiple file name retrieval failed"
      else
        print*, "Results from retrieving multi-value strings:"
        print*, "The first file name was was retrieved from the Resource File"
        print*, "Its value is: ", trim (fn1)
        print*, "The second file name was was retrieved from the Resource File"
        print*, "Its value is: ", trim (fn2)
        print*, "The third file name was was retrieved from the Resource File"
        print*, "Its value is: ", trim (fn3)
        print*, "---------------------------------------------------------------"
      endif

      if (fn1.ne.'jan87.dat' .or. fn2.ne.'jan88.dat' .or. fn3.ne.'jan89.dat') then
        finalrc = ESMF_FAILURE
        print*, "*****The file names not retrieved correctly using the multi-value method"
      endif

!----------------------------------------------------------------
! Retrieval of a Table
!----------------------------------------------------------------
!BOE
!\subsubsection{How to retrieve a table}

! To access tabular data, the user must use the multi-value method. 
!EOE

!BOC
      call ESMF_ConfigFindLabel(cf, 'my_table_name::', &
               rc=rc)        ! Step a) Set the label location to the 
                             ! beginning of the table
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigFindLabel' failed"
      endif

!BOE
! Subsequently, {\tt 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).
!EOE

!BOC
      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
!EOC


      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigGetAttribute' for table retrieval failed"
      else
        print*, "Results from retrieving a table"
        print*, "The (1,3) table value should be 263.0"
        print*, "Its retrieved value is: ", table(1,3)
        print*, "The (6,1) table value should be 400"
        print*, "Its retrieved value is: ", table(6,1)
        print*, "---------------------------------------------------------------"
      endif

      if(table(1,3) .ne. 263.0 .or. table(6,1) .ne. 400)then
        finalrc = ESMF_FAILURE
        print*, "***** Tables values are incorrect"
      endif

!----------------------------------------------------------------
! Destruction of a Config
!----------------------------------------------------------------
!BOE
!\subsubsection{Destruction of a Config}

! The work with the Config object {\tt cf} is finalized by callling
! {\tt ESMF\_ConfigDestroy()}.
!EOE

!BOC
      call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_ConfigDestroy' failed"
      end if

!----------------------------------------------------------------
! YAML File
!----------------------------------------------------------------
!BOE
!\subsubsection{Loading a YAML file}

! The Config class supports loading of YAML files. As before, an empty Config
! object is created with {\tt ESMF\_ConfigCreate()} and then populated via the
! {\tt ESMF\_ConfigLoadFile()} method.
!EOE

!BOC
      cf = ESMF_ConfigCreate(rc=rc)          ! Create the empty Config object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigCreate' failed"
      endif
!BOE
! Files ending in {\tt .yaml}, {\tt .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 {\em RFs} as
! documented earlier.
!EOE

!BOC
      call ESMF_ConfigLoadFile(cf, "myResourceFile.yaml", & ! Load the YAML File
        rc=rc)                                    ! into the empty Config object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigLoadFile' failed"
      endif
!BOE
! Here the {\tt myResourceFile.yaml} contains a YAML version of the previously
! used {\tt myResourceFile.rc} file contents:
!
! \begin{verbatim}
!# 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]
! \end{verbatim}
!
! 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:
!  \begin{itemize}
!  \item Scalars
!  \item List of scalars
!  \item List of lists of scalars
!  \end{itemize}
! All other YAML constructs are silently ignored when loaded through this
! interface. Constructs successfully ingested become available in the
! {\tt cf} object, and can be accessed via the regular {\tt ESMF\_Config}
! methods as outlined in the previous sections.
!
! As an example, access the {\tt my\_table\_name} element:
!EOE
!BOC
      call ESMF_ConfigFindLabel(cf, 'my_table_name::', &
               rc=rc)        ! Step a) Set the label location to the 
                             ! beginning of the table
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigFindLabel' failed"
      endif

!BOE
! When done, the resources held by the Config object are released by calling
! the {\tt ESMF\_ConfigDestroy()} method.
!EOE

!BOC
      call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_ConfigDestroy' failed"
      end if

!----------------------------------------------------------------
! YAML HConfig
!----------------------------------------------------------------
!BOE
!\subsubsection{Creating from HConfig 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.
!EOE

!BOC
      ! Create HConfig object
      hconfig = ESMF_HConfigCreate(filename="myResourceFile.yaml", rc=rc)
!EOC
      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_HConfigCreate' failed"
      endif
!BOE
! The {\tt myResourceFile.yaml} contains the following YAML contents:
!
! \begin{verbatim}
!# 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]
! \end{verbatim}
!
! A Config object can be created from the HConfig object simply by passing
! {\tt hconfig} into {\tt ESMF\_CreateConfig()} as argument.
!EOE

!BOC
      ! Create Config object from HConfig
      cf = ESMF_ConfigCreate(hconfig=hconfig, rc=rc)
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_HConfigCreate' failed"
      end if

!BOE
! Notice that {\tt cf} uses the specified {\tt hconfig} object via reference.
! It remains the callers responsibility to destroy the {\tt hconfig} object
! when finished. Care must be taken to {\em not} destroy until access via
! {\tt cf} is complete.
!
! Here, as an example, access the {\tt my\_table\_name} element:
!EOE
!BOC
      call ESMF_ConfigFindLabel(cf, 'my_table_name::', &
               rc=rc)        ! Step a) Set the label location to the 
                             ! beginning of the table
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****' call ESMF_ConfigFindLabel' failed"
      endif
!EOE

! When done, the resources held by the Config object are released by calling
! the {\tt ESMF\_ConfigDestroy()} method.
!EOE

!BOC
      call ESMF_ConfigDestroy(cf, rc=rc) ! Destroy the Config object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_ConfigDestroy' failed"
      end if

!BOE
! As discussed above, the {\tt hconfig} object requires its own destroy call
! for a complete release.
!EOE

!BOC
      call ESMF_HConfigDestroy(hconfig, rc=rc) ! Destroy the HConfig object
!EOC

      if (rc .ne. ESMF_SUCCESS) then
        finalrc = ESMF_FAILURE
        print*, "*****'call ESMF_HConfigDestroy' failed"
      end if


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

      print*, "Final Word"
      print*,"---------------------------------------------------"
      if (finalrc.eq.ESMF_SUCCESS) then
        print *, "PASS: ESMF_ConfigOverviewEx.F90"
      else
        print *, "FAIL: ESMF_ConfigOverviewEx.F90"
      end if
 
      ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log
      ! file that the scripts grep for.
      call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE)


      call ESMF_Finalize(rc=rc)

      end program ESMF_ConfigOverviewEx