HistoryCollectionGridComp_private.F90 Source File


This file depends on

sourcefile~~historycollectiongridcomp_private.f90~~EfferentGraph sourcefile~historycollectiongridcomp_private.f90 HistoryCollectionGridComp_private.F90 sourcefile~base_base.f90 Base_Base.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~base_base.f90 sourcefile~errorhandling.f90 ErrorHandling.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~errorhandling.f90 sourcefile~generic3g.f90 Generic3g.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~generic3g.f90 sourcefile~geom_mgr.f90 geom_mgr.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~geom_mgr.f90 sourcefile~mapl_newarthparser.f90 MAPL_NewArthParser.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~mapl_newarthparser.f90 sourcefile~outputinfo.f90 OutputInfo.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~outputinfo.f90 sourcefile~timestringconversion.f90 TimeStringConversion.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~timestringconversion.f90 sourcefile~ungriddeddims.f90 UngriddedDims.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~ungriddeddims.f90 sourcefile~variablespec.f90 VariableSpec.F90 sourcefile~historycollectiongridcomp_private.f90->sourcefile~variablespec.f90

Files dependent on this one

sourcefile~~historycollectiongridcomp_private.f90~~AfferentGraph sourcefile~historycollectiongridcomp_private.f90 HistoryCollectionGridComp_private.F90 sourcefile~historycollectiongridcomp.f90 HistoryCollectionGridComp.F90 sourcefile~historycollectiongridcomp.f90->sourcefile~historycollectiongridcomp_private.f90 sourcefile~test_historycollectiongridcomp.pf Test_HistoryCollectionGridComp.pf sourcefile~test_historycollectiongridcomp.pf->sourcefile~historycollectiongridcomp_private.f90 sourcefile~historygridcomp.f90 HistoryGridComp.F90 sourcefile~historygridcomp.f90->sourcefile~historycollectiongridcomp.f90

Source Code

#include "MAPL_Generic.h"
module mapl3g_HistoryCollectionGridComp_private

   use generic3g
   use mapl3g_VariableSpec
   use esmf
   use Mapl_ErrorHandling
   use gFTL2_StringVector
   use mapl3g_geom_mgr
   use MAPL_NewArthParserMod, only: parser_variables_in_expression
   use MAPL_TimeStringConversion
   use MAPL_BaseMod, only: MAPL_UnpackTime
   use mapl3g_output_info, only: get_num_levels, get_vertical_dim_spec_names
   use mapl3g_output_info, only: get_vertical_dim_spec_name, get_ungridded_dims
   use mapl3g_UngriddedDims
   use gFTL2_StringSet

   implicit none
   private

   public :: make_geom
   public :: register_imports
   public :: create_output_bundle
   public :: create_output_alarm
   public :: set_start_stop_time
   public :: get_current_time_index
   ! These are public for testing.
   public :: parse_item_common
   public :: replace_delimiter
   public :: get_expression_variables

   interface parse_item
      module procedure :: parse_item_expression
      module procedure :: parse_item_simple
   end interface parse_item

   character(len=*), parameter :: VAR_LIST_KEY = 'var_list'

contains

   function make_geom(hconfig, rc) result(geom)
      type(ESMF_Geom) :: geom
      type(ESMF_HConfig), intent(inout) :: hconfig
      integer, optional, intent(out) :: rc
      integer :: status
      type(GeomManager), pointer :: geom_mgr
      type(ESMF_HConfig) :: geom_hconfig
      type(MaplGeom) :: mapl_geom

      geom_mgr => get_geom_manager()
      geom_hconfig = ESMF_HConfigCreateAt(hconfig, keystring='geom', _RC)
      mapl_geom = geom_mgr%get_mapl_geom(geom_hconfig, _RC)
      geom = mapl_geom%get_geom()
      call ESMF_HConfigDestroy(geom_hconfig, _RC)

      _RETURN(_SUCCESS)
   end function make_geom

   subroutine register_imports(gridcomp, hconfig, rc)
      type(ESMF_GridComp), intent(inout) :: gridcomp
      type(ESMF_HConfig), intent(in) :: hconfig
      integer, optional, intent(out) :: rc
      type(ESMF_HConfigIter) :: iter, iter_begin, iter_end
      type(ESMF_HConfig) :: var_list
      character(len=:), allocatable :: item_name
      type(StringVector) :: variable_names
      integer :: status

      var_list = ESMF_HConfigCreateAt(hconfig, keystring=VAR_LIST_KEY, rc=status)
      if(status==ESMF_RC_NOT_FOUND) then
         _FAIL(VAR_LIST_KEY // ' was not found.')
      end if
      _VERIFY(status)

      iter_begin = ESMF_HConfigIterBegin(var_list,_RC)
      iter_end = ESMF_HConfigIterEnd(var_list,_RC)
      iter = iter_begin
      do while (ESMF_HConfigIterLoop(iter,iter_begin,iter_end,rc=status))
         _VERIFY(status)
         call parse_item(iter, item_name, variable_names, _RC)
         call add_specs(gridcomp, variable_names, _RC)
      end do

      _RETURN(_SUCCESS)
   end subroutine register_imports

   function create_output_bundle(hconfig, import_state, rc) result(bundle)
      type(ESMF_FieldBundle) :: bundle
      type(ESMF_HConfig), intent(in) :: hconfig
      type(ESMF_State), intent(in) :: import_state
      integer, optional, intent(out) :: rc

      integer :: status
      type(ESMF_HConfigIter) :: iter, iter_begin, iter_end
      type(ESMF_HConfig) :: var_list
      character(len=:), allocatable :: alias, short_name
      type(ESMF_Field) :: field, new_field
      type(ESMF_Info) :: info, new_info
      type(ESMF_StateItem_Flag) :: itemType

      var_list = ESMF_HConfigCreateAt(hconfig, keystring=VAR_LIST_KEY, _RC)
      iter_begin = ESMF_HConfigIterBegin(var_list,_RC)
      iter_end = ESMF_HConfigIterEnd(var_list,_RC)
      iter = iter_begin

      bundle = ESMF_FieldBundleCreate(_RC)
      do while (ESMF_HConfigIterLoop(iter,iter_begin,iter_end,rc=status))
         call parse_item(iter, alias, short_name, _RC)
         call ESMF_StateGet(import_state, short_name, field, _RC)
         new_field = ESMF_FieldCreate(field, dataCopyFlag=ESMF_DATACOPY_REFERENCE, name=alias,  _RC)
         call ESMF_InfoGetFromHost(field, info, _RC)
         call ESMF_InfoGetFromHost(new_field, new_info, _RC)
         call ESMF_InfoSet(new_info, key="", value=info, _RC)
         call ESMF_FieldBundleAdd(bundle, [new_field], _RC)
      end do

      _RETURN(_SUCCESS)
   end function create_output_bundle

   subroutine create_output_alarm(clock, hconfig, comp_name, rc)
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_HConfig), intent(in) :: hconfig
      character(len=*), intent(in) :: comp_name
      integer, intent(out), optional :: rc

      type(ESMF_Alarm) :: alarm
      integer :: status
      type(ESMF_HConfig) :: time_hconfig
      type(ESMF_TimeInterval) :: time_interval
      character(len=:), allocatable :: iso_time
      type(ESMF_Time) :: first_ring_time, currTime, startTime
      integer :: int_time, yy, mm, dd, m, h, s
      logical :: has_ref_time, has_frequency

      call ESMF_ClockGet(clock, currTime=currTime, timeStep=time_interval, startTime = startTime, _RC)

      time_hconfig = ESMF_HConfigCreateAt(hconfig, keyString='time_spec', _RC)

      has_frequency = ESMF_HConfigIsDefined(time_hconfig, keyString='frequency', _RC)
      if (has_frequency) then
         time_interval = hconfig_to_esmf_timeinterval(time_hconfig, 'frequency', _RC)
      end if

      int_time = 0
      has_ref_time = ESMF_HConfigIsDefined(time_hconfig, keyString='ref_time', _RC)
      if (has_ref_time) then
         iso_time = ESMF_HConfigAsString(time_hconfig, keyString='ref_time', _RC)
         int_time = string_to_integer_time(iso_time, _RC)
      end if

      call MAPL_UnpackTime(int_time, h, m, s)
      call ESMF_TimeGet(currTime, yy=yy, mm=mm, dd=dd, _RC)
      call ESMF_TimeSet(first_ring_time, yy=yy, mm=mm, dd=dd, h=h, m=m, s=s, _RC)

      ! These 2 lines are borrowed from old History. Unforunately until ESMF alarms
      ! get fixed kluges like this are neccessary so alarms will acutally ring
      if (first_ring_time == startTime) first_ring_time = first_ring_time + time_interval
      if (first_ring_time < currTime) &
           first_ring_time = first_ring_time +(INT((currTime - first_ring_time)/time_interval)+1)*time_interval

      alarm = ESMF_AlarmCreate(clock=clock, RingInterval=time_interval, RingTime=first_ring_time, sticky=.false., name=comp_name//"_write_alarm",  _RC)

      _RETURN(_SUCCESS)
   end subroutine create_output_alarm

   function set_start_stop_time(clock, hconfig, rc) result(start_stop_time)
      type(ESMF_Time) :: start_stop_time(2)
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_HConfig), intent(in) :: hconfig
      integer, intent(out), optional :: rc

      integer :: status
      logical :: has_start, has_stop, has_timespec
      character(len=:), allocatable :: time_string
      type(ESMF_HConfig) :: time_hconfig

      time_hconfig = ESMF_HConfigCreateAt(hconfig, keyString='time_spec', _RC)
      call ESMF_ClockGet(clock, startTime=start_stop_time(1), stopTime=start_stop_time(2), _RC)
      has_start = ESMF_HConfigIsDefined(time_hconfig, keyString='start', _RC)
      has_stop = ESMF_HConfigIsDefined(time_hconfig, keyString='stop', _RC)
      if (has_start) then
         time_string = ESMF_HConfigAsString(time_hconfig, keyString='start', _RC)
         call ESMF_TimeSet(start_stop_time(1), timeString=time_string, _RC)
      end if
      if (has_stop) then
         time_string = ESMF_HConfigAsString(time_hconfig, keyString='stop', _RC)
         call ESMF_TimeSet(start_stop_time(2), timeString=time_string, _RC)
      end if
      _RETURN(_SUCCESS)
   end function set_start_stop_time

   subroutine parse_item_expression(item, item_name, var_names, rc)
      type(ESMF_HConfigIter), intent(in) :: item
      character(len=:), allocatable, intent(out) :: item_name
      type(StringVector), intent(out) :: var_names
      integer, optional, intent(out) :: rc
      character(len=:), allocatable :: expression
      integer :: status

      call parse_item_common(item, item_name, expression, _RC)
      var_names = get_expression_variables(expression, _RC)

      _RETURN(_SUCCESS)
   end subroutine parse_item_expression

   subroutine parse_item_simple(item, item_name, var_name, rc)
      type(ESMF_HConfigIter), intent(in) :: item
      character(len=:), allocatable, intent(out) :: item_name
      character(len=:), allocatable, intent(out) :: var_name
      integer, optional, intent(out) :: rc
      character(len=:), allocatable :: expression
      integer :: status

      call parse_item_common(item, item_name, expression, _RC)
      var_name = replace_delimiter(expression)

      _RETURN(_SUCCESS)
   end subroutine parse_item_simple

   subroutine parse_item_common(item, item_name, expression, rc)
      type(ESMF_HConfigIter), intent(in) :: item
      character(len=:), allocatable, intent(out) :: item_name
      character(len=:), allocatable, intent(out) :: expression
      integer, optional, intent(out) :: rc
      character(len=*), parameter :: EXPRESSION_KEY = 'expr'
      integer :: status
      logical :: asOK, isScalar, isMap
      type(ESMF_HConfig) :: value

      isScalar = ESMF_HConfigIsScalarMapKey(item, _RC)
      _ASSERT(isScalar, 'Variable list item does not have a scalar name.')
      isMap = ESMF_HConfigIsMapMapVal(item, _RC)
      _ASSERT(isMap, 'Variable list item does not have a map value.')

      item_name = ESMF_HConfigAsStringMapKey(item, asOkay=asOK, _RC)
      _ASSERT(asOK, 'Item name could not be processed as a String.')

      value = ESMF_HConfigCreateAtMapVal(item, _RC)
      expression = ESMF_HConfigAsString(value, keyString=EXPRESSION_KEY, _RC)

      _RETURN(_SUCCESS)
   end subroutine parse_item_common

   subroutine add_specs(gridcomp, names, rc)
      type(ESMF_GridComp), intent(inout) :: gridcomp
      type(StringVector), intent(in) :: names
      integer, optional, intent(out) :: rc
      integer :: status
      type(StringVectorIterator) :: ftn_iter, ftn_end
      type(VariableSpec) :: varspec
      character(len=:), allocatable :: short_name
      type(UngriddedDims) :: mirror_ungrid

      mirror_ungrid = mirror_ungridded_dims()
      ftn_end = names%ftn_end()
      ftn_iter = names%ftn_begin()
      do while (ftn_iter /= ftn_end)
         call ftn_iter%next()
         short_name = ftn_iter%of()
         varspec = VariableSpec(ESMF_STATEINTENT_IMPORT, short_name, vertical_dim_spec=VERTICAL_DIM_MIRROR, ungridded_dims=mirror_ungrid)
         call MAPL_AddSpec(gridcomp, varspec, _RC)
      end do

      _RETURN(_SUCCESS)
   end subroutine add_specs

   function replace_delimiter(string, delimiter, replacement) result(replaced)
      character(len=:), allocatable :: replaced
      character(len=*), intent(in) :: string
      character(len=*), optional, intent(in) :: delimiter
      character(len=*), optional, intent(in) :: replacement
      character(len=:), allocatable :: del, rep
      integer :: i

      replaced = string
      if(len(string) == 0) return

      del = '.'
      if(present(delimiter)) del = delimiter
      if(len(del) == 0) return

      rep = '/'
      if(present(replacement)) rep = replacement
      if(len(rep) == 0) return

      i = index(replaced, del)
      if(i > 0) replaced = replaced(:(i-1))// rep // replaced((i+len(del)):)

   end function replace_delimiter

   function get_expression_variables(expression, rc) result(variables)
      type(StringVector) :: variables
      character(len=*), intent(in) :: expression
      integer, optional, intent(out) :: rc
      integer :: status
      type(StringVector) :: raw_vars
      type(StringVectorIterator) :: iter

      raw_vars = parser_variables_in_expression(expression, _RC)
      iter = raw_vars%begin()
      do while(iter /= raw_vars%end())
        call variables%push_back(replace_delimiter(iter%of()))
        call iter%next()
      end do

      _RETURN(_SUCCESS)
   end function get_expression_variables

   function get_current_time_index(initial_time, current_time, frequency) result(time_index)
      integer :: time_index
      type(ESMF_Time), intent(in) :: initial_time
      type(ESMF_Time), intent(in) :: current_time
      type(ESMF_TimeInterval), intent(in) :: frequency

      type(ESMF_Time) :: temp_time
      time_index = 0
      temp_time = initial_time
      do while( temp_time <= current_time)
         temp_time = temp_time + frequency
         time_index = time_index + 1
      enddo
   end function get_current_time_index

end module mapl3g_HistoryCollectionGridComp_private