Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 57 additions & 6 deletions components/lfric-xios/source/lfric_xios_read_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ module lfric_xios_read_mod
use constants_mod, only: i_def, l_def, str_def, r_def, rmdi, &
LARGE_DP_NEGATIVE
use lfric_xios_constants_mod, only: dp_xios
use key_value_mod, only: abstract_value_type
use io_value_mod, only: io_value_type
use integer_io_value_mod, only: integer_io_value_type
use field_mod, only: field_type, field_proxy_type
use field_real32_mod, only: field_real32_type, field_real32_proxy_type
use field_real64_mod, only: field_real64_type, field_real64_proxy_type
Expand Down Expand Up @@ -61,11 +63,18 @@ module lfric_xios_read_mod
private
public :: checkpoint_read_xios, &
checkpoint_read_value, &
checkpoint_read_r_def_value, &
checkpoint_read_integer_value, &
read_field_generic, &
read_state, &
read_checkpoint, &
read_field_time_var

interface checkpoint_read_value
procedure :: checkpoint_read_r_def_value
procedure :: checkpoint_read_integer_value
end interface checkpoint_read_value

contains

!> @brief I/O handler for reading an XIOS netcdf checkpoint
Expand Down Expand Up @@ -112,17 +121,55 @@ subroutine checkpoint_read_xios(xios_field_name, file_name, field_proxy)

end subroutine checkpoint_read_xios

!> @brief Read the data from an XIOS checkpoint file into the io_value
!> @brief Read r_def data from an XIOS checkpoint file into the io_value
!> @param[in,out] io_value The io_value to read data into
!> @param[in] value_name The id defined in the XIOS context
!>
subroutine checkpoint_read_value(io_value, value_name)
subroutine checkpoint_read_r_def_value(io_value, value_name)
class(io_value_type), intent(inout) :: io_value
character(*), optional, intent(in) :: value_name
character(str_def) :: restart_id
integer(i_def) :: array_dims
integer(tik) :: timing_id
real(dp_xios), allocatable :: dp_equiv(:)

if ( LPROF ) call start_timing(timing_id, 'lfric_xios.chkpt_readrv')

if(present(value_name)) then
restart_id = trim(value_name)
else
restart_id = "restart_" // trim(io_value%io_id)
end if
array_dims = size(io_value%data)

if ( xios_is_valid_field(trim(restart_id)) ) then
allocate(dp_equiv(array_dims))
call xios_recv_field( trim(restart_id), &
dp_equiv(1:array_dims) )
io_value%data = real(dp_equiv,r_def)
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(restart_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if

if ( LPROF ) call stop_timing(timing_id, 'lfric_xios.chkpt_readrv')

end subroutine checkpoint_read_r_def_value

!> @brief Read int data from an XIOS checkpoint file into the io_value
!> @param[in,out] io_value The io_value to read data into
!> @param[in] value_name The id defined in the XIOS context
!>
subroutine checkpoint_read_integer_value(io_value, value_name)
class(integer_io_value_type), intent(inout) :: io_value
character(*), optional, intent(in) :: value_name
character(str_def) :: restart_id
integer(i_def) :: array_dims
integer(tik) :: timing_id
real(dp_xios), allocatable :: dp_equiv(:)

if ( LPROF ) call start_timing(timing_id, 'lfric_xios.chkpt_readv')
if ( LPROF ) call start_timing(timing_id, 'lfric_xios.chkpt_readiv')

if(present(value_name)) then
restart_id = trim(value_name)
Expand All @@ -132,15 +179,19 @@ subroutine checkpoint_read_value(io_value, value_name)
array_dims = size(io_value%data)

if ( xios_is_valid_field(trim(restart_id)) ) then
allocate(dp_equiv(array_dims))
call xios_recv_field( trim(restart_id), &
io_value%data(1:array_dims) )
dp_equiv(1:array_dims) )
io_value%data = int(dp_equiv,i_def)
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(restart_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
if ( LPROF ) call stop_timing(timing_id, 'lfric_xios.chkpt_readv')

end subroutine checkpoint_read_value
if ( LPROF ) call stop_timing(timing_id, 'lfric_xios.chkpt_readiv')

end subroutine checkpoint_read_integer_value

!> @brief Post-processing after reading field data
!> @details Performs a halo swap if necessary
Expand Down
128 changes: 105 additions & 23 deletions components/lfric-xios/source/lfric_xios_write_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module lfric_xios_write_mod
use field_real32_mod, only: field_real32_type, field_real32_proxy_type
use field_real64_mod, only: field_real64_type, field_real64_proxy_type
use io_value_mod, only: io_value_type
use integer_io_value_mod, only: integer_io_value_type
use key_value_mod, only: key_value_type, abstract_key_value_type, &
abstract_value_type
use key_value_collection_mod, &
Expand Down Expand Up @@ -67,39 +68,74 @@ module lfric_xios_write_mod
write_field_generic, &
write_empty_field, &
checkpoint_write_value, &
checkpoint_write_r_def_value, &
checkpoint_write_integer_value, &
write_value_generic, &
write_state, &
write_checkpoint, &
create_checkpoint_list

interface checkpoint_write_value
procedure :: checkpoint_write_r_def_value
procedure :: checkpoint_write_integer_value
end interface checkpoint_write_value

contains

!> @brief Write io_value data via XIOS
!> @details This routine assumes there is a XIOS field defined
!> with a field id the same as the io_value id
!> @param[in,out] io_value The io_value to write data from
!> @param[in] io_value The io_value to write data from
!> @param[in] value_name The id defined in the XIOS context
!>
subroutine write_value_generic(io_value, value_name)
class(io_value_type), intent(inout) :: io_value
class(abstract_value_type), intent(in) :: io_value
character(*), optional, intent(in) :: value_name

integer(i_def) :: array_dims
character(:), allocatable :: value_id
integer(i_def) :: array_dims
character(:), allocatable :: value_id
real(dp_xios), allocatable :: dp_equiv(:)

if (present(value_name)) then
value_id = value_name
else
value_id = io_value%io_id
end if
select type(io_value)
type is (io_value_type)
if (present(value_name)) then
value_id = value_name
else
value_id = io_value%io_id
end if

array_dims = size(io_value%data)
if ( xios_is_valid_field(trim(value_id)) ) then
call xios_send_field( trim(value_id), &
reshape(io_value%data, (/ 1, array_dims /)) )
else
call log_event( 'No XIOS field with id="'//trim(io_value%io_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
array_dims = size(io_value%data)
if ( xios_is_valid_field(trim(value_id)) ) then
! Support 32-bit and 64-bit input by converting to XIOS real kind
allocate(dp_equiv(array_dims))
dp_equiv = real(io_value%data, dp_xios)
call xios_send_field( trim(value_id), &
reshape(dp_equiv, (/ 1, array_dims /)) )
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(io_value%io_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
type is (integer_io_value_type)
if (present(value_name)) then
value_id = value_name
else
value_id = io_value%io_id
end if

array_dims = size(io_value%data)
if ( xios_is_valid_field(trim(value_id)) ) then
! Integers must be converted to XIOS real kind
allocate(dp_equiv(array_dims))
dp_equiv = real(io_value%data,dp_xios)
call xios_send_field( trim(value_id), &
reshape(dp_equiv, (/ 1, array_dims /)) )
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(io_value%io_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
Comment on lines +126 to +137
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is a repetition of the XIOS real conversion above, would it make more sense to move this into a small helper subroutine to improve readability and future maintenance ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The io_value object is an abstract type. The select type disambiguates between either io_value_type or integer_io_value_type so that within the first block io_value behaves as an io_value_type but within the second it behaves as an integer_io_value_type. So two helper subroutines would be needed to satisfy the two types!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Steve Mullerworth (@stevemullerworth), this is super helpful, I may need to pick your brains some more to understand this further but for now I'm happy for this to head into testing and then onto main :) .

end select

end subroutine write_value_generic

Expand Down Expand Up @@ -181,17 +217,52 @@ subroutine write_empty_field(field_name, field_proxy)

end subroutine write_empty_field

!> @brief Checkpoint an io_value with XIOS
!> @brief Checkpoint an r_def io_value with XIOS
!> @details This routine assumes there is an XIOS field
!> with the "checkpoint_" prefix
!> @param[in] io_value The io_value to write data from
!> @param[in] value_name The id defined in the XIOS context
!>
subroutine checkpoint_write_r_def_value(io_value, value_name)
class(io_value_type), intent(in) :: io_value
character(*), optional, intent(in) :: value_name

character(str_def) :: checkpoint_id
integer(i_def) :: array_dims
real(dp_xios), allocatable :: dp_equiv(:)

if(present(value_name)) then
checkpoint_id = trim(value_name)
else
checkpoint_id = trim(io_value%io_id)
end if
array_dims = size(io_value%data)
if ( xios_is_valid_field(trim(checkpoint_id)) ) then
allocate(dp_equiv(array_dims))
dp_equiv = real(io_value%data, dp_xios)
call xios_send_field( trim(checkpoint_id), &
reshape(dp_equiv, (/ 1, array_dims /)) )
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(checkpoint_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
Comment on lines +239 to +249
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to the last comment the moving of this block to a subroutine would benefit the code here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reply as above


end subroutine checkpoint_write_r_def_value

!> @brief Checkpoint an integer io_value with XIOS
!> @details This routine assumes there is an XIOS field
!> with the "checkpoint_" prefix
!> @param[in,out] io_value The io_value to write data from
!> @param[in] io_value The io_value to write data from
!> @param[in] value_name The id defined in the XIOS context
!>
subroutine checkpoint_write_value(io_value, value_name)
class(io_value_type), intent(inout) :: io_value
subroutine checkpoint_write_integer_value(io_value, value_name)
class(integer_io_value_type), intent(in) :: io_value
character(*), optional, intent(in) :: value_name

character(str_def) :: checkpoint_id
integer(i_def) :: array_dims
real(dp_xios), allocatable :: dp_equiv(:)

if(present(value_name)) then
checkpoint_id = trim(value_name)
Expand All @@ -200,14 +271,17 @@ subroutine checkpoint_write_value(io_value, value_name)
end if
array_dims = size(io_value%data)
if ( xios_is_valid_field(trim(checkpoint_id)) ) then
allocate(dp_equiv(array_dims))
dp_equiv = real(io_value%data, dp_xios)
call xios_send_field( trim(checkpoint_id), &
reshape(io_value%data, (/ 1, array_dims /)) )
reshape(dp_equiv, (/ 1, array_dims /)) )
deallocate(dp_equiv)
else
call log_event( 'No XIOS field with id="'//trim(checkpoint_id)//'" is defined', &
LOG_LEVEL_ERROR )
end if
Comment on lines 272 to 282
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replacement also needs to happen here.


end subroutine checkpoint_write_value
end subroutine checkpoint_write_integer_value

!> @brief I/O handler for writing an XIOS netcdf checkpoint
!> @details Note this routine accepts a filename but doesn't use it - this is
Expand Down Expand Up @@ -482,6 +556,14 @@ subroutine write_checkpoint( fields, values, clock, checkpoint_stem_name, &
call io_value_object%write_checkpoint( &
trim(field_prefix) // trim(io_value_object%io_id))
end if
type is (integer_io_value_type)
if(io_value_object%can_write_checkpoint()) then
call log_event( 'Writing checkpoint for ' // &
trim(io_value_object%io_id), &
LOG_LEVEL_INFO )
call io_value_object%write_checkpoint( &
trim(field_prefix) // trim(io_value_object%io_id))
end if
end select
end select
end do
Expand Down
Loading
Loading