FieldDictionary.F90 Source File


This file depends on

sourcefile~~fielddictionary.f90~~EfferentGraph sourcefile~fielddictionary.f90 FieldDictionary.F90 sourcefile~errorhandling.f90 ErrorHandling.F90 sourcefile~fielddictionary.f90->sourcefile~errorhandling.f90 sourcefile~fielddictionaryitem.f90 FieldDictionaryItem.F90 sourcefile~fielddictionary.f90->sourcefile~fielddictionaryitem.f90 sourcefile~fielddictionaryitemmap.f90 FieldDictionaryItemMap.F90 sourcefile~fielddictionary.f90->sourcefile~fielddictionaryitemmap.f90 sourcefile~mapl_throw.f90 MAPL_Throw.F90 sourcefile~errorhandling.f90->sourcefile~mapl_throw.f90 sourcefile~fielddictionaryitemmap.f90->sourcefile~fielddictionaryitem.f90

Files dependent on this one

sourcefile~~fielddictionary.f90~~AfferentGraph sourcefile~fielddictionary.f90 FieldDictionary.F90 sourcefile~fieldspec.f90~2 FieldSpec.F90 sourcefile~fieldspec.f90~2->sourcefile~fielddictionary.f90 sourcefile~variablespec.f90 VariableSpec.F90 sourcefile~fieldspec.f90~2->sourcefile~variablespec.f90 sourcefile~test_fielddictionary.pf Test_FieldDictionary.pf sourcefile~test_fielddictionary.pf->sourcefile~fielddictionary.f90 sourcefile~variablespec.f90->sourcefile~fielddictionary.f90 sourcefile~bracketspec.f90 BracketSpec.F90 sourcefile~bracketspec.f90->sourcefile~fieldspec.f90~2 sourcefile~componentspec.f90 ComponentSpec.F90 sourcefile~componentspec.f90->sourcefile~variablespec.f90 sourcefile~componentspecparser.f90 ComponentSpecParser.F90 sourcefile~componentspecparser.f90->sourcefile~variablespec.f90 sourcefile~historycollectiongridcomp_private.f90 HistoryCollectionGridComp_private.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~variablespec.f90 sourcefile~make_itemspec.f90 make_itemSpec.F90 sourcefile~make_itemspec.f90->sourcefile~fieldspec.f90~2 sourcefile~make_itemspec.f90->sourcefile~variablespec.f90 sourcefile~mapl_generic.f90~2 MAPL_Generic.F90 sourcefile~mapl_generic.f90~2->sourcefile~variablespec.f90 sourcefile~mockitemspec.f90 MockItemSpec.F90 sourcefile~mockitemspec.f90->sourcefile~variablespec.f90 sourcefile~modelverticalgrid.f90 ModelVerticalGrid.F90 sourcefile~modelverticalgrid.f90->sourcefile~fieldspec.f90~2 sourcefile~outermetacomponent.f90 OuterMetaComponent.F90 sourcefile~outermetacomponent.f90->sourcefile~variablespec.f90 sourcefile~servicespec.f90 ServiceSpec.F90 sourcefile~servicespec.f90->sourcefile~variablespec.f90 sourcefile~statespec.f90 StateSpec.F90 sourcefile~statespec.f90->sourcefile~variablespec.f90 sourcefile~test_addfieldspec.pf Test_AddFieldSpec.pf sourcefile~test_addfieldspec.pf->sourcefile~fieldspec.f90~2 sourcefile~test_bracketspec.pf Test_BracketSpec.pf sourcefile~test_bracketspec.pf->sourcefile~fieldspec.f90~2 sourcefile~test_fieldinfo.pf Test_FieldInfo.pf sourcefile~test_fieldinfo.pf->sourcefile~fieldspec.f90~2 sourcefile~test_fieldspec.pf Test_FieldSpec.pf sourcefile~test_fieldspec.pf->sourcefile~fieldspec.f90~2 sourcefile~test_modelverticalgrid.pf Test_ModelVerticalGrid.pf sourcefile~test_modelverticalgrid.pf->sourcefile~variablespec.f90 sourcefile~variablespecvector.f90 VariableSpecVector.F90 sourcefile~variablespecvector.f90->sourcefile~variablespec.f90

Source Code

#include "MAPL_ErrLog.h"

! The FieldDictionary serves as a central structure for both ensuring
! consistent standard names and units across GEOS as well as a convenient
! mechanism to avoid duplicating such information in the FieldSpec's in
! various components.

! The dictionary keys are CF standard names, and each entry must include a
! long name and units.   It may optionally include additional short names that
! are convenient as alternative keys into the dictionary.

! Note that each short name must be unique such that it is unambiguous
! as to which entry a short name is referring.

module mapl3g_FieldDictionary

   use esmf
   use mapl_ErrorHandling
   use gftl2_StringVector
   use gftl2_StringStringMap
   use mapl3g_FieldDictionaryItem
   use mapl3g_FieldDictionaryItemMap

   implicit none
   private

   public :: FieldDictionary

   type :: FieldDictionary
      private
      type(FieldDictionaryItemMap) :: entries
      type(StringStringMap) :: alias_map  ! For efficiency
   contains
      procedure :: add_item
      procedure :: add_aliases
      ! accessors
      procedure :: get_item   ! returns a pointer
      procedure :: get_units
      procedure :: get_long_name
      procedure :: get_standard_name
      procedure :: get_regrid_method
      procedure :: size
   end type FieldDictionary

   interface FieldDictionary
      module procedure new_from_yaml
   end interface FieldDictionary

contains

   function new_from_yaml(filename, stream, rc) result(fd)
      type(FieldDictionary) :: fd
      character(len=*), optional, intent(in) :: filename
      character(len=*), optional, intent(in) :: stream
      integer, optional, intent(out) :: rc

      type(ESMF_HConfig), target :: node
      type(ESMF_HConfigIter) :: hconfigIter, hconfigIterBegin, hconfigIterEnd
      integer :: status
      character(:), allocatable :: standard_name
      type(FieldDictionaryItem) :: item
      type(ESMF_HConfig) :: val

      _ASSERT( .not.(present(filename) .and. present(stream)), "cannot specify both")
      if (present(filename)) then
         node = ESMF_HConfigCreate(filename=filename,_RC)
      else if (present(stream)) then
         node = ESMF_HConfigCreate(content=stream,_RC)
      else
         node = ESMF_HConfigCreate(content='{}',_RC)
         _RETURN(_SUCCESS)
      end if

      _ASSERT(ESMF_HConfigIsMap(node), 'FieldDictionary requires a YAML mapping node')

      hconfigIter = ESMF_HConfigIterBegin(node)
      hconfigIterBegin = ESMF_HConfigIterBegin(node)
      hconfigIterEnd = ESMF_HConfigIterEnd(node)
      do while (ESMF_HConfigIterLoop(hconfigIter,hconfigIterBegin,hconfigIterEnd))
         standard_name = ESMF_HConfigAsStringMapKey(hconfigIter,_RC)
         _ASSERT(len_trim(standard_name) /= 0, 'Standard name is all blanks.')
         _ASSERT(fd%entries%count(standard_name) == 0, 'Duplicate standard name: <'//trim(standard_name)//'>')
         val = ESMF_HConfigCreateAtMapVal(hconfigIter,_RC)
         item = to_item(val,_RC)
         call fd%add_item(standard_name, item)
      enddo

      _RETURN(_SUCCESS)

   contains

      function to_item(item_node, rc) result(item)
         type(FieldDictionaryItem) :: item
         type(ESMF_HConfig), intent(in) :: item_node
         integer, optional, intent(out) :: rc

         integer :: status
         type(ESMF_HConfig) :: aliases_node
         character(:), allocatable :: long_name, units, temp_string
         type(StringVector) :: aliases
         type(ESMF_HConfigIter) :: hconfigIter,hconfigIterBegin,hconfigIterEnd

         _ASSERT(ESMF_HConfigIsMap(item_node), 'Each node in FieldDictionary yaml must be a mapping node')

         long_name = ESMF_HconfigAsString(item_node,keyString='long_name',_RC)
         units = ESMF_HConfigAsString(item_node,keyString='canonical_units',_RC)

         if (ESMF_HConfigIsDefined(item_node,keyString='aliases')) then
          
            aliases_node = ESMF_HConfigCreateAt(item_node,keyString='aliases',_RC) 
            _ASSERT(ESMF_HConfigIsSequence(aliases_node), "'aliases' must be a sequence")

            hconfigIter = ESMF_HConfigIterBegin(aliases_node)
            hconfigIterBegin = ESMF_HConfigIterBegin(aliases_node)
            hconfigIterEnd = ESMF_HConfigIterEnd(aliases_node)

            do while (ESMF_HConfigIterLoop(hconfigIter,hconfigIterBegin,hconfigIterEnd))
               temp_string = ESMF_HConfigAsString(hconfigIter,_RC)
               call aliases%push_back(temp_string)
            enddo

         end if

         item = FieldDictionaryItem(long_name, units, aliases)
         
         _RETURN(_SUCCESS)
      end function to_item

   end function new_from_yaml

   subroutine add_item(this, standard_name, field_item, rc)
      class(FieldDictionary), intent(inout) :: this
      character(*), intent(in) :: standard_name
      type(FieldDictionaryItem), intent(in) :: field_item
      integer, intent(out), optional :: rc

      integer :: status

      call this%entries%insert(standard_name, field_item)
      call this%add_aliases(standard_name, field_item%get_aliases(), _RC)

      _RETURN(_SUCCESS)
   end subroutine add_item

   subroutine add_aliases(this, standard_name, aliases, rc)
      class(FieldDictionary), intent(inout) :: this
      character(*), intent(in) :: standard_name
      type(StringVector), intent(in) :: aliases
      integer, optional, intent(out) :: rc

      type(StringVectorIterator) :: iter
      character(:), pointer :: alias

      associate (b => aliases%begin(), e => aliases%end())
        iter = b
        do while (iter /= e)
           alias => iter%of()
           _ASSERT(this%alias_map%count(alias) == 0, 'ambiguous short name references more than one item in dictionary')
           call this%alias_map%insert(alias, standard_name)
           call iter%next()
        end do
      end associate

      _RETURN(_SUCCESS)
   end subroutine add_aliases
      
   ! This accessor returns a copy for safety reasons.  Returning a
   ! pointer would be more efficient, but it would allow client code
   ! to modify the dictionary.
   function get_item(this, standard_name, rc) result(item)
      type(FieldDictionaryItem) :: item
      class(FieldDictionary), intent(in) :: this
      character(*), intent(in) :: standard_name
      integer, optional, intent(out) :: rc

      integer :: status

      item = this%entries%at(standard_name, _RC)

      _RETURN(_SUCCESS)
   end function get_item

   function get_units(this, standard_name, rc) result(canonical_units)
      character(:), allocatable :: canonical_units
      class(FieldDictionary), target, intent(in) :: this
      character(*), intent(in) :: standard_name
      integer, optional, intent(out) :: rc

      type(FieldDictionaryItem), pointer :: item
      integer :: status

      item => this%entries%at(standard_name, _RC)
      canonical_units = item%get_units()

      _RETURN(_SUCCESS)
   end function get_units

   function get_long_name(this, standard_name, rc) result(long_name)
      character(:), allocatable :: long_name
      class(FieldDictionary), target, intent(in) :: this
      character(*), intent(in) :: standard_name
      integer, optional, intent(out) :: rc

      type(FieldDictionaryItem), pointer :: item
      integer :: status

      item => this%entries%at(standard_name, _RC)
      long_name = item%get_long_name()

      _RETURN(_SUCCESS)
   end function get_long_name

   function get_standard_name(this, alias, rc) result(standard_name)
      character(:), allocatable :: standard_name
      class(FieldDictionary), target, intent(in) :: this
      character(*), intent(in) :: alias
      integer, optional, intent(out) :: rc

      integer :: status

      standard_name = this%alias_map%at(alias, _RC)
      
      _RETURN(_SUCCESS)
   end function get_standard_name

   function get_regrid_method(this, standard_name, rc) result(regrid_method)
      type(ESMF_RegridMethod_Flag) :: regrid_method
      class(FieldDictionary), target, intent(in) :: this
      character(*), intent(in) :: standard_name
      integer, optional, intent(out) :: rc

      type(FieldDictionaryItem), pointer :: item
      integer :: status

      item => this%entries%at(standard_name, _RC)
      regrid_method = item%get_regrid_method()

      _RETURN(_SUCCESS)
   end function get_regrid_method

   integer function size(this)
      class(FieldDictionary), intent(in) :: this
      size = this%entries%size()
   end function size
   
end module mapl3g_FieldDictionary