From 63b1c5932a3dd53d8897a2e4c1fee5bfc1c4f352 Mon Sep 17 00:00:00 2001 From: Robert Hallberg Date: Sun, 28 Apr 2024 17:06:16 -0400 Subject: [PATCH] Add units to the descriptions of 79 variables This commit improves the documentation of the remaining real variables with previously undocumented units in the framework directory, with some other similar unit documentation improvements in other files. Units were added to comments describing about 79 real variables in 4 framework modules, atmos_ocean_fluxes.F90 for 2 drivers, MOM_oda_incupd.F90, MOM_oda_driver.F90 and MOM_variables.F90. The variable nhours_incupd in initialize_oda_incupd was renamed to incupd_timescale and the factor of 3600.0 that converts ODA_INCUPD_NHOURS from hours into seconds was moved from where this variable is used into the scale argument where it is set to help document the meaning and units of this variable as simply and clearly as possible. The unused variable smb was removed from Shelf_main in ice_shelf_driver.F90. The internal variable tmp in RGC_initialize_sponges was renamed rho to reflect its contents, and its contents and units are now described in a comment. Although the units have been added to the description in MEKE_vec as though it is being used in a dimensionally consistent way, I suspect that this might actually be in MKS units, in which case a unit conversion factor might be needed, and a comment has been added to note this. However, the machine learning code that is used to set this array comes from an external package that is not being used yet at GFDL, so it is not clear what code should be examined to address this question. A comment was added in set_up_global_tgrid noting a unit rescaling factor that appears to be missing from a dimensional constant. All answers are bitwise identical, and for the most part only comments are changed, although two internal variables were renamed. --- .../ice_solo_driver/atmos_ocean_fluxes.F90 | 7 ++- .../ice_solo_driver/ice_shelf_driver.F90 | 1 - .../solo_driver/atmos_ocean_fluxes.F90 | 7 ++- src/core/MOM_variables.F90 | 4 +- src/framework/MOM_coms.F90 | 50 ++++++++++--------- src/framework/MOM_coupler_types.F90 | 46 ++++++++++++----- src/framework/MOM_intrinsic_functions.F90 | 8 +-- src/framework/MOM_random.F90 | 12 ++--- src/ocean_data_assim/MOM_oda_driver.F90 | 10 +++- src/ocean_data_assim/MOM_oda_incupd.F90 | 42 +++++++++------- src/parameterizations/lateral/MOM_MEKE.F90 | 10 ++-- src/user/RGC_initialization.F90 | 6 +-- 12 files changed, 124 insertions(+), 79 deletions(-) diff --git a/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 b/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 index 4a4ddf6da3..fb9fbe3e22 100644 --- a/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 +++ b/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 @@ -20,9 +20,12 @@ function aof_set_coupler_flux(name, flux_type, implementation, atm_tr_index, character(len=*), intent(in) :: flux_type !< An unused argument character(len=*), intent(in) :: implementation !< An unused argument integer, optional, intent(in) :: atm_tr_index !< An unused argument - real, dimension(:), optional, intent(in) :: param !< An unused argument + real, dimension(:), optional, intent(in) :: param !< An unused argument that would be used to + !! pass parameters for flux parameterizations + !! in other contexts [various] logical, dimension(:), optional, intent(in) :: flag !< An unused argument - real, optional, intent(in) :: mol_wt !< An unused argument + real, optional, intent(in) :: mol_wt !< An unused argument that would usually be + !! the tracer's molecular weight [g mol-1] character(len=*), optional, intent(in) :: ice_restart_file !< An unused argument character(len=*), optional, intent(in) :: ocean_restart_file !< An unused argument character(len=*), optional, intent(in) :: units !< An unused argument diff --git a/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 b/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 index c4be8c769d..387f0442f9 100644 --- a/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 +++ b/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 @@ -142,7 +142,6 @@ program Shelf_main integer :: yr, mon, day, hr, mins, sec ! Temp variables for writing the date. type(param_file_type) :: param_file ! The structure indicating the file(s) ! containing all run-time parameters. - real :: smb !A constant surface mass balance that can be specified in the param_file character(len=9) :: month character(len=16) :: calendar = 'noleap' integer :: calendar_type=-1 diff --git a/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 b/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 index 4a4ddf6da3..fb9fbe3e22 100644 --- a/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 +++ b/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 @@ -20,9 +20,12 @@ function aof_set_coupler_flux(name, flux_type, implementation, atm_tr_index, character(len=*), intent(in) :: flux_type !< An unused argument character(len=*), intent(in) :: implementation !< An unused argument integer, optional, intent(in) :: atm_tr_index !< An unused argument - real, dimension(:), optional, intent(in) :: param !< An unused argument + real, dimension(:), optional, intent(in) :: param !< An unused argument that would be used to + !! pass parameters for flux parameterizations + !! in other contexts [various] logical, dimension(:), optional, intent(in) :: flag !< An unused argument - real, optional, intent(in) :: mol_wt !< An unused argument + real, optional, intent(in) :: mol_wt !< An unused argument that would usually be + !! the tracer's molecular weight [g mol-1] character(len=*), optional, intent(in) :: ice_restart_file !< An unused argument character(len=*), optional, intent(in) :: ocean_restart_file !< An unused argument character(len=*), optional, intent(in) :: units !< An unused argument diff --git a/src/core/MOM_variables.F90 b/src/core/MOM_variables.F90 index cb20837d3b..2291e5bf17 100644 --- a/src/core/MOM_variables.F90 +++ b/src/core/MOM_variables.F90 @@ -31,11 +31,11 @@ module MOM_variables !> A structure for creating arrays of pointers to 3D arrays type, public :: p3d - real, dimension(:,:,:), pointer :: p => NULL() !< A pointer to a 3D array + real, dimension(:,:,:), pointer :: p => NULL() !< A pointer to a 3D array [various] end type p3d !> A structure for creating arrays of pointers to 2D arrays type, public :: p2d - real, dimension(:,:), pointer :: p => NULL() !< A pointer to a 2D array + real, dimension(:,:), pointer :: p => NULL() !< A pointer to a 2D array [various] end type p2d !> Pointers to various fields which may be used describe the surface state of MOM, and which diff --git a/src/framework/MOM_coms.F90 b/src/framework/MOM_coms.F90 index 38ad55fd96..e7c38d988d 100644 --- a/src/framework/MOM_coms.F90 +++ b/src/framework/MOM_coms.F90 @@ -26,8 +26,8 @@ module MOM_coms ! This module provides interfaces to the non-domain-oriented communication subroutines. integer(kind=8), parameter :: prec=2_8**46 !< The precision of each integer. -real, parameter :: r_prec=2.0**46 !< A real version of prec. -real, parameter :: I_prec=1.0/(2.0**46) !< The inverse of prec. +real, parameter :: r_prec=2.0**46 !< A real version of prec [nondim]. +real, parameter :: I_prec=1.0/(2.0**46) !< The inverse of prec [nondim]. integer, parameter :: max_count_prec=2**(63-46)-1 !< The number of values that can be added together !! with the current value of prec before there will @@ -37,12 +37,12 @@ module MOM_coms !< a real number. real, parameter, dimension(ni) :: & pr = (/ r_prec**2, r_prec, 1.0, 1.0/r_prec, 1.0/r_prec**2, 1.0/r_prec**3 /) - !< An array of the real precision of each of the integers + !< An array of the real precision of each of the integers in arbitrary units [a] real, parameter, dimension(ni) :: & I_pr = (/ 1.0/r_prec**2, 1.0/r_prec, 1.0, r_prec, r_prec**2, r_prec**3 /) - !< An array of the inverse of the real precision of each of the integers + !< An array of the inverse of the real precision of each of the integers in arbitrary units [a-1] real, parameter :: max_efp_float = pr(1) * (2.**63 - 1.) - !< The largest float with an EFP representation. + !< The largest float with an EFP representation in arbitrary units [a]. !! NOTE: Only the first bin can exceed precision, !! but is bounded by the largest signed integer. @@ -91,7 +91,7 @@ module MOM_coms !! using EFP_to_real. This technique is described in Hallberg & Adcroft, 2014, Parallel Computing, !! doi:10.1016/j.parco.2014.04.007. function reproducing_EFP_sum_2d(array, isr, ier, jsr, jer, overflow_check, err, only_on_PE) result(EFP_sum) - real, dimension(:,:), intent(in) :: array !< The array to be summed + real, dimension(:,:), intent(in) :: array !< The array to be summed in arbitrary units [a] integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting !! that the array indices starts at 1 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting @@ -117,8 +117,8 @@ function reproducing_EFP_sum_2d(array, isr, ier, jsr, jer, overflow_check, err, integer(kind=8), dimension(ni) :: ints_sum integer(kind=8) :: ival, prec_error - real :: rs - real :: max_mag_term + real :: rs ! The remaining value to add, in arbitrary units [a] + real :: max_mag_term ! A running maximum magnitude of the values in arbitrary units [a] logical :: over_check, do_sum_across_PEs character(len=256) :: mesg integer :: i, j, n, is, ie, js, je, sgn @@ -218,7 +218,7 @@ end function reproducing_EFP_sum_2d !! doi:10.1016/j.parco.2014.04.007. function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, & overflow_check, err, only_on_PE) result(sum) - real, dimension(:,:), intent(in) :: array !< The array to be summed + real, dimension(:,:), intent(in) :: array !< The array to be summed in arbitrary units [a] integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting !! that the array indices starts at 1 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting @@ -239,7 +239,7 @@ function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, & !! this routine. logical, optional, intent(in) :: only_on_PE !< If present and true, do not do the sum !! across processors, only reporting the local sum - real :: sum !< Result + real :: sum !< The sum of the values in array in arbitrary units [a] ! This subroutine uses a conversion to an integer representation ! of real numbers to give order-invariant sums that will reproduce @@ -247,7 +247,7 @@ function reproducing_sum_2d(array, isr, ier, jsr, jer, EFP_sum, reproducing, & integer(kind=8), dimension(ni) :: ints_sum integer(kind=8) :: prec_error - real :: rsum(1) + real :: rsum(1) ! The running sum, in arbitrary units [a] logical :: repro, do_sum_across_PEs character(len=256) :: mesg type(EFP_type) :: EFP_val ! An extended fixed point version of the sum @@ -323,7 +323,7 @@ end function reproducing_sum_2d !! doi:10.1016/j.parco.2014.04.007. function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, EFP_lay_sums, err, only_on_PE) & result(sum) - real, dimension(:,:,:), intent(in) :: array !< The array to be summed + real, dimension(:,:,:), intent(in) :: array !< The array to be summed in arbitrary units [a] integer, optional, intent(in) :: isr !< The starting i-index of the sum, noting !! that the array indices starts at 1 integer, optional, intent(in) :: ier !< The ending i-index of the sum, noting @@ -332,7 +332,7 @@ function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, EFP_lay_su !! that the array indices starts at 1 integer, optional, intent(in) :: jer !< The ending j-index of the sum, noting !! that the array indices starts at 1 - real, dimension(:), optional, intent(out) :: sums !< The sums by vertical layer + real, dimension(:), optional, intent(out) :: sums !< The sums by vertical layer in abitrary units [a] type(EFP_type), optional, intent(out) :: EFP_sum !< The result in extended fixed point format type(EFP_type), dimension(:), & optional, intent(out) :: EFP_lay_sums !< The sums by vertical layer in EFP format @@ -341,13 +341,14 @@ function reproducing_sum_3d(array, isr, ier, jsr, jer, sums, EFP_sum, EFP_lay_su !! this routine. logical, optional, intent(in) :: only_on_PE !< If present and true, do not do the sum !! across processors, only reporting the local sum - real :: sum !< Result + real :: sum !< The sum of the values in array in arbitrary units [a] ! This subroutine uses a conversion to an integer representation ! of real numbers to give order-invariant sums that will reproduce ! across PE count. This idea comes from R. Hallberg and A. Adcroft. - real :: val, max_mag_term + real :: val ! The real number that is extracted in arbitrary units [a] + real :: max_mag_term ! A running maximum magnitude of the val's in arbitrary units [a] integer(kind=8), dimension(ni) :: ints_sum integer(kind=8), dimension(ni,size(array,3)) :: ints_sums integer(kind=8) :: prec_error @@ -506,7 +507,7 @@ end function reproducing_sum_3d !> Convert a real number into the array of integers constitute its extended-fixed-point representation function real_to_ints(r, prec_error, overflow) result(ints) - real, intent(in) :: r !< The real number being converted + real, intent(in) :: r !< The real number being converted in arbitrary units [a] integer(kind=8), optional, intent(in) :: prec_error !< The PE-count dependent precision of the !! integers that is safe from overflows during global !! sums. This will be larger than the compile-time @@ -517,7 +518,7 @@ function real_to_ints(r, prec_error, overflow) result(ints) ! This subroutine converts a real number to an equivalent representation ! using several long integers. - real :: rs + real :: rs ! The remaining value to add, in arbitrary units [a] character(len=80) :: mesg integer(kind=8) :: ival, prec_err integer :: sgn, i @@ -549,7 +550,7 @@ end function real_to_ints !! representation into a real number function ints_to_real(ints) result(r) integer(kind=8), dimension(ni), intent(in) :: ints !< The array of EFP integers - real :: r + real :: r ! The real number that is extracted in arbitrary units [a] ! This subroutine reverses the conversion in real_to_ints. integer :: i @@ -596,13 +597,14 @@ end subroutine increment_ints !! of overflows and using only minimal error checking. subroutine increment_ints_faster(int_sum, r, max_mag_term) integer(kind=8), dimension(ni), intent(inout) :: int_sum !< The array of EFP integers being incremented - real, intent(in) :: r !< The real number being added. - real, intent(inout) :: max_mag_term !< A running maximum magnitude of the r's. + real, intent(in) :: r !< The real number being added in arbitrary units [a] + real, intent(inout) :: max_mag_term !< A running maximum magnitude of the r's + !! in arbitrary units [a] ! This subroutine increments a number with another, both using the integer ! representation in real_to_ints, but without doing any carrying of overflow. ! The entire operation is embedded in a single call for greater speed. - real :: rs + real :: rs ! The remaining value to add, in arbitrary units [a] integer(kind=8) :: ival integer :: sgn, i @@ -740,7 +742,7 @@ end subroutine EFP_assign !> Return the real number that an extended-fixed-point number corresponds with function EFP_to_real(EFP1) type(EFP_type), intent(inout) :: EFP1 !< The extended fixed point number being converted - real :: EFP_to_real + real :: EFP_to_real !< The real version of the number in abitrary units [a] call regularize_ints(EFP1%v) EFP_to_real = ints_to_real(EFP1%v) @@ -752,7 +754,7 @@ function EFP_real_diff(EFP1, EFP2) type(EFP_type), intent(in) :: EFP1 !< The first extended fixed point number type(EFP_type), intent(in) :: EFP2 !< The extended fixed point number being !! subtracted from the first extended fixed point number - real :: EFP_real_diff !< The real result + real :: EFP_real_diff !< The real result in arbitrary units [a] type(EFP_type) :: EFP_diff @@ -763,7 +765,7 @@ end function EFP_real_diff !> Return the extended-fixed-point number that a real number corresponds with function real_to_EFP(val, overflow) - real, intent(in) :: val !< The real number being converted + real, intent(in) :: val !< The real number being converted in arbitrary units [a] logical, optional, intent(inout) :: overflow !< Returns true if the conversion is being !! done on a value that is too large to be represented type(EFP_type) :: real_to_EFP diff --git a/src/framework/MOM_coupler_types.F90 b/src/framework/MOM_coupler_types.F90 index f87b409694..1baef24f76 100644 --- a/src/framework/MOM_coupler_types.F90 +++ b/src/framework/MOM_coupler_types.F90 @@ -246,11 +246,15 @@ end subroutine CT_copy_data_2d_3d !> Increment data in all elements of one coupler_2d_bc_type with the data from another. Both !! must have the same array sizes. subroutine CT_increment_data_2d(var_in, var, halo_size, scale_factor, scale_prev) - type(coupler_2d_bc_type), intent(in) :: var_in !< coupler_type structure with the data to add to the other type - type(coupler_2d_bc_type), intent(inout) :: var !< The coupler_type structure whose fields are being incremented + type(coupler_2d_bc_type), intent(in) :: var_in !< A coupler_type structure with data in arbitrary + !! arbitrary units [A] to add to the other type + type(coupler_2d_bc_type), intent(inout) :: var !< A coupler_type structure with data in arbitrary + !! units [B] whose fields are being incremented integer, optional, intent(in) :: halo_size !< The extent of the halo to increment; 0 by default real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added + !! in arbitrary units [C A-1] real, optional, intent(in) :: scale_prev !< A scaling factor for the data that is already here + !! in arbitrary units [C B-1] call CT_increment_data(var_in, var, halo_size=halo_size, scale_factor=scale_factor, & scale_prev=scale_prev) @@ -260,11 +264,15 @@ end subroutine CT_increment_data_2d !> Increment data in all elements of one coupler_3d_bc_type with the data from another. Both !! must have the same array sizes. subroutine CT_increment_data_3d(var_in, var, halo_size, scale_factor, scale_prev, exclude_flux_type, only_flux_type) - type(coupler_3d_bc_type), intent(in) :: var_in !< coupler_type structure with the data to add to the other type - type(coupler_3d_bc_type), intent(inout) :: var !< The coupler_type structure whose fields are being incremented + type(coupler_3d_bc_type), intent(in) :: var_in !< A coupler_type structure with data in arbitrary + !! arbitrary units [A] to add to the other type + type(coupler_3d_bc_type), intent(inout) :: var !< A coupler_type structure with data in arbitrary + !! units [B] whose fields are being incremented integer, optional, intent(in) :: halo_size !< The extent of the halo to increment; 0 by default real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added + !! in arbitrary units [C A-1] real, optional, intent(in) :: scale_prev !< A scaling factor for the data that is already here + !! in arbitrary units [C B-1] character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types !! of fluxes to exclude from this increment. character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types @@ -281,7 +289,7 @@ end subroutine CT_increment_data_3d subroutine CT_increment_data_2d_3d(var_in, weights, var, halo_size) type(coupler_3d_bc_type), intent(in) :: var_in !< coupler_type structure with the data to add to the other type real, dimension(:,:,:), intent(in) :: weights !< An array of normalized weights for the 3d-data to - !! increment the 2d-data. There is no renormalization, + !! increment the 2d-data [nondim]. There is no renormalization, !! so if the weights do not sum to 1 in the 3rd dimension !! there may be adverse consequences! type(coupler_2d_bc_type), intent(inout) :: var !< The coupler_type structure whose fields are being incremented @@ -294,8 +302,11 @@ end subroutine CT_increment_data_2d_3d !> Rescales the fields in the elements of a coupler_2d_bc_type by multiplying by a factor scale. !! If scale is 0, this is a direct assignment to 0, so that NaNs will not persist. subroutine CT_rescale_data_2d(var, scale) - type(coupler_2d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being rescaled - real, intent(in) :: scale !< A scaling factor to multiply fields by + type(coupler_2d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being rescaled, + !! with the internal data units perhaps changing from + !! arbitrary units [A] to other arbitrary units [B] + real, intent(in) :: scale !< A scaling factor to multiply fields by in + !! arbitrary units [B A-1] call CT_rescale_data(var, scale) @@ -304,8 +315,11 @@ end subroutine CT_rescale_data_2d !> Rescales the fields in the elements of a coupler_3d_bc_type by multiplying by a factor scale. !! If scale is 0, this is a direct assignment to 0, so that NaNs will not persist. subroutine CT_rescale_data_3d(var, scale) - type(coupler_3d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being rescaled - real, intent(in) :: scale !< A scaling factor to multiply fields by + type(coupler_3d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being rescaled, + !! with the internal data units perhaps changing from + !! arbitrary units [A] to other arbitrary units [B] + real, intent(in) :: scale !< A scaling factor to multiply fields by in + !! arbitrary units [B A-1] call CT_rescale_data(var, scale) @@ -351,12 +365,15 @@ end subroutine coupler_type_data_override subroutine extract_coupler_type_data(var_in, bc_index, array_out, scale_factor, & halo_size, idim, jdim, field_index) type(coupler_2d_bc_type), intent(in) :: var_in !< BC_type structure with the data to extract + !! The internal data has arbitrary units [B]. integer, intent(in) :: bc_index !< The index of the boundary condition !! that is being copied - real, dimension(1:,1:), intent(out) :: array_out !< The recipient array for the field; its size + real, dimension(1:,1:), intent(out) :: array_out !< The recipient array for the field in + !! arbitrary units [A]; the size of this array !! must match the size of the data being copied !! unless idim and jdim are supplied. - real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added + real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being + !! extracted, in arbitrary units [A B-1] integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default integer, dimension(4), optional, intent(in) :: idim !< The data and computational domain extents of !! the first dimension of the output array @@ -382,16 +399,19 @@ end subroutine extract_coupler_type_data !! MOM-specific interface. subroutine set_coupler_type_data(array_in, bc_index, var, solubility, scale_factor, & halo_size, idim, jdim, field_index) - real, dimension(1:,1:), intent(in) :: array_in !< The source array for the field; its size + real, dimension(1:,1:), intent(in) :: array_in !< The source array for the field in + !! arbitrary units [A]; the size of this array !! must match the size of the data being copied !! unless idim and jdim are supplied. integer, intent(in) :: bc_index !< The index of the boundary condition !! that is being copied type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure with the data to set + !! The internal data has arbitrary units [B]. logical, optional, intent(in) :: solubility !< If true and field index is missing, set !! the solubility field. Otherwise set the !! surface concentration (the default). - real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added + real, optional, intent(in) :: scale_factor !< A scaling factor for the data that is being + !! set, in arbitrary units [B A-1] integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default integer, dimension(4), optional, intent(in) :: idim !< The data and computational domain extents of !! the first dimension of the output array diff --git a/src/framework/MOM_intrinsic_functions.F90 b/src/framework/MOM_intrinsic_functions.F90 index ae0a68df5f..3fd9ace1ad 100644 --- a/src/framework/MOM_intrinsic_functions.F90 +++ b/src/framework/MOM_intrinsic_functions.F90 @@ -117,9 +117,9 @@ end function cuberoot !> Rescale `a` to the range [0.125, 1) and compute its cube-root exponent. pure subroutine rescale_cbrt(a, x, e_r, s_a) real, intent(in) :: a - !< The real parameter to be rescaled for cube root + !< The real parameter to be rescaled for cube root in abitrary units cubed [A3] real, intent(out) :: x - !< The rescaled value of a + !< The rescaled value of a in the range from 0.125 < asx <= 1.0, in ambiguous units cubed [B3] integer(kind=int64), intent(out) :: e_r !< Cube root of the exponent of the rescaling of `a` integer(kind=int64), intent(out) :: s_a @@ -162,13 +162,13 @@ end subroutine rescale_cbrt !> Undo the rescaling of a real number back to its original base. pure function descale(x, e_a, s_a) result(a) real, intent(in) :: x - !< The rescaled value which is to be restored. + !< The rescaled value which is to be restored in ambiguous units [B] integer(kind=int64), intent(in) :: e_a !< Exponent of the unscaled value integer(kind=int64), intent(in) :: s_a !< Sign bit of the unscaled value real :: a - !< Restored value with the corrected exponent and sign + !< Restored value with the corrected exponent and sign in abitrary units [A] integer(kind=int64) :: xb ! Bit-packed real number into integer form diff --git a/src/framework/MOM_random.F90 b/src/framework/MOM_random.F90 index f5e996d3e4..6fcc6903c9 100644 --- a/src/framework/MOM_random.F90 +++ b/src/framework/MOM_random.F90 @@ -99,7 +99,7 @@ end function random_norm subroutine random_2d_01(CS, HI, rand) type(PRNG), intent(inout) :: CS !< Container for pseudo-random number generators type(hor_index_type), intent(in) :: HI !< Horizontal index structure - real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), intent(out) :: rand !< Random numbers between 0 and 1 + real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), intent(out) :: rand !< Random numbers between 0 and 1 [nondim] ! Local variables integer :: i,j @@ -116,7 +116,7 @@ end subroutine random_2d_01 subroutine random_2d_norm(CS, HI, rand) type(PRNG), intent(inout) :: CS !< Container for pseudo-random number generators type(hor_index_type), intent(in) :: HI !< Horizontal index structure - real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), intent(out) :: rand !< Random numbers between 0 and 1 + real, dimension(HI%isd:HI%ied,HI%jsd:HI%jed), intent(out) :: rand !< Random numbers between 0 and 1 [nondim] ! Local variables integer :: i,j,n @@ -318,14 +318,14 @@ logical function random_unit_tests(verbose) ! Local variables type(PRNG) :: test_rng ! Generator type(time_type) :: Time ! Model time - real :: r1, r2, r3 ! Some random numbers and re-used work variables - real :: mean, var, ar1, std ! Some statistics + real :: r1, r2, r3 ! Some random numbers and re-used work variables [nondim] + real :: mean, var, ar1, std ! Some statistics [nondim] integer :: stdunit ! For messages integer, parameter :: n_samples = 800 integer :: i, j, ni, nj ! Fake being on a decomposed domain type(hor_index_type), pointer :: HI => null() !< Not the real HI - real, dimension(:,:), allocatable :: r2d ! Random numbers + real, dimension(:,:), allocatable :: r2d ! Random numbers [nondim] ! Fake a decomposed domain ni = 6 @@ -547,7 +547,7 @@ logical function test_fn(verbose, good, label, rvalue, ivalue) logical, intent(in) :: verbose !< Verbosity logical, intent(in) :: good !< True if pass, false otherwise character(len=*), intent(in) :: label !< Label for messages - real, intent(in) :: rvalue !< Result of calculation + real, intent(in) :: rvalue !< Result of calculation [nondim] integer, intent(in) :: ivalue !< Result of calculation optional :: rvalue, ivalue diff --git a/src/ocean_data_assim/MOM_oda_driver.F90 b/src/ocean_data_assim/MOM_oda_driver.F90 index 6e24b9faee..8453ceb497 100644 --- a/src/ocean_data_assim/MOM_oda_driver.F90 +++ b/src/ocean_data_assim/MOM_oda_driver.F90 @@ -119,7 +119,7 @@ module MOM_oda_driver_mod logical :: use_basin_mask !< If true, use a basin file to delineate weakly coupled ocean basins logical :: do_bias_adjustment !< If true, use spatio-temporally varying climatological tendency !! adjustment for Temperature and Salinity - real :: bias_adjustment_multiplier !< A scaling for the bias adjustment + real :: bias_adjustment_multiplier !< A scaling for the bias adjustment [nondim] integer :: assim_method !< Method: NO_ASSIM,EAKF_ASSIM or OI_ASSIM integer :: ensemble_size !< Size of the ensemble integer :: ensemble_id = 0 !< id of the current ensemble member @@ -734,13 +734,17 @@ subroutine apply_oda_tracer_increments(dt, Time_end, G, GV, tv, h, CS) end subroutine apply_oda_tracer_increments +!> Set up the grid of thicknesses at tracer points throughout the global domain subroutine set_up_global_tgrid(T_grid, CS, G) type(grid_type), pointer :: T_grid !< global tracer grid type(ODA_CS), pointer, intent(in) :: CS !< A pointer to DA control structure. type(ocean_grid_type), pointer :: G !< domain and grid information for ocean model ! local variables - real, dimension(:,:), allocatable :: global2D, global2D_old + real, dimension(:,:), allocatable :: & + global2D, & ! A layer thickness in the entire global domain [H ~> m or kg m-2] + global2D_old ! The thickness of the layer above the one in global2D in the entire + ! global domain [H ~> m or kg m-2] integer :: i, j, k ! get global grid information from ocean_model @@ -769,6 +773,8 @@ subroutine set_up_global_tgrid(T_grid, CS, G) do k = 1, CS%nk call global_field(G%Domain%mpp_domain, CS%h(:,:,k), global2D) do i=1,CS%ni ; do j=1,CS%nj + ! ###Does the next line need to be revised? Perhaps it should be + ! if ( global2D(i,j) > 1.0*GV%H_to_m ) then if ( global2D(i,j) > 1 ) then T_grid%mask(i,j,k) = 1.0 endif diff --git a/src/ocean_data_assim/MOM_oda_incupd.F90 b/src/ocean_data_assim/MOM_oda_incupd.F90 index be57bbe748..d54d34506e 100644 --- a/src/ocean_data_assim/MOM_oda_incupd.F90 +++ b/src/ocean_data_assim/MOM_oda_incupd.F90 @@ -52,9 +52,11 @@ module MOM_oda_incupd type :: p3d integer :: id !< id for FMS external time interpolator integer :: nz_data !< The number of vertical levels in the input field. - real, dimension(:,:,:), pointer :: mask_in => NULL() !< pointer to the data mask. - real, dimension(:,:,:), pointer :: p => NULL() !< pointer to the data. - real, dimension(:,:,:), pointer :: h => NULL() !< pointer to the data grid. + real, dimension(:,:,:), pointer :: mask_in => NULL() !< pointer to the data mask (perhaps unused) [nondim] + real, dimension(:,:,:), pointer :: p => NULL() !< pointer to the data, in units that depend + !! on the field it refers to [various]. + real, dimension(:,:,:), pointer :: h => NULL() !< pointer to the data grid (perhaps unused) + !! in [H ~> m or kg m-2] end type p3d !> oda incupd control structure @@ -67,11 +69,12 @@ module MOM_oda_incupd type(p3d) :: Inc(MAX_FIELDS_) !< The increments to be applied to the field type(p3d) :: Inc_u !< The increments to be applied to the u-velocities, with data in [L T-1 ~> m s-1] type(p3d) :: Inc_v !< The increments to be applied to the v-velocities, with data in [L T-1 ~> m s-1] - type(p3d) :: Ref_h !< Vertical grid on which the increments are provided + type(p3d) :: Ref_h !< Vertical grid on which the increments are provided, with data in [H ~> m or kg m-2] integer :: nstep_incupd !< number of time step for full update - real :: ncount = 0.0 !< increment time step counter + real :: ncount = 0.0 !< increment time step counter [nondim]. This could be an integer + !! but a real variable works better with the existing restarts. type(remapping_cs) :: remap_cs !< Remapping parameters and work arrays logical :: incupdDataOngrid !< True if the incupd data are on the model horizontal grid logical :: uv_inc !< use u and v increments @@ -136,7 +139,8 @@ subroutine initialize_oda_incupd( G, GV, US, param_file, CS, data_h, nz_data, re logical :: bndExtrapolation = .true. ! If true, extrapolate boundaries logical :: reset_ncount integer :: i, j, k - real :: nhours_incupd, dt, dt_therm + real :: incupd_timescale ! The amount of timer over which to apply the full update [T ~> s] + real :: dt, dt_therm ! Model timesteps [T ~> s] character(len=256) :: mesg character(len=64) :: remapScheme if (.not.associated(CS)) then @@ -153,9 +157,9 @@ subroutine initialize_oda_incupd( G, GV, US, param_file, CS, data_h, nz_data, re if (.not.use_oda_incupd) return - call get_param(param_file, mdl, "ODA_INCUPD_NHOURS", nhours_incupd, & + call get_param(param_file, mdl, "ODA_INCUPD_NHOURS", incupd_timescale, & "Number of hours for full update (0=direct insertion).", & - default=3.0,units="h", scale=US%s_to_T) + default=3.0, units="h", scale=3600.0*US%s_to_T) call get_param(param_file, mdl, "ODA_INCUPD_RESET_NCOUNT", reset_ncount, & "If True, reinitialize number of updates already done, ncount.", & default=.true.) @@ -199,10 +203,10 @@ subroutine initialize_oda_incupd( G, GV, US, param_file, CS, data_h, nz_data, re 'The oda_incupd code only applies ODA increments on the same horizontal grid. ') ! get number of timestep for full update - if (nhours_incupd == 0) then + if (incupd_timescale == 0) then CS%nstep_incupd = 1 !! direct insertion else - CS%nstep_incupd = floor( nhours_incupd * 3600. / dt_therm + 0.001 ) - 1 + CS%nstep_incupd = floor( incupd_timescale / dt_therm + 0.001 ) - 1 endif write(mesg,'(i12)') CS%nstep_incupd if (is_root_pe()) & @@ -243,8 +247,9 @@ subroutine set_up_oda_incupd_field(sp_val, G, GV, CS) type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure type(oda_incupd_CS), pointer :: CS !< oda_incupd control structure (in/out). real, dimension(SZI_(G),SZJ_(G),CS%nz_data), & - intent(in) :: sp_val !< increment field, it can have an - !! arbitrary number of layers. + intent(in) :: sp_val !< increment field, it can have an arbitrary number + !! of layers, in various units depending on the + !! field it refers to [various]. integer :: i, j, k character(len=256) :: mesg ! String for error messages @@ -524,17 +529,20 @@ subroutine apply_oda_incupd(h, tv, u, v, dt, G, GV, US, CS) type(oda_incupd_CS), pointer :: CS !< A pointer to the control structure for this module !! that is set by a previous call to initialize_oda_incupd (in). - real, allocatable, dimension(:) :: tmp_val2 ! data values on the increment grid - real, dimension(SZK_(GV)) :: tmp_val1 ! data values remapped to model grid - real, dimension(SZK_(GV)) :: hu, hv ! A column of thicknesses at u or v points [H ~> m or kg m-2] + ! Local variables + real, allocatable, dimension(:) :: tmp_val2 ! data values remapped to increment grid, in rescaled units + ! like [S ~> ppt] for salinity. + real, dimension(SZK_(GV)) :: tmp_val1 ! data values on the model grid, in rescaled units + ! like [S ~> ppt] for salinity. + real, dimension(SZK_(GV)) :: hu, hv ! A column of thicknesses at u or v points [H ~> m or kg m-2] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: tmp_t !< A temporary array for t increments [C ~> degC] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: tmp_s !< A temporary array for s increments [S ~> ppt] real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: tmp_u !< A temporary array for u increments [L T-1 ~> m s-1] real, dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: tmp_v !< A temporary array for v increments [L T-1 ~> m s-1] - real, allocatable, dimension(:,:,:) :: h_obs !< h of increments - real, allocatable, dimension(:) :: tmp_h !< temporary array for corrected h_obs + real, allocatable, dimension(:,:,:) :: h_obs !< h of increments [H ~> m or kg m-2] + real, allocatable, dimension(:) :: tmp_h !< temporary array for corrected h_obs [H ~> m or kg m-2] real, allocatable, dimension(:) :: hu_obs ! A column of observation-grid thicknesses at u points [H ~> m or kg m-2] real, allocatable, dimension(:) :: hv_obs ! A column of observation-grid thicknesses at v points [H ~> m or kg m-2] diff --git a/src/parameterizations/lateral/MOM_MEKE.F90 b/src/parameterizations/lateral/MOM_MEKE.F90 index a44eec7727..bfa79ba053 100644 --- a/src/parameterizations/lateral/MOM_MEKE.F90 +++ b/src/parameterizations/lateral/MOM_MEKE.F90 @@ -643,7 +643,7 @@ subroutine step_forward_MEKE(MEKE, h, SN_u, SN_v, visc, dt, G, GV, US, CS, hu, h call pass_vector(u, v, G%Domain) call MEKE_lengthScales(CS, MEKE, G, GV, US, SN_u, SN_v, MEKE%MEKE, depth_tot, bottomFac2, barotrFac2, LmixScale) call ML_MEKE_calculate_features(G, GV, US, CS, MEKE%Rd_dx_h, u, v, tv, h, dt, features_array) - call predict_meke(G, CS, SIZE(h), Time, features_array, MEKE%MEKE) + call predict_MEKE(G, CS, SIZE(h), Time, features_array, MEKE%MEKE) case default call MOM_error(FATAL,"Invalid method specified for calculating EKE") end select @@ -1665,12 +1665,14 @@ subroutine predict_MEKE(G, CS, npts, Time, features_array, MEKE) type(time_type), intent(in ) :: Time !< The current model time real(kind=real32), dimension(npts,num_features), intent(in ) :: features_array !< The array of features needed for machine - !! learning inference + !! learning inference, with different units + !! for the various subarrays [various] real, dimension(SZI_(G),SZJ_(G)), intent( out) :: MEKE !< Eddy kinetic energy [L2 T-2 ~> m2 s-2] integer :: db_return_code character(len=255), dimension(1) :: model_out, model_in character(len=255) :: time_suffix - real(kind=real32), dimension(SIZE(MEKE)) :: MEKE_vec + real(kind=real32), dimension(SIZE(MEKE)) :: MEKE_vec ! A one-dimensional array of eddy kinetic + ! energy [L2 T-2 ~> m2 s-2] integer :: i, j, is, ie, js, je is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec @@ -1692,6 +1694,8 @@ subroutine predict_MEKE(G, CS, npts, Time, features_array, MEKE) db_return_code = CS%client%unpack_tensor( model_out(1), MEKE_vec, shape(MEKE_vec) ) call cpu_clock_end(CS%id_unpack_tensor) + !### Does MEKE_vec need to be rescaled from [m2 s-2] to [L2 T-2 ~> m2 s-2] by + ! multiplying MEKE_vec by US%m_s_to_L_T**2 here? MEKE = reshape(MEKE_vec, shape(MEKE)) do j=js,je; do i=is,ie MEKE(i,j) = MIN(MAX(exp(MEKE(i,j)),0.),CS%eke_max) diff --git a/src/user/RGC_initialization.F90 b/src/user/RGC_initialization.F90 index 6102c2a5ef..e21936ddb4 100644 --- a/src/user/RGC_initialization.F90 +++ b/src/user/RGC_initialization.F90 @@ -62,7 +62,7 @@ subroutine RGC_initialize_sponges(G, GV, US, tv, u, v, depth_tot, PF, use_ALE, C real :: S(SZI_(G),SZJ_(G),SZK_(GV)) ! A temporary array for salinity [S ~> ppt] real :: U1(SZIB_(G),SZJ_(G),SZK_(GV)) ! A temporary array for u [L T-1 ~> m s-1] real :: V1(SZI_(G),SZJB_(G),SZK_(GV)) ! A temporary array for v [L T-1 ~> m s-1] - real :: tmp(SZI_(G),SZJ_(G)) ! A temporary array for tracers. + real :: rho(SZI_(G),SZJ_(G)) ! A temporary array for mixed layer density [R ~> kg m-3]. real :: dz(SZI_(G),SZJ_(G),SZK_(GV)) ! Sponge layer thicknesses in height units [Z ~> m] real :: Idamp(SZI_(G),SZJ_(G)) ! The sponge damping rate at h points [T-1 ~> s-1] real :: TNUDG ! Nudging time scale [T ~> s] @@ -186,10 +186,10 @@ subroutine RGC_initialize_sponges(G, GV, US, tv, u, v, depth_tot, PF, use_ALE, C do i=is-1,ie ; pres(i) = tv%P_Ref ; enddo EOSdom(:) = EOS_domain(G%HI) do j=js,je - call calculate_density(T(:,j,1), S(:,j,1), pres, tmp(:,j), tv%eqn_of_state, EOSdom) + call calculate_density(T(:,j,1), S(:,j,1), pres, rho(:,j), tv%eqn_of_state, EOSdom) enddo - call set_up_sponge_ML_density(tmp, G, CSp) + call set_up_sponge_ML_density(rho, G, CSp) endif ! Apply sponge in tracer fields