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
55 changes: 39 additions & 16 deletions components/lfric-xios/source/lfric_xios_context_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ module lfric_xios_context_mod
use field_mod, only : field_type
use file_mod, only : file_type
use io_context_mod, only : io_context_type, callback_clock_arg
use io_config_mod, only : file_convention, &
file_convention_ugrid, &
file_convention_cf
use lfric_xios_file_mod, only : lfric_xios_file_type
use lfric_mpi_mod, only : lfric_comm_type
use log_mod, only : log_event, log_scratch_space, &
Expand All @@ -24,6 +27,7 @@ module lfric_xios_context_mod
setup_xios_files
use lfric_xios_file_mod, only : lfric_xios_file_type
use linked_list_mod, only : linked_list_type, linked_list_item_type
use mesh_mod, only : mesh_type
use model_clock_mod, only : model_clock_type
use timer_mod, only : timer
use xios, only : xios_context, &
Expand All @@ -49,6 +53,9 @@ module lfric_xios_context_mod

logical :: uses_timer = .false.
logical :: xios_context_initialised = .false.
!> Flag denoting if this file is a UGRID Planar mesh file with
!> projected coordinates that have been scaled
logical :: ugrid_scaled_projected_coordinates = .false.

contains
private
Expand Down Expand Up @@ -112,6 +119,7 @@ subroutine initialise_xios_context( this, communicator, &
type(field_type), optional, intent(in) :: alt_panel_ids(:)
logical, optional, intent(in) :: start_at_zero

type(mesh_type), pointer :: mesh => null()
type(linked_list_item_type), pointer :: loop => null()
type(lfric_xios_file_type), pointer :: file => null()
logical :: zero_start
Expand All @@ -133,8 +141,17 @@ subroutine initialise_xios_context( this, communicator, &

! Run XIOS setup routines
call init_xios_calendar(model_clock, calendar, zero_start, this%context_clock_step)

call init_xios_dimensions(chi, panel_id, alt_coords, alt_panel_ids)
if (this%filelist%get_length() > 0) call setup_xios_files(this%filelist)
! Obtain information on whether the mesh is ugrid and planar here?
! This is to inform decisions on file post processing work around code path.
mesh => chi(1)%get_mesh()
if ( mesh%is_geometry_planar() .and. &
file_convention == file_convention_ugrid ) then
this%ugrid_scaled_projected_coordinates = .true.
end if
if (this%filelist%get_length() > 0) call setup_xios_files(this%filelist, &
this%ugrid_scaled_projected_coordinates)

if (associated(before_close)) call before_close(model_clock)

Expand Down Expand Up @@ -197,22 +214,28 @@ subroutine finalise_xios_context( this )
call log_event(log_scratch_space, log_level_debug)
call xios_context_finalize()

! We have closed the context on our end, but we need to make sure that XIOS
! has closed the files for all servers before we process them.
call init_wait()

! Close all files in list
if (this%filelist%get_length() > 0) then
loop => this%filelist%get_head()
do while (associated(loop))
select type( list_item => loop%payload )
type is (lfric_xios_file_type)
file => list_item
call file%file_close()
end select
loop => loop%next
end do
! Only take action if this is a regional model with UGRID Projected
! coordinates, as these are awaiting XIOS feature development
if ( this%ugrid_scaled_projected_coordinates ) then
call log_event("Closing file for post processing.", LOG_LEVEL_DEBUG)
! We have closed the context on our end, but we need to make sure that XIOS
! has closed the files for all servers before we process them.
call init_wait()

! Close all files in list
if (this%filelist%get_length() > 0) then
loop => this%filelist%get_head()
do while (associated(loop))
select type( list_item => loop%payload )
type is (lfric_xios_file_type)
file => list_item
call file%file_close()
end select
loop => loop%next
end do
end if
end if

this%xios_context_initialised = .false.
end if
nullify(loop)
Expand Down
31 changes: 27 additions & 4 deletions components/lfric-xios/source/lfric_xios_file_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ module lfric_xios_file_mod
logical :: is_diag = .false.
!> Flag denoting if the always-on sampling mode is selected
logical :: diag_always_on_sampling = .true.
!> Flag denoting if this file is a UGRID Planar mesh file with
!> projected coordinates that have been scaled
logical :: ugrid_scaled_projected_coordinates = .false.
!> Will the file be read again from the beginning once the end is reached
logical :: cyclic = .false.
!>
Expand Down Expand Up @@ -116,6 +119,7 @@ module lfric_xios_file_mod
procedure, public :: mode_is_write
procedure, public :: recv_fields
procedure, public :: send_fields
procedure, public :: set_ugrid_scaled_projected_coordinates
final :: lfric_xios_file_final

end type lfric_xios_file_type
Expand Down Expand Up @@ -312,10 +316,16 @@ subroutine file_close(self)
if (self%is_closed) return

if ( self%io_mode == FILE_MODE_WRITE ) then
call log_event( "Waiting for XIOS to close file ["//trim(self%path)//".nc]", &
log_level_debug )
call init_wait()
call process_output_file(trim(self%path)//".nc")
! Only take action if this is a regional model with UGRID Projected
! coordinates, as these are awaiting XIOS feature development
if ( self%ugrid_scaled_projected_coordinates ) then
call log_event( "Waiting for XIOS to close file ["//trim(self%path)//".nc]", &
log_level_debug )
call init_wait()
call log_event( "post processing file ["//trim(self%path)//".nc]", &
log_level_debug )
call process_output_file(trim(self%path)//".nc")
end if
end if

self%is_closed = .true.
Expand Down Expand Up @@ -570,4 +580,17 @@ subroutine lfric_xios_file_final(self)

end subroutine lfric_xios_file_final

!> @brief Setter for the file object ugrid_scaled_projected_coordinates
!> @param[in] ugrid_scaled_projected_coordinates Logical
!>
subroutine set_ugrid_scaled_projected_coordinates(self, ugrid_scaled_projected_coordinates)

implicit none
logical, intent(in) :: ugrid_scaled_projected_coordinates
class(lfric_xios_file_type), intent(inout) :: self

self%ugrid_scaled_projected_coordinates = ugrid_scaled_projected_coordinates

end subroutine set_ugrid_scaled_projected_coordinates

end module lfric_xios_file_mod
138 changes: 18 additions & 120 deletions components/lfric-xios/source/lfric_xios_process_output_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
! under which the code may be used.
!-------------------------------------------------------------------------------

!> @brief Module to hold routines for processing XIOS output for compliance
!> with downstream data requirements
!> @brief Module to only hold routines for re-processing files output by XIOS
!> where the configuration is unable to be delivered by XIOS.
!> The only facet in scope for this module is post processing projected
!> coordinates for UGRId specification files, pending new feature
!> development in XIOS. This is technical debt, and this
!> post processing approach should not be used for other file
!> manipulations.
!>
module lfric_xios_process_output_mod

Expand All @@ -21,24 +26,21 @@ module lfric_xios_process_output_mod
use lfric_ncdf_field_group_mod, only: lfric_ncdf_field_group_type
use lfric_ncdf_file_mod, only: lfric_ncdf_file_type
use lfric_xios_constants_mod, only: dp_xios
use lfric_xios_utils_mod, only: parse_date_as_xios, seconds_from_date
use log_mod, only: log_event, log_level_trace
use xios, only: xios_date, xios_get_start_date
use log_mod, only: log_event, log_level_trace, &
log_level_info

implicit none

public :: process_output_file, set_xios_geometry_planar
public :: process_output_file
private

! Public scaling factor for planar mesh coordinates to circumvent XIOS issue
real(kind=dp_xios), public, parameter :: xyz_scaling_factor = 1.0e-4_dp_xios

logical :: model_has_planar_geometry = .false.

contains

!> @brief Processes a NetCDF file produced by XIOS to align with the LFRic
!! UGRID file format
!> @brief Processes a NetCDF file produced by XIOS to work around
!> limmitations in UGRID projected coordinates only.
!>
!> @param[in] file_path The path to the NetCDF file to be edited
subroutine process_output_file(file_path)
Expand All @@ -53,7 +55,7 @@ subroutine process_output_file(file_path)
! Output processing must be done in serial
if (global_mpi%get_comm_rank() /= 0) return

call log_event("Processing output file: "//trim(file_path), log_level_trace)
call log_event("Processing output file: "//trim(file_path), log_level_info)

! If file has not been written out, then don't attempt to process it
inquire(file=trim(file_path), exist=file_exists)
Expand All @@ -64,41 +66,14 @@ subroutine process_output_file(file_path)
open_mode=FILE_OP_OPEN, &
io_mode=FILE_MODE_WRITE )

call format_version(file_ncdf)

if (file_convention == file_convention_ugrid) then
call format_mesh(file_ncdf)
end if

call format_time(file_ncdf)

call file_ncdf%close_file()

end subroutine process_output_file

!> @brief Tags output file with the current version number of the LFRic file
!! format
!>
!> @param[in] file_ncdf The netcdf file to be edited
subroutine format_version(file_ncdf)

implicit none

type(lfric_ncdf_file_type), intent(inout) :: file_ncdf

call file_ncdf%set_attribute("description", "LFRic file format v0.2.0")

select case(file_convention)
case (file_convention_ugrid)
call file_ncdf%set_attribute("Conventions", "UGRID-1.0")

case (file_convention_cf)
call file_ncdf%set_attribute("Conventions", "CF")

end select

end subroutine format_version

!> @brief Formats the mesh object in the output file
!>
!> @param[in] file_ncdf The netcdf file to be edited
Expand All @@ -114,83 +89,15 @@ subroutine format_mesh(file_ncdf)

mesh_var = lfric_ncdf_field_type("Mesh2d", file_ncdf)

if (model_has_planar_geometry) then
call mesh_var%set_char_attribute("geometry", "planar")
call fix_planar_coordinates(file_ncdf)
else
call mesh_var%set_char_attribute("geometry", "spherical")
end if
! This post process code should only be called on a file where
! the model has Planar geometry and is UGRID encoded.
! This is controlled by lfric_xios_context_mod,
! lfric_xios_file_mod and lfric_xios_setup_mod
call fix_planar_coordinates(file_ncdf)

end subroutine format_mesh


!> @brief Formats the time coordinate into CF compliant forecast metadata
!>
!> @param[in] file_ncdf The netcdf file to be edited
subroutine format_time(output_file)

implicit none

type(lfric_ncdf_file_type), intent(in) :: output_file
! In the future we may need an optional argument to determine the expected
! name of the time axis

type(lfric_ncdf_dims_type) :: time_dims
type(lfric_ncdf_field_type) :: time_field, frt_field, fp_field
type(lfric_ncdf_field_group_type) :: fields_in_file, time_var_fields
type(xios_date) :: time_origin_date, model_start_date
character(:), allocatable :: time_var_name, time_dim_name
real(r_def), allocatable :: time_data(:), fp(:)
real(r_def) :: frt(1)
integer(i_def) :: i

! Set time variable and dimension names
time_var_name = "time"
time_dim_name = "time"

! Files that contain no time-variation will not have a time
! variable/dimension, so they do not need to be processed
if (.not. output_file%contains_var(trim(time_var_name))) return

! Read the time data from the output file
time_field = lfric_ncdf_field_type(trim(time_var_name), output_file)
time_dims = lfric_ncdf_dims_type(trim(time_dim_name), output_file)
allocate(time_data(time_dims%get_size()))
call time_field%read_data(time_data)

! Calculate forecast metadata using XIOS calendar
time_origin_date = parse_date_as_xios( &
trim(adjustl(time_field%get_char_attribute("time_origin"))) )
call xios_get_start_date(model_start_date)
frt(1) = seconds_from_date(model_start_date) - &
seconds_from_date(time_origin_date)

allocate(fp(time_dims%get_size()))
do i = 1, time_dims%get_size()
fp(i) = time_data(i) - seconds_from_date(time_origin_date)
end do

! Setup netCDF fields for forecast metadata
frt_field = lfric_ncdf_field_type("forecast_reference_time", output_file)
call frt_field%write_data(frt)
call frt_field%set_char_attribute("units", "seconds since "// &
trim(adjustl(time_field%get_char_attribute("time_origin"))))
call frt_field%set_char_attribute("calendar", time_field%get_char_attribute("calendar"))
call frt_field%set_char_attribute("standard_name", "forecast_reference_time")

fp_field = lfric_ncdf_field_type("forecast_period", output_file, time_dims)
call fp_field%write_data(fp)
call fp_field%set_char_attribute("units", "seconds")
call fp_field%set_char_attribute("standard_name", "forecast_period")

! Set forecast metadata as time coordinates
fields_in_file = lfric_ncdf_field_group_type(output_file, output_file%get_all_varids())
time_var_fields = fields_in_file%get_group_subset(dimension=time_dims)
call time_var_fields%add_coordinate("forecast_reference_time")
call time_var_fields%add_coordinate("forecast_period")

end subroutine format_time

!> @brief Fixes issues with planar coordinates in output file
!>
!> @param[in] file_ncdf The netcdf file to be edited
Expand Down Expand Up @@ -224,13 +131,4 @@ subroutine fix_planar_coordinates(file_ncdf)

end subroutine fix_planar_coordinates

!> @brief Specifies that the model is running on a mesh with planar geometry
subroutine set_xios_geometry_planar()

implicit none

model_has_planar_geometry = .true.

end subroutine set_xios_geometry_planar

end module lfric_xios_process_output_mod
Loading
Loading