From afd71b1b3ceb8f0d6e306fe0faa94820017b3596 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Mon, 15 Jul 2024 13:24:41 -0600 Subject: [PATCH] tracer_forcing_utils moved into MOM_interpolate To make these subroutines more accessible, they were moved out of src/tracer/ and made available through MOM_interpolate --- src/framework/MOM_interpolate.F90 | 77 ++++++++++++++++++++++++- src/tracer/MARBL_tracers.F90 | 6 +- src/tracer/tracer_forcing_utils.F90 | 88 ----------------------------- 3 files changed, 79 insertions(+), 92 deletions(-) delete mode 100644 src/tracer/tracer_forcing_utils.F90 diff --git a/src/framework/MOM_interpolate.F90 b/src/framework/MOM_interpolate.F90 index e131e8db9d..9c725f7f1a 100644 --- a/src/framework/MOM_interpolate.F90 +++ b/src/framework/MOM_interpolate.F90 @@ -10,13 +10,27 @@ module MOM_interpolate use MOM_interp_infra, only : horiz_interp_type, get_external_field_info use MOM_interp_infra, only : run_horiz_interp, build_horiz_interp_weights use MOM_interp_infra, only : external_field -use MOM_time_manager, only : time_type +use MOM_time_manager, only : time_type, real_to_time, operator(+), operator(<), operator(>) implicit none ; private +!> Data type used to store information about forcing datasets that are time series +!! E.g. how do we align the data in the model with the time axis in the file? +type, public :: forcing_timeseries_dataset + character(len=200) :: file_name !< name of file containing river flux forcing + logical :: l_time_varying !< .true. => forcing is dependent on model time, .false. => static forcing + ! logical :: l_FMS_modulo !< .true. => let FMS handle determining time level to read (e.g. for climatologies) + type(time_type) :: data_forcing !< convert data_forcing_year to time type + type(time_type) :: data_start !< convert data_start_year to time type + type(time_type) :: data_end !< convert data_end_year to time type + type(time_type) :: m2d_offset !< add to model time to get data time +end type forcing_timeseries_dataset + public :: time_interp_external, init_external_field, time_interp_external_init, get_external_field_info public :: horiz_interp_type, run_horiz_interp, build_horiz_interp_weights public :: external_field +public :: forcing_timeseries_set_time_type_vars +public :: map_model_time_to_forcing_time !> Read a field based on model time, and rotate to the model domain. interface time_interp_external @@ -210,4 +224,65 @@ subroutine time_interp_external_3d(field, time, data_in, interp, & end subroutine time_interp_external_3d +!> Set time_type variables in forcing_timeseries_dataset type based on integer input +!! TODO: make this part of forcing_timeseries_dataset class if OO is okay in MOM6? +subroutine forcing_timeseries_set_time_type_vars(data_start_year, data_end_year, data_ref_year, & + model_ref_year, data_forcing_year, forcing_dataset) + + integer, intent(in) :: data_start_year !< first year of data to read + !! (this is ignored for static forcing) + integer, intent(in) :: data_end_year !< last year of data to read + !! (this is ignored for static forcing) + integer, intent(in) :: data_ref_year !< for time-varying forcing, align + !! data_ref_year in file with + !! model_ref_year in model + integer, intent(in) :: model_ref_year !< for time-varying forcing, align + !! data_ref_year in file with + !! model_ref_year in model + integer, intent(in) :: data_forcing_year !< for static forcing, read file at this + !! date (this is ignored for time-varying + !! forcing) + type(forcing_timeseries_dataset), intent(inout) :: forcing_dataset !< information about forcing file + + if (forcing_dataset%l_time_varying) then + forcing_dataset%data_start = real_to_time(year_to_sec(data_start_year)) + forcing_dataset%data_end = real_to_time(year_to_sec(data_end_year)) + forcing_dataset%m2d_offset = real_to_time(year_to_sec(data_ref_year - model_ref_year)) + else + forcing_dataset%data_forcing = real_to_time(year_to_sec(data_forcing_year)) + endif + +end subroutine forcing_timeseries_set_time_type_vars + +!> If necessary, apply an offset to convert from model time to forcing time and then +!! ensure result is within acceptable bounds +function map_model_time_to_forcing_time(Time, forcing_dataset) + + type(time_type), intent(in) :: Time !< Model time + type(forcing_timeseries_dataset), intent(in) :: forcing_dataset !< information about forcing file + type(time_type) :: map_model_time_to_forcing_time !< time to read forcing file + + if (forcing_dataset%l_time_varying) then + map_model_time_to_forcing_time = Time + forcing_dataset%m2d_offset + ! If Time + offset is not between data_start and data_end, use whichever of those values is closer + if (map_model_time_to_forcing_time < forcing_dataset%data_start) & + map_model_time_to_forcing_time = forcing_dataset%data_start + if (map_model_time_to_forcing_time > forcing_dataset%data_end) & + map_model_time_to_forcing_time = forcing_dataset%data_end + else + map_model_time_to_forcing_time = forcing_dataset%data_forcing + endif + +end function map_model_time_to_forcing_time + +!> real_to_time converts from seconds since 0001-01-01 to time_type so we need to convert from years -> seconds +function year_to_sec(year) + + integer, intent(in) :: year + real :: year_to_sec + + year_to_sec = 86400. * 365. * real(year-1) + +end function year_to_sec + end module MOM_interpolate diff --git a/src/tracer/MARBL_tracers.F90 b/src/tracer/MARBL_tracers.F90 index fc93994044..359dd23720 100644 --- a/src/tracer/MARBL_tracers.F90 +++ b/src/tracer/MARBL_tracers.F90 @@ -17,6 +17,9 @@ module MARBL_tracers use MOM_interpolate, only : external_field, init_external_field, time_interp_external use MOM_CVMix_KPP, only : KPP_NonLocalTransport, KPP_CS use MOM_hor_index, only : hor_index_type +use MOM_interpolate, only : forcing_timeseries_dataset +use MOM_interpolate, only : forcing_timeseries_set_time_type_vars +use MOM_interpolate, only : map_model_time_to_forcing_time use MOM_io, only : file_exists, MOM_read_data, slasher, vardesc, var_desc, query_vardesc use MOM_open_boundary, only : ocean_OBC_type use MOM_remapping, only : reintegrate_column @@ -29,9 +32,6 @@ module MARBL_tracers use MOM_tracer_types, only : tracer_type, tracer_registry_type use MOM_tracer_diabatic, only : tracer_vertdiff, applyTracerBoundaryFluxesInOut use MOM_tracer_initialization_from_Z, only : MOM_initialize_tracer_from_Z -use tracer_forcing_utils_mod, only : forcing_timeseries_dataset -use tracer_forcing_utils_mod, only : forcing_timeseries_set_time_type_vars -use tracer_forcing_utils_mod, only : map_model_time_to_forcing_time use MOM_tracer_Z_init, only : read_Z_edges use MOM_unit_scaling, only : unit_scale_type use MOM_variables, only : surface, thermo_var_ptrs diff --git a/src/tracer/tracer_forcing_utils.F90 b/src/tracer/tracer_forcing_utils.F90 deleted file mode 100644 index 99f618e075..0000000000 --- a/src/tracer/tracer_forcing_utils.F90 +++ /dev/null @@ -1,88 +0,0 @@ -!> This module provides a common framework for interacting with time_interp_external. -!! Its main goal is to allow for offsets between the time axis in the forcing file -!! and the model run itself. It also provides a mechanism for using specific dates -!! as earliest / latest dates to read from file (so use data_start until Time + m2d_offset -!! catches up, and use data_end once Time + m2doffset exceeds it) -module tracer_forcing_utils_mod - -use MOM_time_manager, only : time_type, real_to_time, operator(+), operator(<), operator(>) - -!> Data type used to store information about forcing datasets that are time series -!! E.g. how do we align the data in the model with the time axis in the file? -type, public :: forcing_timeseries_dataset - character(len=200) :: file_name !< name of file containing river flux forcing - logical :: l_time_varying !< .true. => forcing is dependent on model time, .false. => static forcing - ! logical :: l_FMS_modulo !< .true. => let FMS handle determining time level to read (e.g. for climatologies) - type(time_type) :: data_forcing !< convert data_forcing_year to time type - type(time_type) :: data_start !< convert data_start_year to time type - type(time_type) :: data_end !< convert data_end_year to time type - type(time_type) :: m2d_offset !< add to model time to get data time -end type forcing_timeseries_dataset - -public :: forcing_timeseries_set_time_type_vars -public :: map_model_time_to_forcing_time - -contains - - !> Set time_type variables in forcing_timeseries_dataset type based on integer input - !! TODO: make this part of forcing_timeseries_dataset class if OO is okay in MOM6? - subroutine forcing_timeseries_set_time_type_vars(data_start_year, data_end_year, data_ref_year, & - model_ref_year, data_forcing_year, forcing_dataset) - - integer, intent(in) :: data_start_year !< first year of data to read - !! (this is ignored for static forcing) - integer, intent(in) :: data_end_year !< last year of data to read - !! (this is ignored for static forcing) - integer, intent(in) :: data_ref_year !< for time-varying forcing, align - !! data_ref_year in file with - !! model_ref_year in model - integer, intent(in) :: model_ref_year !< for time-varying forcing, align - !! data_ref_year in file with - !! model_ref_year in model - integer, intent(in) :: data_forcing_year !< for static forcing, read file at this - !! date (this is ignored for time-varying - !! forcing) - type(forcing_timeseries_dataset), intent(inout) :: forcing_dataset !< information about forcing file - - if (forcing_dataset%l_time_varying) then - forcing_dataset%data_start = real_to_time(year_to_sec(data_start_year)) - forcing_dataset%data_end = real_to_time(year_to_sec(data_end_year)) - forcing_dataset%m2d_offset = real_to_time(year_to_sec(data_ref_year - model_ref_year)) - else - forcing_dataset%data_forcing = real_to_time(year_to_sec(data_forcing_year)) - endif - - end subroutine forcing_timeseries_set_time_type_vars - - !> If necessary, apply an offset to convert from model time to forcing time and then - !! ensure result is within acceptable bounds - function map_model_time_to_forcing_time(Time, forcing_dataset) - - type(time_type), intent(in) :: Time !< Model time - type(forcing_timeseries_dataset), intent(in) :: forcing_dataset !< information about forcing file - type(time_type) :: map_model_time_to_forcing_time !< time to read forcing file - - if (forcing_dataset%l_time_varying) then - map_model_time_to_forcing_time = Time + forcing_dataset%m2d_offset - ! If Time + offset is not between data_start and data_end, use whichever of those values is closer - if (map_model_time_to_forcing_time < forcing_dataset%data_start) & - map_model_time_to_forcing_time = forcing_dataset%data_start - if (map_model_time_to_forcing_time > forcing_dataset%data_end) & - map_model_time_to_forcing_time = forcing_dataset%data_end - else - map_model_time_to_forcing_time = forcing_dataset%data_forcing - endif - - end function map_model_time_to_forcing_time - - !> real_to_time converts from seconds since 0001-01-01 to time_type so we need to convert from years -> seconds - function year_to_sec(year) - - integer, intent(in) :: year - real :: year_to_sec - - year_to_sec = 86400. * 365. * real(year-1) - - end function year_to_sec - -end module tracer_forcing_utils_mod \ No newline at end of file