Skip to content

Commit

Permalink
Fix the multi-file and flexible timing capability in the diag manager
Browse files Browse the repository at this point in the history
  • Loading branch information
uramirez8707 committed Jan 8, 2025
1 parent d885552 commit 4163521
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 51 deletions.
2 changes: 1 addition & 1 deletion diag_manager/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ diag_util_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT) diag_axis_mod.$(FC_MODEXT
diag_grid_mod.$(FC_MODEXT) fms_diag_time_utils_mod.$(FC_MODEXT) fms_diag_bbox_mod.$(FC_MODEXT)
fms_diag_time_utils_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT)
diag_table_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT) diag_util_mod.$(FC_MODEXT)
fms_diag_yaml_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT)
fms_diag_yaml_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT) fms_diag_time_utils_mod.$(FC_MODEXT)
fms_diag_object_mod.$(FC_MODEXT): diag_data_mod.$(FC_MODEXT) fms_diag_file_object_mod.$(FC_MODEXT) fms_diag_field_object_mod.$(FC_MODEXT) fms_diag_yaml_mod.$(FC_MODEXT) \
fms_diag_time_utils_mod.$(FC_MODEXT) \
fms_diag_output_buffer_mod.$(FC_MODEXT) \
Expand Down
3 changes: 3 additions & 0 deletions diag_manager/diag_manager.F90
Original file line number Diff line number Diff line change
Expand Up @@ -3859,6 +3859,9 @@ SUBROUTINE diag_manager_set_time_end(Time_end_in)
TYPE (time_type), INTENT(in) :: Time_end_in

Time_end = Time_end_in
if (use_modern_diag) then
call fms_diag_object%set_time_end(time_end_in)
endif

END SUBROUTINE diag_manager_set_time_end

Expand Down
66 changes: 44 additions & 22 deletions diag_manager/fms_diag_file_object.F90
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ module fms_diag_file_object_mod
procedure :: write_field_metadata
procedure :: write_axis_data
procedure :: writing_on_this_pe
procedure :: is_time_to_write
procedure :: check_file_times
procedure :: is_time_to_close_file
procedure :: write_time_data
procedure :: update_next_write
Expand All @@ -200,6 +200,7 @@ module fms_diag_file_object_mod
procedure :: close_diag_file
procedure :: set_model_time
procedure :: get_model_time
procedure :: time_to_start_doing_math
end type fmsDiagFileContainer_type

!type(fmsDiagFile_type), dimension (:), allocatable, target :: FMS_diag_file !< The array of diag files
Expand Down Expand Up @@ -264,8 +265,12 @@ logical function fms_diag_files_object_init (files_array)
!! Set this to the time passed in to diag_manager_init
!! This will be the base_time if nothing was passed in
!! This time is appended to the filename if the prepend_date namelist is .True.
obj%start_time = diag_init_time
obj%last_output = diag_init_time
if (obj%has_file_start_time()) then
obj%start_time = obj%get_file_start_time()
else
obj%start_time = diag_init_time
endif
obj%last_output = obj%start_time
obj%model_time = diag_init_time
obj%next_output = diag_time_inc(obj%start_time, obj%get_file_freq(), obj%get_file_frequnit())
obj%next_next_output = diag_time_inc(obj%next_output, obj%get_file_freq(), obj%get_file_frequnit())
Expand All @@ -274,7 +279,12 @@ logical function fms_diag_files_object_init (files_array)
obj%next_close = diag_time_inc(obj%start_time, obj%get_file_new_file_freq(), &
obj%get_file_new_file_freq_units())
else
obj%next_close = diag_time_inc(obj%start_time, VERY_LARGE_FILE_FREQ, DIAG_DAYS)
if (obj%has_file_duration()) then
obj%next_close = diag_time_inc(obj%start_time, obj%get_file_duration(), &
obj%get_file_duration_units())
else
obj%next_close = diag_time_inc(obj%start_time, VERY_LARGE_FILE_FREQ, DIAG_DAYS)
endif
endif
obj%is_file_open = .false.

Expand Down Expand Up @@ -597,7 +607,7 @@ end function get_file_new_file_freq_units
!! \return Copy of file_start_time
pure function get_file_start_time (this) result(res)
class(fmsDiagFile_type), intent(in) :: this !< The file object
character (len=:), allocatable :: res
type(time_type):: res
res = this%diag_yaml_file%get_file_start_time()
end function get_file_start_time

Expand Down Expand Up @@ -639,6 +649,7 @@ pure function is_done_writing_data (this) result(res)
class(fmsDiagFile_type), intent(in) :: this !< The file object
logical :: res
res = this%done_writing_data
if (this%is_file_open) res = .false.
end function is_done_writing_data

!> \brief Checks if file_fname is allocated in the yaml object
Expand Down Expand Up @@ -1014,6 +1025,11 @@ subroutine add_start_time(this, start_time)
!! this%start_time was already set to the diag_init_time
if (start_time .eq. diag_init_time) return

!< If the start_time sent is is greater than or equal to the start time already
!! in the diag file obj return because either this%start_time was already updated
!! or the file has start_time defined in the yaml
if (this%start_time >= start_time) return

if (this%start_time .ne. diag_init_time) then
!> If the this%start_time is not equal to the diag_init_time from the diag_table
!! this%start_time was already updated so make sure it is the same for the current variable
Expand Down Expand Up @@ -1383,11 +1399,14 @@ end subroutine write_field_data

!> \brief Determine if it is time to close the file
!! \return .True. if it is time to close the file
logical function is_time_to_close_file (this, time_step)
logical function is_time_to_close_file (this, time_step, force_close)
class(fmsDiagFileContainer_type), intent(in), target :: this !< The file object
TYPE(time_type), intent(in) :: time_step !< Current model step time
logical, intent(in) :: force_close !< if .true. return true

if (time_step >= this%FMS_diag_file%next_close) then
if (force_close) then
is_time_to_close_file = .true.
elseif (time_step >= this%FMS_diag_file%next_close) then
is_time_to_close_file = .true.
else
if (this%FMS_diag_file%is_static) then
Expand All @@ -1398,8 +1417,18 @@ logical function is_time_to_close_file (this, time_step)
endif
end function

!> \brief Determine if it is time to start doing mathz
!! \return .True. if it is time to start doing mathz
logical function time_to_start_doing_math (this)
class(fmsDiagFileContainer_type), intent(in), target :: this !< The file object
time_to_start_doing_math = .false.
if (this%FMS_diag_file%model_time >= this%FMS_diag_file%start_time) then
time_to_start_doing_math = .true.
endif
end function

!> \brief Determine if it is time to "write" to the file
logical function is_time_to_write(this, time_step, output_buffers, diag_fields, do_not_write)
subroutine check_file_times(this, time_step, output_buffers, diag_fields, do_not_write)
class(fmsDiagFileContainer_type), intent(inout), target :: this !< The file object
TYPE(time_type), intent(in) :: time_step !< Current model step time
type(fmsDiagOutputBuffer_type), intent(in) :: output_buffers(:) !< Array of output buffer.
Expand All @@ -1411,7 +1440,6 @@ logical function is_time_to_write(this, time_step, output_buffers, diag_fields,

do_not_write = .false.
if (time_step > this%FMS_diag_file%next_output) then
is_time_to_write = .true.
if (this%FMS_diag_file%is_static) return
if (time_step > this%FMS_diag_file%next_next_output) then
if (this%FMS_diag_file%get_file_freq() .eq. 0) then
Expand All @@ -1421,9 +1449,7 @@ logical function is_time_to_write(this, time_step, output_buffers, diag_fields,
call this%FMS_diag_file%check_buffer_times(output_buffers, diag_fields)
this%FMS_diag_file%next_output = time_step
this%FMS_diag_file%next_next_output = time_step
is_time_to_write = .true.
endif
return
elseif (this%FMS_diag_file%num_registered_fields .eq. 0) then
!! If no variables have been registered, write a dummy time dimension for the first level
!! At least one time level is needed for the combiner to work ...
Expand All @@ -1433,26 +1459,20 @@ logical function is_time_to_write(this, time_step, output_buffers, diag_fields,
this%FMS_diag_file%data_has_been_written = .true.
this%FMS_diag_file%unlim_dimension_level = 1
endif
is_time_to_write =.false.
else
!! Only fail if send data has actually been called for at least one variable
if (this%FMS_diag_file%has_send_data_been_called(output_buffers, .false.)) &
call mpp_error(FATAL, this%FMS_diag_file%get_file_fname()//&
": diag_manager_mod: You skipped a time_step. Be sure that diag_send_complete is called at every "//&
"time_step needed by the file.")
is_time_to_write =.false.
endif
endif
else
is_time_to_write = .false.
if (this%FMS_diag_file%is_static) then
! This is to ensure that static files get finished in the begining of the run
if (this%FMS_diag_file%unlim_dimension_level .eq. 1) is_time_to_write = .true.
else if(this%FMS_diag_file%get_file_freq() .eq. 0) then
if(this%FMS_diag_file%get_file_freq() .eq. 0) then
do_not_write = .true.
endif
endif
end function is_time_to_write
end subroutine check_file_times

!> \brief Determine if the current PE has data to write
logical function writing_on_this_pe(this)
Expand Down Expand Up @@ -1532,7 +1552,6 @@ subroutine update_current_new_file_freq_index(this, time_step)
diag_file%next_output = diag_file%no_more_data
diag_file%next_next_output = diag_file%no_more_data
diag_file%last_output = diag_file%no_more_data
diag_file%next_close = diag_file%no_more_data
endif
endif

Expand Down Expand Up @@ -1776,10 +1795,11 @@ subroutine write_axis_data(this, diag_axis)
end subroutine write_axis_data

!< @brief Closes the diag_file
subroutine close_diag_file(this, output_buffers, diag_fields)
subroutine close_diag_file(this, output_buffers, model_end_time, diag_fields)
class(fmsDiagFileContainer_type), intent(inout), target :: this !< The file object
type(fmsDiagOutputBuffer_type), intent(in) :: output_buffers(:) !< Array of output buffers
!! This is needed for error checking
type(time_type), intent(in) :: model_end_time !< Time that simulation ends
type(fmsDiagField_type), intent(in), optional :: diag_fields(:) !< Array of diag fields
!! This is needed for error checking

Expand All @@ -1805,9 +1825,11 @@ subroutine close_diag_file(this, output_buffers, diag_fields)
this%FMS_diag_file%get_file_new_file_freq(), &
this%FMS_diag_file%get_file_new_file_freq_units())
else
this%FMS_diag_file%next_close = diag_time_inc(this%FMS_diag_file%next_close, VERY_LARGE_FILE_FREQ, DIAG_DAYS)
this%FMS_diag_file%next_close = model_end_time
endif

if (this%FMS_diag_file%model_time >= model_end_time) &
this%FMS_diag_file%done_writing_data = .true.
if (this%FMS_diag_file%has_send_data_been_called(output_buffers, .True., diag_fields)) return
end subroutine close_diag_file

Expand Down
27 changes: 19 additions & 8 deletions diag_manager/fms_diag_object.F90
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ module fms_diag_object_mod
logical, private :: fields_initialized=.false. !< True if the fmsDiagObject is initialized
logical, private :: buffers_initialized=.false. !< True if the fmsDiagObject is initialized
logical, private :: axes_initialized=.false. !< True if the fmsDiagObject is initialized
type(time_type) :: model_end_time !< The time that the simulation is going to end
!! (set by calling diag_manager_set_time_end)
#endif
contains
procedure :: init => fms_diag_object_init
Expand All @@ -94,6 +96,7 @@ module fms_diag_object_mod
procedure :: fms_diag_field_add_cell_measures
procedure :: allocate_diag_field_output_buffers
procedure :: fms_diag_compare_window
procedure :: set_time_end
#ifdef use_yaml
procedure :: get_diag_buffer
#endif
Expand Down Expand Up @@ -821,14 +824,14 @@ subroutine fms_diag_do_io(this, end_time)

!< Go away if the file is a subregional file and the current PE does not have any data for it
if (.not. diag_file%writing_on_this_pe()) cycle
if (diag_file%FMS_diag_file%is_done_writing_data()) cycle

if (present (end_time)) then
force_write = .true.
model_time => end_time
else
model_time => diag_file%get_model_time()
endif
if (diag_file%FMS_diag_file%is_done_writing_data()) cycle

call diag_file%open_diag_file(model_time, file_is_opened_this_time_step)
if (file_is_opened_this_time_step) then
Expand All @@ -842,7 +845,7 @@ subroutine fms_diag_do_io(this, end_time)
call diag_file%write_axis_data(this%diag_axis)
endif

finish_writing = diag_file%is_time_to_write(model_time, this%FMS_diag_output_buffers, &
call diag_file%check_file_times(model_time, this%FMS_diag_output_buffers, &
this%FMS_diag_fields, do_not_write)
unlim_dim_was_increased = .false.

Expand Down Expand Up @@ -881,16 +884,14 @@ subroutine fms_diag_do_io(this, end_time)
call diag_file%write_time_data()
call diag_file%flush_diag_file()
call diag_file%update_next_write(model_time)
endif

if (finish_writing) then
call diag_file%update_current_new_file_freq_index(model_time)
if (diag_file%is_time_to_close_file(model_time)) call diag_file%close_diag_file(this%FMS_diag_output_buffers, &
diag_fields = this%FMS_diag_fields)
if (diag_file%is_time_to_close_file(model_time, force_write)) call diag_file%close_diag_file(this%FMS_diag_output_buffers, &
this%model_end_time, diag_fields = this%FMS_diag_fields)
else if (force_write) then
call diag_file%prepare_for_force_write()
call diag_file%write_time_data()
call diag_file%close_diag_file(this%FMS_diag_output_buffers, diag_fields = this%FMS_diag_fields)
call diag_file%close_diag_file(this%FMS_diag_output_buffers, &
this%model_end_time, diag_fields = this%FMS_diag_fields)
endif
enddo
#endif
Expand Down Expand Up @@ -979,6 +980,7 @@ function fms_diag_do_reduction(this, field_data, diag_field_id, oor_mask, weight
if (buffer_ptr%is_done_with_math()) cycle

if (present(time)) call file_ptr%set_model_time(time)
if (.not. file_ptr%time_to_start_doing_math()) cycle

bounds_out = bounds
if (.not. using_blocking) then
Expand Down Expand Up @@ -1503,4 +1505,13 @@ function fms_diag_compare_window(this, field, field_id, &
#endif
end function fms_diag_compare_window

!> @brief Set the model_end_time in a diag object
subroutine set_time_end(this, time_end_in)
class(fmsDiagObject_type), intent(inout) :: this !< Diag Object
type(time_type), intent(in) :: time_end_in !< Time at the end of the simulation
#ifdef use_yaml
this%model_end_time = time_end_in
#endif
end subroutine

end module fms_diag_object_mod
37 changes: 36 additions & 1 deletion diag_manager/fms_diag_time_utils.F90
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
module fms_diag_time_utils_mod

use time_manager_mod, only: time_type, increment_date, increment_time, get_calendar_type, NO_CALENDAR, leap_year, &
get_date, get_time, operator(>), operator(<), operator(-), set_date
get_date, get_time, operator(>), operator(<), operator(-), set_date, set_time
use diag_data_mod, only: END_OF_RUN, EVERY_TIME, DIAG_SECONDS, DIAG_MINUTES, DIAG_HOURS, DIAG_DAYS, DIAG_MONTHS, &
DIAG_YEARS, use_clock_average
USE constants_mod, ONLY: SECONDS_PER_DAY, SECONDS_PER_HOUR, SECONDS_PER_MINUTE
Expand All @@ -40,6 +40,7 @@ module fms_diag_time_utils_mod
public :: diag_time_inc
public :: get_time_string
public :: get_date_dif
public :: set_time_type

contains

Expand Down Expand Up @@ -383,4 +384,38 @@ REAL FUNCTION get_date_dif(t2, t1, units)
CALL mpp_error(FATAL, 'diag_util_mod::diag_date_dif illegal time units')
END IF
END FUNCTION get_date_dif

!> @brief Sets up a time_type based on 6 member array of integers defining the
!! [year month day hour min sec]
subroutine set_time_type(time_int, time)
integer, intent(in) :: time_int(6) !< The time in the format [year month day hour min second]
type(time_type), intent(inout) :: time !< The time converted to the time_type

integer :: year !< Year of the time type
integer :: month !< Month of the time type
integer :: day !< Day of the time type
integer :: hour !< Hour of the time type
integer :: minute !< Minute of the time type
integer :: second !< Second of the time type

year = time_int(1)
month = time_int(2)
day = time_int(3)
hour = time_int(4)
minute = time_int(5)
second = time_int(6)

! Set up the time type for time passed in
IF ( get_calendar_type() /= NO_CALENDAR ) THEN
IF ( year==0 .OR. month==0 .OR. day==0 ) THEN
call mpp_error(FATAL, 'fms_diag_time_utils_mod::set_time_type'//&
& 'The year/month/day can not equal zero')
END IF
time = set_date(year, month, day, hour, minute, second)
ELSE
! No calendar - ignore year and month
time = set_time(NINT(hour*SECONDS_PER_HOUR)+NINT(minute*SECONDS_PER_MINUTE)+second, &
& day)
END IF
end subroutine set_time_type
end module fms_diag_time_utils_mod
Loading

0 comments on commit 4163521

Please sign in to comment.