tem_timeformatter_module.f90 Source File


Source Code

! Copyright (c) 2025 Harald Klimach <harald.klimach@dlr.de>
!
! Redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions are met:
!
! 1. Redistributions of source code must retain the above copyright notice, this
! list of conditions and the following disclaimer.
!
! 2. Redistributions in binary form must reproduce the above copyright notice,
! this list of conditions and the following disclaimer in the documentation
! and/or other materials provided with the distribution.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! **************************************************************************** !
!
!> Formatting of time points.
!!
!! The formatters alllow the specification of how time-stamps for given time
!! objects are to be formatted.
!!
module tem_timeformatter_module
  use env_module, only: labelLen

  use aotus_module, only: flu_State, &
    &                     aot_get_val
  use aot_table_module, only: aot_table_open, &
    &                         aot_table_close

  use tem_time_module, only: tem_time_type

  implicit none

  private

  public :: tem_timeformatter_type
  public :: tem_timeformatter_load
  public :: tem_timeformatter_init

  character(len=8), parameter :: default_form = '(EN12.3)'

  type tem_timeformatter_type
    character(len=labelLen) :: timeform = default_form
    procedure(timestamp), pointer, pass(formatter) :: stamp => null()
  end type tem_timeformatter_type

  abstract interface
    function timestamp(formatter, time) result(stamp)
      import :: tem_time_type, tem_timeformatter_type, labelLen
      class(tem_timeformatter_type), intent(in) :: formatter
      type(tem_time_type), intent(in) :: time
      character(len=LabelLen) :: stamp
    end function timestamp
  end interface


contains


  ! ************************************************************************ !
  !> Reading a timeformatter description from a Lua script given by conf.
  !!
  !! Initializing a timeformatter
  !! * timeform defines the formatting string to be used for the timestamp
  !!   this defaults to `default_form`
  !! * stamp defines the routine to use for the timestamp generation and
  !!   defaults to `tem_timeformatter_sim_stamp`
  function tem_timeformatter_init(timeform, stamp) result(formatter)
    character(len=*), optional, intent(in) :: timeform
    procedure(timestamp), optional :: stamp
    type(tem_timeformatter_type) :: formatter

    if (present(timeform)) then
      formatter%timeform = timeform
    else
      formatter%timeform = default_form
    end if

    if (present(stamp)) then
      formatter%stamp => stamp
    else
      formatter%stamp => tem_timeformatter_sim_stamp
    end if

  end function tem_timeformatter_init
  ! ************************************************************************ !


  ! ************************************************************************ !
  !> Reading a timeformatter description from a Lua script given by conf.
  !!
  !! The timeformatter description has to be provided in the table given by
  !! thandle.
  !! There are two settings for the formatting:
  !! - use_iter: use the number of iterations rather than simulated time
  !!             Default: false, but may be overwritten by caller.
  !! - simform: Fortran formatting string for the real number of the
  !!            simulated time.
  !!            Default: '(EN12.3)'
  !! Thus, the configuration looks like:
  !!
  !! \verbatim
  !! timeformat = { use_iter = false, simform = '(EN12.3)' }
  !! \end verbatim
  !!
  !! If timeformat is not a table, the value is attempted to be read as a
  !! string for the simform, so it is also possible to write:
  !!
  !! \verbatim
  !! timeformat = '(EN15.6)'
  !! \end verbatim
  !!
  !! The key to be used for reading these settings could also be changed by
  !! the caller by passing the key to be used in the key argument.
  subroutine tem_timeformatter_load(me, conf, key, parent, use_iter_default)
    ! -------------------------------------------------------------------- !
    !> Time to be read from the Lua script
    type(tem_timeformatter_type), intent(out) :: me

    !> Handle to the Lua script.
    type(flu_state), intent(inout) :: conf

    !> Name of the table containing the time definition. Default: 'time'.
    character(len=*), intent(in), optional :: key

    !> Handle to the parent table.
    integer, intent(in), optional :: parent

    !> Default for the use_iter setting
    logical, intent(in), optional :: use_iter_default
    ! -------------------------------------------------------------------- !
    integer :: iErr
    character(len=labelLen) :: loc_key
    character(len=labelLen) :: timeform
    integer :: thandle
    logical :: use_iter
    logical :: loc_iter_default
    ! -------------------------------------------------------------------- !

    if ( present(key) ) then
      loc_key = trim(key)
    else
      loc_key = 'timeformat'
    end if

    if ( present(use_iter_default) ) then
      loc_iter_default = use_iter_default
    else
      loc_iter_default = .false.
    end if

    call aot_table_open(L       = conf,    &
      &                 parent  = parent,  &
      &                 thandle = thandle, &
      &                 key     = loc_key  )

    use_iter = loc_iter_default

    if (thandle /= 0) then
      ! The timeformat is given as a table load its components accordingly.
      call aot_get_val(L       = conf,             &
        &              thandle = thandle,          &
        &              val     = use_iter,         &
        &              key     = 'use_iter',       &
        &              default = loc_iter_default, &
        &              ErrCode = iErr              )

      call aot_get_val(L       = conf,         &
        &              thandle = thandle,      &
        &              val     = timeform,     &
        &              key     = 'simform',    &
        &              default = default_form, &
        &              ErrCode = iErr          )

    else
      ! The time is not given as a table, try to interpret it as a setting for
      ! the simform.
      call aot_get_val(L       = conf,         &
        &              thandle = parent,       &
        &              key     = loc_key,      &
        &              val     = timeform,     &
        &              default = default_form, &
        &              ErrCode = iErr          )
    end if

    call aot_table_close(conf, thandle)

    if (use_iter) then
      me = tem_timeformatter_init(timeform = '(I0)',                      &
        &                         stamp    = tem_timeformatter_iter_stamp )
    else
      me = tem_timeformatter_init(timeform = timeform,                   &
        &                         stamp    = tem_timeformatter_sim_stamp )
    end if

  end subroutine tem_timeformatter_load
  ! ************************************************************************ !


  ! ************************************************************************ !
  !> Generate a time stamp from the simulation time in the given time
  !! definition.
  !!
  !! This basically generates a string identifying the solution time and
  !! writing it in a meaningful format, so that it can be easily recognized.
  function tem_timeformatter_sim_stamp(formatter, time) result(timeStamp)
    ! -------------------------------------------------------------------- !
    !> Formatting object to generate the time stamp
    class(tem_timeformatter_type), intent(in) :: formatter
    !> Time definition to create the stamp off.
    type(tem_time_type), intent(in) :: time

    !> String representation of the given simulation time.
    character(len=labelLen) :: timeStamp
    ! -------------------------------------------------------------------- !
    ! -------------------------------------------------------------------- !

    write(timeStamp, formatter%timeform) time%sim

    ! remove leading empty spaces in the timestamp
    timeStamp = adjustl(timeStamp)

  end function  tem_timeformatter_sim_stamp
  ! ************************************************************************ !


  ! ************************************************************************ !
  !> Generate a time stamp from the iteration in the given time
  !! definition.
  function tem_timeformatter_iter_stamp(formatter, time) result(timeStamp)
    ! -------------------------------------------------------------------- !
    !> Formatting object to generate the time stamp
    class(tem_timeformatter_type), intent(in) :: formatter
    !> Time definition to create the stamp off.
    type(tem_time_type), intent(in) :: time

    !> String representation of the given simulation time.
    character(len=labelLen) :: timeStamp
    ! -------------------------------------------------------------------- !
    ! -------------------------------------------------------------------- !

    write(timeStamp, formatter%timeform) time%iter

    ! remove leading empty spaces in the timestamp
    timeStamp = adjustl(timeStamp)

  end function  tem_timeformatter_iter_stamp
  ! ************************************************************************ !

end module tem_timeformatter_module