output_manager_core.F90 Source File


This file depends on

sourcefile~~output_manager_core.f90~~EfferentGraph sourcefile~output_manager_core.f90 output_manager_core.F90 sourcefile~field_manager.f90 field_manager.F90 sourcefile~output_manager_core.f90->sourcefile~field_manager.f90

Files dependent on this one

sourcefile~~output_manager_core.f90~~AfferentGraph sourcefile~output_manager_core.f90 output_manager_core.F90 sourcefile~output_manager.f90 output_manager.F90 sourcefile~output_manager.f90->sourcefile~output_manager_core.f90 sourcefile~netcdf_output.f90 netcdf_output.F90 sourcefile~output_manager.f90->sourcefile~netcdf_output.f90 sourcefile~slice.f90 slice.F90 sourcefile~output_manager.f90->sourcefile~slice.f90 sourcefile~time_average.f90 time_average.F90 sourcefile~output_manager.f90->sourcefile~time_average.f90 sourcefile~library.f90 library.F90 sourcefile~output_manager.f90->sourcefile~library.f90 sourcefile~text_output.f90 text_output.F90 sourcefile~output_manager.f90->sourcefile~text_output.f90 sourcefile~netcdf_output.f90->sourcefile~output_manager_core.f90 sourcefile~slice.f90->sourcefile~output_manager_core.f90 sourcefile~base.f90 base.F90 sourcefile~slice.f90->sourcefile~base.f90 sourcefile~base.f90->sourcefile~output_manager_core.f90 sourcefile~time_average.f90->sourcefile~output_manager_core.f90 sourcefile~time_average.f90->sourcefile~base.f90 sourcefile~interp.f90 interp.F90 sourcefile~interp.f90->sourcefile~output_manager_core.f90 sourcefile~interp.f90->sourcefile~base.f90 sourcefile~library.f90->sourcefile~output_manager_core.f90 sourcefile~library.f90->sourcefile~slice.f90 sourcefile~library.f90->sourcefile~base.f90 sourcefile~library.f90->sourcefile~time_average.f90 sourcefile~library.f90->sourcefile~interp.f90 sourcefile~text_output.f90->sourcefile~output_manager_core.f90

Contents


Source Code

module output_manager_core

   use iso_fortran_env, only: error_unit

   use field_manager
   use yaml_settings

   implicit none

   public type_output_variable_settings,type_output_item,type_output_field, type_file, write_time_string, read_time_string, host, type_host
   public type_base_output_field, type_base_operator, wrap_field

   private

   integer,parameter,public :: max_path = 256

   integer,parameter,public :: time_method_none          = 0  ! time-independent variable
   integer,parameter,public :: time_method_instantaneous = 1
   integer,parameter,public :: time_method_mean          = 2
   integer,parameter,public :: time_method_integrated    = 3

   integer,parameter,public :: time_unit_none   = 0
   integer,parameter,public :: time_unit_second = 1
   integer,parameter,public :: time_unit_hour   = 2
   integer,parameter,public :: time_unit_day    = 3
   integer,parameter,public :: time_unit_month  = 4
   integer,parameter,public :: time_unit_year   = 5
   integer,parameter,public :: time_unit_dt     = 6
   integer,parameter,public :: time_from_list   = 7

   integer,parameter,public :: rk = kind(_ONE_)

   type,abstract :: type_host
   contains
      procedure (host_julian_day),deferred :: julian_day
      procedure (host_calendar_date),deferred :: calendar_date
      procedure :: fatal_error => host_fatal_error
      procedure :: log_message => host_log_message
   end type

   abstract interface
      subroutine host_julian_day(self,yyyy,mm,dd,julian)
         import type_host
         class (type_host), intent(in) :: self
         integer, intent(in)  :: yyyy,mm,dd
         integer, intent(out) :: julian
      end subroutine
   end interface

   abstract interface
      subroutine host_calendar_date(self,julian,yyyy,mm,dd)
         import type_host
         class (type_host), intent(in) :: self
         integer, intent(in)  :: julian
         integer, intent(out) :: yyyy,mm,dd
      end subroutine
   end interface

   type type_output_variable_settings
      integer :: time_method = time_method_instantaneous
      class (type_base_operator), pointer :: final_operator => null()
   contains
      procedure :: initialize => output_variable_settings_initialize
   end type

   type type_output_item
      class (type_output_variable_settings), pointer :: settings => null()
      character(len=string_length)         :: name = ''
      character(len=string_length)         :: prefix = ''
      character(len=string_length)         :: postfix = ''
      integer                              :: output_level = output_level_default
      class (type_category_node),  pointer :: category => null()
      type (type_field),           pointer :: field => null()
      type (type_output_item),     pointer :: next => null()
   end type

   type type_output_field_pointer
      class (type_base_output_field), pointer :: p => null()
   end type

   type type_base_output_field
      class (type_output_variable_settings), pointer :: settings => null()
      character(len=string_length)                   :: output_name = ''
      logical                                        :: is_coordinate = .false.
      type (type_nd_data_pointer)                    :: data
      type (type_output_field_pointer), allocatable  :: coordinates(:)
      class (type_base_output_field),        pointer :: next => null()
   contains
      procedure :: new_data         => base_field_new_data
      procedure :: before_save      => base_field_before_save
      procedure :: flag_as_required => base_field_flag_as_required
      procedure :: get_metadata     => base_field_get_metadata
      procedure :: get_field        => base_field_get_field
   end type type_base_output_field

   type, extends(type_base_output_field) :: type_output_field
      type (type_field), pointer :: source => null()
   contains
      procedure :: flag_as_required => field_flag_as_required
      procedure :: get_metadata     => field_get_metadata
   end type type_output_field

   type type_file
      type (type_field_manager),    pointer :: field_manager   => null()
      character(len=max_path)               :: path            = ''
      character(len=max_path)               :: postfix         = ''
      character(len=string_length)          :: title           = ''
      integer                               :: time_unit       = time_unit_none
      integer                               :: time_step       = 0
      integer                               :: first_index     = 0
      integer                               :: next_julian     = -1
      integer                               :: next_seconds    = -1
      integer                               :: first_julian    = -1
      integer                               :: first_seconds   = -1
      integer                               :: last_julian     = huge(1)
      integer                               :: last_seconds    = 0
      type (type_output_item),       pointer :: first_item     => null()
      class (type_base_output_field),pointer :: first_field    => null()
      class (type_file),             pointer :: next           => null()
   contains
      procedure :: configure
      procedure :: initialize
      procedure :: save
      procedure :: finalize
      procedure :: create_settings
      procedure :: is_dimension_used
      procedure :: append_item
   end type type_file

   type type_base_operator
      class (type_base_operator), pointer :: previous => null()
   contains
      procedure :: configure => operator_configure
      procedure :: apply     => operator_apply
      procedure :: apply_all => operator_apply_all
   end type

   class (type_host),pointer,save :: host => null()

contains

   recursive subroutine base_field_flag_as_required(self, required)
      class (type_base_output_field), intent(inout) :: self
      logical, intent(in) :: required
   end subroutine

   recursive subroutine base_field_get_metadata(self, long_name, units, dimensions, minimum, maximum, fill_value, standard_name, path, attributes)
      class (type_base_output_field), intent(in) :: self
      character(len=:), allocatable, intent(out), optional :: long_name, units, standard_name, path
      type (type_dimension_pointer), allocatable, intent(out), optional :: dimensions(:)
      real(rk), intent(out), optional :: minimum, maximum, fill_value
      type (type_attributes), intent(out), optional :: attributes
      if (present(dimensions)) allocate(dimensions(0))
   end subroutine

   recursive subroutine base_field_new_data(self)
      class (type_base_output_field), intent(inout) :: self
   end subroutine

   recursive subroutine base_field_before_save(self)
      class (type_base_output_field), intent(inout) :: self
   end subroutine

   recursive function base_field_get_field(self, field) result(output_field)
      class (type_base_output_field), intent(in) :: self
      type (type_field), target                  :: field
      class (type_base_output_field), pointer    :: output_field
      output_field => wrap_field(field, .false.)
   end function

   function wrap_field(field, allow_unregistered) result(output_field)
      type (type_field), target          :: field
      logical, intent(in)                :: allow_unregistered
      class (type_output_field), pointer :: output_field
      output_field => null()
      select case (field%status)
      case (status_not_registered)
         if (allow_unregistered) then
            call host%log_message('WARNING: output field "'//trim(field%name)//'" is skipped because it has not been registered with field manager.')
         else
            call host%fatal_error('create_field', 'Requested output field "'//trim(field%name)//'" has not been registered with field manager.')
         end if
      case (status_registered_no_data)
         call host%fatal_error('create_field', 'Data for requested field "'//trim(field%name)//'" have not been provided to field manager.')
      case default
         allocate(output_field)
         output_field%source => field
         output_field%data = output_field%source%data
         output_field%output_name = trim(field%name)
      end select
   end function

   recursive subroutine field_flag_as_required(self, required)
      class (type_output_field), intent(inout) :: self
      logical, intent(in) :: required
      if (associated(self%source%used_now) .and. required) self%source%used_now = .true.
   end subroutine

   recursive subroutine field_get_metadata(self, long_name, units, dimensions, minimum, maximum, fill_value, standard_name, path, attributes)
      class (type_output_field), intent(in) :: self
      character(len=:), allocatable, intent(out), optional :: long_name, units, standard_name, path
      type (type_dimension_pointer), allocatable, intent(out), optional :: dimensions(:)
      type (type_attributes), intent(out), optional :: attributes
      real(rk), intent(out), optional :: minimum, maximum, fill_value

      if (self%source%status == status_not_registered) then
         if (present(dimensions)) allocate(dimensions(0))
         return
      end if
      if (present(long_name)) long_name = trim(self%source%long_name)
      if (present(units)) units = trim(self%source%units)
      if (present(dimensions)) then
         allocate(dimensions(size(self%source%dimensions)))
         dimensions(:) = self%source%dimensions(:)
      end if
      if (present(minimum)) minimum = self%source%minimum
      if (present(maximum)) maximum = self%source%maximum
      if (present(fill_value)) fill_value = self%source%fill_value
      if (present(standard_name) .and. self%source%standard_name /= '') standard_name = trim(self%source%standard_name)
      if (present(path) .and. associated(self%source%category)) path = trim(self%source%category%get_path())
      if (present(attributes)) call attributes%update(self%source%attributes)
   end subroutine

   subroutine configure(self, settings)
      class (type_file),     intent(inout) :: self
      class (type_settings), intent(inout) :: settings
   end subroutine

   subroutine initialize(self)
      class (type_file),intent(inout) :: self
      stop 'output_manager_core:initialize not implemented'
   end subroutine

   function create_settings(self) result(settings)
      class (type_file),intent(inout) :: self
      class (type_output_variable_settings), pointer :: settings
      allocate(settings)
   end function create_settings

   subroutine save(self,julianday,secondsofday,microseconds)
      class (type_file),intent(inout) :: self
      integer,          intent(in)    :: julianday,secondsofday,microseconds
      stop 'output_manager_core:save not implemented'
   end subroutine

   subroutine finalize(self)
      class (type_file),intent(inout) :: self
   end subroutine

   subroutine write_time_string(jul,secs,timestr)
      integer,         intent(in)  :: jul,secs
      character(len=*),intent(out) :: timestr

      integer :: ss,min,hh,dd,mm,yy

      hh   = secs/3600
      min  = (secs-hh*3600)/60
      ss   = secs - 3600*hh - 60*min

      call host%calendar_date(jul,yy,mm,dd)

      write(timestr,'(i4.4,a1,i2.2,a1,i2.2,1x,i2.2,a1,i2.2,a1,i2.2)')  &
                           yy,'-',mm,'-',dd,hh,':',min,':',ss
   end subroutine write_time_string

   subroutine read_time_string(timestr,jul,secs,success)
      character(len=19)    :: timestr
      integer, intent(out) :: jul,secs
      logical, intent(out) :: success

      integer   :: ios
      character :: c1,c2,c3,c4
      integer   :: yy,mm,dd,hh,min,ss

      read(timestr,'(i4,a1,i2,a1,i2,1x,i2,a1,i2,a1,i2)',iostat=ios)  &
                          yy,c1,mm,c2,dd,hh,c3,min,c4,ss
      success = ios == 0
      if (ios==0) then
         call host%julian_day(yy,mm,dd,jul)
         secs = 3600*hh + 60*min + ss
      end if
   end subroutine read_time_string

   subroutine host_fatal_error(self,location,error)
      class (type_host), intent(in) :: self
      character(len=*),  intent(in) :: location,error

      write (error_unit,*) trim(location)//': '//trim(error)
      stop 1
   end subroutine

   subroutine host_log_message(self,message)
      class (type_host), intent(in) :: self
      character(len=*),  intent(in) :: message

      write (error_unit,*) trim(message)
   end subroutine

   logical function is_dimension_used(self,dim)
      class (type_file),intent(inout) :: self
      type (type_dimension), target   :: dim

      class (type_base_output_field),pointer :: output_field
      type (type_dimension_pointer), allocatable :: dimensions(:)
      integer :: i

      is_dimension_used = .true.
      output_field => self%first_field
      do while (associated(output_field))
         call output_field%get_metadata(dimensions=dimensions)
         do i=1,size(dimensions)
            if (associated(dimensions(i)%p,dim)) return
         end do
         output_field => output_field%next
      end do
      is_dimension_used = .false.
   end function is_dimension_used


   subroutine append_item(self, item)
      class (type_file),intent(inout) :: self
      type (type_output_item), target :: item

      ! Select this category for output in the field manager.
      if (.not.associated(item%settings)) item%settings => self%create_settings()
      if (.not. associated(item%field)) item%category => self%field_manager%select_category_for_output(item%name, item%output_level)

      ! Prepend to list of output categories.
      item%next => self%first_item
      self%first_item => item
   end subroutine append_item

   subroutine output_variable_settings_initialize(self, settings, parent)
      class (type_output_variable_settings), intent(inout)        :: self
      class (type_settings),                 intent(inout)        :: settings
      class (type_output_variable_settings), intent(in), optional :: parent

      if (present(parent)) then
         self%time_method = parent%time_method
         self%final_operator => parent%final_operator
      end if

      call settings%get(self%time_method, 'time_method', 'treatment of time dimension', options=(/type_option(time_method_mean, 'mean', 'mean'), &
         type_option(time_method_instantaneous, 'instantaneous', 'point'), type_option(time_method_integrated, 'integrated', 'integrated')/), default=self%time_method)
   end subroutine output_variable_settings_initialize

   subroutine operator_configure(self, settings, field_manager)
      class (type_base_operator), target, intent(inout) :: self
      class (type_settings),              intent(inout) :: settings
      type (type_field_manager),          intent(inout) :: field_manager
   end subroutine

   function operator_apply(self, source) result(output_field)
      class (type_base_operator), intent(inout), target :: self
      class (type_base_output_field), target            :: source
      class (type_base_output_field), pointer           :: output_field
      output_field => source
   end function

   recursive function operator_apply_all(self, source) result(output_field)
      class (type_base_operator), intent(inout), target :: self
      class (type_base_output_field), target            :: source
      class (type_base_output_field), pointer           :: output_field
      output_field => source
      if (associated(self%previous)) output_field => self%previous%apply_all(output_field)
      if (associated(output_field)) output_field => self%apply(output_field)
   end function

end module output_manager_core