FieldBundleDelta.F90 Source File


This file depends on

sourcefile~~fieldbundledelta.f90~~EfferentGraph sourcefile~fieldbundledelta.f90 FieldBundleDelta.F90 sourcefile~errorhandling.f90 ErrorHandling.F90 sourcefile~fieldbundledelta.f90->sourcefile~errorhandling.f90 sourcefile~fieldbundleget.f90 FieldBundleGet.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldbundleget.f90 sourcefile~fieldbundletype_flag.f90 FieldBundleType_Flag.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldbundletype_flag.f90 sourcefile~fieldcreate.f90 FieldCreate.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldcreate.f90 sourcefile~fielddelta.f90 FieldDelta.F90 sourcefile~fieldbundledelta.f90->sourcefile~fielddelta.f90 sourcefile~fieldget.f90 FieldGet.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldget.f90 sourcefile~fieldinfo.f90 FieldInfo.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldinfo.f90 sourcefile~fieldpointerutilities.f90 FieldPointerUtilities.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldutilities.f90 FieldUtilities.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldutilities.f90 sourcefile~infoutilities.f90 InfoUtilities.F90 sourcefile~fieldbundledelta.f90->sourcefile~infoutilities.f90 sourcefile~keywordenforcer.f90 KeywordEnforcer.F90 sourcefile~fieldbundledelta.f90->sourcefile~keywordenforcer.f90 sourcefile~lu_bound.f90 LU_Bound.F90 sourcefile~fieldbundledelta.f90->sourcefile~lu_bound.f90 sourcefile~ungriddeddims.f90 UngriddedDims.F90 sourcefile~fieldbundledelta.f90->sourcefile~ungriddeddims.f90 sourcefile~verticalstaggerloc.f90 VerticalStaggerLoc.F90 sourcefile~fieldbundledelta.f90->sourcefile~verticalstaggerloc.f90 sourcefile~mapl_throw.f90 MAPL_Throw.F90 sourcefile~errorhandling.f90->sourcefile~mapl_throw.f90 sourcefile~fieldbundleget.f90->sourcefile~errorhandling.f90 sourcefile~fieldbundleget.f90->sourcefile~fieldbundletype_flag.f90 sourcefile~fieldbundleget.f90->sourcefile~infoutilities.f90 sourcefile~fieldbundleget.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldbundleget.f90->sourcefile~lu_bound.f90 sourcefile~fieldbundleget.f90->sourcefile~ungriddeddims.f90 sourcefile~api.f90 API.F90 sourcefile~fieldbundleget.f90->sourcefile~api.f90 sourcefile~fieldbundleinfo.f90 FieldBundleInfo.F90 sourcefile~fieldbundleget.f90->sourcefile~fieldbundleinfo.f90 sourcefile~fieldcreate.f90->sourcefile~errorhandling.f90 sourcefile~fieldcreate.f90->sourcefile~fieldinfo.f90 sourcefile~fieldcreate.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldcreate.f90->sourcefile~lu_bound.f90 sourcefile~fieldcreate.f90->sourcefile~ungriddeddims.f90 sourcefile~fieldcreate.f90->sourcefile~verticalstaggerloc.f90 sourcefile~fielddelta.f90->sourcefile~errorhandling.f90 sourcefile~fielddelta.f90->sourcefile~fieldget.f90 sourcefile~fielddelta.f90->sourcefile~fieldinfo.f90 sourcefile~fielddelta.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fielddelta.f90->sourcefile~infoutilities.f90 sourcefile~fielddelta.f90->sourcefile~keywordenforcer.f90 sourcefile~fielddelta.f90->sourcefile~verticalstaggerloc.f90 sourcefile~fieldget.f90->sourcefile~errorhandling.f90 sourcefile~fieldget.f90->sourcefile~fieldinfo.f90 sourcefile~fieldget.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldget.f90->sourcefile~ungriddeddims.f90 sourcefile~fieldget.f90->sourcefile~verticalstaggerloc.f90 sourcefile~fieldinfo.f90->sourcefile~errorhandling.f90 sourcefile~fieldinfo.f90->sourcefile~infoutilities.f90 sourcefile~fieldinfo.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldinfo.f90->sourcefile~ungriddeddims.f90 sourcefile~fieldinfo.f90->sourcefile~verticalstaggerloc.f90 sourcefile~mapl_esmf_infokeys.f90 MAPL_ESMF_InfoKeys.F90 sourcefile~fieldinfo.f90->sourcefile~mapl_esmf_infokeys.f90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~fieldpointerutilities.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~fieldutilities.f90->sourcefile~errorhandling.f90 sourcefile~fieldutilities.f90->sourcefile~fieldinfo.f90 sourcefile~fieldutilities.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldutilities.f90->sourcefile~infoutilities.f90 sourcefile~fieldutilities.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldutilities.f90->sourcefile~lu_bound.f90 sourcefile~fieldutilities.f90->sourcefile~ungriddeddims.f90 sourcefile~infoutilities.f90->sourcefile~errorhandling.f90 sourcefile~infoutilities.f90->sourcefile~keywordenforcer.f90 sourcefile~infoutilities.f90->sourcefile~mapl_esmf_infokeys.f90 sourcefile~ungriddeddims.f90->sourcefile~errorhandling.f90 sourcefile~ungriddeddims.f90->sourcefile~infoutilities.f90 sourcefile~ungriddeddims.f90->sourcefile~lu_bound.f90 sourcefile~ungriddeddims.f90->sourcefile~mapl_esmf_infokeys.f90 sourcefile~ungriddeddim.f90 UngriddedDim.F90 sourcefile~ungriddeddims.f90->sourcefile~ungriddeddim.f90 sourcefile~ungriddeddimvector.f90 UngriddedDimVector.F90 sourcefile~ungriddeddims.f90->sourcefile~ungriddeddimvector.f90 sourcefile~api.f90->sourcefile~fieldcreate.f90 sourcefile~api.f90->sourcefile~fieldinfo.f90 sourcefile~api.f90->sourcefile~verticalstaggerloc.f90 sourcefile~fieldbundleinfo.f90->sourcefile~errorhandling.f90 sourcefile~fieldbundleinfo.f90->sourcefile~fieldbundletype_flag.f90 sourcefile~fieldbundleinfo.f90->sourcefile~fieldinfo.f90 sourcefile~fieldbundleinfo.f90->sourcefile~infoutilities.f90 sourcefile~fieldbundleinfo.f90->sourcefile~keywordenforcer.f90 sourcefile~fieldbundleinfo.f90->sourcefile~ungriddeddims.f90 sourcefile~fieldbundleinfo.f90->sourcefile~verticalstaggerloc.f90 sourcefile~fieldbundleinfo.f90->sourcefile~mapl_esmf_infokeys.f90 sourcefile~mapl_esmf_infokeys.f90->sourcefile~errorhandling.f90 sourcefile~mapl_exceptionhandling.f90->sourcefile~errorhandling.f90 sourcefile~mapl_exceptionhandling.f90->sourcefile~mapl_throw.f90 sourcefile~ungriddeddim.f90->sourcefile~errorhandling.f90 sourcefile~ungriddeddim.f90->sourcefile~infoutilities.f90 sourcefile~ungriddeddim.f90->sourcefile~lu_bound.f90 sourcefile~ungriddeddimvector.f90->sourcefile~ungriddeddim.f90

Files dependent on this one

sourcefile~~fieldbundledelta.f90~~AfferentGraph sourcefile~fieldbundledelta.f90 FieldBundleDelta.F90 sourcefile~test_fieldbundledelta.pf Test_FieldBundleDelta.pf sourcefile~test_fieldbundledelta.pf->sourcefile~fieldbundledelta.f90

Source Code

! This class is to support propagation of time-dependent Field
! attributes across couplers as well as to provide guidance to the
! containt Action objects on when to recompute internal items.

#include "MAPL_Exceptions.h"
module mapl3g_FieldBundleDelta
   use mapl3g_FieldBundleGet
   use mapl3g_FieldBundleType_Flag
   use mapl3g_LU_Bound
   use mapl3g_FieldDelta
   use mapl3g_InfoUtilities
   use mapl3g_VerticalStaggerLoc
   use mapl3g_FieldCreate
   use mapl3g_FieldGet
   use mapl3g_FieldInfo
   use mapl_FieldUtilities
   use mapl3g_UngriddedDims
   use mapl_FieldPointerUtilities
   use mapl_ErrorHandling
   use mapl_KeywordEnforcer
   use esmf
   implicit none(type, external)
   private

   public :: FieldBundleDelta

   ! Note fieldCount can be derivedy from weights
   type :: FieldBundleDelta
      private
      type(FieldDelta) :: field_delta ! constant across bundle
      real(ESMF_KIND_R4), allocatable :: interpolation_weights(:)
   contains
      procedure :: initialize_bundle_delta
      generic :: initialize => initialize_bundle_delta
      procedure :: update_bundle
      procedure :: reallocate_bundle
   end type FieldBundleDelta


   interface FieldBundleDelta
      procedure new_FieldBundleDelta
      procedure new_FieldBundleDelta_field_delta
   end interface FieldBundleDelta

contains

   function new_FieldBundleDelta(fieldCount, geom, typekind, num_levels, units, interpolation_weights) result(bundle_delta)
      type(FieldBundleDelta) :: bundle_delta
      integer, optional, intent(in) :: fieldCount
      type(ESMF_Geom), optional, intent(in) :: geom
      type(ESMF_TypeKind_Flag), optional, intent(in) :: typekind
      integer, optional, intent(in) :: num_levels
      character(*), optional, intent(in) :: units
      real(ESMF_KIND_R4), intent(in), optional :: interpolation_weights(:)

      associate (field_delta => FieldDelta(geom=geom, typekind=typekind, num_levels=num_levels, units=units))
        bundle_delta = FieldBundleDelta(field_delta, fieldCount, interpolation_weights)
      end associate

   end function new_FieldBundleDelta

   function new_FieldBundleDelta_field_delta(field_delta, fieldCount, interpolation_weights) result(bundle_delta)
      type(FieldBundleDelta) :: bundle_delta
      type(FieldDelta), intent(in) :: field_delta
      integer, optional, intent(in) :: fieldCount
      real(ESMF_KIND_R4), optional, intent(in) :: interpolation_weights(:)

      bundle_delta%field_delta = field_delta

      if (present(interpolation_weights)) then
         bundle_delta%interpolation_weights = interpolation_weights
      end if

   end function new_FieldBundleDelta_field_delta


   ! delta = bundle_b - bundle_a
   subroutine initialize_bundle_delta(this, bundle_a, bundle_b, rc) 
      class(FieldBundleDelta), intent(out) :: this
      type(ESMF_FieldBundle), intent(in) :: bundle_a
      type(ESMF_FieldBundle), intent(in) :: bundle_b
      integer, optional, intent(out) :: rc

      integer :: status

      call compute_interpolation_weights_delta(this%interpolation_weights, bundle_a, bundle_b, _RC)
      call compute_field_delta(this%field_delta, bundle_a, bundle_b, _RC)

      _RETURN(_SUCCESS)


   contains

      subroutine compute_interpolation_weights_delta(interpolation_weights, bundle_a, bundle_b, rc)
         real(ESMF_KIND_R4), allocatable, intent(out) :: interpolation_weights(:)
         type(ESMF_FieldBundle), intent(in) :: bundle_a
         type(ESMF_FieldBundle), intent(in) :: bundle_b
         integer, optional, intent(out) :: rc

         integer :: status
         real(ESMF_KIND_R4), allocatable :: weights_a(:), weights_b(:)

         call MAPL_FieldBundleGet(bundle_a, interpolation_weights=weights_a, _RC)
         call MAPL_FieldBundleGet(bundle_b, interpolation_weights=weights_b, _RC)

         if (any(weights_a /= weights_b)) then
            interpolation_weights = weights_b
         end if

         _RETURN(_SUCCESS)

      end subroutine compute_interpolation_weights_delta

      subroutine compute_field_delta(field_delta, bundle_a, bundle_b, rc)
         type(FieldDelta), intent(out) :: field_delta
         type(ESMF_FieldBundle), intent(in) :: bundle_a
         type(ESMF_FieldBundle), intent(in) :: bundle_b
         integer, optional, intent(out) :: rc

         integer :: status
         integer :: fieldCount_a, fieldCount_b
         type(ESMF_Field), allocatable :: fieldList_a(:), fieldList_b(:)
         type(FieldBundleType_Flag) :: fieldBundleType_a, fieldBundleType_b

         call MAPL_FieldBundleGet(bundle_a, &
              fieldCount=fieldCount_a, fieldBundleType=fieldBundleType_a, fieldList=fieldList_a, _RC)
         call MAPL_FieldBundleGet(bundle_b, &
              fieldCount=fieldCount_b, fieldBundleType=fieldBundleType_b, fieldList=fieldList_b, _RC)
         
         _ASSERT(fieldBundleType_a == FIELDBUNDLETYPE_BRACKET, 'incorrect type of FieldBundle')
         _ASSERT(fieldBundleType_b == FIELDBUNDLETYPE_BRACKET, 'incorrect type of FieldBundle')

         ! TODO: add check thta name of 1st field is "bracket-prototype" or similar.
         if (fieldCount_a > 0 .and. fieldCount_b > 0) then
            call field_delta%initialize(fieldList_a(1), fieldList_b(1), _RC)
            _RETURN(_SUCCESS)
         end if

         if (fieldCount_b > 1) then
            ! full FieldDelta
            call field_delta%initialize(fieldList_b(1), _RC)
            _RETURN(_SUCCESS)
         end if

         ! Otherwise nothing to do. Fields are either going away
         ! (n_fields_b = 0) or there are no fields on either side
         ! (n_fields_a = 0 and n_fields_b = 0).
            
         _RETURN(_SUCCESS)
      end subroutine compute_field_delta
      

   end subroutine initialize_bundle_delta

   subroutine update_bundle(this, bundle, ignore, rc)
      class(FieldBundleDelta), intent(in) :: this
      type(ESMF_FieldBundle), intent(inout) :: bundle
      character(*), intent(in), optional :: ignore
      integer, optional, intent(out) :: rc

      integer :: status
      character(:), allocatable :: ignore_
      type(ESMF_Field), allocatable :: fieldList(:)

      ignore_ = ''
      if (present(ignore)) ignore_ = ignore

      call this%reallocate_bundle(bundle, ignore=ignore_, _RC)
      call MAPL_FieldBundleGet(bundle, fieldList=fieldList, _RC)
      call this%field_delta%update_fields(fieldList, ignore=ignore_, _RC)

      ! unique attribute in bundle
      call update_interpolation_weights(this%interpolation_weights, bundle, ignore=ignore_, _RC)

      _RETURN(_SUCCESS)
   contains


      subroutine update_interpolation_weights(interpolation_weights, bundle, ignore, rc)
         real(ESMF_KIND_R4), optional, intent(in) :: interpolation_weights(:)
         type(ESMF_FieldBundle), intent(inout) :: bundle
         character(*), intent(in) :: ignore
         integer, optional, intent(out) :: rc

         integer :: status

         _RETURN_UNLESS(present(interpolation_weights))
         _RETURN_IF(ignore == 'interpolation_weights')

         call MAPL_FieldBundleSet(bundle, interpolation_weights=interpolation_weights, _RC)

         _RETURN(_SUCCESS)
      end subroutine update_interpolation_weights

   end subroutine update_bundle


   ! If the size of the bundle is not changing, then any reallocation is
   ! relegated to fields through the FieldDelta component.
   ! Otherwise we need to create or destroy fields in the bundle.
   
   subroutine reallocate_bundle(this, bundle, ignore, unusable, rc)
      class(FieldBundleDelta), intent(in) :: this
      type(ESMF_FieldBundle), intent(inout) :: bundle
      character(*), intent(in) :: ignore
      class(KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      type(ESMF_Field), allocatable :: fieldList(:)
      type(ESMF_Geom) :: bundle_geom
      integer :: i
      type(LU_Bound), allocatable :: bounds(:)
      type(LU_Bound) :: vertical_bounds
      type(ESMF_TypeKind_Flag) :: typekind
      integer, allocatable :: ungriddedLbound(:), ungriddedUbound(:)
      integer :: old_field_count, new_field_count
      integer, allocatable :: num_levels
      character(:), allocatable :: units, vert_staggerloc_str
      type(VerticalStaggerLoc) :: vert_staggerloc
      character(ESMF_MAXSTR), allocatable :: fieldNameList(:)
      type(UngriddedDims) :: ungridded_dims

      ! Easy case 1: field count unchanged
      call MAPL_FieldBundleGet(bundle, fieldList=fieldList, _RC)
      _RETURN_UNLESS(allocated(this%interpolation_weights))
      ! The number of weights is always one larger than the number of fields to support a constant
      ! offset.  ("Weights" is a funny term in that case.)
      new_field_count = size(this%interpolation_weights) - 1
      old_field_count = size(fieldList)
      _RETURN_IF(new_field_count == old_field_count)

      ! Easy case 2: field count changing to zero
      if (new_field_count == 0) then! "/dev/null" case
         call destroy_fields(fieldList, _RC)
         _RETURN(_SUCCESS)
      end if

      ! Hard case: need to create new fields?
      _ASSERT(size(fieldList) == 0, 'fieldCount should only change to or from zero.  ExtData use case.')
      deallocate(fieldList)
      allocate(fieldList(new_field_count))

      ! Need geom, typekind, and bounds to allocate fields before 
      call MAPL_FieldBundleGet(bundle, geom=bundle_geom, &
           typekind=typekind, &
           ungridded_dims=ungridded_dims, &
           units=units, &
           vert_staggerloc=vert_staggerloc, &
           _RC)

      _ASSERT(vert_staggerloc /= VERTICAL_STAGGER_INVALID, 'Vert stagger is INVALID.')
      if (vert_staggerloc /= VERTICAL_STAGGER_NONE) then
         ! Allocate num_levels so that it is PRESENT() int FieldEmptyComplete() below.
         allocate(num_levels)
         call MAPL_FieldBundleGet(bundle, num_levels=num_levels, _RC)
      end if

      do i = 1, new_field_count
         fieldList(i) = ESMF_FieldEmptyCreate(_RC)
         call ESMF_FieldEmptySet(fieldList(i), geom=bundle_geom, _RC)
         call MAPL_FieldEmptyComplete(fieldList(i), typekind=typekind, &
              ungridded_dims=ungridded_dims, &
              num_levels=num_levels, vert_staggerLoc=vert_staggerLoc, &
              units=units, _RC)
      end do

      allocate(fieldNameList(old_field_count))
      call ESMF_FieldBundleGet(bundle, fieldNameList=fieldNameList, _RC)
      call ESMF_FieldBundleRemove(bundle, fieldNameList, multiflag=.true., _RC)

      call ESMF_FieldBundleAdd(bundle, fieldList, multiFlag=.true., relaxedFlag=.true., _RC)

      _RETURN(_SUCCESS)

   contains

      subroutine destroy_fields(fieldList, rc)
         type(ESMF_Field), intent(inout) :: fieldList(:)
         integer, optional, intent(out) :: rc

         integer :: status
         integer :: i

         do i = 1, size(fieldList)
            call ESMF_FieldDestroy(fieldList(i), _RC)
         end do

         _RETURN(_SUCCESS)
      end subroutine destroy_fields
      
   end subroutine reallocate_bundle

end module mapl3g_FieldBundleDelta