From 81cad456a482af16845f639285d9a6c1ab46ca88 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Fri, 11 Apr 2025 14:27:50 -0600 Subject: [PATCH 01/41] Add option to auto-compute an io layout for auto masking. (#342) When Auto Masking is enabled, the LAYOUT is unknown a priori, so it's not possible to predetermine a compatible IO_LAYOUT. This commit introduces an option to set a target number of IO PEs (TARGET_IO_PES), to be used as a reference for the auto masking routine to come up with an IO_LAYOUT compatible with LAYOUT on the fly. If original TARGET_IO_PES is not achievable without having to sacrifice too much land masking, IO PEs is decremented until a feasible combination of LAYOUT and IO_LAYOUT is found. --- src/framework/MOM_domains.F90 | 145 ++++++++++++++++++++++++++++------ 1 file changed, 119 insertions(+), 26 deletions(-) diff --git a/src/framework/MOM_domains.F90 b/src/framework/MOM_domains.F90 index de4391d1a8..5c99872412 100644 --- a/src/framework/MOM_domains.F90 +++ b/src/framework/MOM_domains.F90 @@ -105,6 +105,7 @@ subroutine MOM_domains_init(MOM_dom, param_file, symmetric, static_memory, & ! Local variables integer, dimension(2) :: layout ! The number of logical processors in the i- and j- directions integer, dimension(2) :: auto_layout ! The layout determined by the auto masking routine + integer, dimension(2) :: auto_io_layout ! The IO layout determined by the auto masking routine integer, dimension(2) :: layout_unmasked ! A temporary layout for unmasked domain integer, dimension(2) :: io_layout ! The layout of logical processors for input and output !$ integer :: ocean_nthreads ! Number of openMP threads @@ -122,6 +123,7 @@ subroutine MOM_domains_init(MOM_dom, param_file, symmetric, static_memory, & ! width of the halos that are updated with each call. logical :: auto_mask_table ! Runtime flag that turns on automatic mask table generator integer :: auto_io_layout_fac ! Used to compute IO layout when auto_mask_table is True. + integer :: target_io_pes ! Target number of IO PEs for when auto_mask_table is True. logical :: mask_table_exists ! True if there is a mask table file logical :: is_MOM_domain ! True if this domain is being set for MOM, and not another component like SIS2. character(len=128) :: inputdir ! The directory in which to find the diag table @@ -323,13 +325,22 @@ subroutine MOM_domains_init(MOM_dom, param_file, symmetric, static_memory, & id_clock_auto_mask = cpu_clock_id('(Ocean gen_auto_mask_table)', grain=CLOCK_ROUTINE) auto_mask_table_fname = "MOM_auto_mask_table" + call get_param(param_file, mdl, "TARGET_IO_PES", target_io_pes, & + "When AUTO_MASKTABLE is enabled, target number of IO PEs. If the given target number "//& + "of IO PEs is not achievable, the target number of IO PEs is set to the nearest smaller "//& + "number of PEs that is achievable.", default=1, layoutParam=.true.) + if (target_io_pes <= 0) then + call MOM_error(FATAL, 'TARGET_IO_PES must be a nonnegative integer.') + endif + ! Auto-generate a mask file and determine the layout call cpu_clock_begin(id_clock_auto_mask) if (is_root_PE()) then call gen_auto_mask_table(n_global, reentrant, tripolar_N, PEs_used, param_file, inputdir, & - auto_mask_table_fname, auto_layout, US) + auto_mask_table_fname, target_io_pes, auto_layout, auto_io_layout, US) endif call broadcast(auto_layout, length=2) + call broadcast(auto_io_layout, length=2) call cpu_clock_end(id_clock_auto_mask) mask_table = auto_mask_table_fname @@ -422,12 +433,20 @@ subroutine MOM_domains_init(MOM_dom, param_file, symmetric, static_memory, & ! Compute a valid IO layout if auto_mask_table is on. Otherwise, read in IO_LAYOUT parameter, if (auto_mask_table) then + ! aa: AUTO_IO_LAYOUT_FAC is fragile and should be deprecated/removed in favor of TARGET_IO_PES. call get_param(param_file, mdl, "AUTO_IO_LAYOUT_FAC", auto_io_layout_fac, & "When AUTO_MASKTABLE is enabled, io layout is calculated by performing integer "//& "division of the runtime-determined domain layout with this factor. If the factor "//& - "is set to 0 (default), the io layout is set to 1,1.", & + "is set to 0 (default), the io layout is set to 1,1. NOTE: TARGET_IO_PES is a more "//& + "robust way to set the number of IO PEs when auto masking is turned on.", & default=0, layoutParam=.true.) - if (auto_io_layout_fac>0) then + if (auto_io_layout_fac>1 .and. target_io_pes>1) then + call MOM_error(FATAL, 'AUTO_IO_LAYOUT_FAC and TARGET_IO_PES cannot be set simultaneously.') + endif + if (target_io_pes>1) then + io_layout(1) = auto_io_layout(1) + io_layout(2) = auto_io_layout(2) + elseif (auto_io_layout_fac>0) then io_layout(1) = max(layout(1)/auto_io_layout_fac, 1) io_layout(2) = max(layout(2)/auto_io_layout_fac, 1) elseif (auto_io_layout_fac<0) then @@ -485,7 +504,8 @@ subroutine MOM_define_layout(n_global, ndivs, layout) end subroutine MOM_define_layout !> Given a desired number of active npes, generate a layout and mask_table -subroutine gen_auto_mask_table(n_global, reentrant, tripolar_N, npes, param_file, inputdir, filename, layout, US) +subroutine gen_auto_mask_table(n_global, reentrant, tripolar_N, npes, param_file, & + inputdir, filename, target_io_pes, layout, io_layout, US) integer, dimension(2), intent(in) :: n_global !< The total number of gridpoints in 2 directions logical, dimension(2), intent(in) :: reentrant !< True if the x- and y- directions are periodic. logical, intent(in) :: tripolar_N !< A flag indicating whether there is n. tripolar connectivity @@ -493,7 +513,9 @@ subroutine gen_auto_mask_table(n_global, reentrant, tripolar_N, npes, param_file type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters character(len=128), intent(in) :: inputdir !< INPUTDIR parameter character(len=:), allocatable, intent(in) :: filename !< Mask table file path (to be auto-generated.) + integer, intent(inout) :: target_io_pes !< Target number of IO PEs when auto_mask_table is True. integer, dimension(2), intent(out) :: layout !< The generated layout of PEs (incl. masked blocks) + integer, dimension(2), intent(out) :: io_layout !< The generated IO layout based on target_io_pes. type(unit_scale_type), optional, pointer :: US !< A dimensional unit scaling type ! Local variables @@ -503,21 +525,27 @@ subroutine gen_auto_mask_table(n_global, reentrant, tripolar_N, npes, param_file character(len=200) :: topo_varname ! Variable name in file character(len=200) :: topo_config character(len=40) :: mdl = "gen_auto_mask_table" ! This subroutine's name. - integer :: i, j, p + integer :: i, j, p, p_up real :: Dmask ! The depth for masking in the same units as D [Z ~> m] real :: min_depth ! The minimum ocean depth in the same units as D [Z ~> m] real :: mask_depth ! The depth shallower than which to mask a point as land. [Z ~> m] real :: glob_ocn_frac ! ratio of ocean points to total number of points [nondim] - real :: r_p ! aspect ratio for division count p. [nondim] + real :: ar ! layout aspect ratio to check if it is too extreme [nondim] real :: m_to_Z ! A conversion factor from m to height units [Z m-1 ~> 1] integer :: nx, ny ! global domain sizes integer, parameter :: ibuf=2, jbuf=2 real, parameter :: r_extreme = 4.0 ! aspect ratio limit (>1) for a layout to be considered [nondim] integer :: num_masked_blocks integer, allocatable :: mask_table(:,:) + integer :: max_feasible_p ! max division count that leads to enough land block masking to arrive at target compute PEs + real, parameter :: pfrac = 0.01 ! fraction by which to reduce the max_feasible_p if target IO PEs is not achievable. + ! (This is to provide a wiggle room for the target IO PEs to be achieved.) [nondim] + character(len=200) :: mesg ! A string to use for error messages m_to_Z = 1.0 ; if (present(US)) m_to_Z = US%m_to_Z + io_layout = [1, 1] + ! Read in params necessary for auto-masking call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, & units="m", default=0.0, scale=m_to_Z, do_not_log=.true.) @@ -591,28 +619,56 @@ subroutine gen_auto_mask_table(n_global, reentrant, tripolar_N, npes, param_file endif glob_ocn_frac = real(sum(mask(1+ibuf:nx+ibuf, 1+jbuf:ny+jbuf))) / (nx * ny) + max_feasible_p = 0 + + ! Iteratively check for all possible division counts starting from the upper bound of npes/glob_ocn_frac. + ! The first encountered feasible division count is stored in max_feasible_p. If the target_io_pes is not + ! achievable with this layout, the iteration continues until max_feasible_p * (1.0 - pfrac) is reached or the + ! target_io_pes is satisfiable. If not, the target_io_pes is decremented and the iteration is re-done from + ! max_feasible_p to max_feasible_p * (1.0 - pfrac). + outer: do i = target_io_pes, 1, -1 + + if (max_feasible_p == 0) then ! first iteration + p_up = ceiling(npes/glob_ocn_frac) + else ! subsequent iterations with reduced target_io_pes + p_up = max_feasible_p + endif - ! Iteratively check for all possible division counts starting from the upper bound of npes/glob_ocn_frac, - ! which is over-optimistic for realistic domains, but may be satisfied with idealized domains. - do p = ceiling(npes/glob_ocn_frac), npes, -1 - - ! compute the layout for the current division count, p - call MOM_define_layout(n_global, p, layout) - - ! don't bother checking this p if the aspect ratio is extreme - r_p = (real(nx)/layout(1)) / (real(ny)/layout(2)) - if ( r_p * r_extreme < 1 .or. r_extreme < r_p ) cycle - - ! Get the number of masked_blocks for this particular division count - call determine_land_blocks(mask, nx, ny, layout(1), layout(2), ibuf, jbuf, num_masked_blocks) + do p = p_up, npes, -1 + + ! compute the layout for the current division count, p + call MOM_define_layout(n_global, p, layout) + + ! don't bother checking this p if the aspect ratio is extreme + ar = (real(nx)/layout(1)) / (real(ny)/layout(2)) + if ( ar * r_extreme < 1 .or. r_extreme < ar ) cycle + + ! Get the number of masked_blocks for this particular division count + call determine_land_blocks(mask, nx, ny, layout(1), layout(2), ibuf, jbuf, num_masked_blocks) + + ! If we can eliminate enough blocks to reach the target compute npes, check if the target IO PEs can also be + ! satisfied with this layout. If so, terminate the whole iteration. + if (p-num_masked_blocks <= npes) then ! We can eliminate enough blocks to reach the target compute npes + if (max_feasible_p == 0) max_feasible_p = p + if (mod(layout(1)*layout(2), i) == 0) then + io_layout = auto_determine_io_layout(layout(1), layout(2), i) + ! skip if aspect ratio is extreme + ar = (real(layout(1))/io_layout(1)) / (real(layout(2))/io_layout(2)) + if ( ar * r_extreme < 1 .or. r_extreme < ar ) cycle + call MOM_error(NOTE, "Found the optimum layout for auto-masking. Terminating iteration.") + if (i /= target_io_pes) then + write(mesg,'(a,i0)') "For compatibility with compute layout, changed number of IO PEs to: ", i + call MOM_error(NOTE, mesg) + endif + exit outer + endif + endif - ! If we can eliminate enough blocks to reach the target npes, adopt - ! this p (and the associated layout) and terminate the iteration. - if (p-num_masked_blocks <= npes) then - call MOM_error(NOTE, "Found the optimum layout for auto-masking. Terminating iteration...") - exit - endif - enddo + ! Do not reduce the division count too much to satisfy the target_io_pes. Instead, re-do the iteration + ! with a reduced target_io_pes. + if (p <= max_feasible_p * (1.0 - pfrac)) exit ! (inner do loop) + enddo + enddo outer if (num_masked_blocks == 0) then call MOM_error(FATAL, "Couldn't auto-eliminate any land blocks. Try to increase the number "//& @@ -701,4 +757,41 @@ subroutine write_auto_mask_file(mask_table, layout, npes, filename) call close_file(file_ascii) end subroutine write_auto_mask_file +!> Computes the io layout based on the domain layout and a target number of IO PEs. +function auto_determine_io_layout(idiv, jdiv, nio) result(best_io_layout) + integer, intent(in) :: idiv ! The number of compute divisions along the x-axis + integer, intent(in) :: jdiv ! The number of compute divisions along the y-axis + integer, intent(in) :: nio ! Target number of IO PEs, s.t., (idiv_io * jdiv_io) % nio == 0 + ! return + integer :: io_layout(2) ! Temporary IO layout + integer :: best_io_layout(2) ! Best IO layout + integer :: f, best_idiv_io, best_jdiv_io + real :: ratio_diff, min_ratio_diff + + if (mod(idiv*jdiv, nio) /= 0) then + call MOM_error(FATAL, "The product of the compute layout must be divisible by the target number of IO PEs.") + endif + + min_ratio_diff = 1.0e30 ! Large initial value + best_io_layout = [1, nio] + + ! Iterate over all factors of nio + do f = 1, nio + if (mod(nio, f) /= 0) cycle + io_layout = [f, nio / f] + + ! Check divisibility constraints + if (mod(idiv, io_layout(1)) == 0 .and. mod(jdiv, io_layout(2)) == 0) then + ratio_diff = abs(real(io_layout(1)) / real(io_layout(2)) - real(idiv) / real(jdiv)) + + ! Update best choice if ratio_diff is smaller + if (ratio_diff < min_ratio_diff) then + min_ratio_diff = ratio_diff + best_io_layout = [io_layout(1), io_layout(2)] + end if + end if + end do + +end function auto_determine_io_layout + end module MOM_domains From fc47ccbb8a59640226256fffdb9514e9e7aa9ce9 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Wed, 2 Apr 2025 14:52:11 -0600 Subject: [PATCH 02/41] Add option to wave enhance ustar in Bodner23 Introduce parameter "WAVE_ENHANCED_USTAR". If true, enhance ustar for equilibrium surface waves (La-2=11.), following Eq. 28 in Bodner23. Default is false. --- .../lateral/MOM_mixed_layer_restrat.F90 | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index bb31255261..41f6cd2dcc 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -102,8 +102,11 @@ module MOM_mixed_layer_restrat !! front-length scales read from a file. type(time_type), pointer :: Time => NULL() !< A pointer to the ocean model's clock. logical :: use_Stanley_ML !< If true, use the Stanley parameterization of SGS T variance + logical :: wave_enhanced_ustar !< If true, enhance ustar for equilibrium surface waves (La-2=11), + !! following Eq. 28 in Bodner23. real :: ustar_min !< A minimum value of ustar in thickness units to avoid numerical !! problems [H T-1 ~> m s-1 or kg m-2 s-1] + real :: Kv_restrat !< A viscosity that sets a floor on the momentum mixing rate !! during restratification, rescaled into thickness-based !! units [H2 T-1 ~> m2 s-1 or kg2 m-4 s-1] @@ -805,6 +808,8 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d real :: h_vel ! htot interpolated onto velocity points [H ~> m or kg m-2] real :: w_star3 ! Cube of turbulent convective velocity [Z3 T-3 ~> m3 s-3] real :: u_star3 ! Cube of surface friction velocity [Z3 T-3 ~> m3 s-3] + real :: E_ustar ! Surface wave ustar enhancement factor [nondim] + real :: Lam2 ! Reciprocal of the squrared turbulent Langmuir number [nondim] real :: r_wpup ! reciprocal of vertical momentum flux [T2 L-1 H-1 ~> s2 m-2 or m s2 kg-1] real :: absf ! absolute value of f, interpolated to velocity points [T-1 ~> s-1] real :: f_h ! Coriolis parameter at h-points [T-1 ~> s-1] @@ -843,7 +848,7 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d covTS(:) = 0.0 ! Might be in tv% in the future. Not implemented for the time being. varS(:) = 0.0 ! Ditto. - ! This value is roughly (pi / (the age of the universe) )^2. + ! This value is roughly (pi / (the age of the universe) )^2. absurdly_small_freq2 = 1e-34*US%T_to_s**2 if (.not.associated(tv%eqn_of_state)) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// & @@ -865,6 +870,17 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d ! Extract the friction velocity from the forcing type. call find_ustar(forces, tv, U_star_2d, G, GV, US, halo=1) + ! wave enhancement of ustar following Eq. 28 in Bodner23 + if (CS%wave_enhanced_ustar) then + ! Assuming wind wave equilibrium (Lam2=11) until Lam2 becomes available + Lam2 = 11. + E_ustar = sqrt( 1.0 + (Lam2 * 0.104) + (Lam2 * Lam2 * 0.00118)) + ! Wave Enhanced + do j=js-1,je+1 ; do i=is-1,ie+1 + U_star_2d(i,j) = E_ustar * U_star_2d(i,j) + enddo ; enddo + endif + if (CS%debug) then call hchksum(h,'mixed_Bodner: h', G%HI, haloshift=1, unscale=GV%H_to_mks) call hchksum(BLD, 'mle_Bodner: BLD', G%HI, haloshift=1, unscale=US%Z_to_m) @@ -1728,6 +1744,9 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "The default is less than the molecular viscosity of water times the Coriolis "//& "parameter a micron away from the equator.", & units="m2 s-2", default=1.0e-24, scale=US%m_to_Z**2*US%T_to_s**2) + call get_param(param_file, mdl, "WAVE_ENHANCED_USTAR", CS%wave_enhanced_ustar, & + "If true, enhance ustar for equilibrium surface waves (La-2=11.), "// & + "following Eq. 28 in Bodner23.", default=.false.) call get_param(param_file, mdl, "TAIL_DH", CS%MLE_tail_dh, & "Fraction by which to extend the mixed-layer restratification "//& "depth used for a smoother stream function at the base of "//& From 2f2679bab2de84ceef2beb7aeb1ad06cf9f686bd Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Mon, 14 Apr 2025 14:34:21 -0600 Subject: [PATCH 03/41] Add Prandtl # for CVMIX shear mixing (#349) * Update cvmix submodule * Add Prandtl # for CVMIX shear mixing - Added parameter `PRANDTL_CVMIX_SHEAR` default value 1.0, which gives b4b with previous answers. - Updated `cvmix_init_shear` call to include `Prandtl_shear` argument. --- pkg/CVMix-src | 2 +- src/parameterizations/vertical/MOM_CVMix_shear.F90 | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/CVMix-src b/pkg/CVMix-src index 65ef5c73bc..14939c5704 160000 --- a/pkg/CVMix-src +++ b/pkg/CVMix-src @@ -1 +1 @@ -Subproject commit 65ef5c73bc7f5663d5688f75c3855d431da4baea +Subproject commit 14939c5704d57b4d68d86b57b13161ea59ab6b5c diff --git a/src/parameterizations/vertical/MOM_CVMix_shear.F90 b/src/parameterizations/vertical/MOM_CVMix_shear.F90 index 46d7b98502..fcd4e2514f 100644 --- a/src/parameterizations/vertical/MOM_CVMix_shear.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_shear.F90 @@ -35,6 +35,8 @@ module MOM_CVMix_shear integer :: n_smooth_ri !< Number of times to smooth Ri using a 1-2-1 filter real :: Ri_zero !< LMD94 critical Richardson number [nondim] real :: Nu_zero !< LMD94 maximum interior diffusivity [Z2 T-1 ~> m2 s-1] + real :: Prandtl !< The turbulent Prandtl number to be used in the + !! CVMIX shear mixing [nondim] real :: KPP_exp !< Exponent of unitless factor of diffusivities !! for KPP internal shear mixing scheme [nondim] real, allocatable, dimension(:,:,:) :: N2 !< Squared Brunt-Vaisala frequency [T-2 ~> s-2] @@ -289,6 +291,9 @@ logical function CVMix_shear_init(Time, G, GV, US, param_file, diag, CS) "NOTE this the internal mixing and this is "// & "not for setting the boundary layer depth.", & units="nondim", default=0.8) + call get_param(param_file, mdl, "PRANDTL_CVMIX_SHEAR", CS%Prandtl, & + "The turbulent Prandtl number to be used in the "// & + "CVMIX shear mixing.", units="nondim", default=1.0) call get_param(param_file, mdl, "KPP_EXP", CS%KPP_exp, & "Exponent of unitless factor of diffusivities, "// & "for KPP internal shear mixing scheme.", & @@ -300,7 +305,8 @@ logical function CVMix_shear_init(Time, G, GV, US, param_file, diag, CS) call cvmix_init_shear(mix_scheme=CS%Mix_Scheme, & KPP_nu_zero=US%Z2_T_to_m2_s*CS%Nu_Zero, & KPP_Ri_zero=CS%Ri_zero, & - KPP_exp=CS%KPP_exp) + KPP_exp=CS%KPP_exp, & + Prandtl_shear=CS%Prandtl) ! Register diagnostics; allocation and initialization CS%diag => diag From 40c808c2eea28805a3b25f398061ab262dc09003 Mon Sep 17 00:00:00 2001 From: "Christopher L. Pitt Wolfe" Date: Tue, 22 Apr 2025 12:52:42 -0400 Subject: [PATCH 04/41] Add diagnostics for parameterized GM tracer fluxes Adds diagnostics [Tr]_ad[x/y]_resolved and [Tr]_ad[x/y]_param, where [Tr] is any tracer and [x/y] is either x or y, to diagnose the separate transports due to the resolved and parameterized (i.e., GM) flow. Modifies tracer advection routines, but only triggers additional calculations for tracers with active resolved/param diagnostics. 1 2 3 4 5 --- src/core/MOM.F90 | 83 +++- src/tracer/MOM_tracer_advect.F90 | 745 ++++++++++++++++++----------- src/tracer/MOM_tracer_registry.F90 | 36 ++ src/tracer/MOM_tracer_types.F90 | 9 + 4 files changed, 579 insertions(+), 294 deletions(-) diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index aeb316b950..a6a9c540e7 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -382,6 +382,15 @@ module MOM type(diag_grid_storage) :: diag_pre_sync !< The grid (thicknesses) before remapping type(diag_grid_storage) :: diag_pre_dyn !< The grid (thicknesses) before dynamics + logical :: accumulate_resolved_flux = .false. !< If true, accumulate resolved flux for tracers for diagnostics + !! separating the tracer flux due to resolved and parameterized flow + logical :: do_resolved_advection = .false. !< If true, calculate advection by resolved flow + logical :: do_param_advection = .false. !< If true, calculate advection by parameterized flow + real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: & + uhtr_resolved !< accumulated zonal thickness fluxes due to resolved flow to advect tracers [H L2 ~> m3 or kg] + real ALLOCABLE_, dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: & + vhtr_resolved !< accumulated meridional thickness fluxes due to resolved flow to advect tracers [H L2 ~> m3 or kg] + ! The remainder of this type provides pointers to child module control structures. type(MOM_dyn_unsplit_CS), pointer :: dyn_unsplit_CSp => NULL() @@ -1284,6 +1293,19 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, & endif ! -------------------------------------------------- end SPLIT + ! Accumulate resolved flux for tracer diagnostics + if (CS%accumulate_resolved_flux) then + !$OMP parallel do default(shared) + do k=1,nz + do j=js-2,je+2 ; do I=Isq-2,Ieq+2 + CS%uhtr_resolved(I,j,k) = CS%uhtr_resolved(I,j,k) + CS%uh(I,j,k)*dt + enddo ; enddo + do J=Jsq-2,Jeq+2 ; do i=is-2,ie+2 + CS%vhtr_resolved(i,J,k) = CS%vhtr_resolved(i,J,k) + CS%vh(i,J,k)*dt + enddo ; enddo + enddo + endif + ! Update the model's current to reflect wind-wave growth if (Waves%Stokes_DDT .and. (.not.Waves%Passive_Stokes_DDT)) then do J=jsq,jeq ; do i=is,ie @@ -1420,9 +1442,19 @@ subroutine step_MOM_tracer_dyn(CS, G, GV, US, h, Time_local) type(group_pass_type) :: pass_T_S integer :: halo_sz ! The size of a halo where data must be valid. logical :: x_first ! If true, advect tracers first in the x-direction, then y. + real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: & + uhtr_tmp ! Temp. variable for advecting with alternate volume fluxes [H L2 ~> m3 or kg] + real, dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: & + vhtr_tmp ! Temp. variable for advecting with alternate volume fluxes[H L2 ~> m3 or kg] + integer :: i, j, k, m, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz + integer :: IsdB, IedB, JsdB, JedB logical :: showCallTree + showCallTree = callTree_showQuery() + is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke + Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB + if (CS%debug) then call cpu_clock_begin(id_clock_other) call hchksum(h,"Pre-advection h", G%HI, haloshift=1, unscale=GV%H_to_MKS) @@ -1451,7 +1483,27 @@ subroutine step_MOM_tracer_dyn(CS, G, GV, US, h, Time_local) endif if (CS%debug) call MOM_tracer_chksum("Pre-advect ", CS%tracer_Reg, G) call advect_tracer(h, CS%uhtr, CS%vhtr, CS%OBC, CS%t_dyn_rel_adv, G, GV, US, & - CS%tracer_adv_CSp, CS%tracer_Reg, x_first_in=x_first) + CS%tracer_adv_CSp, CS%tracer_Reg, x_first_in=x_first, flux_type=0) + + if (CS%do_resolved_advection) then + call advect_tracer(h, CS%uhtr_resolved, CS%vhtr_resolved, CS%OBC, CS%t_dyn_rel_adv, G, GV, US, & + CS%tracer_adv_CSp, CS%tracer_Reg, x_first_in=x_first, flux_type=1) + endif + + if (CS%do_param_advection) then + !$OMP parallel do default(shared) + do k=1,nz + do j=js-2,je+2 ; do I=Isq-2,Ieq+2 + uhtr_tmp(I,j,k) = CS%uhtr(I,j,k) - CS%uhtr_resolved(I,j,k) + enddo ; enddo + do J=Jsq-2,Jeq+2 ; do i=is-2,ie+2 + vhtr_tmp(i,J,k) = CS%vhtr(i,J,k) - CS%vhtr_resolved(i,J,k) + enddo ; enddo + enddo + call advect_tracer(h, uhtr_tmp, vhtr_tmp, CS%OBC, CS%t_dyn_rel_adv, G, GV, US, & + CS%tracer_adv_CSp, CS%tracer_Reg, x_first_in=x_first, flux_type=2) + endif + if (CS%debug) call MOM_tracer_chksum("Post-advect ", CS%tracer_Reg, G) call tracer_hordiff(h, CS%t_dyn_rel_adv, CS%MEKE, CS%VarMix, CS%visc, G, GV, US, & CS%tracer_diff_CSp, CS%tracer_Reg, CS%tv) @@ -1479,6 +1531,10 @@ subroutine step_MOM_tracer_dyn(CS, G, GV, US, h, Time_local) call cpu_clock_begin(id_clock_thermo) ; call cpu_clock_begin(id_clock_tracer) CS%uhtr(:,:,:) = 0.0 CS%vhtr(:,:,:) = 0.0 + if (CS%accumulate_resolved_flux) then + CS%uhtr_resolved(:,:,:) = 0.0 + CS%vhtr_resolved(:,:,:) = 0.0 + endif CS%n_dyn_steps_in_adv = 0 CS%t_dyn_rel_adv = 0.0 call cpu_clock_end(id_clock_tracer) ; call cpu_clock_end(id_clock_thermo) @@ -2099,7 +2155,7 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, & ! This include declares and sets the variable "version". # include "version_variable.h" - integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz + integer :: i, j, k, m, is, ie, js, je, isd, ied, jsd, jed, nz integer :: IsdB, IedB, JsdB, JedB real :: dtbt ! If negative, this specifies the barotropic timestep as a fraction ! of the maximum stable value [nondim]. @@ -3412,6 +3468,25 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, & call ALE_register_diags(Time, G, GV, US, diag, CS%ALE_CSp) endif + ! determine if we need to accumulate resolved transports for tracer advection diagnostics + do m = 1,CS%tracer_Reg%ntr + if (CS%tracer_Reg%Tr(m)%id_adx_resolved > 0 .or. & + CS%tracer_Reg%Tr(m)%id_ady_resolved > 0) then + CS%accumulate_resolved_flux = .true. + CS%do_resolved_advection = .true. + endif + if (CS%tracer_Reg%Tr(m)%id_adx_param > 0 .or. & + CS%tracer_Reg%Tr(m)%id_ady_param > 0) then + CS%accumulate_resolved_flux = .true. + CS%do_param_advection = .true. + endif + enddo + if (CS%accumulate_resolved_flux) then + ALLOC_(CS%uhtr_resolved(IsdB:IedB,jsd:jed,nz)) ; CS%uhtr_resolved(:,:,:) = 0.0 + ALLOC_(CS%vhtr_resolved(isd:ied,JsdB:JedB,nz)) ; CS%vhtr_resolved(:,:,:) = 0.0 + endif + + ! Do any necessary halo updates on any auxiliary variables that have been initialized. call cpu_clock_begin(id_clock_pass_init) if (associated(CS%visc%Kv_shear)) & @@ -4295,6 +4370,10 @@ subroutine MOM_end(CS) DEALLOC_(CS%uhtr) ; DEALLOC_(CS%vhtr) + if (CS%accumulate_resolved_flux) then + DEALLOC_(CS%uhtr_resolved) ; DEALLOC_(CS%vhtr_resolved) + endif + if (associated(CS%Hml)) deallocate(CS%Hml) if (associated(CS%tv%salt_deficit)) deallocate(CS%tv%salt_deficit) if (associated(CS%tv%frazil)) deallocate(CS%tv%frazil) diff --git a/src/tracer/MOM_tracer_advect.F90 b/src/tracer/MOM_tracer_advect.F90 index 0e129b2d03..5d4959c7e1 100644 --- a/src/tracer/MOM_tracer_advect.F90 +++ b/src/tracer/MOM_tracer_advect.F90 @@ -50,7 +50,8 @@ module MOM_tracer_advect !> This routine time steps the tracer concentration using a !! monotonic, conservative, weakly diffusive scheme. subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first_in, & - vol_prev, max_iter_in, update_vol_prev, uhr_out, vhr_out) + vol_prev, max_iter_in, update_vol_prev, uhr_out, vhr_out, & + flux_type) type(ocean_grid_type), intent(inout) :: G !< ocean grid structure type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & @@ -68,7 +69,7 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first type(tracer_registry_type), pointer :: Reg !< pointer to tracer registry logical, optional, intent(in) :: x_first_in !< If present, indicate whether to update !! first in the x- or y-direction. - ! The remaining optional arguments are only used in offline tracer mode. + ! The next four optional arguments are only used in offline tracer mode. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & optional, intent(inout) :: vol_prev !< Cell volume before advection [H L2 ~> m3 or kg]. !! If update_vol_prev is true, the returned value is @@ -84,7 +85,15 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), & optional, intent(out) :: vhr_out !< Remaining accumulated volume or mass fluxes !! through the meridional faces [H L2 ~> m3 or kg] - + ! The next optional argument is for diagnosing resolved vs parameterized tracer flux and control + ! which diagnostics are written. The tracers are only updated if flux_type = 0 (the default). Otherwise + ! the routines are dry run to collect diagnostics. + integer, optional, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to + !! the residual (= 0), resolved (= 1), or parameterized (= 2) + !! flow + + ! local variables + integer :: flux_type_ctrl !< To allow setting a default value for flux_type real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: & hprev ! cell volume at the end of previous tracer change [H L2 ~> m3 or kg] real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: & @@ -101,6 +110,12 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first logical :: domore_u(SZJ_(G),SZK_(GV)) ! domore_u and domore_v indicate whether there is more logical :: domore_v(SZJB_(G),SZK_(GV)) ! advection to be done in the corresponding row or column. logical :: x_first ! If true, advect in the x-direction first. + logical :: advect_this_tracer(Reg%ntr) ! If true, advect the mth tracer. Diagnostics of advection due to the + ! resolved and parameterized flow are collected by re-running the advection + ! routines with different advecting fluxes without updating the tracer. + ! This can be expensive if there are lots of tracers and only a few you + ! want diagnostics about. We therefore only calculate advection on the + ! tracers for which there are active resolved/parameterized diagnostics. integer :: max_iter ! maximum number of iterations in each layer integer :: domore_k(SZK_(GV)) integer :: stencil ! stencil of the advection scheme @@ -111,6 +126,7 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first domore_u(:,:) = .false. domore_v(:,:) = .false. + advect_this_tracer(:) = .false. is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB @@ -136,6 +152,10 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first if (present(max_iter_in)) max_iter = max_iter_in if (present(x_first_in)) x_first = x_first_in + + flux_type_ctrl = 0 + if (present(flux_type)) flux_type_ctrl = flux_type ! default to residual flow + call cpu_clock_begin(id_clock_pass) call create_group_pass(CS%pass_uhr_vhr_t_hprev, uhr, vhr, G%Domain) call create_group_pass(CS%pass_uhr_vhr_t_hprev, hprev, G%Domain) @@ -187,16 +207,48 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first vh_neglect(i,J) = GV%H_subroundoff * MIN(G%areaT(i,j), G%areaT(i,j+1)) enddo ; enddo - ! initialize diagnostic fluxes and tendencies - !$OMP do - do m=1,ntr - if (associated(Reg%Tr(m)%ad_x)) Reg%Tr(m)%ad_x(:,:,:) = 0.0 - if (associated(Reg%Tr(m)%ad_y)) Reg%Tr(m)%ad_y(:,:,:) = 0.0 - if (associated(Reg%Tr(m)%advection_xy)) Reg%Tr(m)%advection_xy(:,:,:) = 0.0 - if (associated(Reg%Tr(m)%ad2d_x)) Reg%Tr(m)%ad2d_x(:,:) = 0.0 - if (associated(Reg%Tr(m)%ad2d_y)) Reg%Tr(m)%ad2d_y(:,:) = 0.0 - enddo - !$OMP end parallel + ! initialize diagnostic fluxes and tendencies and determine which tracers to advect + if (flux_type_ctrl == 0) then ! Flux is residual + !$OMP do + do m=1,ntr + advect_this_tracer(m) = .true. ! Advect all the tracers regardless of diagnostic output + if (associated(Reg%Tr(m)%ad_x)) Reg%Tr(m)%ad_x(:,:,:) = 0.0 + if (associated(Reg%Tr(m)%ad_y)) Reg%Tr(m)%ad_y(:,:,:) = 0.0 + if (associated(Reg%Tr(m)%advection_xy)) Reg%Tr(m)%advection_xy(:,:,:) = 0.0 + if (associated(Reg%Tr(m)%ad2d_x)) Reg%Tr(m)%ad2d_x(:,:) = 0.0 + if (associated(Reg%Tr(m)%ad2d_y)) Reg%Tr(m)%ad2d_y(:,:) = 0.0 + enddo + !$OMP end parallel + elseif (flux_type_ctrl == 1) then ! Flux is resolved + !$OMP do + do m=1,ntr + if (associated(Reg%Tr(m)%ad_x_resolved)) then + Reg%Tr(m)%ad_x_resolved(:,:,:) = 0.0 + advect_this_tracer(m) = .true. ! advect this tracer + endif + if (associated(Reg%Tr(m)%ad_y_resolved)) then + Reg%Tr(m)%ad_y_resolved(:,:,:) = 0.0 + advect_this_tracer(m) = .true. ! advect this tracer + endif + enddo + !$OMP end parallel + elseif (flux_type_ctrl == 2) then ! Flux is parameterized + !$OMP do + do m=1,ntr + if (associated(Reg%Tr(m)%ad_x_param)) then + Reg%Tr(m)%ad_x_param(:,:,:) = 0.0 + advect_this_tracer(m) = .true. ! advect this tracer + endif + if (associated(Reg%Tr(m)%ad_y_param)) then + Reg%Tr(m)%ad_y_param(:,:,:) = 0.0 + advect_this_tracer(m) = .true. ! advect this tracer + endif + enddo + !$OMP end parallel + else + call MOM_error(FATAL, & + "Inconsistent flux type in advect_tracer. Must be of 0 (residual), 1 (resolved), or 2 (parameterized)") + endif ! flux_type_ctrl isv = is ; iev = ie ; jsv = js ; jev = je @@ -252,14 +304,16 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first do k=1,nz ; if (domore_k(k) > 0) then ! First, advect zonally. call advect_x(Reg%Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & - isv, iev, jsv-stencil, jev+stencil, k, G, GV, US, CS%usePPM, CS%useHuynh) + isv, iev, jsv-stencil, jev+stencil, k, G, GV, US, & + CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer) endif ; enddo !$OMP do ordered do k=1,nz ; if (domore_k(k) > 0) then ! Next, advect meridionally. call advect_y(Reg%Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & - isv, iev, jsv, jev, k, G, GV, US, CS%usePPM, CS%useHuynh) + isv, iev, jsv, jev, k, G, GV, US, & + CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer) ! Update domore_k(k) for the next iteration domore_k(k) = 0 @@ -274,14 +328,16 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first do k=1,nz ; if (domore_k(k) > 0) then ! First, advect meridionally. call advect_y(Reg%Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & - isv-stencil, iev+stencil, jsv, jev, k, G, GV, US, CS%usePPM, CS%useHuynh) + isv-stencil, iev+stencil, jsv, jev, k, G, GV, US, & + CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer) endif ; enddo !$OMP do ordered do k=1,nz ; if (domore_k(k) > 0) then ! Next, advect zonally. call advect_x(Reg%Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & - isv, iev, jsv, jev, k, G, GV, US, CS%usePPM, CS%useHuynh) + isv, iev, jsv, jev, k, G, GV, US, & + CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer) ! Update domore_k(k) for the next iteration domore_k(k) = 0 @@ -327,7 +383,8 @@ end subroutine advect_tracer !> This subroutine does 1-d flux-form advection in the zonal direction using !! a monotonic piecewise linear scheme. subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & - is, ie, js, je, k, G, GV, US, usePPM, useHuynh) + is, ie, js, je, k, G, GV, US, usePPM, useHuynh, & + flux_type, advect_this_tracer) type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure integer, intent(in) :: ntr !< The number of tracers @@ -351,6 +408,10 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & logical, intent(in) :: usePPM !< If true, use PPM instead of PLM logical, intent(in) :: useHuynh !< If true, use the Huynh scheme !! for PPM interface values + integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to + !! the residual (= 0), resolved (= 1), or parameterized (= 2) + !! flow + logical, dimension(ntr), intent(in) :: advect_this_tracer !< If true, advect this tracer real, dimension(SZI_(G),ntr) :: & slope_x ! The concentration slope per grid point [conc]. @@ -409,34 +470,40 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & ! Calculate the i-direction profiles (slopes) of each tracer that is being advected. if (usePLMslope) then - do m=1,ntr ; do i=is-stencil,ie+stencil - !if (ABS(Tr(m)%t(i+1,j,k)-Tr(m)%t(i,j,k)) < & - ! ABS(Tr(m)%t(i,j,k)-Tr(m)%t(i-1,j,k))) then - ! maxslope = 4.0*(Tr(m)%t(i+1,j,k)-Tr(m)%t(i,j,k)) - !else - ! maxslope = 4.0*(Tr(m)%t(i,j,k)-Tr(m)%t(i-1,j,k)) - !endif - !if ((Tr(m)%t(i+1,j,k)-Tr(m)%t(i,j,k)) * (Tr(m)%t(i,j,k)-Tr(m)%t(i-1,j,k)) < 0.0) then - ! slope_x(i,m) = 0.0 - !elseif (ABS(Tr(m)%t(i+1,j,k)-Tr(m)%t(i-1,j,k))= 0.0) then - i_up = i - else - i_up = i+1 - endif - - ! Implementation of PPM-H3 - Tp = T_tmp(i_up+1,m) ; Tc = T_tmp(i_up,m) ; Tm = T_tmp(i_up-1,m) + do m=1,ntr + if (advect_this_tracer(m)) then + do I=is-1,ie + ! centre cell depending on upstream direction + if (uhh(I) >= 0.0) then + i_up = i + else + i_up = i+1 + endif - if (useHuynh) then - aL = ( 5.*Tc + ( 2.*Tm - Tp ) )/6. ! H3 estimate - aL = max( min(Tc,Tm), aL) ; aL = min( max(Tc,Tm), aL) ! Bound - aR = ( 5.*Tc + ( 2.*Tp - Tm ) )/6. ! H3 estimate - aR = max( min(Tc,Tp), aR) ; aR = min( max(Tc,Tp), aR) ! Bound - else - aL = 0.5 * ((Tm + Tc) + (slope_x(i_up-1,m) - slope_x(i_up,m)) / 3.) - aR = 0.5 * ((Tc + Tp) + (slope_x(i_up,m) - slope_x(i_up+1,m)) / 3.) - endif + ! Implementation of PPM-H3 + Tp = T_tmp(i_up+1,m) ; Tc = T_tmp(i_up,m) ; Tm = T_tmp(i_up-1,m) + + if (useHuynh) then + aL = ( 5.*Tc + ( 2.*Tm - Tp ) )/6. ! H3 estimate + aL = max( min(Tc,Tm), aL) ; aL = min( max(Tc,Tm), aL) ! Bound + aR = ( 5.*Tc + ( 2.*Tp - Tm ) )/6. ! H3 estimate + aR = max( min(Tc,Tp), aR) ; aR = min( max(Tc,Tp), aR) ! Bound + else + aL = 0.5 * ((Tm + Tc) + (slope_x(i_up-1,m) - slope_x(i_up,m)) / 3.) + aR = 0.5 * ((Tc + Tp) + (slope_x(i_up,m) - slope_x(i_up+1,m)) / 3.) + endif - dA = aR - aL ; mA = 0.5*( aR + aL ) - if (G%mask2dCu(I_up,j)*G%mask2dCu(I_up-1,j)*(Tp-Tc)*(Tc-Tm) <= 0.) then - aL = Tc ; aR = Tc ! PCM for local extrema and boundary cells - elseif ( dA*(Tc-mA) > (dA*dA)/6. ) then - aL = (3.*Tc) - 2.*aR - elseif ( dA*(Tc-mA) < - (dA*dA)/6. ) then - aR = (3.*Tc) - 2.*aL - endif + dA = aR - aL ; mA = 0.5*( aR + aL ) + if (G%mask2dCu(I_up,j)*G%mask2dCu(I_up-1,j)*(Tp-Tc)*(Tc-Tm) <= 0.) then + aL = Tc ; aR = Tc ! PCM for local extrema and boundary cells + elseif ( dA*(Tc-mA) > (dA*dA)/6. ) then + aL = 3.*Tc - 2.*aR + elseif ( dA*(Tc-mA) < - (dA*dA)/6. ) then + aR = 3.*Tc - 2.*aL + endif - a6 = 6.*Tc - 3. * (aR + aL) ! Curvature + a6 = 6.*Tc - 3. * (aR + aL) ! Curvature - if (uhh(I) >= 0.0) then - flux_x(I,j,m) = uhh(I)*( aR - 0.5 * CFL(I) * ( & - ( aR - aL ) - a6 * ( 1. - 2./3. * CFL(I) ) ) ) - else - flux_x(I,j,m) = uhh(I)*( aL + 0.5 * CFL(I) * ( & - ( aR - aL ) + a6 * ( 1. - 2./3. * CFL(I) ) ) ) + if (uhh(I) >= 0.0) then + flux_x(I,j,m) = uhh(I)*( aR - 0.5 * CFL(I) * ( & + ( aR - aL ) - a6 * ( 1. - 2./3. * CFL(I) ) ) ) + else + flux_x(I,j,m) = uhh(I)*( aL + 0.5 * CFL(I) * ( & + ( aR - aL ) + a6 * ( 1. - 2./3. * CFL(I) ) ) ) + endif + enddo endif - enddo ; enddo + enddo else ! PLM - do m=1,ntr ; do I=is-1,ie - if (uhh(I) >= 0.0) then - ! Indirect implementation of PLM - !aL = Tr(m)%t(i,j,k) - 0.5 * slope_x(i,m) - !aR = Tr(m)%t(i,j,k) + 0.5 * slope_x(i,m) - !flux_x(I,j,m) = uhh(I)*( aR - 0.5 * (aR-aL) * CFL(I) ) - ! Alternative implementation of PLM - Tc = T_tmp(i,m) - flux_x(I,j,m) = uhh(I)*( Tc + 0.5 * slope_x(i,m) * ( 1. - CFL(I) ) ) - else - ! Indirect implementation of PLM - !aL = Tr(m)%t(i+1,j,k) - 0.5 * slope_x(i+1,m) - !aR = Tr(m)%t(i+1,j,k) + 0.5 * slope_x(i+1,m) - !flux_x(I,j,m) = uhh(I)*( aL + 0.5 * (aR-aL) * CFL(I) ) - ! Alternative implementation of PLM - Tc = T_tmp(i+1,m) - flux_x(I,j,m) = uhh(I)*( Tc - 0.5 * slope_x(i+1,m) * ( 1. - CFL(I) ) ) + do m=1,ntr + if (advect_this_tracer(m)) then + do I=is-1,ie + if (uhh(I) >= 0.0) then + ! Indirect implementation of PLM + !aL = Tr(m)%t(i,j,k) - 0.5 * slope_x(i,m) + !aR = Tr(m)%t(i,j,k) + 0.5 * slope_x(i,m) + !flux_x(I,j,m) = uhh(I)*( aR - 0.5 * (aR-aL) * CFL(I) ) + ! Alternative implementation of PLM + Tc = T_tmp(i,m) + flux_x(I,j,m) = uhh(I)*( Tc + 0.5 * slope_x(i,m) * ( 1. - CFL(I) ) ) + else + ! Indirect implementation of PLM + !aL = Tr(m)%t(i+1,j,k) - 0.5 * slope_x(i+1,m) + !aR = Tr(m)%t(i+1,j,k) + 0.5 * slope_x(i+1,m) + !flux_x(I,j,m) = uhh(I)*( aL + 0.5 * (aR-aL) * CFL(I) ) + ! Alternative implementation of PLM + Tc = T_tmp(i+1,m) + flux_x(I,j,m) = uhh(I)*( Tc - 0.5 * slope_x(i+1,m) * ( 1. - CFL(I) ) ) + endif + enddo endif - enddo ; enddo + enddo endif ! usePPM if (associated(OBC)) then ; if (OBC%OBC_pe) then @@ -593,9 +672,11 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & ! should the reservoir evolve for this case Kate ?? - Nope do m=1,segment%tr_Reg%ntseg ntr_id = segment%tr_reg%Tr(m)%ntr_index - if (allocated(segment%tr_Reg%Tr(m)%tres)) then - flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%tres(I,j,k) - else ; flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + if (advect_this_tracer(ntr_id)) then + if (allocated(segment%tr_Reg%Tr(m)%tres)) then + flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%tres(I,j,k) + else ; flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + endif ! advect_this_tracer enddo endif endif @@ -617,9 +698,11 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & uhh(I) = uhr(I,j,k) do m=1,segment%tr_Reg%ntseg ntr_id = segment%tr_reg%Tr(m)%ntr_index - if (allocated(segment%tr_Reg%Tr(m)%tres)) then - flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%tres(I,j,k) - else; flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%OBC_inflow_conc; endif + if (advect_this_tracer(ntr_id)) then + if (allocated(segment%tr_Reg%Tr(m)%tres)) then + flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%tres(I,j,k) + else; flux_x(I,j,ntr_id) = uhh(I)*segment%tr_Reg%Tr(m)%OBC_inflow_conc; endif + endif ! advect_this_tracer enddo endif endif @@ -650,60 +733,78 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & ! update tracer concentration from i-flux and save some diagnostics do m=1,ntr - - ! update tracer - do i=is,ie - if (do_i(i,j)) then - if (Ihnew(i) > 0.0) then - Tr(m)%t(i,j,k) = (Tr(m)%t(i,j,k) * hlst(i) - & - (flux_x(I,j,m) - flux_x(I-1,j,m))) * Ihnew(i) + if (advect_this_tracer(m)) then + + ! update tracer + if (flux_type == 0) then ! Only update tracer if using residual flux + do i=is,ie + if (do_i(i,j)) then + if (Ihnew(i) > 0.0) then + Tr(m)%t(i,j,k) = (Tr(m)%t(i,j,k) * hlst(i) - & + (flux_x(I,j,m) - flux_x(I-1,j,m))) * Ihnew(i) + endif + endif + enddo + endif ! flux_type == 0 + + ! diagnostics + if (flux_type == 0) then + if (associated(Tr(m)%ad_x)) then ; do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then + Tr(m)%ad_x(I,j,k) = Tr(m)%ad_x(I,j,k) + flux_x(I,j,m)*Idt + endif ; enddo ; endif + + ! diagnose convergence of flux_x (do not use the Ihnew(i) part of the logic). + ! division by areaT to get into W/m2 for heat and kg/(s*m2) for salt. + if (associated(Tr(m)%advection_xy)) then + do i=is,ie ; if (do_i(i,j)) then + Tr(m)%advection_xy(i,j,k) = Tr(m)%advection_xy(i,j,k) - (flux_x(I,j,m) - flux_x(I-1,j,m)) * & + Idt * G%IareaT(i,j) + endif ; enddo endif - endif - enddo - - ! diagnostics - if (associated(Tr(m)%ad_x)) then ; do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then - Tr(m)%ad_x(I,j,k) = Tr(m)%ad_x(I,j,k) + flux_x(I,j,m)*Idt - endif ; enddo ; endif - - ! diagnose convergence of flux_x (do not use the Ihnew(i) part of the logic). - ! division by areaT to get into W/m2 for heat and kg/(s*m2) for salt. - if (associated(Tr(m)%advection_xy)) then - do i=is,ie ; if (do_i(i,j)) then - Tr(m)%advection_xy(i,j,k) = Tr(m)%advection_xy(i,j,k) - (flux_x(I,j,m) - flux_x(I-1,j,m)) * & - Idt * G%IareaT(i,j) - endif ; enddo - endif - + elseif (flux_type == 1) then + if (associated(Tr(m)%ad_x_resolved)) then ; do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then + Tr(m)%ad_x_resolved(I,j,k) = Tr(m)%ad_x_resolved(I,j,k) + flux_x(I,j,m)*Idt + endif ; enddo ; endif + elseif (flux_type == 2) then + if (associated(Tr(m)%ad_x_param)) then ; do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then + Tr(m)%ad_x_param(I,j,k) = Tr(m)%ad_x_param(I,j,k) + flux_x(I,j,m)*Idt + endif ; enddo ; endif + endif ! the case of flux_type not equal 0, 1, or 2 is caught in advect_tracer above. + endif ! advect_this_tracer enddo endif ; enddo ! End of j-loop. ! Do user controlled underflow of the tracer concentrations. - do m=1,ntr ; if (Tr(m)%conc_underflow > 0.0) then - do j=js,je ; do i=is,ie - if (abs(Tr(m)%t(i,j,k)) < Tr(m)%conc_underflow) Tr(m)%t(i,j,k) = 0.0 - enddo ; enddo - endif ; enddo + if (flux_type == 0) then ! Only update tracer if using residual flux + do m=1,ntr ; if (Tr(m)%conc_underflow > 0.0) then + do j=js,je ; do i=is,ie + if (abs(Tr(m)%t(i,j,k)) < Tr(m)%conc_underflow) Tr(m)%t(i,j,k) = 0.0 + enddo ; enddo + endif ; enddo + endif ! compute ad2d_x diagnostic outside above j-loop so as to make the summation ordered when OMP is active. - !$OMP ordered - do m=1,ntr ; if (associated(Tr(m)%ad2d_x)) then - do j=js,je ; if (domore_u_initial(j,k)) then - do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then - Tr(m)%ad2d_x(I,j) = Tr(m)%ad2d_x(I,j) + flux_x(I,j,m)*Idt + if (flux_type == 0) then ! Only update tracer if using residual flux + !$OMP ordered + do m=1,ntr ; if (associated(Tr(m)%ad2d_x)) then + do j=js,je ; if (domore_u_initial(j,k)) then + do I=is-1,ie ; if (do_i(i,j) .or. do_i(i+1,j)) then + Tr(m)%ad2d_x(I,j) = Tr(m)%ad2d_x(I,j) + flux_x(I,j,m)*Idt + endif ; enddo endif ; enddo - endif ; enddo - endif ; enddo ! End of m-loop. - !$OMP end ordered + endif ; enddo ! End of m-loop. + !$OMP end ordered + endif end subroutine advect_x !> This subroutine does 1-d flux-form advection using a monotonic piecewise !! linear scheme. subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & - is, ie, js, je, k, G, GV, US, usePPM, useHuynh) + is, ie, js, je, k, G, GV, US, usePPM, useHuynh, & + flux_type, advect_this_tracer) type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure integer, intent(in) :: ntr !< The number of tracers @@ -727,6 +828,10 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & logical, intent(in) :: usePPM !< If true, use PPM instead of PLM logical, intent(in) :: useHuynh !< If true, use the Huynh scheme !! for PPM interface values + integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to + !! the residual (= 0), resolved (= 1), or parameterized (= 2) + !! flow + logical, dimension(ntr), intent(in) :: advect_this_tracer !< If true, advect this tracer real, dimension(SZI_(G),ntr,SZJ_(G)) :: & slope_y ! The concentration slope per grid point [conc]. @@ -791,35 +896,43 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & ! Calculate the j-direction profiles (slopes) of each tracer that ! is being advected. if (usePLMslope) then - do j=js-stencil,je+stencil ; if (do_j_tr(j)) then ; do m=1,ntr ; do i=is,ie - !if (ABS(Tr(m)%t(i,j+1,k)-Tr(m)%t(i,j,k)) < & - ! ABS(Tr(m)%t(i,j,k)-Tr(m)%t(i,j-1,k))) then - ! maxslope = 4.0*(Tr(m)%t(i,j+1,k)-Tr(m)%t(i,j,k)) - !else - ! maxslope = 4.0*(Tr(m)%t(i,j,k)-Tr(m)%t(i,j-1,k)) - !endif - !if ((Tr(m)%t(i,j+1,k)-Tr(m)%t(i,j,k))*(Tr(m)%t(i,j,k)-Tr(m)%t(i,j-1,k)) < 0.0) then - ! slope_y(i,m,j) = 0.0 - !elseif (ABS(Tr(m)%t(i,j+1,k)-Tr(m)%t(i,j-1,k))= 0.0) then - j_up = j - else - j_up = j + 1 - endif - - ! Implementation of PPM-H3 - Tp = T_tmp(i,m,j_up+1) ; Tc = T_tmp(i,m,j_up) ; Tm = T_tmp(i,m,j_up-1) + do m=1,ntr + if (advect_this_tracer(m)) then + do i=is,ie + ! centre cell depending on upstream direction + if (vhh(i,J) >= 0.0) then + j_up = j + else + j_up = j + 1 + endif - if (useHuynh) then - aL = ( 5.*Tc + ( 2.*Tm - Tp ) )/6. ! H3 estimate - aL = max( min(Tc,Tm), aL) ; aL = min( max(Tc,Tm), aL) ! Bound - aR = ( 5.*Tc + ( 2.*Tp - Tm ) )/6. ! H3 estimate - aR = max( min(Tc,Tp), aR) ; aR = min( max(Tc,Tp), aR) ! Bound - else - aL = 0.5 * ((Tm + Tc) + (slope_y(i,m,j_up-1) - slope_y(i,m,j_up)) / 3.) - aR = 0.5 * ((Tc + Tp) + (slope_y(i,m,j_up) - slope_y(i,m,j_up+1)) / 3.) - endif + ! Implementation of PPM-H3 + Tp = T_tmp(i,m,j_up+1) ; Tc = T_tmp(i,m,j_up) ; Tm = T_tmp(i,m,j_up-1) + + if (useHuynh) then + aL = ( 5.*Tc + ( 2.*Tm - Tp ) )/6. ! H3 estimate + aL = max( min(Tc,Tm), aL) ; aL = min( max(Tc,Tm), aL) ! Bound + aR = ( 5.*Tc + ( 2.*Tp - Tm ) )/6. ! H3 estimate + aR = max( min(Tc,Tp), aR) ; aR = min( max(Tc,Tp), aR) ! Bound + else + aL = 0.5 * ((Tm + Tc) + (slope_y(i,m,j_up-1) - slope_y(i,m,j_up)) / 3.) + aR = 0.5 * ((Tc + Tp) + (slope_y(i,m,j_up) - slope_y(i,m,j_up+1)) / 3.) + endif - dA = aR - aL ; mA = 0.5*( aR + aL ) - if (G%mask2dCv(i,J_up)*G%mask2dCv(i,J_up-1)*(Tp-Tc)*(Tc-Tm) <= 0.) then - aL = Tc ; aR = Tc ! PCM for local extrema and boundary cells - elseif ( dA*(Tc-mA) > (dA*dA)/6. ) then - aL = (3.*Tc) - 2.*aR - elseif ( dA*(Tc-mA) < - (dA*dA)/6. ) then - aR = (3.*Tc) - 2.*aL - endif + dA = aR - aL ; mA = 0.5*( aR + aL ) + if (G%mask2dCv(i,J_up)*G%mask2dCv(i,J_up-1)*(Tp-Tc)*(Tc-Tm) <= 0.) then + aL = Tc ; aR = Tc ! PCM for local extrema and boundary cells + elseif ( dA*(Tc-mA) > (dA*dA)/6. ) then + aL = 3.*Tc - 2.*aR + elseif ( dA*(Tc-mA) < - (dA*dA)/6. ) then + aR = 3.*Tc - 2.*aL + endif - a6 = 6.*Tc - 3. * (aR + aL) ! Curvature + a6 = 6.*Tc - 3. * (aR + aL) ! Curvature - if (vhh(i,J) >= 0.0) then - flux_y(i,m,J) = vhh(i,J)*( aR - 0.5 * CFL(i) * ( & - ( aR - aL ) - a6 * ( 1. - 2./3. * CFL(I) ) ) ) - else - flux_y(i,m,J) = vhh(i,J)*( aL + 0.5 * CFL(i) * ( & - ( aR - aL ) + a6 * ( 1. - 2./3. * CFL(I) ) ) ) - endif - enddo ; enddo + if (vhh(i,J) >= 0.0) then + flux_y(i,m,J) = vhh(i,J)*( aR - 0.5 * CFL(i) * ( & + ( aR - aL ) - a6 * ( 1. - 2./3. * CFL(I) ) ) ) + else + flux_y(i,m,J) = vhh(i,J)*( aL + 0.5 * CFL(i) * ( & + ( aR - aL ) + a6 * ( 1. - 2./3. * CFL(I) ) ) ) + endif + enddo + endif ! advect_this_tracer + enddo else ! PLM - do m=1,ntr ; do i=is,ie - if (vhh(i,J) >= 0.0) then - ! Indirect implementation of PLM - !aL = Tr(m)%t(i,j,k) - 0.5 * slope_y(i,m,j) - !aR = Tr(m)%t(i,j,k) + 0.5 * slope_y(i,m,j) - !flux_y(i,m,J) = vhh(i,J)*( aR - 0.5 * (aR-aL) * CFL(i) ) - ! Alternative implementation of PLM - Tc = T_tmp(i,m,j) - flux_y(i,m,J) = vhh(i,J)*( Tc + 0.5 * slope_y(i,m,j) * ( 1. - CFL(i) ) ) - else - ! Indirect implementation of PLM - !aL = Tr(m)%t(i,j+1,k) - 0.5 * slope_y(i,m,j+1) - !aR = Tr(m)%t(i,j+1,k) + 0.5 * slope_y(i,m,j+1) - !flux_y(i,m,J) = vhh(i,J)*( aL + 0.5 * (aR-aL) * CFL(i) ) - ! Alternative implementation of PLM - Tc = T_tmp(i,m,j+1) - flux_y(i,m,J) = vhh(i,J)*( Tc - 0.5 * slope_y(i,m,j+1) * ( 1. - CFL(i) ) ) - endif - enddo ; enddo + do m=1,ntr + if (advect_this_tracer(m)) then + do i=is,ie + if (vhh(i,J) >= 0.0) then + ! Indirect implementation of PLM + !aL = Tr(m)%t(i,j,k) - 0.5 * slope_y(i,m,j) + !aR = Tr(m)%t(i,j,k) + 0.5 * slope_y(i,m,j) + !flux_y(i,m,J) = vhh(i,J)*( aR - 0.5 * (aR-aL) * CFL(i) ) + ! Alternative implementation of PLM + Tc = T_tmp(i,m,j) + flux_y(i,m,J) = vhh(i,J)*( Tc + 0.5 * slope_y(i,m,j) * ( 1. - CFL(i) ) ) + else + ! Indirect implementation of PLM + !aL = Tr(m)%t(i,j+1,k) - 0.5 * slope_y(i,m,j+1) + !aR = Tr(m)%t(i,j+1,k) + 0.5 * slope_y(i,m,j+1) + !flux_y(i,m,J) = vhh(i,J)*( aL + 0.5 * (aR-aL) * CFL(i) ) + ! Alternative implementation of PLM + Tc = T_tmp(i,m,j+1) + flux_y(i,m,J) = vhh(i,J)*( Tc - 0.5 * slope_y(i,m,j+1) * ( 1. - CFL(i) ) ) + endif + enddo + endif ! advect_this_tracer + enddo endif ! usePPM if (associated(OBC)) then ; if (OBC%OBC_pe) then @@ -978,9 +1103,11 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & vhh(i,J) = vhr(i,J,k) do m=1,segment%tr_Reg%ntseg ntr_id = segment%tr_reg%Tr(m)%ntr_index - if (allocated(segment%tr_Reg%Tr(m)%tres)) then - flux_y(i,ntr_id,J) = vhh(i,J)*OBC%segment(n)%tr_Reg%Tr(m)%tres(i,J,k) - else ; flux_y(i,ntr_id,J) = vhh(i,J)*OBC%segment(n)%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + if (advect_this_tracer(ntr_id)) then + if (allocated(segment%tr_Reg%Tr(m)%tres)) then + flux_y(i,ntr_id,J) = vhh(i,J)*OBC%segment(n)%tr_Reg%Tr(m)%tres(i,J,k) + else ; flux_y(i,ntr_id,J) = vhh(i,J)*OBC%segment(n)%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + endif ! advect_this_tracer enddo endif enddo @@ -1002,9 +1129,11 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & vhh(i,J) = vhr(i,J,k) do m=1,segment%tr_Reg%ntseg ntr_id = segment%tr_reg%Tr(m)%ntr_index - if (allocated(segment%tr_Reg%Tr(m)%tres)) then - flux_y(i,ntr_id,J) = vhh(i,J)*segment%tr_Reg%Tr(m)%tres(i,J,k) - else ; flux_y(i,ntr_id,J) = vhh(i,J)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + if (advect_this_tracer(ntr_id)) then + if (allocated(segment%tr_Reg%Tr(m)%tres)) then + flux_y(i,ntr_id,J) = vhh(i,J)*segment%tr_Reg%Tr(m)%tres(i,J,k) + else ; flux_y(i,ntr_id,J) = vhh(i,J)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ; endif + endif ! advect_this_tracer enddo endif enddo @@ -1015,7 +1144,11 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & else ! not domore_v. do i=is,ie ; vhh(i,J) = 0.0 ; enddo - do m=1,ntr ; do i=is,ie ; flux_y(i,m,J) = 0.0 ; enddo ; enddo + do m=1,ntr + if (advect_this_tracer(m)) then + do i=is,ie ; flux_y(i,m,J) = 0.0 ; enddo + endif ! advect_this_tracer + enddo endif ; enddo ! End of j-loop do J=js-1,je ; do i=is,ie @@ -1041,48 +1174,76 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & ! update tracer and save some diagnostics do m=1,ntr - do i=is,ie ; if (do_i(i,j)) then - Tr(m)%t(i,j,k) = (Tr(m)%t(i,j,k) * hlst(i) - & - (flux_y(i,m,J) - flux_y(i,m,J-1))) * Ihnew(i) - endif ; enddo + if (advect_this_tracer(m)) then - ! diagnose convergence of flux_y and add to convergence of flux_x. - ! division by areaT to get into W/m2 for heat and kg/(s*m2) for salt. - if (associated(Tr(m)%advection_xy)) then - do i=is,ie ; if (do_i(i,j)) then - Tr(m)%advection_xy(i,j,k) = Tr(m)%advection_xy(i,j,k) - (flux_y(i,m,J) - flux_y(i,m,J-1))* Idt * & - G%IareaT(i,j) - endif ; enddo - endif + if (flux_type == 0) then ! Only update tracer if using residual flux + do i=is,ie ; if (do_i(i,j)) then + Tr(m)%t(i,j,k) = (Tr(m)%t(i,j,k) * hlst(i) - & + (flux_y(i,m,J) - flux_y(i,m,J-1))) * Ihnew(i) + endif ; enddo + ! diagnose convergence of flux_y and add to convergence of flux_x. + ! division by areaT to get into W/m2 for heat and kg/(s*m2) for salt. + if (associated(Tr(m)%advection_xy)) then + do i=is,ie ; if (do_i(i,j)) then + Tr(m)%advection_xy(i,j,k) = Tr(m)%advection_xy(i,j,k) - (flux_y(i,m,J) - flux_y(i,m,J-1))* Idt * & + G%IareaT(i,j) + endif ; enddo + endif + endif ! flux_type == 0 + endif ! advect_this_tracer enddo endif ; enddo ! End of j-loop. ! Do user controlled underflow of the tracer concentrations. - do m=1,ntr ; if (Tr(m)%conc_underflow > 0.0) then - do j=js,je ; do i=is,ie - if (abs(Tr(m)%t(i,j,k)) < Tr(m)%conc_underflow) Tr(m)%t(i,j,k) = 0.0 - enddo ; enddo - endif ; enddo + if (flux_type == 0) then ! Only update tracer if using residual flux + do m=1,ntr ; if (Tr(m)%conc_underflow > 0.0) then + do j=js,je ; do i=is,ie + if (abs(Tr(m)%t(i,j,k)) < Tr(m)%conc_underflow) Tr(m)%t(i,j,k) = 0.0 + enddo ; enddo + endif ; enddo + endif ! compute ad_y and ad2d_y diagnostic outside above j-loop so as to make the summation ordered when OMP is active. - !$OMP ordered - do m=1,ntr ; if (associated(Tr(m)%ad_y)) then - do J=js-1,je ; if (domore_v_initial(J)) then - do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then - Tr(m)%ad_y(i,J,k) = Tr(m)%ad_y(i,J,k) + flux_y(i,m,J)*Idt + if (flux_type == 0) then + !$OMP ordered + do m=1,ntr ; if (associated(Tr(m)%ad_y)) then + do J=js-1,je ; if (domore_v_initial(J)) then + do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then + Tr(m)%ad_y(i,J,k) = Tr(m)%ad_y(i,J,k) + flux_y(i,m,J)*Idt + endif ; enddo endif ; enddo - endif ; enddo - endif ; enddo ! End of m-loop. + endif ; enddo ! End of m-loop. - do m=1,ntr ; if (associated(Tr(m)%ad2d_y)) then - do J=js-1,je ; if (domore_v_initial(J)) then - do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then - Tr(m)%ad2d_y(i,J) = Tr(m)%ad2d_y(i,J) + flux_y(i,m,J)*Idt + do m=1,ntr ; if (associated(Tr(m)%ad2d_y)) then + do J=js-1,je ; if (domore_v_initial(J)) then + do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then + Tr(m)%ad2d_y(i,J) = Tr(m)%ad2d_y(i,J) + flux_y(i,m,J)*Idt + endif ; enddo endif ; enddo - endif ; enddo - endif ; enddo ! End of m-loop. - !$OMP end ordered + endif ; enddo ! End of m-loop. + !$OMP end ordered + elseif (flux_type == 1) then + !$OMP ordered + do m=1,ntr ; if (associated(Tr(m)%ad_y_resolved)) then + do J=js-1,je ; if (domore_v_initial(J)) then + do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then + Tr(m)%ad_y_resolved(i,J,k) = Tr(m)%ad_y_resolved(i,J,k) + flux_y(i,m,J)*Idt + endif ; enddo + endif ; enddo + endif ; enddo ! End of m-loop. + !$OMP end ordered + elseif (flux_type == 2) then + !$OMP ordered + do m=1,ntr ; if (associated(Tr(m)%ad_y_param)) then + do J=js-1,je ; if (domore_v_initial(J)) then + do i=is,ie ; if (do_i(i,j) .or. do_i(i,j+1)) then + Tr(m)%ad_y_param(i,J,k) = Tr(m)%ad_y_param(i,J,k) + flux_y(i,m,J)*Idt + endif ; enddo + endif ; enddo + endif ; enddo ! End of m-loop. + !$OMP end ordered + endif ! the case of flux_type not equal 0, 1, or 2 is caught in advect_tracer above. end subroutine advect_y diff --git a/src/tracer/MOM_tracer_registry.F90 b/src/tracer/MOM_tracer_registry.F90 index f144faf69e..aa5e93ac87 100644 --- a/src/tracer/MOM_tracer_registry.F90 +++ b/src/tracer/MOM_tracer_registry.F90 @@ -353,6 +353,22 @@ subroutine register_tracer_diagnostics(Reg, h, Time, diag, G, GV, US, use_ALE, u diag%axesCvL, Time, trim(flux_longname)//" advective meridional flux" , & trim(flux_units), v_extensive=.true., x_cell_method='sum', & conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) + Tr%id_adx_resolved = register_diag_field("ocean_model", trim(shortnm)//"_adx_resolved", & + diag%axesCuL, Time, trim(flux_longname)//" resolved advective zonal flux" , & + trim(flux_units), v_extensive=.true., y_cell_method='sum', & + conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) + Tr%id_ady_resolved = register_diag_field("ocean_model", trim(shortnm)//"_ady_resolved", & + diag%axesCvL, Time, trim(flux_longname)//" resolved advective meridional flux" , & + trim(flux_units), v_extensive=.true., x_cell_method='sum', & + conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) + Tr%id_adx_param = register_diag_field("ocean_model", trim(shortnm)//"_adx_param", & + diag%axesCuL, Time, trim(flux_longname)//" parameterized advective zonal flux" , & + trim(flux_units), v_extensive=.true., y_cell_method='sum', & + conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) + Tr%id_ady_param = register_diag_field("ocean_model", trim(shortnm)//"_ady_param", & + diag%axesCvL, Time, trim(flux_longname)//" resolved parameterized meridional flux" , & + trim(flux_units), v_extensive=.true., x_cell_method='sum', & + conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) Tr%id_dfx = register_diag_field("ocean_model", trim(shortnm)//"_dfx", & diag%axesCuL, Time, trim(flux_longname)//" diffusive zonal flux" , & trim(flux_units), v_extensive=.true., y_cell_method='sum', & @@ -376,6 +392,18 @@ subroutine register_tracer_diagnostics(Reg, h, Time, diag, G, GV, US, use_ALE, u Tr%id_ady = register_diag_field("ocean_model", trim(shortnm)//"_ady", & diag%axesCvL, Time, "Advective (by residual mean) Meridional Flux of "//trim(flux_longname), & flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, x_cell_method='sum') + Tr%id_adx_resolved = register_diag_field("ocean_model", trim(shortnm)//"_adx_resolved", & + diag%axesCuL, Time, "Advective (by resolved flow) Zonal Flux of "//trim(flux_longname), & + flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, y_cell_method='sum') + Tr%id_ady_resolved = register_diag_field("ocean_model", trim(shortnm)//"_ady_resolved", & + diag%axesCvL, Time, "Advective (by resolved flow) Meridional Flux of "//trim(flux_longname), & + flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, x_cell_method='sum') + Tr%id_adx_param = register_diag_field("ocean_model", trim(shortnm)//"_adx_param", & + diag%axesCuL, Time, "Advective (by parameterized flow) Zonal Flux of "//trim(flux_longname), & + flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, y_cell_method='sum') + Tr%id_ady_param = register_diag_field("ocean_model", trim(shortnm)//"_ady_param", & + diag%axesCvL, Time, "Advective (by parameterized flow) Meridional Flux of "//trim(flux_longname), & + flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, x_cell_method='sum') Tr%id_dfx = register_diag_field("ocean_model", trim(shortnm)//"_diffx", & diag%axesCuL, Time, "Diffusive Zonal Flux of "//trim(flux_longname), & flux_units, v_extensive=.true., conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & @@ -405,6 +433,10 @@ subroutine register_tracer_diagnostics(Reg, h, Time, diag, G, GV, US, use_ALE, u diag%axesT1, Time, "Surface values of "// trim(longname), trim(units)) if (Tr%id_adx > 0) call safe_alloc_ptr(Tr%ad_x,IsdB,IedB,jsd,jed,nz) if (Tr%id_ady > 0) call safe_alloc_ptr(Tr%ad_y,isd,ied,JsdB,JedB,nz) + if (Tr%id_adx_resolved > 0) call safe_alloc_ptr(Tr%ad_x_resolved,IsdB,IedB,jsd,jed,nz) + if (Tr%id_ady_resolved > 0) call safe_alloc_ptr(Tr%ad_y_resolved,isd,ied,JsdB,JedB,nz) + if (Tr%id_adx_param > 0) call safe_alloc_ptr(Tr%ad_x_param,IsdB,IedB,jsd,jed,nz) + if (Tr%id_ady_param > 0) call safe_alloc_ptr(Tr%ad_y_param,isd,ied,JsdB,JedB,nz) if (Tr%id_dfx > 0) call safe_alloc_ptr(Tr%df_x,IsdB,IedB,jsd,jed,nz) if (Tr%id_dfy > 0) call safe_alloc_ptr(Tr%df_y,isd,ied,JsdB,JedB,nz) if (Tr%id_hbd_dfx > 0) call safe_alloc_ptr(Tr%hbd_dfx,IsdB,IedB,jsd,jed,nz) @@ -774,6 +806,10 @@ subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) if (Tr%id_tr_post_horzn> 0) call post_data(Tr%id_tr_post_horzn, Tr%t, diag) if (Tr%id_adx > 0) call post_data(Tr%id_adx, Tr%ad_x, diag, alt_h=h_diag) if (Tr%id_ady > 0) call post_data(Tr%id_ady, Tr%ad_y, diag, alt_h=h_diag) + if (Tr%id_adx_resolved > 0) call post_data(Tr%id_adx_resolved, Tr%ad_x_resolved, diag, alt_h=h_diag) + if (Tr%id_ady_resolved > 0) call post_data(Tr%id_ady_resolved, Tr%ad_y_resolved, diag, alt_h=h_diag) + if (Tr%id_adx_param > 0) call post_data(Tr%id_adx_param, Tr%ad_x_param, diag, alt_h=h_diag) + if (Tr%id_ady_param > 0) call post_data(Tr%id_ady_param, Tr%ad_y_param, diag, alt_h=h_diag) if (Tr%id_dfx > 0) call post_data(Tr%id_dfx, Tr%df_x, diag, alt_h=h_diag) if (Tr%id_dfy > 0) call post_data(Tr%id_dfy, Tr%df_y, diag, alt_h=h_diag) if (Tr%id_adx_2d > 0) call post_data(Tr%id_adx_2d, Tr%ad2d_x, diag) diff --git a/src/tracer/MOM_tracer_types.F90 b/src/tracer/MOM_tracer_types.F90 index 6809c865ee..f937bbc34f 100644 --- a/src/tracer/MOM_tracer_types.F90 +++ b/src/tracer/MOM_tracer_types.F90 @@ -19,6 +19,14 @@ module MOM_tracer_types !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:,:), pointer :: ad_y => NULL() !< diagnostic array for y-advective tracer flux !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_x_resolved => NULL() !< diagnostic array for x-advective resolved tracer flux + !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_y_resolved => NULL() !< diagnostic array for y-advective resolved tracer flux + !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_x_param => NULL() !< diagnostic array for x-advective parameterized tracer flux + !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_y_param => NULL() !< diagnostic array for y-advective parameterized tracer flux + !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:), pointer :: ad2d_x => NULL() !< diagnostic vertical sum x-advective tracer flux !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:), pointer :: ad2d_y => NULL() !< diagnostic vertical sum y-advective tracer flux @@ -104,6 +112,7 @@ module MOM_tracer_types !>@{ Diagnostic IDs integer :: id_tr = -1, id_tr_post_horzn = -1 integer :: id_adx = -1, id_ady = -1, id_dfx = -1, id_dfy = -1 + integer :: id_adx_resolved = -1, id_ady_resolved = -1, id_adx_param = -1, id_ady_param = -1 integer :: id_hbd_dfx = -1, id_hbd_dfy = -1 integer :: id_hbd_dfx_2d = -1, id_hbd_dfy_2d = -1 integer :: id_adx_2d = -1, id_ady_2d = -1, id_dfx_2d = -1, id_dfy_2d = -1 From 3b78f092eae77e664b1f0dc4f6f64421055f3f45 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Wed, 23 Apr 2025 10:37:58 -0600 Subject: [PATCH 05/41] add u and v coordinates to the ocean_geometry file (#353) * add geolat_u, geolat_v, geolon_u, and geolon_v coordinates to the ocean_geometry file. --- .../MOM_shared_initialization.F90 | 96 ++++++++++--------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/initialization/MOM_shared_initialization.F90 b/src/initialization/MOM_shared_initialization.F90 index 2197fdf038..dbdc855495 100644 --- a/src/initialization/MOM_shared_initialization.F90 +++ b/src/initialization/MOM_shared_initialization.F90 @@ -1361,7 +1361,7 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file) call callTree_enter('write_ocean_geometry_file()') - nFlds = 19 ; if (G%bathymetry_at_vel) nFlds = 23 + nFlds = 23 ; if (G%bathymetry_at_vel) nFlds = 27 allocate(vars(nFlds)) allocate(fields(nFlds)) @@ -1380,28 +1380,32 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file) vars(2) = var_desc("geolonb","degree","longitude at corner (Bu) points",'q','1','1') vars(3) = var_desc("geolat","degree", "latitude at tracer (T) points", 'h','1','1') vars(4) = var_desc("geolon","degree","longitude at tracer (T) points",'h','1','1') - vars(5) = var_desc("D","meter","Basin Depth",'h','1','1') - vars(6) = var_desc("f","s-1","Coriolis Parameter",'q','1','1') - vars(7) = var_desc("dxCv","m","Zonal grid spacing at v points",'v','1','1') - vars(8) = var_desc("dyCu","m","Meridional grid spacing at u points",'u','1','1') - vars(9) = var_desc("dxCu","m","Zonal grid spacing at u points",'u','1','1') - vars(10)= var_desc("dyCv","m","Meridional grid spacing at v points",'v','1','1') - vars(11)= var_desc("dxT","m","Zonal grid spacing at h points",'h','1','1') - vars(12)= var_desc("dyT","m","Meridional grid spacing at h points",'h','1','1') - vars(13)= var_desc("dxBu","m","Zonal grid spacing at q points",'q','1','1') - vars(14)= var_desc("dyBu","m","Meridional grid spacing at q points",'q','1','1') - vars(15)= var_desc("Ah","m2","Area of h cells",'h','1','1') - vars(16)= var_desc("Aq","m2","Area of q cells",'q','1','1') - - vars(17)= var_desc("dxCvo","m","Open zonal grid spacing at v points",'v','1','1') - vars(18)= var_desc("dyCuo","m","Open meridional grid spacing at u points",'u','1','1') - vars(19)= var_desc("wet", "nondim", "land or ocean?", 'h','1','1') + vars(5) = var_desc("geolatu","degree","latitude at zonal velocity (Cu) points",'u','1','1') + vars(6) = var_desc("geolonu","degree","longitude at zonal velocity (Cu) points",'u','1','1') + vars(7) = var_desc("geolatv","degree","latitude at meridional velocity (Cv) points",'v','1','1') + vars(8) = var_desc("geolonv","degree","longitude at meridional velocity (Cv) points",'v','1','1') + vars(9) = var_desc("D","meter","Basin Depth",'h','1','1') + vars(10)= var_desc("f","s-1","Coriolis Parameter",'q','1','1') + vars(11)= var_desc("dxCv","m","Zonal grid spacing at v points",'v','1','1') + vars(12)= var_desc("dyCu","m","Meridional grid spacing at u points",'u','1','1') + vars(13)= var_desc("dxCu","m","Zonal grid spacing at u points",'u','1','1') + vars(14)= var_desc("dyCv","m","Meridional grid spacing at v points",'v','1','1') + vars(15)= var_desc("dxT","m","Zonal grid spacing at h points",'h','1','1') + vars(16)= var_desc("dyT","m","Meridional grid spacing at h points",'h','1','1') + vars(17)= var_desc("dxBu","m","Zonal grid spacing at q points",'q','1','1') + vars(18)= var_desc("dyBu","m","Meridional grid spacing at q points",'q','1','1') + vars(19)= var_desc("Ah","m2","Area of h cells",'h','1','1') + vars(20)= var_desc("Aq","m2","Area of q cells",'q','1','1') + + vars(21)= var_desc("dxCvo","m","Open zonal grid spacing at v points",'v','1','1') + vars(22)= var_desc("dyCuo","m","Open meridional grid spacing at u points",'u','1','1') + vars(23)= var_desc("wet", "nondim", "land or ocean?", 'h','1','1') if (G%bathymetry_at_vel) then - vars(20) = var_desc("Dblock_u","m","Blocked depth at u points",'u','1','1') - vars(21) = var_desc("Dopen_u","m","Open depth at u points",'u','1','1') - vars(22) = var_desc("Dblock_v","m","Blocked depth at v points",'v','1','1') - vars(23) = var_desc("Dopen_v","m","Open depth at v points",'v','1','1') + vars(24) = var_desc("Dblock_u","m","Blocked depth at u points",'u','1','1') + vars(25) = var_desc("Dopen_u","m","Open depth at u points",'u','1','1') + vars(26) = var_desc("Dblock_v","m","Blocked depth at v points",'v','1','1') + vars(27) = var_desc("Dopen_v","m","Open depth at v points",'v','1','1') endif if (present(geom_file)) then @@ -1436,31 +1440,35 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file) call MOM_write_field(IO_handle, fields(2), G%Domain, G%geoLonBu) call MOM_write_field(IO_handle, fields(3), G%Domain, G%geoLatT) call MOM_write_field(IO_handle, fields(4), G%Domain, G%geoLonT) - - call MOM_write_field(IO_handle, fields(5), G%Domain, G%bathyT, unscale=US%Z_to_m) - call MOM_write_field(IO_handle, fields(6), G%Domain, G%CoriolisBu, unscale=US%s_to_T) - - call MOM_write_field(IO_handle, fields(7), G%Domain, G%dxCv, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(8), G%Domain, G%dyCu, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(9), G%Domain, G%dxCu, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(10), G%Domain, G%dyCv, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(11), G%Domain, G%dxT, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(12), G%Domain, G%dyT, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(13), G%Domain, G%dxBu, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(14), G%Domain, G%dyBu, unscale=US%L_to_m) - - call MOM_write_field(IO_handle, fields(15), G%Domain, G%areaT, unscale=US%L_to_m**2) - call MOM_write_field(IO_handle, fields(16), G%Domain, G%areaBu, unscale=US%L_to_m**2) - - call MOM_write_field(IO_handle, fields(17), G%Domain, G%dx_Cv, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(18), G%Domain, G%dy_Cu, unscale=US%L_to_m) - call MOM_write_field(IO_handle, fields(19), G%Domain, G%mask2dT) + call MOM_write_field(IO_handle, fields(5), G%Domain, G%geoLatCu) + call MOM_write_field(IO_handle, fields(6), G%Domain, G%geoLonCu) + call MOM_write_field(IO_handle, fields(7), G%Domain, G%geoLatCv) + call MOM_write_field(IO_handle, fields(8), G%Domain, G%geoLonCv) + + call MOM_write_field(IO_handle, fields(9), G%Domain, G%bathyT, unscale=US%Z_to_m) + call MOM_write_field(IO_handle, fields(10), G%Domain, G%CoriolisBu, unscale=US%s_to_T) + + call MOM_write_field(IO_handle, fields(11), G%Domain, G%dxCv, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(12), G%Domain, G%dyCu, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(13), G%Domain, G%dxCu, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(14), G%Domain, G%dyCv, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(15), G%Domain, G%dxT, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(16), G%Domain, G%dyT, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(17), G%Domain, G%dxBu, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(18), G%Domain, G%dyBu, unscale=US%L_to_m) + + call MOM_write_field(IO_handle, fields(19), G%Domain, G%areaT, unscale=US%L_to_m**2) + call MOM_write_field(IO_handle, fields(20), G%Domain, G%areaBu, unscale=US%L_to_m**2) + + call MOM_write_field(IO_handle, fields(21), G%Domain, G%dx_Cv, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(22), G%Domain, G%dy_Cu, unscale=US%L_to_m) + call MOM_write_field(IO_handle, fields(23), G%Domain, G%mask2dT) if (G%bathymetry_at_vel) then - call MOM_write_field(IO_handle, fields(20), G%Domain, G%Dblock_u, unscale=US%Z_to_m) - call MOM_write_field(IO_handle, fields(21), G%Domain, G%Dopen_u, unscale=US%Z_to_m) - call MOM_write_field(IO_handle, fields(22), G%Domain, G%Dblock_v, unscale=US%Z_to_m) - call MOM_write_field(IO_handle, fields(23), G%Domain, G%Dopen_v, unscale=US%Z_to_m) + call MOM_write_field(IO_handle, fields(24), G%Domain, G%Dblock_u, unscale=US%Z_to_m) + call MOM_write_field(IO_handle, fields(25), G%Domain, G%Dopen_u, unscale=US%Z_to_m) + call MOM_write_field(IO_handle, fields(26), G%Domain, G%Dblock_v, unscale=US%Z_to_m) + call MOM_write_field(IO_handle, fields(27), G%Domain, G%Dopen_v, unscale=US%Z_to_m) endif call IO_handle%close() From 6624bf83c2453cd03e3834315d522cad367d938c Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Mon, 28 Apr 2025 10:13:02 -0600 Subject: [PATCH 06/41] Fix ERS and DIMCS failures for when `USE_CR_GRID` is on (#357) * add missing scale arg when reading Cr_space * register MLD and h_ML as restart fields when BODNER23 is on * add dimensional scaling factor for sfc_buoy_flx when set to KPP_buoy_flux * fix OMP directive in mixedlayer_restrat_Bodner --- src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 | 4 ++-- src/parameterizations/vertical/MOM_diabatic_driver.F90 | 2 +- src/parameterizations/vertical/MOM_set_viscosity.F90 | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 41f6cd2dcc..9885b19f4b 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -1013,7 +1013,7 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d !$OMP default(shared) & !$OMP private(i, j, k, keep_going, line_is_empty, dh, & !$OMP grid_dsd, absf, h_sml, h_big, grd_b, r_wpup, psi_mag, IhTot, & - !$OMP sigint, muzb, muza, hAtVel, Rml_int, SpV_int) + !$OMP sigint, muzb, muza, hAtVel, Rml_int, SpV_int, rho_ml, SpV_ml, dmu ) !$OMP do do j=js-1,je+1 @@ -1779,7 +1779,7 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "The variable name for Cr field.", & default="Cr") filename = trim(inputdir) // "/" // trim(filename) - call MOM_read_data(filename, varname, CS%Cr_space, G%domain) + call MOM_read_data(filename, varname, CS%Cr_space, G%domain, scale=1.0) call pass_var(CS%Cr_space, G%domain) endif call closeParameterBlock(param_file) ! The remaining parameters do not have MLE% prepended diff --git a/src/parameterizations/vertical/MOM_diabatic_driver.F90 b/src/parameterizations/vertical/MOM_diabatic_driver.F90 index 7fe5d0b777..577c01ad6e 100644 --- a/src/parameterizations/vertical/MOM_diabatic_driver.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_driver.F90 @@ -1337,7 +1337,7 @@ subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions. if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV) if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:) - if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1) + if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1) * US%L_to_Z**2 if (showCallTree) call callTree_waypoint("done with KPP_calculate (diabatic)") if (CS%debug) then diff --git a/src/parameterizations/vertical/MOM_set_viscosity.F90 b/src/parameterizations/vertical/MOM_set_viscosity.F90 index 3b388385f5..574ea6baa9 100644 --- a/src/parameterizations/vertical/MOM_set_viscosity.F90 +++ b/src/parameterizations/vertical/MOM_set_viscosity.F90 @@ -2799,12 +2799,12 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C call safe_alloc_ptr(visc%h_ML, isd, ied, jsd, jed) endif - if (MLE_use_PBL_MLD) then + if (MLE_use_PBL_MLD .or. MLE_use_Bodner) then call register_restart_field(visc%MLD, "MLD", .false., restart_CS, & "Instantaneous active mixing layer depth", units="m", conversion=US%Z_to_m) endif if (MLE_use_PBL_MLD .or. do_brine_plume .or. use_fpmix .or. & - use_neutral_diffusion .or. use_hor_bnd_diff) then + use_neutral_diffusion .or. use_hor_bnd_diff .or. MLE_use_Bodner) then call register_restart_field(visc%h_ML, "h_ML", .false., restart_CS, & "Instantaneous active mixing layer thickness", & units=get_thickness_units(GV), conversion=GV%H_to_mks) From 450d3854b0e11fa7d5f54bca3c822ab7765a4698 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Mon, 19 May 2025 08:36:55 -0600 Subject: [PATCH 07/41] Add *_glc enthalpy terms in heat_in (#364) --- src/diagnostics/MOM_sum_output.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/diagnostics/MOM_sum_output.F90 b/src/diagnostics/MOM_sum_output.F90 index a0f1d5157e..f39a38d2c2 100644 --- a/src/diagnostics/MOM_sum_output.F90 +++ b/src/diagnostics/MOM_sum_output.F90 @@ -1089,7 +1089,8 @@ subroutine accumulate_net_input(fluxes, sfc_state, tv, dt, G, US, CS) heat_in(i,j) = heat_in(i,j) + dt * QRZL2_to_J * G%areaT(i,j) * & (fluxes%heat_content_evap(i,j) + fluxes%heat_content_lprec(i,j) + & fluxes%heat_content_cond(i,j) + fluxes%heat_content_fprec(i,j) + & - fluxes%heat_content_lrunoff(i,j) + fluxes%heat_content_frunoff(i,j)) + fluxes%heat_content_lrunoff(i,j) + fluxes%heat_content_frunoff(i,j) + & + fluxes%heat_content_lrunoff_glc(i,j) + fluxes%heat_content_frunoff_glc(i,j)) enddo ; enddo elseif (associated(tv%TempxPmE)) then do j=js,je ; do i=is,ie From b424dba4fcbb58cbc7f5d2e23e2445eab78fe126 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Tue, 24 Jun 2025 11:07:23 -0600 Subject: [PATCH 08/41] Remove left-over arguments --- src/tracer/MOM_tracer_advect.F90 | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/tracer/MOM_tracer_advect.F90 b/src/tracer/MOM_tracer_advect.F90 index 73fbe5e125..93c95c4a32 100644 --- a/src/tracer/MOM_tracer_advect.F90 +++ b/src/tracer/MOM_tracer_advect.F90 @@ -329,16 +329,14 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first ! First, advect zonally. call advect_x(Reg%Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & isv, iev, jsv-stencil, jev+stencil, k, G, GV, US, & - CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer, & - local_advect_scheme) + flux_type_ctrl, advect_this_tracer, local_advect_scheme) endif ; enddo !$OMP do ordered do k=1,nz ; if (domore_k(k) > 0) then ! Next, advect meridionally. call advect_y(Reg%Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & - isv, iev, jsv, jev, k, G, GV, US, & - CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer, & + isv, iev, jsv, jev, k, G, GV, US, flux_type_ctrl, advect_this_tracer, & local_advect_scheme) ! Update domore_k(k) for the next iteration @@ -355,16 +353,14 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first ! First, advect meridionally. call advect_y(Reg%Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & isv-stencil, iev+stencil, jsv, jev, k, G, GV, US, & - CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer, & - local_advect_scheme) + flux_type_ctrl, advect_this_tracer, local_advect_scheme) endif ; enddo !$OMP do ordered do k=1,nz ; if (domore_k(k) > 0) then ! Next, advect zonally. call advect_x(Reg%Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & - isv, iev, jsv, jev, k, G, GV, US, & - CS%usePPM, CS%useHuynh, flux_type_ctrl, advect_this_tracer, & + isv, iev, jsv, jev, k, G, GV, US, flux_type_ctrl, advect_this_tracer, & local_advect_scheme) ! Update domore_k(k) for the next iteration @@ -411,8 +407,8 @@ end subroutine advect_tracer !> This subroutine does 1-d flux-form advection in the zonal direction using !! a monotonic piecewise linear scheme. subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & - is, ie, js, je, k, G, GV, US, usePPM, useHuynh, & - flux_type, advect_this_tracer, advect_schemes) + is, ie, js, je, k, G, GV, US, flux_type, advect_this_tracer, & + advect_schemes) type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure integer, intent(in) :: ntr !< The number of tracers @@ -433,9 +429,6 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & integer, intent(in) :: je !< The ending tracer j-index to work on integer, intent(in) :: k !< The k-level to work on type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - logical, intent(in) :: usePPM !< If true, use PPM instead of PLM - logical, intent(in) :: useHuynh !< If true, use the Huynh scheme - !! for PPM interface values integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to !! the residual (= 0), resolved (= 1), or parameterized (= 2) !! flow @@ -861,8 +854,8 @@ end subroutine advect_x !> This subroutine does 1-d flux-form advection using a monotonic piecewise !! linear scheme. subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & - is, ie, js, je, k, G, GV, US, usePPM, useHuynh, & - flux_type, advect_this_tracer, advect_schemes) + is, ie, js, je, k, G, GV, US, flux_type, advect_this_tracer, & + advect_schemes) type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure integer, intent(in) :: ntr !< The number of tracers @@ -883,9 +876,6 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & integer, intent(in) :: je !< The ending tracer j-index to work on integer, intent(in) :: k !< The k-level to work on type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - logical, intent(in) :: usePPM !< If true, use PPM instead of PLM - logical, intent(in) :: useHuynh !< If true, use the Huynh scheme - !! for PPM interface values integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to !! the residual (= 0), resolved (= 1), or parameterized (= 2) !! flow From 0f11ed0c17df3802a0284f627d21131cf4cd9282 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Tue, 24 Jun 2025 16:30:38 -0600 Subject: [PATCH 09/41] Move instance suffix to correct position in restart file names (#366) * add the instance suffix to the correct part of the restart filename and do not re-add it later on * Revert "add the instance suffix to the correct part of the restart filename and do not re-add it later on" This reverts commit a749486cd1c1033a2890d69576de7f880a05561b. * fix multiinstance restart filename --- config_src/drivers/nuopc_cap/mom_cap.F90 | 10 ++++--- src/framework/MOM_restart.F90 | 33 +++++++++++++++++++++--- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_cap.F90 b/config_src/drivers/nuopc_cap/mom_cap.F90 index e0e618c76e..2c8271a028 100644 --- a/config_src/drivers/nuopc_cap/mom_cap.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap.F90 @@ -1943,12 +1943,14 @@ subroutine ModelAdvance(gcomp, rc) msg=subname//' ERROR opening '//rpointer_filename, line=__LINE__, file=u_FILE_u, rcToReturn=rc) return endif - if (len_trim(inst_suffix) == 0) then - write(writeunit,'(a)') trim(restartname)//'.nc' - else - write(writeunit,'(a)') trim(restartname)//'.'//trim(inst_suffix)//'.nc' + + ! update restart file name to include the instance suffix + if (len_trim(inst_suffix) > 0) then + write(restartname, '(A,".mom6",A,".r",A)') trim(casename), trim(inst_suffix), timestamp endif + write(writeunit,'(a)') trim(restartname)//'.nc' + if (num_rest_files > 1) then ! append i.th restart file name to rpointer do i=1, num_rest_files-1 diff --git a/src/framework/MOM_restart.F90 b/src/framework/MOM_restart.F90 index b99cd3f184..ce47e3b0fa 100644 --- a/src/framework/MOM_restart.F90 +++ b/src/framework/MOM_restart.F90 @@ -132,6 +132,7 @@ module MOM_restart type(p4d), pointer :: var_ptr4d(:) => NULL() !>@} integer :: max_fields !< The maximum number of restart fields + character(len=32) :: restartfile_appx_prefix !< The prefix for the restart file appendix (i.e., ensemble id) end type MOM_restart_CS !> Register fields for restarts @@ -1613,6 +1614,8 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_ integer :: turns ! Number of quarter turns from input to model domain integer, parameter :: nmax_extradims = 5 type(axis_info), dimension(:), allocatable :: extra_axes + integer :: prefix_index ! The index of the first occurrence of prefix in the restart filename. + integer :: prefix_length ! The length of the prefix string. turns = CS%turns @@ -1654,10 +1657,26 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_ call get_filename_appendix(filename_appendix) if (len_trim(filename_appendix) > 0) then length = len_trim(restartname) - if (restartname(length-2:length) == '.nc') then - restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc' - else - restartname = restartname(1:length) //'.'//trim(filename_appendix) + + ! Determine if a valid prefix for appendix is provided. + prefix_index = 0 + prefix_length = len_trim(CS%restartfile_appx_prefix) + if (prefix_length > 0) prefix_index = index(restartname, trim(CS%restartfile_appx_prefix)) + + if (prefix_index == 0) then ! No prefix is found + if (restartname(length-2:length) == '.nc') then + restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc' + else + restartname = restartname(1:length) //'.'//trim(filename_appendix) + endif + else ! Prefix is found + if (restartname(length-2:length) == '.nc') then + restartname = restartname(1:prefix_index-1+prefix_length) // & + trim(filename_appendix) // restartname(prefix_index+prefix_length:length-3) // '.nc' + else + restartname = restartname(1:prefix_index-1+prefix_length) // & + trim(filename_appendix) // restartname(prefix_index+prefix_length:) + endif endif endif @@ -2304,6 +2323,12 @@ subroutine restart_init(param_file, CS, restart_root) "made from a run with a different mask_table than the current run, "//& "in which case the checksums will not match and cause crash.",& default=.true.) + call get_param(param_file, mdl, "RESTARTFILE_APPENDIX_PREFIX", CS%restartfile_appx_prefix, & + "The prefix for the restart file appendix (i.e., ensemble id for ensemble runs). "// & + "If this prefix is found in the restart file name, the appendix is added right after the "// & + "first occurrence of the prefix. If not found, the appendix is added to the end of the "// & + "file name. This parameter is ignored for non-ensemble runs.", & + default="") call get_param(param_file, mdl, "RESTART_SYMMETRIC_CHECKSUMS", CS%symmetric_checksums, & "If true, do the restart checksums on all the edge points for a non-reentrant "//& "grid. This requires that SYMMETRIC_MEMORY_ is defined at compile time.", & From 142db86e5fd2e08b12f30f04c833d16ebc5694c0 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Mon, 30 Jun 2025 15:23:20 -0600 Subject: [PATCH 10/41] Fix OMP directives and reduce line length --- src/tracer/MOM_tracer_advect.F90 | 16 ++++++---------- src/tracer/MOM_tracer_types.F90 | 8 ++++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/tracer/MOM_tracer_advect.F90 b/src/tracer/MOM_tracer_advect.F90 index 93c95c4a32..223816a4da 100644 --- a/src/tracer/MOM_tracer_advect.F90 +++ b/src/tracer/MOM_tracer_advect.F90 @@ -244,7 +244,6 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first enddo !$OMP end parallel elseif (flux_type_ctrl == 1) then ! Flux is resolved - !$OMP do do m=1,ntr if (associated(Reg%Tr(m)%ad_x_resolved)) then Reg%Tr(m)%ad_x_resolved(:,:,:) = 0.0 @@ -255,9 +254,7 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first advect_this_tracer(m) = .true. ! advect this tracer endif enddo - !$OMP end parallel elseif (flux_type_ctrl == 2) then ! Flux is parameterized - !$OMP do do m=1,ntr if (associated(Reg%Tr(m)%ad_x_param)) then Reg%Tr(m)%ad_x_param(:,:,:) = 0.0 @@ -268,7 +265,6 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first advect_this_tracer(m) = .true. ! advect this tracer endif enddo - !$OMP end parallel else call MOM_error(FATAL, & "Inconsistent flux type in advect_tracer. Must be of 0 (residual), 1 (resolved), or 2 (parameterized)") @@ -429,9 +425,9 @@ subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, & integer, intent(in) :: je !< The ending tracer j-index to work on integer, intent(in) :: k !< The k-level to work on type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to - !! the residual (= 0), resolved (= 1), or parameterized (= 2) - !! flow + integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux + !! due to the residual (= 0), resolved (= 1), + !! or parameterized (= 2) flow logical, dimension(ntr), intent(in) :: advect_this_tracer !< If true, advect this tracer integer, dimension(ntr), intent(in) :: advect_schemes !< list of advection schemes to use @@ -876,9 +872,9 @@ subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, & integer, intent(in) :: je !< The ending tracer j-index to work on integer, intent(in) :: k !< The k-level to work on type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux due to - !! the residual (= 0), resolved (= 1), or parameterized (= 2) - !! flow + integer, intent(in) :: flux_type !< Indicates whether uhtr, vhtr are the flux + !! due to the residual (= 0), resolved (= 1), + !! or parameterized (= 2) flow logical, dimension(ntr), intent(in) :: advect_this_tracer !< If true, advect this tracer integer, dimension(ntr), intent(in) :: advect_schemes !< list of advection schemes to use diff --git a/src/tracer/MOM_tracer_types.F90 b/src/tracer/MOM_tracer_types.F90 index ae95f6caa4..a42f3ea72a 100644 --- a/src/tracer/MOM_tracer_types.F90 +++ b/src/tracer/MOM_tracer_types.F90 @@ -23,10 +23,10 @@ module MOM_tracer_types !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:,:), pointer :: ad_y_resolved => NULL() !< diagnostic array for y-advective resolved tracer flux !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] - real, dimension(:,:,:), pointer :: ad_x_param => NULL() !< diagnostic array for x-advective parameterized tracer flux - !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] - real, dimension(:,:,:), pointer :: ad_y_param => NULL() !< diagnostic array for y-advective parameterized tracer flux - !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_x_param => NULL() !< diagnostic array for x-advective parameterized tracer + !! flux [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] + real, dimension(:,:,:), pointer :: ad_y_param => NULL() !< diagnostic array for y-advective parameterized tracer + !! flux [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:), pointer :: ad2d_x => NULL() !< diagnostic vertical sum x-advective tracer flux !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] real, dimension(:,:), pointer :: ad2d_y => NULL() !< diagnostic vertical sum y-advective tracer flux From 55c187272bab33c908c00f4c25c6f99bcacb8385 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Mon, 30 Jun 2025 16:56:57 -0600 Subject: [PATCH 11/41] Move end parallel to after endif --- src/tracer/MOM_tracer_advect.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracer/MOM_tracer_advect.F90 b/src/tracer/MOM_tracer_advect.F90 index 223816a4da..7c80554ba9 100644 --- a/src/tracer/MOM_tracer_advect.F90 +++ b/src/tracer/MOM_tracer_advect.F90 @@ -242,7 +242,6 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first if (associated(Reg%Tr(m)%ad2d_x)) Reg%Tr(m)%ad2d_x(:,:) = 0.0 if (associated(Reg%Tr(m)%ad2d_y)) Reg%Tr(m)%ad2d_y(:,:) = 0.0 enddo - !$OMP end parallel elseif (flux_type_ctrl == 1) then ! Flux is resolved do m=1,ntr if (associated(Reg%Tr(m)%ad_x_resolved)) then @@ -269,6 +268,7 @@ subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, x_first call MOM_error(FATAL, & "Inconsistent flux type in advect_tracer. Must be of 0 (residual), 1 (resolved), or 2 (parameterized)") endif ! flux_type_ctrl + !$OMP end parallel isv = is ; iev = ie ; jsv = js ; jev = je From 59d31a6a15ec9eab512b639f81e7711a3fee621f Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Tue, 1 Jul 2025 10:34:32 -0600 Subject: [PATCH 12/41] Allow Leith+E and other Kh schemes to work at the same time (#358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Leith+E Smoothing Efficiency This commit replaces the smoothing in Leith+E (which applies to the velocity components, the coefficient `m_leithy`, and the biharmonic coefficient `Ah`). The old way applied a 3x3 weighted moving average twice. The new version applies a 5x5 weighted moving average once. In exact arithmetic the results are equivalent, but the new way reduces number of floating point operations by more than a factor of 3. * Bug fix for write_energy with short dt (#749) Fix a bug with subroutine write_energy when using a DT<2. Otherwise, the energy outputs are written at wrong time steps. The reason was that time type divide is essentially a floor. So DT/2 = 0 if DT<2. Remove extra copy of compute_global_grid_integrals The subroutine compute_global_grid_integrals appeared in both the MOM_state_initialization and MOM_shared_initialization modules, but was only being called from the latter. This commit removes the extra copy in MOM_state_initialization. It also removes some unnecessary parentheses in the copy that is being retained, in part to facilitate the review of this commit. All answers are bitwise identical, and no publicly visible interfaces are altered. Make REMAPPING_USE_OM4_SUBCELLS the default In addition to REMAPPING_USE_OM4_SUBCELLS, for ALE remapping, there are several parameters of the form XXX_REMAPPING_USE_OM4_SUBCELLS, where XXX identifies the target, and they all currently default to True. To simplify setting them all to False, which is recommended, the defaults for the XXX versions is changed to the value of REMAPPING_USE_OM4_SUBCELLS. Answers are only changed if REMAPPING_USE_OM4_SUBCELLS is set to False and the default (now False) is used for one or more of the other parameters. In such cases the original behaviour can be recovered by explicitly setting the other parameters to True. Removed default for mandatory time scale in OBCs Removed two instances of `fail_if_missing=.true., default=0.` which are contradictory: a default value is meaningless if the parameter must be specified. I encountered this when adding the `defaults=` option to `get_param_real_array()`. Adds a vector of default values to get_param_real_array() The `default=` optional argument to get_param() only provides a uniform value to initialize an array of reals. This commit adds the optional `defaults=` argument that must have the same length as the `values` argument. I've also added a few instances of this optional argument: - by adding the `initialize_thickness_param()` procedure, selected by `THICKNESS_CONFIG = "param"`. The procedure was based on the "uniform" method, and uses the parameter `THICKNESS_INIT_VALUES` which defaults to uniform values derived from `MAXIMUM_DEPTH` - the setting of MLD_EN_VALS in MOM_diabatic_driver.F90 which was previously using a work around to set defaults to 25, 2500, 250000 J/m2. - two vectors of 4 values in user/user_change_diffusivity.F90 There will be some doc file changes, but no answer changes. FMS API: Convert real kind of constants Two latent heat constants are imported directly from FMS, which is built independently of MOM6. Previously, it was a safe assumption that both would be built with double precision, but this is no longer the case since FMS now supports both single and double precision. This could cause conflicts with mixed-precision builds. This patch converts the values from FMS-precision to MOM-precision. Single->double should not affect reproducibility since every single-precision number can be exactly represented in double precision. Double->single could affect reproducibility, but this is not an issue since MOM6 does not run in single precision. Inline harmonic analysis (#744) * Inline harmonic analysis Important bug fix: 1) The Cholesky decomposition was operating on entries below the main diagonal of FtF, whereas in the accumulator of FtF, only entries along and above the main diagonal were calculated. In this revision, I modified HA_accum_FtF so that entries below the main diagonal are accumulated instead. 2) In the accumulator of FtSSH, the first entry for the mean (zero frequency) is moved out of the loop over different tidal constituents, so that it is not accumulated multiple times within a single time step. * Inline harmonic analysis Another bug fix: initial state added back to the mean state. * Inline harmonic analysis Minor update to HA_solver Tidal angular frequency has units [rad s-1] (#764) * Tidal angular frequency has units [rad s-1] Tidal frequencies are always angular frequencies to simplify applying sine and cosine. These have MKS units [rad s-1] but they are all currently listed as [s-1]. Updated dOxygen comments for variables, e.g. [T-1 ~> s-1] becomes [rad T-1 ~> rad s-1]. Updated get_param units. e.g. units="s-1" becomes units="rad s-1". No answers are changed, but the logged parameter units are different. There are frequencies in MOM_internal_tides.F90 but these have not been updated because they may be specified incorrectly. They are used as if they are [T-1] but they are calculated as 2PI/period [rad T-1]. real, allocatable, dimension(:) :: frequency !< The frequency of each band [T-1 ~> s-1]. real :: period ! A tidal period read from namelist [T ~> s] ! The periods of the tidal constituents for internal tides raytracing call read_param(param_file, "TIDAL_PERIODS", periods) do fr=1,num_freq period = US%s_to_T*extract_real(periods, " ,", fr, 0.) CS%frequency(fr) = 8.0*atan(1.0)/period enddo All MOM6-examples cases have INTERNAL_TIDES=False and so can't resolve this issue. * fixed too-long line Refactor of vertical reconstruction adding six new schemes (#741) add diagnostic for Kd_Work related to the Kd_add part (#765) * add diagnostic for Kd_Work related to the Kd_add part * also corrects some capitalization typos * fix id init --------- Co-authored-by: Raphael Dussin Co-authored-by: Alistair Adcroft +*Obsolete WIND_CONFIG = "SCM_ideal_hurr" (#770) Changed the code to issue a fatal error message when WIND_CONFIG = "SCM_ideal_hurr", with the message including instructions on how to recover mathematically equivalent solutions, and eliminated the subroutine SCM_idealized_hurricane_wind_forcing() from the Idealized_hurricane module. The ocean_only MOM_parameter_doc files have also been modified to reflect that "SCM_ideal_hurr" is no longer a valid setting for WIND_CONFIG. All answers are bitwise identical in any cases that run, but some cases may fail during initialization with instructions on how to fix them. *Fix a bug when EPBL_ORIGINAL_PE_CALC is false Corrected a bug that causes ePBL column to set the wrong variable and then use an uninitialized variable when EPBL_ORIGINAL_PE_CALC is set to false. This bug was present when the EPBL_ORIGINAL_PE_CALC was first added on Sept. 30, 2016, but it was not detected because only the default case with EPBL_ORIGINAL_PE_CALC = True appears to being used or tested. Any runs that used this code with debugging compile options would have trapped it immediately. This will change answers when EPBL_ORIGINAL_PE_CALC is false. +Add EPBL_MLD_ITER_BUG runtime parameter Added the new runtime parameter EPBL_MLD_ITER_BUG that can be set to false to correct buggy logic that gives the wrong bounds for the next iteration when USE_MLD_ITERATION is true and successive guesses increase by exactly EPBL_MLD_TOLERANCE. By default all answers are bitwise identical, but there is a new runtime parameter in some MOM_parameter_doc files. +Add run-time ability to debug ePBL sensitivities Added the ability to passively run ePBL_column twice in a diagnostic mode and then provide diagnostics of the differences in the diffusivities and boundary layer depths that are generated with the two options. This is controlled by the new runtime parameter EPBL_OPTIONS_DIFF, which is an integer that specifies which options to change or 0 (the default) to disable this capability. Associated with this are the new diagnostics ePBL_opt_diff_Kd_ePBL, ePBL_opt_maxdiff_Kd_ePBL and ePBL_opt_diff_h_ML, which only are registered when the differencing is enabled. For now, only changes associated with the settings of EPBL_ORIGINAL_PE_CALC and EPBL_ANSWER_DATE can be evaluated, but this list will grow as new options are added. As a part of these changes, there were some other reforms to the way that MOM_energetic_PBL handles diagnostics, with the 2-d and 3-d arrays changed from allocatable arrays with enduring memory commitments in the energetic_PBL_CS type into simple arrays in energetic_PBL, relying on the fact that compilers will be smart enough to avoid actually allocating this memory when it is unused to avoid expanding the overall memory requirements of MOM6. A number of allocate and deallocate calls were eliminated by these changes. In addition, explicit 'units=' descriptors were added to numerous register_diag_field calls to help identify inconsistent conversion factors. Also, the diagnostic of the number of boundary layer depth iterations was added to the ePBL_column_diags, which enabled the intent of the CS and G arguments to ePBL_column to be changed to intent(in). The unnecessary extra logic associated with the use of the OBL_converged variable in ePBL_column was eliminated, but the results are uneffected. Because the MOM_parameter_doc files were changing anyway, and because this commit is only a diagnostic change, about 6 spelling errors were corrected in ePBL parameter descriptions as a part of this commit. All answers are bitwise identical, but there is a new runtime parameter and there may be new diagnostics depending on the choice of a non-default value for that new parameter. +Add and test find_Kd_from_PE_chg Added the new internal subroutine find_Kd_from_PE_chg inside of the MOM_energetic_PBL module to directly calculate an increment in the diapycnal diffusivity from an energy input. This can be used when ePBL does not convert released mean kinetic energy into turbulent kinetic energy (i.e., if MKE_TO_TKE_EFFIC = 0.) and is more efficient than the more general iterative approach. To preserve old answers, this new option is only enabled for the surface boundary layer when the new runtime parameter DIRECT_EPBL_MIXING_CALC is set to true. This new option can be tested passively by setting EPBL_OPTIONS_DIFF to 3 in a run that uses ePBL. By default all answers are bitwise identical, but there is a new runtime parameter in some of the MOM_parameter_doc files. +(*)Add ePBL bottom boundary mixing option Add the option to do energetically consistent bottom boundary layer mixing with the new routine ePBL_BBL_column. ePBL_BBL_column is closely based on the surface-focused ePBL mixing in ePBL_column, but without adding convective instability driven mixing or mean-TKE driven mixing to avoid possible double-counting. This new option is enabled by setting the new runtime parameter EPBL_BBL_EFFIC to be positive. If both EPBL_BBL_EFFIC and BBL_EFFIC are set to positive values, there is a risk of double-counting, but this case is not being trapped for now. The changes include the addition of a new mandatory vertvisc_type argument to the publicly visible routine energetic_PBL. When this new ePBL bottom boundary layer mixing option is enabled, there are several new diagnostics available that are related to bottom boundary layer mixing. Several new checksum calls were also added with this new option when DEBUG = True. The MOM_parameter_doc files are altered by the addition of two new runtime parameters, and by the correction of several spelling errors in the descriptions of other ePBL parameters. By default, all answers are bitwise identical. +Add DECAY_ADJUSTED_BBL_TKE option for ePBL BBL Added the ability to modify the bottom boundary layer TKE budget to account for an exponential decay of TKE away from the boundary and the fact that when the diffusivity is increased at an interface, it causes an increased buoyancy flux that varies linearly throughout a well mixed bottom boundary layer and through the layer above. This new capability is enabled by the new runtime parameter DECAY_ADJUSTED_BBL_TKE and is implemented via the new internal function exp_decay_TKE_adjust. In addition, this commit adds 9 bottom-boundary layer specific run-time parameters that are analogous to parameters that set the properties of the surface-driven mixing, and take their defaults from them, but can now be set independently for the bottom boundary layer. The inefficient option to use bisection to estimate the bottom boundary layer depth was eliminated, as it certain that it is not being used yet in any cases, and it should be deprecated for the estimation of the surface boundary layer. By default, all answers are bitwise identical, but there are up to 10 new runtime parameters that will appear in some MOM_parameter_doc files. +Add optional unscale argument to reproducing_sum Added the new optional unscale argument to reproducing_sum() and reproducing_sum_EFP(). When this is used, the resulting real sum is restored to the same scaling as the input arrays, but when there is an EFP_type returned it is the same as it would have been had the input array been rescaled before it was passed in. All answers are bitwise identical, but thre is a new optional argument to a two publicly visible interfaces. +Add RZL2_to_kg element to unit_scale_type Added the new element RZL2_to_kg to the unit_scale_type for convenience when rescaling masses and other globally integrated variables. All answers are bitwise identical, but there is a new element in a transparent type. Work in rescaled units in write_energy Revised write_energy() and accumulate_net_input() to work more extensively in dimensionally rescaled variables by using the new unscale arguments to the reproducing_sum functions. As a result of these changes, 15 rescaling factors were eliminated or moved toward the end of write_energy(). All answers are bitwise identical. Use reproducing_sum with unscale in 5 places Use reproducing_sum with unscale to calculate the global mass diagnostic, globally integrated ocean surface area, offline tracer transport residuals and in calculating the OBC inflow area in tidal_bay_set_OBC_data(). This change allows for the elimination or replacement of 6 rescaling factors and one added instance with a consistent conversion factor and diagnostic units occur on the same line. All answers are bitwise identical. Bug fix related to directional internal wave drag (#774) Co-authored-by: Robert Hallberg Fix indexing error in extract_surface_state Correct a bug that G%gridLonT/G%gridLatT were not using global indexing in outputing extreme surface information. Minor change of SSH check in extract_surface_state Previously extreme surface message is triggered when `sea_lev` is smaller than or **equal** to ocean topography: sfc_state%sea_lev(i,j) <= -G%bathyT(i,j) - G%Z_ref The equality is innocuous for a non-zero minimum thickness (Angstrom/=0), but it can be problematic for true zero thickness. Besides, there is the fourth criterion in this check: sfc_state%sea_lev(i,j) + G%bathyT(i,j) + G%Z_ref < CS%bad_val_col_thick This is supposed to allow a user-specified tolerance (default=0.0), which should be a more stringent check when the tolerance is larger than zero. The equality from the first check contradicts this logic. Recover diagnostic "SSH_inst" Fix a bug that sea surface height averaged over every dynamic time step (SSH_inst) is not outputted correctly. Update MOM_wave_interface.F90 (#784) * Update MOM_wave_interface.F90 The index at the interface has been changed from I-1 ->i+1 and J-1 -> j+1, which helps fixed model error in 3D simulations while keeping halo_size to 1. * Update MOM_wave_interface.F90 Corrected the index for thickness which fixed the issue of 3D wave coupled simulations while keeping the halo_size in thickness as 1 Updates to use EPBL_BBL_EFFIC - The present code only tests BBL_EFFIC when deciding whether to set the bottom TKE and ustar, but this means they are all zero when EPBL_BBL_EFFIC is non-zero and BBL_EFFIC is zero. - Adds logic to also check EPBL_BBL_EFFIC, thereby allowing non-zero ustar and TKE for EPBL_BBL_EFFIC>0.0 - Fixed BBL_TKE diagnostic in EPBL that was not populated. - Will change answers when EPBL_BBL_EFFIC>0.0, but won't change answers in any of our existing configurations. Move MOM_generic_tracer with no changes (#22) * Move MOM_generic_tracer with no changes Renames src/tracer/MOM_generic_tracer.F90 to config_src/external/GFDL_ocean_BGC/MOM_generic_tracer.F90 * Remove MOM_generic_tracer Git rm MOM_generic_tracer.F90 --------- Co-authored-by: Theresa Morrison Corrected the rescaling of 5 KPP diagnostics Added missing factors to the conversion arguments in the register_diag_field calls for the diagnostics of the KPP non-local transport tendency and the net surface tracer fluxes, and corrected the dimensional scaling that is being applied to the KPP_Vt2 diagnostic as calculated in KPP_compute_BLD. All solutions are bitwise identical, but now output files with these 3 sets of KPP diagnostics are invariant to dimensional rescaling. This can be verified with the visc.nc file generated by the single_column/KPP test case in MOM6-examples. Whereas previously the diagnostics KPP_Vt2, KPP_QminusSW, KPP_netSalt, KPP_NLT_dTdt and KPP_NLT_dSdt in that file would change when dimensional rescaling was applied, now they do not. No output is changed unless dimensional rescaling is used. +Add a vector of defaults to get_param_array_int The `default=` optional argument to get_param() only provides a uniform value to initialize an array of integers. This commit adds an optional `defaults=` argument to get_param_int_array(), doc_param_int_array() and log_param_int_array() to allow for the specification of an array of default values. These additions are analogous to what had previously been added for real arrays in github.com/NOAA-GFDL/MOM6/pull/760. This commit also adds the new internal function int_array_string(), analogous to real_array_string(), in MOM_document. This differs slightly from its real array counterpart in that it only uses the syntax like `3*75` for lists of integers that are longer than we would use to specify dates and times or pairs of layout parameters, because "(0, 0)" seems more readily interpretable than "(2*0)". The new defaults argument is now used in the get_param calls for LAYOUT and IO_LAYOUT, and in setting the tidal reference dates. Several spelling errors in comments were also corrected in the files that were being edited. All answers are bitwise identical, but there are minor changes in many MOM_parameter_doc.layout files and some MOM_parameter_doc.all files. set descale in reproducing_sum_3d Fix ALE_sponge tendency diagnostic units Corrected the units and conversion factor in init_ALE_sponge_diags for the various sp_tendency_... diagnostics. Previously they had only been correct for the tendencies of nondimensional quantities. The code also now stores the scaling factor that is set in set_up_ALE_sponge_field_fixed for later use in registering the sponge tendency diagnostics. Several instances of unusual spacing around semicolons in MOM_ALE_sponge were also standardized. The documented units and conversion factors for some diagnostics were corrected, but all solutions are bitwise identical. Refactor horizontally_average_field Refactored the horizontally_average_field() routine in MOM_diag_remap to work in rescaled units by making use of the unscale arguments to the reproducing_sum() routines. A total of 9 rescaling variables were moved into unscale arguments. All answers and diagnostics are bitwise identical, and no interfaces are changed. +Refactor homogenize_field and revise its interface Refactored the homogenize_field routine in MOM_horizontal_regridding to make use of the unscale argument to reproducing_sum(), and revised its interface to make it more nearly consistent with the interface to homogenize_field_t() in MOM_forcing_type. The interface changes include revising the order of the arguments, making the weight argument options, replacing the scale argument with an optional tmp_scale argument that is the inverse of the previous scale, and making the default for the use of reproducing sums to be true when the answer_date argument is absent. The two homogenize_field routines now give equivalent behavior when none of the optional arguments to homogenize_field() are absent. The homogenize_field calls in MOM_temp_salt_initialize_from_Z() and the horiz_interp_and_extrap_tracer() routines have been modified in accordance with the interface changes. All answers are bitwise identical, but the interface to a publicly visible routine has been substantially changed to the point where any calls using the previous interface will not compile. Revise the ice_shelf dimensional rescaling Refactored the volume_above_floatation, write_ice_shelf_energy and ice_shelf_solve_outer routines to work in rescaled units by making use of the unscale arguments to reproducing_sum(). Also added or corrected comments documenting the units of 11 real variables in these routines. The routine integrate_over_Ice_sheet_area was converted into a function and var_scale was renamed to unscale for more consistency with the rest of the MOM6 code. Additionally, add_shelf_flux and update_shelf_mass were modified to use the scale arguments to time_interp_external. A total of 12 rescaling variables were eliminated or moved into unscale arguments, and 2 blocks of code that scale input variables were eliminated. All answers and diagnostics are bitwise identical, and no interfaces are changed. (*)Conversion arguments for ice shelf scalar diags Revised volume_above_floatation and integrate_over_ice_sheet_area to return values in scaled units, and added conversion factors to the register_scalar_field calls in MOM_ice_shelf so that all unit unscaling of diagnostics occurs via the diag mediator and not in the code itself. After this commit, all of the dimensional scaling factors for diagnostics in the ice_shelf code occur via conversion factors that are immediately adjacent to the declaration of the units of those diagnostics, facilitating comparison for consistency. The declared units of one diagnostic, "taub_beta", were revised from "MPa s m-1" to "MPa yr m-1" to be consistent with its conversion factor, which was also corrected (essentially by a factor of [Z L-1 ~> 1]. Several missing unit conversion factors for rates of mass change were also added, and about 15 missing or incorrect units in lines documenting real variables were added or fixed. The input scale factor for the (perhaps unused) variable INPUT_VEL_ICE_SHELF was corrected from `US%m_s_to_L_T*US%m_to_Z` to just `US%m_s_to_L_T`. With these changes, all solutions are bitwise identical, apart from regional cases with a specified inflow when run with dimensional rescaling. The ice shelf diagnostics should now be invariant when dimensional rescaling is applied, and the units of the ice shelf diagnostics are now all consistent with the required rescaling factors. Users set solo driver forcing time records per day Refactored the solo_driver version of MOM_surface_forcing to modify how the time levels to read from forcing files, with a series of 11 new runtime parameters (WIND_FILE_DAYS_PER_RECORD, etc.) giving the user to specify how many days each time record spans (for positive values) or the number of time records in the file per day (for negative values). If these parameters are set to 31, the month returned by the FMS `get_date()` function sets the time level. If they are set to 0 (the default) the previous behavior is obtained, in which the time level is determined from the number of records in the file. To always take the first record in the file, set these parameters to large values (greater than 1000000 will always work, but in practice smaller values do the same thing). By default all answers are bitwise identical, but there are up to 10 new runtime parameters in some MOM_parameter_doc files for cases that have `WIND_CONFIG = "file"` or `BUOY_CONFIG = "file"`. The list of new runtime parameters is `WIND_FILE_DAYS_PER_RECORD`, `LONGWAVE_FILE_DAYS_PER_RECORD`, `SHORTWAVE_FILE_DAYS_PER_RECORD`, `EVAPORATION_FILE_DAYS_PER_RECORD`, `LATENTHEAT_FILE_DAYS_PER_RECORD`, `SENSIBLEHEAT_FILE_DAYS_PER_RECORD`, `RAIN_FILE_DAYS_PER_RECORD`, `SHORTWAVE_FILE_DAYS_PER_RECORD`, `RUNOFF_FILE_DAYS_PER_RECORD`, `SSTRESTORE_FILE_DAYS_PER_RECORD` and `SALINITYRESTORE_FILE_DAYS_PER_RECORD`. The problem identified in github.com/NOAA-GFDL/MOM6/issues/631 is addressed by this commit, and that issue can be closed once this commit is merged onto the main branch of MOM6. Merge branch 'main' into dev/gfdl Fix dimensional rescaling in predict_MEKE Refactored predict_MEKE() to include two missing dimensional rescaling factors and correct a third and to clearly indicate the units and the nature of the variables where they are being used, in coordination with Andrew Shao. Some white spacing around semicolons in the same MOM_MEKE file was also modified to follow the patterns used elsewhere in the MOM6 code. All answers are bitwise identical in cases that do not use dimensional rescaling. Refactor SAL in MOM_PressureForce_FV Self-attraction and loading calculation in Boussinesq pressure gradient force is refactored to be consistent with the algorithm in non-Boussinesq version. Add option for SAL to use bottom pressure anomaly Using SSH to calculate self-attraction and loading (SAL) is only accurate for barotropic flows. Bottom pressure anomaly should really be used for general purposes. * New runtime parameter A runtime parameter SAL_USE_BPA is added to use bottom pressure anomaly. The option requires an input file for long term mean reference bottom pressure. The reference bottom pressure field is stored with SAL_CS. * Refactor SAL and tides in Boussinesq mode As the total bottom pressure is needed for bottom pressure anomaly, SAL calculation in Boussinesq mode needs to be refactored. In addition, there is a longstanding bug in Boussinesq mode that interface height is modified by SAL and tides, and the modified interface height is erroneously used for density and pressure calculation later on. Therefore the SAL and tides are refactored by moving their calculations after pressure is calculated. Tide answers before 20230630 is retained. Answers after 20230630 are changed for Boussinesq mode. Rename variables with tides in Pressure Force * Local variable SSH is renamed to pbot_anom. * Tides related local variable names are changed to be less confusing. Notably, `e_sal_tide` is renamed to `e_sal_and_tide` (the summation of sal and tide), not to be confused with `e_tide_sal`, which is renamed to `e_tidal_sal` (sal from tides). * Fix e_tidal diagnostics in Boussinesq mode. The term was not assigned if tide answer date is >20230630. Alternative method for SAL and tides in Boussinesq Add an alternative method for SAL and tides in Boussinesq mode. The current method adjusts interface heights with geopotential height anomaly for SAL and tides. For non-Boussinesq mode, the current method is algebraically the same as taking the gradient of SAL and tide geopotential (body forcing). For Boussinesq mode, there is a baroclinic component of tidal forcing and SAL. The alternative method is added to calculate the gradient of tidal forcing and SAL directly at the cost of additional multiplications. The new method is controlled by runtime parameter BOUSSINESQ_SAL_TIDES. Remove rescaling bottom pressure in SAL * Instead of rescaling bottom pressure to height unit, calc_Loving_scaling is modified to be conditionally dimensional. When calculating self-attraction and loading, Love numbers are now dimensional when bottom pressure anomaly is used as an input. This change eliminate Love numbers' dependence on mean seawater density. * A new coefficient called linear_scaling is added to SAL CS for the same purpose, although to use bottom pressure anomaly for scalar approximation is not quite justifiable. A WARNING is given when users try to do that. * Two separate field, SSH (sea surface height anomaly) and pbot (total bottom pressure), are used for calculating self attraction and loading when SAL_USE_BPA = False and SAL_USE_BPA = True, respectively. The change is to enhance code readability. Add answer date flag for tide/SAL A new date for TIDES_ANSWER_DATE is added to recover answers for tides in Boussinesq mode before 20250201. Refactor Love_scaling calculation in SAL module * Precalcualte a local field `coef_rhoE` to avoid in-loop division and if-blocks. The unit of coef_rhoE depends on use_bpa. * Fix a few unit description typos in SAL module and two other files. +Refactor MOM_opacity to replace hard-coded params Refactored MOM_opacity to replace hard-coded dimensional parameters for the Manizza and Morel opacity fits with run-time parameters, and also added the runtime parameter OPACITY_BAND_WAVELENGTHS to provide the ability to set the wavelengths of the bands, even though these are not actually used in MOM6. By default, these parameters are all set to the previous hard-coded values, using the recently added defaults argument to get_param_real_array(). The bounds of the frequency band label arrays with the MANIZZA_05 opacity scheme were also corrected when PEN_SW_NBANDS > 3, but it would not be typical to use so many bands for no purpose and these labeling arrays (optics%min_wavelength_band and optics%max_wavelength_band) do not appear to be used anywhere. In addition, the unused publicly visible routines opacity_manizza and opacity_morel were eliminated or made private. All answers are bitwise identical, but there are new entries in some MOM_parameter_doc files. implement spatially varying decay rates for internal tides leakage (#794) * add option to specify horizontally varying decay * extend to vertical modes * fix comments * corrected description of decay_rate array --------- Co-authored-by: Raphael Dussin Add ice shelf pressure initialisation bug fix (#800) * Add ice shelf pressure initialisation bug fix This commit adds a new parameter FRAC_DP_AT_POS_NEGATIVE_P_BUGFIX and associated bug fix. This bug occurs when TRIM_IC_FOR_P_SURF pressure initialisation is used for ice shelf, whilst in Boussinesq mode and a nonlinear equation of state. The subroutine trim_for_ice calls cut_off_column_top. This routine in Boussinesq mode calls find_depth_of_pressure_in_cell in MOM_density_integrals.F90. This subsequently calls the function frac_dp_at_pos which calls the density equation of state based on given salinity, temperature and depth, which is incorrectly converted into pressure by z position (which is negative) multiplied by g and rho0. The bug results in incorrect densities from the equation of state and therefore an imperfect initialisation of layer thicknesses and sea surface height due to the displacement of water by the ice. The bug is fixed by multiplying the pressure by -1. This commit introduces parameter FRAC_DP_AT_POS_NEGATIVE_P_BUGFIX with default value False to preserve answers. If true, the ice shelf initialisation is accurate to a high degree with a nonlinear equation of state. Answers should not change, except for the added parameter in MOM_parameter_doc. The same functions are called by a unit test in MOM_state_initialization; in this commit I set the MOM_state_initialization unit test to use the existing bug (with a false flag). * Resolve indenting and white space inconsitencies with MOM6 style for ice shelf pressure initialisation bug fix FRAC_DP_AT_POS_NEGATIVE_P_BUGFIX +Add the optional argument old_name to get_param Added the new optional argument old_name to the 8 get_param() routines. This new capability allows for an archaic parameter name to be specified and for appropriate warnings encouraging the user to migrate to using the new name while still setting the parameter as intended, or error messages in the case of inconsistent setting via the archaic name and the correct name. The logging inside of the MOM_parameter_doc files only uses the correct parameter name. Also added the new optional argument set to the 8 read_param routines, to indicate whether a parameter has been found and successfully set. The new set argument is now being used in read_param() calls in obsolete_int(), obsolete_real(), obsolete_char() and obsolete_logical(). Obsolete_logical() in particular was substantially simplified by the use of this new argument, and is now only about half as long as it was. The read_param() set argument is also used in all of the get_param() routines when they are given an old_name argument. The new old_name argument to get_param() is not yet being used in the version of the MOM6 code that is being checked in, but it has been tested extensively by adding or modifying get_param calls in a variant of the initialization code, and it will be used in an updated version of github.com/NOAA-GFDL/MOM6/pull/725 to gracefully handle the deprecation of 4 parameter names. All answers are bitwise identical, but there are new optional arguments to two widely used interfaces. +Add grid_unit_to_L to the ocean_grid_type Add the new element grid_unit_to_L to the ocean_grid_type and the dyn_horgrid_type, which can be used to convert the units of the geoLat and geoLon variables to rescaled horizontal distance units ([L ~> m]) when they are Cartesian coordinates. When Cartesian coordinates are not in use, G%grid_unit_to_L is set to 0. This new element of the grid type is used to test for inconsistent grids or to eliminate rescaling variables in set_rotation_beta_plane(), initialize_velocity_circular(), DOME_initialize_topography(), DOME_initialize_sponges(), DOME_set_OBC_data(), ISOMIP_initialize_topography(), idealized_hurricane_wind_forcing(), Kelvin_set_OBC_data(), Rossby_front_initialize_velocity(), soliton_initialize_thickness(), and soliton_initialize_velocity(). These are the instances where this new variable could be used and bitwise identical answers are recovered. There are a few other places where they should be used, but where answers would change, and these will be deferred to a subsequent commit. All answers are bitwise identical, but there are new elements in two transparent and widely used types. Update particles_run call to allow accurate particle advection using u, v or uh, vh The drifters package is able to run in 2 different modes: one where the particles are advected using u and v, and one where they are advected using uh and vh. When u and v are used (i.e. the drifters are advected using the resolved velocities only, with no sub-grd component), the particles package needs the layer thickness that is consistent with these velocities, so particles_run needs to be called before any subgrid scale parameterizations are applied. This was not implemented correctly in my last PR, and is corrected here. The particles package also needs the correct timestep for particle advection. This is added here. +Remove dyn_horgrid_type%Rad_Earth Remove the unused element Rad_Earth from ocean_grid_type and dyn_horgrid_type. The dimensionally rescaled equivalent element G%Rad_Earth_L is extensively used, and it will continue to exist. G%Rad_Earth_L was introduced in November 27, 2021 as a dimensionally rescaled version of G%Rad_Earth, while the unscaled version was retained because at the time, the Rad_Earth element of the dyn_horgrid_type is also used in SIS2. However, SIS2 has not used G%Rad_Earth since December 23, 2021, so after 3 years we can now safely remove this unused element. Any cases on other branches that might be impacted by this change will not compile. All answers are bitwise identical, but there is one less element in two transparent types. Nodal modulation This commit fixes a few (potential) inconsistencies between open boundary tidal forcing and astronomical tidal forcing. 1. There was an inconsistency in the code that the nodal modulation can be calculated in OBC tidal forcing but not in the astronomical tidal forcing. This commit fixes this bug so that nodal modulation is applied to both forcings. 2. In the previous version of MOM_open_boundary.F90, a different set of tidal parameters can be set for open boundary tidal forcing, leading to potential inconsistency with astronomical tidal forcing. This commit obsoletes those for open boundary tidal forcing. 3. Another important bug fix is that the equilibrium phase is added to the SAL term, which was missing in the original code. Correct unit conversion for BS_coeff_h diagnostic Added missing conversion arguments for the register_diag_field calls for the recently added diagnostics BS_coeff_h and BS_coeff_q. All answers are bitwise identical, but two diagnostics will have corrected dimensional rescaling when EY24_EBT_BS is true. Streaming Filter The filters and their target frequencies are no longer hard-coded. Instead, multiple filters with tidal or arbitrary frequencies as their target frequencies can be turned on. The filter names are specified in MOM_input and must consist of two letters/numbers. If the name of a filter is the same as the name of a tidal constituent, then the corresponding tidal frequency will be used as its target frequency. Otherwise, the user must specify the target frequency by "FILTER_${FILTER_NAME}_OMEGA" in MOM_input. The restarting capability has also been implemented. Because the filtering is a point-wise operation, all variables are considered as fields, even if they are velocity components. Merge branch 'dev/gfdl' into rescale_predict_MEKE +Refactor the spatial mean calculations Refactored the spatial mean calculations in the functions global_area_mean(), global_area_mean_u(), global_area_mean_v(), global_layer_mean(), global_volume_mean() and adjust_area_mean_to_zero() to work in rescaled units by making use of the unscale arguments to the reproducing_sum routines. Comments were also added to explain what the code does when both tmp_scale and unscale arguments are provided, which effectively acts as to allow for changes in the rescaled units. Global_area_integral() and global_mass_integral() were also similarly refactored, but with the added difference that when a tmp_scale argument is provided, the areas or masses in the integrals have units of [L2 A ~> m2 a] or [R Z L2 A ~> kg a] instead of the mixed units of [m2 A ~> m2 a] or [kg A ~> kg a]. As a result the code surrounding the 4 instances where global_area_integral or global_mass_integral were being called with tmp_scale arguments (in MOM.F90 and MOM_ice_shelf.F90) also had to be modified in this same commit. When the optional var argument is absent from a call to global_mass_integral() so that it is the mass itself that is returned, the values (if any) of scale, unscale and tmp_scale are ignored, but the presence of tmp_scale determines whether the mass is returned in [R Z L2 ~> kg] or [kg], consistent with the behavior that would have been obtained if var had been an array of nondimensional 1s. This commit also includes a rescaling in the units of the areaT_global and IareaT_global elements of the ocean_grid_type and dyn_horgrid_type to [L2 ~> m2] and [L-2 ~> m-2], respectively. Although the dyn_horgrid_type is shared between MOM6 and SIS2, these elements are not used in SIS2. A total of 12 rescaling factors were eliminated or moved into unscale arguments as a result of these changes. All answers are bitwise identical, but there are changes in the rescaled units of two elements each in two transparent types, and changes to the rescaling behavior of two publicly visible routines when they are called with tmp_scale arguments. Diagnose area integrated fluxes in rescaled units Keep 36 area integrated surface mass, heat or salt flux diagnostics in forcing_diagnostics in rescaled units by replacing an unscale argument with a tmp_scale argument to global_area_integral. Also added the corresponding conversion arguments to the register_scalar_field calls for each of these diagnostics, so that the documented units and conversion factors can be used to confirm the correctness of the documented units for these variables. The internal variables used for the integrated or averaged heat, mass or salt fluxes were also separated for clarity about the units of these variables. All answers and diagnostics are bitwise identical. Fix rescaling of internal tide of debugging code Corrected the internal tide rescaling arguments so that some of the debugging variables have units that are consistent with their documented units. This involved changing the scale arguments to global_area_integral to tmp_scale arguments in 8 places so that the units of the output retain the scaling of the input variable. The multiplication by the reverse of the scaling factor was also added to 4 debugging output messages. The documented units of internal wave energies in 5 register_restart_field calls were previously given as "m3 s-2" in non-Boussinesq mode and "J m-2" in Boussinesq mode when the reverse was actually true. This has now been corrected. Also replaced the scale argument to 35 chksum calls with the equivalent but preferred unscale argument, following the pattern elsewhere in the MOM6 code. All answers are bitwise identical, and only debugging code was modified. Corrected many unit descriptions in comments Corrected the descriptions of the units of about 113 variables spread across 30 files. These were either inconsistent unit descriptions or descriptions using a non-standard syntax. Only comments are changed, and all answers are bitwise identical. Fix rotation in set_coupler_type_data `rotate_array` in `set_coupler_type_data` was trying to rotate an array to another of different size when `idim` and `jdim` are present. Some compilers seemed to let this through, but it raised a double-deallocation error in GCC. I'm guessing it's because the rotation was implicitly allocating to a new array which was automatically deallocated. But I did not confirm this. This was modified to rotate onto a new array of the same size. The `idim` and `jdim` are passed to `CT_set_data`, which (hopefully) sorts out the indexing. Remove implicit copies in CT_extract_data rotation Following on the previous commit, the implicit copies in `extract_coupler_type_data`'s `allocate_rotated_array` and `rotate_array` are replaced with the full-sized arrays, with halos managed by `idim` and `jdim` arguments to `CT_extract_data`. I tested this in a rotated `Baltic` test and saw no answer changes. The `ocean.stats` and CFC restart files agree, but there are still known rotation reordering and negative-zero errors in `MOM.res.nc` output. Refactor spherical_harmonics_forward Refactored the spherical_harmonics_forward routine in MOM_spherical_harmonics to work in rescaled units by making use of the unscale arguments to reproducing_sum(). A total of 4 rescaling variables were moved into unscale arguments, and a block of code that restores the scaling of the output variables was eliminated. The comments describing the units of several variables in this module were made more explicit. The two temporary arrays that store un-summed contributions to the transforms were also moved out of the control structure and made into local variables in the spherical_harmonics_forward routine to allow for the reuse of that memory. All answers and diagnostics are bitwise identical, and no interfaces are changed. Rescale 7 ice shelf variables Changed the rescaling of 7 ice shelf variables to cancel out common conversion factors that appear in several expressions. The C_basal_friction argument to initialize_ice_C_basal_friction is now in partially rescaled units, reflecting the portion that does not cancel out fractional-power units from a power law fit with an arbitrary power. The C_basal_friction array in ice_shelf_dyn_CS and the C_friction variable in initialize_ice_C_basal_friction were similarly rescaled. There are new scale factors in a get_param_call and a MOM_read_data call and a conversion factor in register_restart_field call that reflect these changes. The KE_tot and mass_tot variables in write_ice_shelf_energy, are kept in scaled units until they are written. The internal variable fN in calc_shelf_taub is kept in scaled units, but there is now a scaling factor of US%L_to_N in the expression for fB. This latter could be folded into the CF_Max element of ice_shelf_dyn_CS, but I am unsure whether this would be physically sensible. All answers should be bitwise identical and no output should change, but this has not been extensively tested yet. +Rename visc%TKE_BBL to visc%BBL_meanKE_loss Revised the name of visc%TKE_BBL to visc%BBL_meanKE_loss to better reflect what these variables contain, and the fact that the efficiency of the conversion from mean kinetic energy loss to turbulent kinetic energy has not been applied yet. The units of visc%BBL_meanKE_loss are [H L2 T-3 ~> m3 s-3 or W m-2], whereas those of visc%TKE_BBL were [H Z2 T-3 ~> m3 s-3 or W m-2]. The factor rescaling between the units of mean kinetic energy and those of turbulent kinetic energy have been incorporated into set_diffusivity_CS%BBL_effic and energetic_PBL_CS%ePBL_BBL_effic. All answers are bitwise identical. +Rename fluxes%TKE_tidal to fluxes%BBL_tidal_dis Revised the name of fluxes%TKE_tidal to fluxes%BBL_tidal_dis to better reflect what this field holds,and the fact that the efficiency of the conversion from mean kinetic energy loss to turbulent kinetic energy has not been applied yet. The units of fluxes%BBL_tidal_dis are [R Z L2 T-3 ~> W m-2], whereas those of fluxes%TKE_tidal were [R Z3 T-3 ~> W m-2]. The factor rescaling between the units of mean kinetic energy and those of turbulent kinetic energy were already in set_diffusivity_CS%BBL_effic, and these have been cancelled out by this change, but this is offset by the addition of rescaling factors in the term setting this array in the NUOPC and mct convert_IOB_to_fluxes routines. In the FMS_cap version of convert_IOB_to_fluxes, the extra rescaling factor is rolled into the scaling factor used in the get_param call for rho_TKE_tidal. All answers are bitwise identical, but there is a change in the name and rescaled units of an element of a transparent type. +Add EPBL_BBL_TIDAL_EFFIC Added the option to use the energy source in fluxes%BBL_tidal_dis to drive mixing in ePBL_BBL_column(), similarly to what is done in add_drag_diffusivity() and add_LOTW_BBL_diffusivity(). Because this was omitted when ePBL_BBL_column() was first added, a separate runtime parameter, EPBL_BBL_TIDAL_EFFIC, is used to determine the extent to which this tidal energy source is used. The default for EPBL_BBL_TIDAL_EFFIC is currently set to 0 to avoid changing answers, but perhaps it should be changed follow the value of EPBL_BBL_EFFIC. By default all answers are bitwise identical, but there is a new runtime parameter in the MOM_parameter_doc files for cases that use ePBL. +(*)EPBL_BBL_EFFIC_BUG & DRAG_DIFFUSIVITY_ANSWER_DATE Previously, visc%BBL_meanKE_loss (which was called visc%TKE_BBL before it was renamed) was missing a factor of the square root of the drag coefficient compared with the net loss of kinetic energy. This was compensated for by multiplication by factors of the square root of the drag coefficient in add_drag_diffusivity and add_LOTW_BBL_diffusivity, but when an equivalent expression was added in the ePBL BBL code this was erroneously omitted. Moreover, Alistair has had a comment questioning this added factor in add_LOTW_BBL_diffusivity for a decade without adequate resolution. To correct this confusing situation, visc%BBL_meanKE_loss has been changed to include the missing factor of the square root of the drag coefficient, while the new variable visc%BBL_meanKE_loss_sqrtCd was added to allow for the previous answers to be recovered when the new runtime parameter EPBL_BBL_EFFIC_BUG is set to true and DRAG_DIFFUSIVITY_ANSWER_DATE is set below 20250302. Because the ePBL bottom boundary layer was only added to dev/gfdl a month ago and has not yet been merged into main, we can be confident that it has only received very limited use as yet, so the default for EPBL_BBL_EFFIC_BUG is false but this default will change answers when EPBL_BBL_EFFIC > 0. The default for DRAG_DIFFUSIVITY_ANSWER_DATE is 20250101, which will preserve the previous answers, but the default should later be taken from DEFAULT_ANSWER_DATE. By default, answers are unchanged in any cases that are more than a month old, but answers can change by default in a few very recent experiments. There are two new runtime parameters in some MOM_parameter_doc files. +Add alternate gravity variable GV%g_Earth_Z_T2 Added the new gravitational acceleration element GV%g_Earth_Z_T2 to the verticalGrid_type as a copy of GV%g_Earth that uses dimensional rescaling of [Z T-2 ~> m s-2] instead of [L2 Z-1 T-2 ~> m s-2]. GV%g_Earth_Z_T2 is more convenient for single-column energy calculations, but the two will only differ by an integer power of two when dimensional rescaling is applied. In addition, the apparently unused element GV%mks_g_Earth was commented out, and it will be eliminated in several months if there are no concerns raised by MOM6 users whose code is not on any of the primary development branches of MOM6. Explicitly rescaled versions of GV%g_Earth were replaced by GV%g_Earth_Z_T2 in 38 places in 14 files, leading to the elimination of 38 US%L_to_Z**2 dimensional rescaling factors. Another US%L_to_Z**2 rescaling factor was eliminated from the code in ePBL_column by folding it into MKE_to_TKE_effic. All answers are bitwise identical, but there are changes to the contents of a transparent type. Revise rescaling in bulkmixedlayer Revised the internal rescaling of turbulent kinetic energies in MOM_bulk_mixed_layer to work in units of [H Z2 T-2] instead of [H L2 T-2], for greater consistency with the rescaling of TKE elsewhere. These changes included using GV%g_Earth_Z_T2 instead of GV%g_Earth in 16 places that contribute to potential energy calculations. In 5 lines, the unit scaling factors were eliminated, while in 2 others the rescaling factors were revised. In addition, the rescaling factors to go from the units of mean kinetic energy to those of turbulent kinetic energy were folded into the internal representation of the bulk Richardson numbers. The units in comments describing 58 variables and the conversion arguments for 10 diagnostics were updated accordingly. All answers and output are bitwise identical. Rescale strat_floor Rescaled the internal representation of the FGNV_STRAT_FLOOR variable and thickness_diffuse%N2_floor to include appropriate factors of US%Z_to_L to reflect the scaling of aspect ratios. This leads to the elimination of one rescaling factor in thickness_diffuse_full() and its replacement by another in a scale factor for a get_param call. All answers are bitwise identical. Add Option to Specify Tracer Advection Time Step (#757) * Add option to set tracer advection timestep Add an option to seperate the tracer advection from the diabatic processes in MOM_step_thermo. Previously the advection and diabatic codes were seperated but called with the same timestep. If DT_TADVECT is not specified, then DT_THERM is used. The comments describing DT_THERM and DT_TADVECT have been modified to refelect this change. * Add error warning if diabatic_first is true Currently, this option is not intended to be used if diabatic_first is true, so a fatal error flag has been added. This will be addressed in a future pull request. * Change variable, add do advection before thermo step Change DT_TADVECT to DT_TRACER_ADVECT to be clearer. dt_tadvect has been changed to dt_tr_adv and tadvect_spans_coupling to tradv_spans_coupling. An additional check has been added before the advection step. If thermo_spans_coupling is true, do_advection is true if t_dyn_rel_thermo is ~DT_THERM so that the thermodynamics step would happen at the next possible time. This ensures that the thermodynamics step is not prevented because advection has not been resolved. * Add logic to do_diabatic check The do_diabatic check should only be done if do_thermo is true. This is relevant when do_dyn or do_thermo are being used from outside step_MOM to order the updates of the thermodynamics and dynamics, such as when the interspesed coupling is used. * Initialize do_diabatic * Change TRADV_SPANS_COUPLING default Change the default for TRADV_SPANS_COUPLING to be the same as THERMO_SPANS_COUPLING, which is read first, instead of false. Initialize do_advection. * Doxygen fix --------- Co-authored-by: Theresa Morrison Co-authored-by: Theresa Morrison Co-authored-by: Theresa Morrison +Add optional conversion argument to register_field Added the option to rescale variables as they are written out via MOM_io_file. These involved adding optional conversion arguments to register_field_infra and register_field_nc, which are then stored in a new element in the MOM_field type, and use the conversion factors to unscale variables before they are written in the ten write_field routines in MOM_io_file. The new optional arguments to register_field are used in MOM_create_file, taking their values from the vardesc types sent to this routine. This commit also alters modify_vardesc to store the value of the conversion optional argument in the conversion element of the vardesc type. Also modified query_vardesc so that the conversion factor is returned via the conversion optional argument. These steps had been intended when these optional arguments were first added, but for some reason they had not actually been used. The conversion values stored in a vardesc type are also now used in the register_diag_field call in ocean_register_diag. However, it does not appear that ocean_register_diag is actually used anymore, so it might be a candidate for deletion. All answers are bitwise identical, but there are new optional arguments to publicly visible routines. Specify conversion factors in write_energy Revised write_energy to use conversion arguments to var_desc to unscale variables. Their units are also documented in the same calls, so this is now analogous to what is done the register_diag_field calls for diagnostics that are handled by the MOM_diag_mediator. All calculations in write_energy and almost all internal variables are now in rescaled units. All answers and output are bitwise identical. Fix 4 conversion arguments to var_desc calls Corrected 4 conversion arguments in calls to var_desc for temperatures and salinities, so that they are consistent with the units of these variables and the described purpose of the conversion element of the var_desc type. Until the conversion arguments to modify_vardesc and query_vardesc, these incorrect values were inconsequential, but now they need to be fixed before they are inadvertently used. All answers are bitwise identical. Deprecate TIDE_SAL_SCALAR_VALUE (#819) Using the recently added `old_name` option in `get_params`. Calculate volo in scaled units Calculate the volo diagnostic in scaled units using the tmp_scale argument to global_area_integral and undo this scaling with a conversion argument on its register_scalar_field call. Also corrected the units in the comments describing the mass_celland masso variables in calculate_diagnostic_fields. All answers are bitwise identical. Rename masked_area in compute_global_grid_integral Renamed the internal variable tmpForSumming to masked_area in compute_global_grid_integrals and corrected the description of its units from [m2] to [L2 ~> m2]. All answers are bitwise identical. Fix the syntax or substance in 10 comment units Corrected incorrect syntax in the descriptions of 4 positions variables in write energy, 1 reused position variable in set_grid_metrics_from_mosaic and 1 position variable in bkgnd_mixing_CS. Also added the unscaled units to the comments documenting two lines of calculations in wave_speeds, and added the scaled units to two variables related to the ice-shelf surface mass balance. Only comments are changed and all answers are bitwise identical. Switched the placeholder element of file_OBC_CS Replaced the unused real tide_flow element of the file_OBC_CS type with the logical OBC_file_used element to more clearly reflect that this placeholder element is only here to avoid having a completely empty type. The actual value of this element is irrelevant, but some compilers require that all Fortran types have at least one element. This change eliminates a meaningless hard-coded real variable with undefined units and a misleading name and replaces it with a logical variable named to reflect its actual purpose. All answers are bitwise identical. Merge branch 'main' into dev/gfdl Correct bug in kappa shear viscosity with vertex shear option. (#824) * Correct bug in kappa shear viscosity with vertex shear option. - Viscosities at vertices along the coast were incorrectly zero'd out. This commit removes that mask so the non-zero shear driven viscosities can be interpolated from in the model. This bug caused diffusivities to be very large in channels and potentially near coastlines. - A bugfix flag is added with an option to use the current behavior for legacy purposes. * Fix missing paranthesis in previous commit (VS_viscosity_bug) * Update logging of vertex shear viscosity bug parameter +Add PHILLIPS_ANSWER_DATE runtime parameter Add the new runtime parameter PHILLIPS_ANSWER_DATE to enable the option to use mathematically equivalent expressions in Phillips_initialize_velocity() that exactly specify the arithmetic to be used, avoid excess divisions and permit full rescaling of the internal variables and the elimination of rescaling variables. This new slightly answer-changing option is enabled by setting PHILLIPS_ANSWER_DATE >= 20250101. For now, the default for PHILLIPS_ANSWER_DATE is set to 20241231 to avoid changing answers without explicitly setting it. This commit also introduces code to use G%grid_unit_to_L to detect and handle various choices for the units of the G%geolat and G%geolon variables. By default, all answers are bitwise identical, but there is a new runtime parameter in some MOM_parameter_doc files. This commit changes answers at roundoff when there is an explicit setting of PHILLIPS_ANSWER_DATE >= 20250101, +Add zero_zeros optional arg to MOM_write_field Added the new zero_zeros optional argument to the 10 MOM_write_field routines in MOM_io and the 6 rescale_comp_data routines in MOM_domain_infra to cause negative zeros to replaced with ordinary signless zeros before they are written out to files. This has no impact at all on answers, but it does help with comparisons between rotated restart files, in which meaningless differences between positive and negative zeros were leading to false differences between files. All answers are bitwise identical, and all output is equivalent, but there are new optional arguments to 16 routines covered by 2 publicly visible interfaces. +Add turns argument to MOM_read_data Added a new turns optional argument to 6 versions of the MOM_read_data routines to allow for the reading to override the number of turns in the MOM_domain that is passed into these routines. Several internal turns variables in the same routines were renamed qturns to allow for the new optional arguments. Also check for whether the MOM_domain%domain_in pointer is associated before it is used, avoiding a segmentation fault that was occurring when a restart file is read and ROTATE_INDEX is true. Also added rotate_array calls to ensure that the halo values are retained while reading data into a rotated array. These changes are necessary to allow for the model to be initialized from a restart files with rotated grids. Several instances of continuation line indentation that do not follow the typical 4-space pattern used elsewhere in the MOM6 code and documented in the MOM6 style guide were also altered to follow the standard. All answers that previously worked are bitwise identical, but there are new optional arguments to publicly visible interfaces. (*)+Modified MOM_restart to fix rotated restarts Modified MOM_restart so that restart files generated by rotated runs match unrotated restart files, and the model can be properly initialized from a restart file when the grid is rotated. Also added runtime options to convert negative zeros into ordinary zeros before they are written to restart files (selected with RESTART_UNSIGNED_ZEROS) and to properly do the checksums on the velocity points on all of the faces (selected with RESTART_SYMMETRIC_CHECKSUMS). Also added the new interfaces copy_restart_var and copy_restart vector to use the names of restart variables and the pointers stored in the restart control structure to obtain a copy of the variables as the restart variables with the option to undo the rotation. These routines are necessary because the reading of restart files occurs during a phase of the model initialization that works on an unrotated grid, and they are called from inside of MOM_initialize_state. The ranges for the checksums are now set correctly for each variable, depending on where it is discretized, but when RESTART_SYMMETRIC_CHECKSUMS is false, the previous ranges are still used so answers do not change in unrotated test case. The conversion factors used for the pair of register_restart_field calls in register_restart_pair now include the necessary sign changes for the rotation, as set in the new internal routine set_conversion_pair. There is also now a scalar_pair optional argument to the register_restart_pair routines to accommodate the rotation of pairs of scalars that do not change sign when rotated (e.g., grid-lengths). Instead of working with the hor_grid character string, the restart code has been modified to instead use the encoded integer position argument returned from query_vardesc. This avoids several redundant blocks of code that translate the hor_grid strings into positions. All answers are bitwise identical when there is no grid rotation, but with grid rotation the restart files that are created are modified to have the correct signs and replicate the restart fields with no rotation. Also, cases with grid rotation can now be reinitialized from restart files, while previously this simply did not work, either giving an incorrect reinitialized state or a segmentation fault. There are also two new runtime parameters in some MOM_parameter_doc files. Describe the units of 33 real function results Added a description of the units of the return values to the comments describing 33 real functions in 8 modules. Only comments are changed and all answers are bitwise identical. Add MASS_WEIGHT_IN_PGF_VANISHED_ONLY to modify mass weighting in PGF (#810) * Add MASS_WEIGHT_IN_PGF_VANISHED_ONLY to modify mass weighting This commit introduces the runtime variable `MASS_WEIGHT_IN_PGF_VANISHED_ONLY` which has default False. If true, then the `MASS_WEIGHT_IN_PRESSURE_GRADIENT` and `MASS_WEIGHT_IN_PRESSURE_GRADIENT_TOP` effect of weighting T/S integrals in slanted grid cell FV PGF calculation is turned off if both sides of the grid cell are nonvanished, where nonvanished means thickness greater than `RESET_INTXPA_H_NONVANISHED` which defaults to 1e-6 m. Since the benefit of `MASS_WEIGHT_IN_PRESSURE_GRADIENT` happens in vanished layers (creating a fake PGF away from vanished layer, which is arrested by upwinded viscosity) the benefit is still there, but now we can use `MASS_WEIGHT_IN_PRESSURE_GRADIENT` for coordinates that also have slanted layers in the open ocean that are not vanished, e.g. sigma coordinates or SIGMA_SHELF_ZSTAR coordinates in the ice shelf where we DO trust T and S values. Additionally, this is required near a grounding line in a 3D z-coord ice shelf as some strange looking slanted non-vanished cells can emerge, and MWIPG being on would create fake PGFs in non-vanished cells (and therefore generating spurious currents). Reccommend `MASS_WEIGHT_IN_PGF_VANISHED_ONLY` to be set to True, as well as `MASS_WEIGHT_IN_PRESSURE_GRADIENT` and `MASS_WEIGHT_IN_PRESSURE_GRADIENT_TOP` if you have vanishing layers with min thickness < 0.1m. Also modifies MassWt_u and MassWt_v diagnostics to reflect usage of MASS_WEIGHT_IN_PRESSURE_GRADIENT. This commit should not change answers since it defaults to False. However, my implementation is not very efficient and should probably be optimised. * Minor style updates to previous commit of Add MASS_WEIGHT_IN_PGF_VANISHED_ONLY to modify mass weighting * Address comments from Bob by adding scaling to dimensional numbers, replacing Boussinesq rho in nonBoussinesq code, and removing white space to follow 2-space indenting. +Obsoleted INTERNAL_TIDE_CORNER_ADVECT This commit cleans up several aspects of the MOM_internal_tides code, including the elimination of one runtime option, the correction of some units in comments and a start toward enabling the propagation directions to alt… --- .../lateral/MOM_hor_visc.F90 | 213 ++++++++++-------- 1 file changed, 123 insertions(+), 90 deletions(-) diff --git a/src/parameterizations/lateral/MOM_hor_visc.F90 b/src/parameterizations/lateral/MOM_hor_visc.F90 index f6e45cffb0..3b76515539 100644 --- a/src/parameterizations/lateral/MOM_hor_visc.F90 +++ b/src/parameterizations/lateral/MOM_hor_visc.F90 @@ -181,7 +181,8 @@ module MOM_hor_visc dx_dyT, & !< Pre-calculated dx/dy at h points [nondim] dy_dxT, & !< Pre-calculated dy/dx at h points [nondim] m_const_leithy, & !< Pre-calculated .5*sqrt(c_K)*max{dx,dy} [L ~> m] - m_leithy_max !< Pre-calculated 4./max(dx,dy)^2 at h points [L-2 ~> m-2] + m_leithy_max, & !< Pre-calculated 4./max(dx,dy)^2 at h points [L-2 ~> m-2] + Iwts !< Pre-calculated 1./sum_5x5(G%mask2dT) [nondim] real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEMB_PTR_) :: & dx2q, & !< Pre-calculated dx^2 at q points [L2 ~> m2] dy2q, & !< Pre-calculated dy^2 at q points [L2 ~> m2] @@ -189,10 +190,12 @@ module MOM_hor_visc dy_dxBu !< Pre-calculated dy/dx at q points [nondim] real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEM_) :: & Idx2dyCu, & !< 1/(dx^2 dy) at u points [L-3 ~> m-3] - Idxdy2u !< 1/(dx dy^2) at u points [L-3 ~> m-3] + Idxdy2u, & !< 1/(dx dy^2) at u points [L-3 ~> m-3] + Iwts_u !< 1/sum_5x5(G%mask2Cu) [nondim] real ALLOCABLE_, dimension(NIMEM_,NJMEMB_PTR_) :: & Idx2dyCv, & !< 1/(dx^2 dy) at v points [L-3 ~> m-3] - Idxdy2v !< 1/(dx dy^2) at v points [L-3 ~> m-3] + Idxdy2v, & !< 1/(dx dy^2) at v points [L-3 ~> m-3] + Iwts_v !< 1/sum_5x5(G%mask2Cv) [nondim] ! The following variables are precalculated time-invariant combinations of ! parameters and metric terms. @@ -653,7 +656,7 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, ! One call applies the filter twice u_smooth(:,:,k) = u(:,:,k) v_smooth(:,:,k) = v(:,:,k) - call smooth_x9_uv(G, u_smooth(:,:,k), v_smooth(:,:,k), zero_land=.false.) + call smooth_x9_uv(CS, G, u_smooth(:,:,k), v_smooth(:,:,k), zero_land=.false.) enddo call pass_vector(u_smooth, v_smooth, G%Domain) endif @@ -1239,14 +1242,6 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, enddo ; enddo endif - ! In Leith+E parameterization Kh is computed after Ah in the biharmonic loop. - ! The harmonic component of str_xx is added in the biharmonic loop. - if (CS%use_Leithy) then - do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh - Kh(i,j) = 0. - enddo ; enddo - endif - if (CS%id_Kh_h>0 .or. CS%debug) then do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh Kh_h(i,j,k) = Kh(i,j) @@ -1339,14 +1334,13 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, else m_leithy(i,j) = CS%m_leithy_max(i,j) endif - m_leithy(i,j) = G%mask2dBu(i,j) * m_leithy(i,j) endif enddo ; enddo if (CS%smooth_Ah) then ! Smooth m_leithy. A single call smoothes twice. call pass_var(m_leithy, G%Domain, halo=2) - call smooth_x9_h(G, m_leithy, zero_land=.true.) + call smooth_x9_h(CS, G, m_leithy, zero_land=.true.) call pass_var(m_leithy, G%Domain) endif ! Get Ah @@ -1365,7 +1359,7 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, enddo ; enddo call pass_var(Ah_sq, G%Domain, halo=2) ! A single call smoothes twice. - call smooth_x9_h(G, Ah_sq, zero_land=.false.) + call smooth_x9_h(CS, G, Ah_sq, zero_land=.false.) call pass_var(Ah_sq, G%Domain) do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh Ah_h(i,j,k) = max(CS%Ah_bg_xx(i,j), sqrt(max(0., Ah_sq(i,j)))) @@ -1432,8 +1426,8 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, ! Compute Leith+E Kh after bounds have been applied to Ah ! and after it has been smoothed. Kh = -m_leithy * Ah do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh - Kh(i,j) = -m_leithy(i,j) * Ah(i,j) - Kh_h(i,j,k) = Kh(i,j) + Kh_BS(i,j) = -m_leithy(i,j) * Ah(i,j) + BS_coeff_h(i,j,k) = Kh_BS(i,j) enddo ; enddo endif @@ -1452,7 +1446,7 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, str_xx(i,j) = str_xx(i,j) + d_str - if (CS%use_Leithy) str_xx(i,j) = str_xx(i,j) - Kh(i,j) * sh_xx_smooth(i,j) + if (CS%use_Leithy) str_xx(i,j) = str_xx(i,j) - Kh_BS(i,j) * sh_xx_smooth(i,j) ! Keep a copy of the biharmonic contribution for backscatter parameterization bhstr_xx(i,j) = d_str * (h(i,j,k) * CS%reduction_xx(i,j)) @@ -1689,9 +1683,16 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, if (CS%use_Leithy) then ! Leith+E doesn't recompute Kh at q points, it just interpolates it from h to q points do J=js-1,Jeq ; do I=is-1,Ieq - Kh(I,J) = 0.25 * ((Kh_h(i,j,k) + Kh_h(i+1,j+1,k)) + (Kh_h(i,j+1,k) + Kh_h(i+1,j,k))) + Kh_BS(I,J) = 0.25 * ((BS_coeff_h(i,j ,k) + BS_coeff_h(i+1,j+1,k)) + & + (BS_coeff_h(i,j+1,k) + BS_coeff_h(i+1,j ,k))) enddo ; enddo - end if + endif + + if (CS%id_BS_coeff_q>0) then + do J=js-1,Jeq ; do I=is-1,Ieq + BS_coeff_q(I,J,k) = Kh_BS(I,J) + enddo ; enddo + endif if (CS%id_Kh_q > 0 .or. CS%debug) then do J=js-1,Jeq ; do I=is-1,Ieq @@ -1711,13 +1712,13 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, enddo ; enddo endif - if (.not. CS%use_Leithy) then - do J=js-1,Jeq ; do I=is-1,Ieq - str_xy(I,J) = -Kh(I,J) * sh_xy(I,J) - enddo ; enddo - else + do J=js-1,Jeq ; do I=is-1,Ieq + str_xy(I,J) = -Kh(I,J) * sh_xy(I,J) + enddo ; enddo + + if (CS%use_Leithy) then do J=js-1,Jeq ; do I=is-1,Ieq - str_xy(I,J) = -Kh(I,J) * sh_xy_smooth(I,J) + str_xy(I,J) = str_xy(I,J) - Kh_BS(I,J) * sh_xy_smooth(I,J) enddo ; enddo endif else @@ -2251,6 +2252,9 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, if (CS%id_visc_limit_q_frac>0) call post_data(CS%id_visc_limit_q_frac, visc_limit_q_frac, CS%diag) if (CS%id_visc_limit_h_flag>0) call post_data(CS%id_visc_limit_h_flag, visc_limit_h_flag, CS%diag) if (CS%id_visc_limit_q_flag>0) call post_data(CS%id_visc_limit_q_flag, visc_limit_q_flag, CS%diag) + endif + + if (CS%EY24_EBT_BS .or. CS%use_leithy) then if (CS%id_BS_coeff_h>0) call post_data(CS%id_BS_coeff_h, BS_coeff_h, CS%diag) if (CS%id_BS_coeff_q>0) call post_data(CS%id_BS_coeff_q, BS_coeff_q, CS%diag) endif @@ -2562,6 +2566,10 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) "If true, use a biharmonic Leith nonlinear eddy "//& "viscosity together with a harmonic backscatter.", & default=.false.) + if (CS%EY24_EBT_BS .and. CS%use_Leithy) then + call MOM_error(FATAL, "MOM_hor_visc.F90, hor_visc_init:"//& + "Cannot simultaneously use EY24 EBT backscatter and Leith+E backscatter") + endif call get_param(param_file, mdl, "BOUND_AH", CS%bound_Ah, & "If true, the biharmonic coefficient is locally limited "//& "to be stable.", default=.true., do_not_log=.not.CS%biharmonic) @@ -2822,6 +2830,9 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) if (CS%use_Leithy) then ALLOC_(CS%m_const_leithy(isd:ied,jsd:jed)) ; CS%m_const_leithy(:,:) = 0.0 ALLOC_(CS%m_leithy_max(isd:ied,jsd:jed)) ; CS%m_leithy_max(:,:) = 0.0 + ALLOC_(CS%Iwts(isd:ied,jsd:jed)) ; CS%Iwts(:,:) = 0.0 + ALLOC_(CS%Iwts_u(IsdB:IedB,jsd:jed)) ; CS%Iwts_u(:,:) = 0.0 + ALLOC_(CS%Iwts_v(isd:ied,JsdB:JedB)) ; CS%Iwts_v(:,:) = 0.0 endif if (CS%Re_Ah > 0.0) then ALLOC_(CS%Re_Ah_const_xx(isd:ied,jsd:jed)) ; CS%Re_Ah_const_xx(:,:) = 0.0 @@ -2984,7 +2995,9 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) if (CS%use_Leithy) then CS%biharm6_const_xx(i,j) = Leith_bi_const * max(G%dxT(i,j),G%dyT(i,j))**6 CS%m_const_leithy(i,j) = 0.5 * sqrt(CS%c_K) * max(G%dxT(i,j),G%dyT(i,j)) - CS%m_leithy_max(i,j) = 4. / max(G%dxT(i,j),G%dyT(i,j))**2 + CS%m_leithy_max(i,j) = 4. / max(G%dxT(i,j),G%dyT(i,j))**2 * & + G%mask2dBu(i,j ) * G%mask2dBu(i-1,j ) * & + G%mask2dBu(i,j-1) * G%mask2dBu(i-1,j-1) endif CS%Ah_bg_xx(i,j) = MAX(Ah, Ah_vel_scale * grid_sp_h2 * sqrt(grid_sp_h2)) if (CS%Re_Ah > 0.0) CS%Re_Ah_const_xx(i,j) = grid_sp_h3 / CS%Re_Ah @@ -2998,6 +3011,18 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) enddo ; enddo call min_across_PEs(min_grid_sp_h4) + if (CS%use_Leithy) then + do j=js,je ; do i=is,ie; if (G%mask2dT(i,j) > 0.0) then + CS%Iwts(i,j) = 1.0 / (sum_5x5(G%mask2dT(i-2:i+2,j-2:j+2)) + 1.0E-32) + endif ; enddo ; enddo + do j=js,je ; do I=Isq,Ieq ; if (G%mask2dCu(I,j) > 0.0) then + CS%Iwts_u(I,j) = 1.0 / (sum_5x5(G%mask2dCu(I-2:I+2,j-2:j+2)) + 1.0E-32) + endif ; enddo ; enddo + do J=Jsq,Jeq ; do i=is,ie ; if (G%mask2dCv(i,J) > 0.0) then + CS%Iwts_v(i,J) = 1.0 / (sum_5x5(G%mask2dCv(i-2:i+2,J-2:J+2)) + 1.0E-32) + endif ; enddo ; enddo + endif + do J=js-1,Jeq ; do I=is-1,Ieq grid_sp_q2 = (2.0*CS%dx2q(I,J)*CS%dy2q(I,J)) / (CS%dx2q(I,J)+CS%dy2q(I,J)) grid_sp_q3 = grid_sp_q2*sqrt(grid_sp_q2) @@ -3272,7 +3297,7 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2) endif - if (CS%EY24_EBT_BS) then + if (CS%EY24_EBT_BS .or. CS%use_leithy) then CS%id_BS_coeff_h = register_diag_field('ocean_model', 'BS_coeff_h', diag%axesTL, Time, & 'Backscatter coefficient at h points', units='m2 s-1', conversion=US%L_to_m**2*US%s_to_T) CS%id_BS_coeff_q = register_diag_field('ocean_model', 'BS_coeff_q', diag%axesBL, Time, & @@ -3400,12 +3425,33 @@ subroutine smooth_GME(CS, G, GME_flux_h, GME_flux_q) enddo ! s-loop end subroutine smooth_GME +!> Apply a 5x5 weighted sum. In exact arithmetic this is the same as applying a 1:2:1 smoother +!! twice in each direction. The implementation here uses fewer arithmetic operations, and is +!! rotationally symmetric. To obtain the weighted average, divide the result by 256. +function sum_5x5(x) result(sum_x) + implicit none + real, intent(in) :: x(:,:) !< 5x5 array to be summed. Assumed-shape to avoid copies. [arbitrary] + real :: sum_x !< output [same as x] + real :: sum_partial !< scalar holding a partial sum, for convenience + + sum_partial = ((x(1,1) + x(5,5)) + (x(1,5) + x(5,1))) + sum_partial = sum_partial + 6.*((x(3,1) + x(1,3)) + (x(3,5) + x(5,3))) + sum_partial = sum_partial + 36.*x(3,3) + sum_partial = sum_partial + 16.*((x(2,2) + x(4,4)) + (x(2,4) + x(4,2))) + sum_x = 4.*( ((x(1,2) + x(2,1)) + (x(1,4) + x(4,1))) + & + ((x(5,2) + x(2,5)) + (x(5,4) + x(4,5))) ) + sum_x = sum_x + 24.*((x(2,3) + x(3,2)) + (x(4,3) + x(3,4))) + sum_x = sum_x + sum_partial + +end function + !> Apply a 9-point smoothing filter twice to a field staggered at a thickness point to reduce -!! horizontal two-grid-point noise. +!! horizontal two-grid-point noise. Implemented using a single 5x5 pass rather than 3x3 twice. !! Note that this subroutine does not conserve mass, so don't use it in situations where you !! need conservation. Also note that it assumes that the input field has valid values in the !! first two halo points upon entry. -subroutine smooth_x9_h(G, field_h, zero_land) +subroutine smooth_x9_h(CS, G, field_h, zero_land) + type(hor_visc_CS), intent(in) :: CS !< Control structure type(ocean_grid_type), intent(in) :: G !< Ocean grid real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: field_h !< h-point field to be smoothed [arbitrary] logical, optional, intent(in) :: zero_land !< If present and false, return the average @@ -3414,42 +3460,36 @@ subroutine smooth_x9_h(G, field_h, zero_land) !! land points and include them in the averages. ! Local variables - real :: fh_prev(SZI_(G),SZJ_(G)) ! The value of the h-point field at the previous iteration [arbitrary] - real :: Iwts ! The inverse of the sum of the weights [nondim] - logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent. - integer :: i, j, s, is, ie, js, je + real :: fh_prev(SZI_(G),SZJ_(G)) ! Copy of the input value of the h-point field [arbitrary] + real :: Iwts_zl = 0.00390625 ! The inverse of the sum of the weights zeroing land, = 1/256 [nondim] + logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent. + integer :: i, j, is, ie, js, je is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec zero_land_val = .true. ; if (present(zero_land)) zero_land_val = zero_land - do s=1,0,-1 - fh_prev(:,:) = field_h(:,:) - ! apply smoothing on field_h using rotationally symmetric expressions. - do j=js-s,je+s ; do i=is-s,ie+s ; if (G%mask2dT(i,j) > 0.0) then - Iwts = 0.0625 - if (.not. zero_land_val) & - Iwts = 1.0 / ( (4.0*G%mask2dT(i,j) + & - ( 2.0*((G%mask2dT(i-1,j) + G%mask2dT(i+1,j)) + & - (G%mask2dT(i,j-1) + G%mask2dT(i,j+1))) + & - ((G%mask2dT(i-1,j-1) + G%mask2dT(i+1,j+1)) + & - (G%mask2dT(i-1,j+1) + G%mask2dT(i+1,j-1))) ) ) + 1.0e-16 ) - field_h(i,j) = Iwts * ( 4.0*G%mask2dT(i,j) * fh_prev(i,j) & - + (2.0*((G%mask2dT(i-1,j) * fh_prev(i-1,j) + G%mask2dT(i+1,j) * fh_prev(i+1,j)) + & - (G%mask2dT(i,j-1) * fh_prev(i,j-1) + G%mask2dT(i,j+1) * fh_prev(i,j+1))) & - + ((G%mask2dT(i-1,j-1) * fh_prev(i-1,j-1) + G%mask2dT(i+1,j+1) * fh_prev(i+1,j+1)) + & - (G%mask2dT(i-1,j+1) * fh_prev(i-1,j+1) + G%mask2dT(i+1,j-1) * fh_prev(i-1,j-1))) )) + fh_prev(:,:) = field_h(:,:) + ! apply smoothing on field_h using rotationally symmetric expressions. + if (zero_land_val) then + do j=js,je ; do i=is,ie ; if (G%mask2dT(i,j) > 0.0) then + field_h(i,j) = Iwts_zl * sum_5x5(fh_prev(i-2:i+2,j-2:j+2) * G%mask2dT(i-2:i+2,j-2:j+2)) + endif ; enddo ; enddo + else + do j=js,je ; do i=is,ie ; if (G%mask2dT(i,j) > 0.0) then + field_h(i,j) = CS%Iwts(i,j) * sum_5x5(fh_prev(i-2:i+2,j-2:j+2) * G%mask2dT(i-2:i+2,j-2:j+2)) endif ; enddo ; enddo - enddo + endif end subroutine smooth_x9_h !> Apply a 9-point smoothing filter twice to a pair of velocity components to reduce -!! horizontal two-grid-point noise. +!! horizontal two-grid-point noise. Implemented using a single 5x5 pass rather than 3x3 twice. !! Note that this subroutine does not conserve angular momentum, so don't use it !! in situations where you need conservation. Also note that it assumes that the !! input fields have valid values in the first two halo points upon entry. -subroutine smooth_x9_uv(G, field_u, field_v, zero_land) +subroutine smooth_x9_uv(CS, G, field_u, field_v, zero_land) + type(hor_visc_CS), intent(in) :: CS !< Control structure type(ocean_grid_type), intent(in) :: G !< Ocean grid real, dimension(SZIB_(G),SZJ_(G)), intent(inout) :: field_u !< u-point field to be smoothed [arbitrary] real, dimension(SZI_(G),SZJB_(G)), intent(inout) :: field_v !< v-point field to be smoothed [arbitrary] @@ -3459,52 +3499,42 @@ subroutine smooth_x9_uv(G, field_u, field_v, zero_land) !! land points and include them in the averages. ! Local variables. - real :: fu_prev(SZIB_(G),SZJ_(G)) ! The value of the u-point field at the previous iteration [arbitrary] - real :: fv_prev(SZI_(G),SZJB_(G)) ! The value of the v-point field at the previous iteration [arbitrary] - real :: Iwts ! The inverse of the sum of the weights [nondim] - logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent. - integer :: i, j, s, is, ie, js, je, Isq, Ieq, Jsq, Jeq + real :: fu_prev(SZIB_(G),SZJ_(G)) ! Copy of the input value of the u-point field [arbitrary] + real :: fv_prev(SZI_(G),SZJB_(G)) ! Copy of the input value of the v-point field [arbitrary] + real :: Iwts_zl = 0.00390625 ! The inverse of the sum of the weights zeroing land, = 1/256 [nondim] + logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent. + integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB zero_land_val = .true. ; if (present(zero_land)) zero_land_val = zero_land - do s=1,0,-1 - fu_prev(:,:) = field_u(:,:) - ! apply smoothing on field_u using the original non-rotationally symmetric expressions. - do j=js-s,je+s ; do I=Isq-s,Ieq+s ; if (G%mask2dCu(I,j) > 0.0) then - Iwts = 0.0625 - if (.not. zero_land_val) & - Iwts = 1.0 / ( (4.0*G%mask2dCu(I,j) + & - ( 2.0*((G%mask2dCu(I-1,j) + G%mask2dCu(I+1,j)) + & - (G%mask2dCu(I,j-1) + G%mask2dCu(I,j+1))) + & - ((G%mask2dCu(I-1,j-1) + G%mask2dCu(I+1,j+1)) + & - (G%mask2dCu(I-1,j+1) + G%mask2dCu(I+1,j-1))) ) ) + 1.0e-16 ) - field_u(I,j) = Iwts * ( 4.0*G%mask2dCu(I,j) * fu_prev(I,j) & - + (2.0*((G%mask2dCu(I-1,j) * fu_prev(I-1,j) + G%mask2dCu(I+1,j) * fu_prev(I+1,j)) + & - (G%mask2dCu(I,j-1) * fu_prev(I,j-1) + G%mask2dCu(I,j+1) * fu_prev(I,j+1))) & - + ((G%mask2dCu(I-1,j-1) * fu_prev(I-1,j-1) + G%mask2dCu(I+1,j+1) * fu_prev(I+1,j+1)) + & - (G%mask2dCu(I-1,j+1) * fu_prev(I-1,j+1) + G%mask2dCu(I+1,j-1) * fu_prev(I-1,j-1))) )) + fu_prev(:,:) = field_u(:,:) + ! apply smoothing on field_u using the original non-rotationally symmetric expressions. + if (zero_land_val) then + do j=js,je ; do I=Isq,Ieq ; if (G%mask2dCu(I,j) > 0.0) then + field_u(I,j) = Iwts_zl * sum_5x5(fu_prev(I-2:I+2,j-2:j+2) * G%mask2dCu(I-2:I+2,j-2:j+2)) + endif ; enddo ; enddo + else + do j=js,je ; do I=Isq,Ieq ; if (G%mask2dCu(I,j) > 0.0) then + field_u(I,j) = CS%Iwts_u(I,j) * & + sum_5x5(fu_prev(I-2:I+2,j-2:j+2) * G%mask2dCu(I-2:I+2,j-2:j+2)) endif ; enddo ; enddo + endif - fv_prev(:,:) = field_v(:,:) - ! apply smoothing on field_v using the original non-rotationally symmetric expressions. - do J=Jsq-s,Jeq+s ; do i=is-s,ie+s ; if (G%mask2dCv(i,J) > 0.0) then - Iwts = 0.0625 - if (.not. zero_land_val) & - Iwts = 1.0 / ( (4.0*G%mask2dCv(i,J) + & - ( 2.0*((G%mask2dCv(i-1,J) + G%mask2dCv(i+1,J)) + & - (G%mask2dCv(i,J-1) + G%mask2dCv(i,J+1))) + & - ((G%mask2dCv(i-1,J-1) + G%mask2dCv(i+1,J+1)) + & - (G%mask2dCv(i-1,J+1) + G%mask2dCv(i+1,J-1))) ) ) + 1.0e-16 ) - field_v(i,J) = Iwts * ( 4.0*G%mask2dCv(i,J) * fv_prev(i,J) & - + (2.0*((G%mask2dCv(i-1,J) * fv_prev(i-1,J) + G%mask2dCv(i+1,J) * fv_prev(i+1,J)) + & - (G%mask2dCv(i,J-1) * fv_prev(i,J-1) + G%mask2dCv(i,J+1) * fv_prev(i,J+1))) & - + ((G%mask2dCv(i-1,J-1) * fv_prev(i-1,J-1) + G%mask2dCv(i+1,J+1) * fv_prev(i+1,J+1)) + & - (G%mask2dCv(i-1,J+1) * fv_prev(i-1,J+1) + G%mask2dCv(i+1,J-1) * fv_prev(i-1,J-1))) )) + fv_prev(:,:) = field_v(:,:) + ! apply smoothing on field_v using the original non-rotationally symmetric expressions. + if (zero_land_val) then + do J=Jsq,Jeq ; do i=is,ie ; if (G%mask2dCv(i,J) > 0.0) then + field_v(i,J) = Iwts_zl * sum_5x5(fv_prev(i-2:i+2,J-2:J+2) * G%mask2dCv(i-2:i+2,J-2:J+2)) endif ; enddo ; enddo - enddo + else + do J=Jsq,Jeq ; do i=is,ie ; if (G%mask2dCv(i,J) > 0.0) then + field_v(i,J) = CS%Iwts_v(i,J) * & + sum_5x5(fv_prev(i-2:i+2,J-2:J+2) * G%mask2dCv(i-2:i+2,J-2:J+2)) + endif ; enddo ; enddo + endif end subroutine smooth_x9_uv @@ -3549,6 +3579,9 @@ subroutine hor_visc_end(CS) if (CS%use_Leithy) then DEALLOC_(CS%m_const_leithy) DEALLOC_(CS%m_leithy_max) + DEALLOC_(CS%Iwts) + DEALLOC_(CS%Iwts_u) + DEALLOC_(CS%Iwts_v) endif if (CS%Re_Ah > 0.0) then DEALLOC_(CS%Re_Ah_const_xx) ; DEALLOC_(CS%Re_Ah_const_xy) From 3231da9a6cd616bf54d83a3ae738f583cc3a305a Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Wed, 23 Jul 2025 09:58:36 -0600 Subject: [PATCH 13/41] Stochastic EOS cleanup (#359) This commit enables the Stanley parameterization for use with the Bodner23 MLE scheme. It also cleans up logic related to the Stanley parameterization throughout. Finally, it adds some documentation for the `MOM_stoch_eos` module. --- docs/zotero.bib | 29 +++++++++++++ src/core/MOM_PressureForce_FV.F90 | 14 +++---- src/core/MOM_stoch_eos.F90 | 41 ++++++++++++++++--- .../lateral/MOM_lateral_mixing_coeffs.F90 | 13 +++--- .../lateral/MOM_mixed_layer_restrat.F90 | 28 ++++++------- .../lateral/MOM_thickness_diffuse.F90 | 14 +++---- 6 files changed, 93 insertions(+), 46 deletions(-) diff --git a/docs/zotero.bib b/docs/zotero.bib index 01fe2c6185..eb2423de02 100644 --- a/docs/zotero.bib +++ b/docs/zotero.bib @@ -1,5 +1,34 @@ % This file is generated by zotero. Manual edits will be lost! +@article{agarwal2023, + title={Impact of Stochastic Ocean Density Corrections on Air-Sea Flux Variability}, + author={Agarwal, Niraj and Small, R Justin and Bryan, Frank O and Grooms, Ian and Pegion, Philip J}, + journal={Geophysical Research Letters}, + volume={50}, + number={13}, + pages={e2023GL104248}, + year={2023}, +} + +@article{kenigson2022, + title={Parameterizing the impact of unresolved temperature variability on the large-scale density field: 2. Modeling}, + author={Kenigson, JS and Adcroft, A and Bachman, SD and Castruccio, F and Grooms, I and Pegion, P and Stanley, Z}, + journal={Journal of Advances in Modeling Earth Systems}, + volume={14}, + number={3}, + pages={e2021MS002844}, + year={2022}, +} + +@article{stanley2020, + title={Parameterizing the Impact of Unresolved Temperature Variability on the Large-Scale Density Field: {Part 1.} Theory.}, + author={Stanley, Z and Grooms, I and Kleiber, W and Bachman, SD and Castruccio, F and Adcroft, A}, + journal={Journal of Advances in Modeling Earth Systems}, + volume={12}, + number={12}, + pages={e2020MS002185}, + year={2020}, +} @article{redi1982, title = {Oceanic {Isopycnal} {Mixing} by {Coordinate} {Rotation}}, diff --git a/src/core/MOM_PressureForce_FV.F90 b/src/core/MOM_PressureForce_FV.F90 index aaabab3500..e55376d568 100644 --- a/src/core/MOM_PressureForce_FV.F90 +++ b/src/core/MOM_PressureForce_FV.F90 @@ -2030,8 +2030,6 @@ subroutine PressureForce_FV_init(Time, G, GV, US, param_file, diag, CS, ADp, SAL type(tidal_forcing_CS), intent(in), target, optional :: tides_CSp !< Tides control structure ! Local variables - real :: Stanley_coeff ! Coefficient relating the temperature gradient and sub-gridscale - ! temperature variance [nondim] integer :: default_answer_date ! Global answer date logical :: use_temperature ! If true, temperature and salinity are used as state variables. logical :: use_EOS ! If true, density calculated from T & S using an equation of state. @@ -2043,6 +2041,7 @@ subroutine PressureForce_FV_init(Time, G, GV, US, param_file, diag, CS, ADp, SAL # include "version_variable.h" character(len=40) :: mdl ! This module's name. logical :: use_ALE ! If true, use the Vertical Lagrangian Remap algorithm + logical :: stoch_eos ! Can't use Stanley param here unless stoch_eos is true integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed ; nz = GV%ke @@ -2182,16 +2181,15 @@ subroutine PressureForce_FV_init(Time, G, GV, US, param_file, diag, CS, ADp, SAL "boundary cells is extrapolated, rather than using PCM "//& "in these cells. If true, the same order polynomial is "//& "used as is used for the interior cells.", default=.true.) + call get_param(param_file, mdl, "STOCH_EOS", stoch_eos, & + default=.false., do_not_log=.true.) call get_param(param_file, mdl, "USE_STANLEY_PGF", CS%use_stanley_pgf, & "If true, turn on Stanley SGS T variance parameterization "// & "in PGF code.", default=.false.) if (CS%use_stanley_pgf) then - call get_param(param_file, mdl, "STANLEY_COEFF", Stanley_coeff, & - "Coefficient correlating the temperature gradient and SGS T variance.", & - units="nondim", default=-1.0, do_not_log=.true.) - if (Stanley_coeff < 0.0) call MOM_error(FATAL, & - "STANLEY_COEFF must be set >= 0 if USE_STANLEY_PGF is true.") - + if (.not.stoch_eos) then + call MOM_error(FATAL, "PressureForce_FV_init: USE_STANLEY_PGF requires STOCH_EOS") + endif CS%id_rho_pgf = register_diag_field('ocean_model', 'rho_pgf', diag%axesTL, & Time, 'rho in PGF', 'kg m-3', conversion=US%R_to_kg_m3) CS%id_rho_stanley_pgf = register_diag_field('ocean_model', 'rho_stanley_pgf', diag%axesTL, & diff --git a/src/core/MOM_stoch_eos.F90 b/src/core/MOM_stoch_eos.F90 index 909c2e9a6a..8db35c72e7 100644 --- a/src/core/MOM_stoch_eos.F90 +++ b/src/core/MOM_stoch_eos.F90 @@ -4,7 +4,7 @@ module MOM_stoch_eos ! This file is part of MOM6. See LICENSE.md for the license. use MOM_diag_mediator, only : register_diag_field, post_data, diag_ctrl use MOM_error_handler, only : MOM_error, FATAL -use MOM_file_parser, only : get_param, param_file_type +use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_grid, only : ocean_grid_type use MOM_hor_index, only : hor_index_type use MOM_isopycnal_slopes, only : vert_fill_TS @@ -62,27 +62,32 @@ logical function MOM_stoch_eos_init(Time, G, GV, US, param_file, diag, CS, resta type(MOM_restart_CS), pointer :: restart_CS !< A pointer to the restart control structure. ! local variables + ! This include declares and sets the variable "version". +# include "version_variable.h" integer :: i,j MOM_stoch_eos_init = .false. CS%seed = 0 + call log_version(param_file, "MOM_stoch_eos", version, "") call get_param(param_file, "MOM_stoch_eos", "STOCH_EOS", CS%use_stoch_eos, & - "If true, stochastic perturbations are applied "//& - "to the EOS in the PGF.", default=.false.) + "If true, computes stochastic perturbations that can be applied "//& + "to the EOS in various places.", default=.false.) call get_param(param_file, "MOM_stoch_eos", "STANLEY_COEFF", CS%stanley_coeff, & "Coefficient correlating the temperature gradient "//& "and SGS T variance.", units="nondim", default=-1.0) + if ((CS%stanley_coeff < 0.0) .and. CS%use_stoch_eos) call MOM_error(FATAL, & + "STANLEY_COEFF must be set >= 0 if STOCH_EOS is true.") call get_param(param_file, "MOM_stoch_eos", "STANLEY_A", CS%stanley_a, & "Coefficient a which scales chi in stochastic perturbation of the "//& "SGS T variance.", units="nondim", default=1.0, & - do_not_log=((CS%stanley_coeff<0.0) .or. .not.CS%use_stoch_eos)) + do_not_log=.not.CS%use_stoch_eos) call get_param(param_file, "MOM_stoch_eos", "KD_SMOOTH", CS%kappa_smooth, & "A diapycnal diffusivity that is used to interpolate "//& "more sensible values of T & S into thin layers.", & units="m2 s-1", default=1.0e-6, scale=GV%m2_s_to_HZ_T, & - do_not_log=(CS%stanley_coeff<0.0)) + do_not_log=.not.CS%use_stoch_eos) ! Don't run anything if STANLEY_COEFF < 0 if (CS%stanley_coeff >= 0.0) then @@ -258,4 +263,30 @@ subroutine MOM_calc_varT(G, GV, US, h, tv, CS, dt) endif end subroutine MOM_calc_varT +!> \namespace mom_stoch_eos +!! +!! This module provides the foundation of the Stanley parameterization (\cite stanley2020) for correcting the +!! computation of density. Density is not a prognostic variable in MOM6; it is computed for various purposes +!! in various places. The correction to this calculation provided by this module has been implemented +!! in some places where density is used, but not all. +!! +!! To use the correction, first set STOCH_EOS=True. Then, choose the constant c from (25) of +!! \cite stanley2020. This is controlled using STANLEY_COEFF. Setting a negative value will +!! result in an error. \cite stanley2020 found a value of 0.2 offline, coarsening from 0.1 to 1 degree +!! resolution. \cite kenigson2022 proposed a value of 0.5 in a 2/3 degree resolution model. +!! +!! Whether the correction is deterministic or stochastic can be controlled using the variable +!! STANLEY_A. Setting this to 0.0 uses the deterministic version, while a value of 1.0 produces +!! the stochastic version. Reducing from 1 to 0 smoothly transitions from stochastic to deterministic. +!! +!! To turn the correction on in various parts of the code, use +!! - USE_STANLEY_PGF=True for the pressure gradient force (cf. \cite kenigson2022) +!! - USE_STANLEY_ISO=True to correct the computation of isopycnal slopes (used in many places) +!! - USE_STANLEY_GM=True to use the parameterization within GM (cf. \cite agarwal2023) +!! - USE_STANLEY_ML=True to use the parameterization within the mixed-layer restratification +!! parameterization. It applies to both the OM4 and Bodner schemes. (cf. \cite agarwal2023) +!! +!! For ensemble simulations, the random number generator seed can be controlled using the parameter +!! SEED_STOCH_EOS + end module MOM_stoch_eos diff --git a/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 b/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 index f2f476b0c8..374cd2ce6c 100644 --- a/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 +++ b/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 @@ -1335,9 +1335,8 @@ subroutine VarMix_init(Time, G, GV, US, param_file, diag, CS) ! scaled by the resolution function. logical :: better_speed_est ! If true, use a more robust estimate of the first ! mode wave speed as the starting point for iterations. - real :: Stanley_coeff ! Coefficient relating the temperature gradient and sub-gridscale - ! temperature variance [nondim] logical :: om4_remap_via_sub_cells ! Use the OM4-era ramap_via_sub_cells for calculating the EBT structure + logical :: stoch_eos ! Can't use Stanley param here unless stoch_eos is true ! This include declares and sets the variable "version". # include "version_variable.h" character(len=40) :: mdl = "MOM_lateral_mixing_coeffs" ! This module's name. @@ -1461,15 +1460,13 @@ subroutine VarMix_init(Time, G, GV, US, param_file, diag, CS) call get_param(param_file, mdl, "DEBUG", CS%debug, default=.false., do_not_log=.true.) + call get_param(param_file, mdl, "STOCH_EOS", stoch_eos, & + default=.false., do_not_log=.true.) call get_param(param_file, mdl, "USE_STANLEY_ISO", CS%use_stanley_iso, & "If true, turn on Stanley SGS T variance parameterization "// & "in isopycnal slope code.", default=.false.) - if (CS%use_stanley_iso) then - call get_param(param_file, mdl, "STANLEY_COEFF", Stanley_coeff, & - "Coefficient correlating the temperature gradient and SGS T variance.", & - units="nondim", default=-1.0, do_not_log=.true.) - if (Stanley_coeff < 0.0) call MOM_error(FATAL, & - "STANLEY_COEFF must be set >= 0 if USE_STANLEY_ISO is true.") + if (CS%use_Stanley_ISO .and. .not.stoch_eos) then + call MOM_error(FATAL, "VarMix_init: USE_STANLEY_ISO requires STOCH_EOS") endif if (CS%Resoln_use_ebt .or. CS%khth_use_ebt_struct .or. CS%kdgl90_use_ebt_struct & diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 00b3e0e616..0f8fe55e73 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -863,6 +863,9 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d "To use the Bodner et al., 2023, MLE parameterization, either MLE_USE_PBL_MLD or "// & "Bodner_detect_MLD must be True.") endif + if (CS%use_Stanley_ML .and. .not.GV%Boussinesq) call MOM_error(FATAL, & + "MOM_mixedlayer_restrat: The Stanley parameterization is not"//& + "available without the Boussinesq approximation.") if (associated(bflux)) & call pass_var(bflux, G%domain, halo=1) @@ -1644,8 +1647,6 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, real :: flux_to_kg_per_s ! A unit conversion factor for fluxes. [kg T s-1 H-1 L-2 ~> kg m-3 or 1] real :: omega ! The Earth's rotation rate [T-1 ~> s-1]. real :: ustar_min_dflt ! The default value for RESTRAT_USTAR_MIN [Z T-1 ~> m s-1] - real :: Stanley_coeff ! Coefficient relating the temperature gradient and sub-gridscale - ! temperature variance [nondim] integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags ! This include declares and sets the variable "version". character(len=200) :: inputdir ! The directory where NetCDF input files @@ -1653,6 +1654,7 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, character(len=128) :: mle_fl_file ! Data containing MLE front-length scale. Used ! when reading from file. character(len=32) :: fl_varname ! Name of front-length scale variable in mle_fl_file. + logical :: stoch_eos ! Can't use Stanley param here unless stoch_eos is true # include "version_variable.h" integer :: i, j @@ -1689,6 +1691,14 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "This sets the default value for the various _ANSWER_DATE parameters.", & default=99991231, do_not_log=.true.) call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".") + call get_param(param_file, mdl, "STOCH_EOS", stoch_eos, & + default=.false., do_not_log=.true.) + call get_param(param_file, mdl, "USE_STANLEY_ML", CS%use_Stanley_ML, & + "If true, turn on Stanley SGS T variance parameterization "// & + "in ML restrat code.", default=.false.) + if (CS%use_Stanley_ML .and. .not.stoch_eos) then + call MOM_error(FATAL, "mixedlayer_restrat_init: USE_STANLEY_ML requires STOCH_EOS") + endif call openParameterBlock(param_file,'MLE') ! Prepend MLE% to all parameters if (GV%nkml==0) then call get_param(param_file, mdl, "USE_BODNER23", CS%use_Bodner, & @@ -1751,9 +1761,6 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "Fraction by which to extend the mixed-layer restratification "//& "depth used for a smoother stream function at the base of "//& "the mixed-layer.", units="nondim", default=0.0) - call get_param(param_file, mdl, "USE_STANLEY_TVAR", CS%use_Stanley_ML, & - "If true, turn on Stanley SGS T variance parameterization "// & - "in ML restrat code.", default=.false.) call get_param(param_file, mdl, "USE_CR_GRID", CS%Cr_grid, & "If true, read in a spatially varying Cr field.", default=.false.) call get_param(param_file, mdl, "USE_MLD_GRID", CS%MLD_grid, & @@ -1811,17 +1818,6 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "geostrophic kinetic energy or 1 plus the square of the "//& "grid spacing over the deformation radius, as detailed "//& "by Fox-Kemper et al. (2011)", units="nondim", default=0.0) - ! These parameters are only used in the OM4-era version of Fox-Kemper - call get_param(param_file, mdl, "USE_STANLEY_ML", CS%use_Stanley_ML, & - "If true, turn on Stanley SGS T variance parameterization "// & - "in ML restrat code.", default=.false.) - if (CS%use_Stanley_ML) then - call get_param(param_file, mdl, "STANLEY_COEFF", Stanley_coeff, & - "Coefficient correlating the temperature gradient and SGS T variance.", & - units="nondim", default=-1.0, do_not_log=.true.) - if (Stanley_coeff < 0.0) call MOM_error(FATAL, & - "STANLEY_COEFF must be set >= 0 if USE_STANLEY_ML is true.") - endif call get_param(param_file, mdl, 'VON_KARMAN_CONST', CS%vonKar, & 'The value the von Karman constant as used for mixed layer viscosity.', & units='nondim', default=0.41) diff --git a/src/parameterizations/lateral/MOM_thickness_diffuse.F90 b/src/parameterizations/lateral/MOM_thickness_diffuse.F90 index cf06be4ed2..e07b95cdca 100644 --- a/src/parameterizations/lateral/MOM_thickness_diffuse.F90 +++ b/src/parameterizations/lateral/MOM_thickness_diffuse.F90 @@ -97,9 +97,6 @@ module MOM_thickness_diffuse !! When this is true, it breaks rotational symmetry. logical :: use_GM_work_bug !< If true, use the incorrect sign for the !! top-level work tendency on the top layer. - real :: Stanley_det_coeff !< The coefficient correlating SGS temperature variance with the mean - !! temperature gradient in the deterministic part of the Stanley parameterization. - !! Negative values disable the scheme. [nondim] logical :: read_khth !< If true, read a file containing the spatially varying horizontal !! isopycnal height diffusivity logical :: use_stanley_gm !< If true, also use the Stanley parameterization in MOM_thickness_diffuse @@ -2195,6 +2192,7 @@ subroutine thickness_diffuse_init(Time, G, GV, US, param_file, diag, CDp, CS) ! available. logical :: use_meke = .false. ! If true, use the MEKE formulation for the thickness diffusivity. integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags. + logical :: stoch_eos ! Can't use Stanley param here unless stoch_eos is true integer :: i, j CS%initialized = .true. @@ -2322,15 +2320,13 @@ subroutine thickness_diffuse_init(Time, G, GV, US, param_file, diag, CDp, CS) "streamfunction formulation, expressed as a fraction of planetary "//& "rotation, OMEGA. This should be tiny but non-zero to avoid degeneracy.", & default=1.e-15, units="nondim", scale=US%Z_to_L, do_not_log=.not.CS%use_FGNV_streamfn) + call get_param(param_file, mdl, "STOCH_EOS", stoch_eos, & + default=.false., do_not_log=.true.) call get_param(param_file, mdl, "USE_STANLEY_GM", CS%use_stanley_gm, & "If true, turn on Stanley SGS T variance parameterization "// & "in GM code.", default=.false.) - if (CS%use_stanley_gm) then - call get_param(param_file, mdl, "STANLEY_COEFF", Stanley_coeff, & - "Coefficient correlating the temperature gradient and SGS T variance.", & - units="nondim", default=-1.0, do_not_log=.true.) - if (Stanley_coeff < 0.0) call MOM_error(FATAL, & - "STANLEY_COEFF must be set >= 0 if USE_STANLEY_GM is true.") + if (CS%use_Stanley_GM .and. .not.stoch_eos) then + call MOM_error(FATAL, "thickness_diffuse_init: USE_STANLEY_GM requires STOCH_EOS") endif call get_param(param_file, mdl, "OMEGA", omega, & "The rotation rate of the earth.", & From 19574b7c39333ed82defbb7aa1e6d27f4fd0fbd8 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Thu, 24 Jul 2025 13:01:41 -0600 Subject: [PATCH 14/41] Fix missing array allocation for DO_SKEB (#371) --- src/parameterizations/stochastic/MOM_stochastics.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parameterizations/stochastic/MOM_stochastics.F90 b/src/parameterizations/stochastic/MOM_stochastics.F90 index ddc34fdbaa..c57919fd66 100644 --- a/src/parameterizations/stochastic/MOM_stochastics.F90 +++ b/src/parameterizations/stochastic/MOM_stochastics.F90 @@ -171,10 +171,10 @@ subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) return endif - if (CS%do_sppt) allocate(CS%sppt_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) + if ((CS%do_sppt) .or. (CS%do_skeb)) allocate(CS%sppt_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) if (CS%do_skeb) allocate(CS%skeb_wts(grid%isdB:grid%iedB,grid%jsdB:grid%jedB)) if (CS%do_skeb) allocate(CS%skeb_diss(grid%isd:grid%ied,grid%jsd:grid%jed,GV%ke), source=0.) - if (CS%pert_epbl) then + if ((CS%pert_epbl) .or. (CS%do_skeb)) then allocate(CS%epbl1_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) allocate(CS%epbl2_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) endif From 5d53c361344eed35bb3abe4e2c9c608e4fa8051f Mon Sep 17 00:00:00 2001 From: Robert Hallberg Date: Thu, 24 Jul 2025 19:38:18 -0400 Subject: [PATCH 15/41] +Refactor stochastics for dimensional consistency (#367) Refactored MOM_stochastics for dimensional and rotational consistency. This involved correcting the dimensions of a hard-coded area, adding missing conversion factors to the register_diag_field calls for 6 stochastics diagnostics, and adding descriptions of the units in comments describing 7 variables in MOM_stochastics. This commit also adds the new runtime parameter STOCHASTICS_ANSWER_DATE that can be set to a value of 20250701 or higher to use rotationally symmetric expressions. The stochastic physics package itself is external to MOM6 and works in unscaled mks units, so fields passed to it (such as the timestep) need to be unscaled back to mks units. As a part of this change, new unit_scale_type arguments were added to stochastics_init and apply_skeb. By default the answers should be bitwise identical in cases without dimensional consistency testing, but the diagnostic conversion factors should correct the problems with dimensional rescaling. --- .../stochastic_physics/stochastic_physics.F90 | 2 +- src/core/MOM.F90 | 4 +- .../stochastic/MOM_stochastics.F90 | 194 ++++++++++++------ 3 files changed, 131 insertions(+), 69 deletions(-) diff --git a/config_src/external/stochastic_physics/stochastic_physics.F90 b/config_src/external/stochastic_physics/stochastic_physics.F90 index 97bcff70d4..196468e317 100644 --- a/config_src/external/stochastic_physics/stochastic_physics.F90 +++ b/config_src/external/stochastic_physics/stochastic_physics.F90 @@ -58,7 +58,7 @@ end subroutine init_stochastic_physics_ocn !> Determines the stochastic physics perturbations. subroutine run_stochastic_physics_ocn(sppt_wts, skeb_wts, t_rp1, t_rp2) real, intent(inout) :: sppt_wts(:,:) !< array containing random weights for SPPT range [0,2] - real, intent(inout) :: skeb_wts(:,:) !< array containing random weights for SKEB + real, intent(inout) :: skeb_wts(:,:) !< array containing random weights for SKEB with units of a length [m] real, intent(inout) :: t_rp1(:,:) !< array containing random weights for ePBL !! perturbations (KE generation) range [0,2] real, intent(inout) :: t_rp2(:,:) !< array containing random weights for ePBL diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index 86c99af2a6..3856e731cf 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -1730,7 +1730,7 @@ subroutine step_MOM_thermo(CS, G, GV, US, u, v, h, tv, fluxes, dtdia, & fluxes%fluxes_used = .true. if (CS%stoch_CS%do_skeb) then - call apply_skeb(CS%G,CS%GV,CS%stoch_CS,CS%u,CS%v,CS%h,CS%tv,dtdia,Time_end_thermo) + call apply_skeb(G, GV, US, CS%stoch_CS, u, v, h, tv, dtdia, Time_end_thermo) endif if (showCallTree) call callTree_waypoint("finished diabatic (step_MOM_thermo)") @@ -3738,7 +3738,7 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, & endif ! initialize stochastic physics - call stochastics_init(CS%dt_therm, CS%G, CS%GV, CS%stoch_CS, param_file, diag, Time) + call stochastics_init(CS%dt_therm, CS%G, CS%GV, US, CS%stoch_CS, param_file, diag, Time) call callTree_leave("initialize_MOM()") call cpu_clock_end(id_clock_init) diff --git a/src/parameterizations/stochastic/MOM_stochastics.F90 b/src/parameterizations/stochastic/MOM_stochastics.F90 index c57919fd66..6f0c8ad464 100644 --- a/src/parameterizations/stochastic/MOM_stochastics.F90 +++ b/src/parameterizations/stochastic/MOM_stochastics.F90 @@ -8,22 +8,23 @@ module MOM_stochastics ! particular version wraps all of the calls for MOM6 in the calls that had ! been used for MOM4. ! +use MOM_coms, only : Get_PElist use MOM_debugging, only : hchksum, uvchksum, qchksum use MOM_diag_mediator, only : register_diag_field, diag_ctrl, time_type, post_data use MOM_diag_mediator, only : register_static_field, enable_averages, disable_averaging -use MOM_grid, only : ocean_grid_type -use MOM_variables, only : thermo_var_ptrs use MOM_domains, only : pass_var, pass_vector, CORNER, SCALAR_PAIR -use MOM_verticalGrid, only : verticalGrid_type +use MOM_domains, only : root_PE, num_PEs use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, is_root_pe use MOM_error_handler, only : callTree_enter, callTree_leave use MOM_file_parser, only : get_param, log_version, close_param_file, param_file_type -use mpp_domains_mod, only : domain2d, mpp_get_layout, mpp_get_global_domain -use mpp_domains_mod, only : mpp_define_domains, mpp_get_compute_domain, mpp_get_data_domain -use MOM_domains, only : root_PE, num_PEs -use MOM_coms, only : Get_PElist +use MOM_grid, only : ocean_grid_type +use MOM_unit_scaling, only : unit_scale_type +use MOM_variables, only : thermo_var_ptrs +use MOM_verticalGrid, only : verticalGrid_type use MOM_EOS, only : calculate_density, EOS_domain use stochastic_physics, only : init_stochastic_physics_ocn, run_stochastic_physics_ocn +use mpp_domains_mod, only : domain2d, mpp_get_layout, mpp_get_global_domain +use mpp_domains_mod, only : mpp_define_domains, mpp_get_compute_domain, mpp_get_data_domain #include @@ -55,12 +56,18 @@ module MOM_stochastics !! dissipation rate used to set the amplitude of SKEBS [nondim] real, allocatable :: skeb_diss(:,:,:) !< Dissipation rate used to set amplitude of SKEBS [L2 T-3 ~> m2 s-2] !! Index into this at h points. + integer :: answer_date !< The vintage of the order of arithmetic in the stochastics + !! calculations. Values below 20250701 recover the answers from + !! early in 2025, while higher values use expressions that have been + !! refactored for rotational symmetry, including with FMAs enabled. + ! stochastic patterns real, allocatable :: sppt_wts(:,:) !< Random pattern for ocean SPPT - !! tendencies with a number between 0 and 2 - real, allocatable :: skeb_wts(:,:) !< Random pattern for ocean SKEB - real, allocatable :: epbl1_wts(:,:) !< Random pattern for K.E. generation - real, allocatable :: epbl2_wts(:,:) !< Random pattern for K.E. dissipation + !! tendencies with a number between 0 and 2 [nondim] + real, allocatable :: skeb_wts(:,:) !< Random pattern of lengthscales for ocean SKEB in mks units [m] + ! Note that SKEB_wts is set via external code in mks units. + real, allocatable :: epbl1_wts(:,:) !< Random pattern for K.E. generation [nondim] + real, allocatable :: epbl2_wts(:,:) !< Random pattern for K.E. dissipation [nondim] type(time_type), pointer :: Time !< Pointer to model time (needed for sponges) type(diag_ctrl), pointer :: diag=>NULL() !< A structure that is used to regulate the @@ -77,10 +84,11 @@ module MOM_stochastics contains !! This subroutine initializes the stochastics physics control structure. -subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) +subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time) real, intent(in) :: dt !< time step [T ~> s] type(ocean_grid_type), intent(in) :: grid !< horizontal grid information type(verticalGrid_type), intent(in) :: GV !< vertical grid structure + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type type(stochastic_CS), pointer, intent(inout) :: CS !< stochastic control structure type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters type(diag_ctrl), target, intent(inout) :: diag !< structure to regulate diagnostic output @@ -94,6 +102,7 @@ subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) integer :: pe_zero ! root pe integer :: nxT, nxB ! number of x-points including halo integer :: nyT, nyB ! number of y-points including halo + integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags. integer :: i, j, k ! loop indices real :: tmp(grid%isdB:grid%iedB,grid%jsdB:grid%jedB) ! Used to construct tapers integer :: taper_width ! Width (in cells) of the taper that brings the stochastic velocity @@ -153,6 +162,14 @@ subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) "production and dissipation terms. Amplitude and correlations are "//& "controlled by the nam_stoch namelist in the UFS model only.", & default=.false.) + call get_param(param_file, mdl, "DEFAULT_ANSWER_DATE", default_answer_date, & + "This sets the default value for the various _ANSWER_DATE parameters.", & + default=99991231, do_not_log=.true.) + call get_param(param_file, mdl, "STOCHASTICS_ANSWER_DATE", CS%answer_date, & + "The vintage of the order of arithmetic in the stochastics calculations. "//& + "Values below 20250701 recover the answers from early in 2025, while higher "//& + "values use expressions that have been refactored for rotational symmetry.", & + default=20250101) !### Change to: default=default_answer_date) if (CS%do_sppt .OR. CS%pert_epbl .OR. CS%do_skeb) then num_procs = num_PEs() @@ -163,7 +180,7 @@ subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) nyT = grid%jed - grid%jsd + 1 nxB = grid%iedB - grid%isdB + 1 nyB = grid%jedB - grid%jsdB + 1 - call init_stochastic_physics_ocn(dt, grid%geoLonT, grid%geoLatT, nxT, nyT, GV%ke, & + call init_stochastic_physics_ocn(dt*US%T_to_s, grid%geoLonT, grid%geoLatT, nxT, nyT, GV%ke, & grid%geoLonBu, grid%geoLatBu, nxB, nyB, & CS%pert_epbl, CS%do_sppt, CS%do_skeb, pe_zero, mom_comm, iret) if (iret/=0) then @@ -183,23 +200,23 @@ subroutine stochastics_init(dt, grid, GV, CS, param_file, diag, Time) CS%id_sppt_wts = register_diag_field('ocean_model', 'sppt_pattern', CS%diag%axesT1, Time, & 'random pattern for sppt', 'None') CS%id_skeb_wts = register_diag_field('ocean_model', 'skeb_pattern', CS%diag%axesB1, Time, & - 'random pattern for skeb', 'None') + 'random pattern for skeb', 'm', conversion=1.0) ! SKEB_wts is set in external code in mks units of [m] CS%id_epbl1_wts = register_diag_field('ocean_model', 'epbl1_wts', CS%diag%axesT1, Time, & 'random pattern for KE generation', 'None') CS%id_epbl2_wts = register_diag_field('ocean_model', 'epbl2_wts', CS%diag%axesT1, Time, & 'random pattern for KE dissipation', 'None') CS%id_skebu = register_diag_field('ocean_model', 'skebu', CS%diag%axesCuL, Time, & - 'zonal current perts', 'None') + 'zonal current perts', 'm s-1', conversion=US%L_T_to_m_s) CS%id_skebv = register_diag_field('ocean_model', 'skebv', CS%diag%axesCvL, Time, & - 'zonal current perts', 'None') + 'zonal current perts', 'm s-1', conversion=US%L_T_to_m_s) CS%id_diss = register_diag_field('ocean_model', 'skeb_amp', CS%diag%axesTL, Time, & - 'SKEB amplitude', 'm s-1') + 'SKEB amplitude', 'm s-1', conversion=US%L_T_to_m_s) CS%id_psi = register_diag_field('ocean_model', 'psi', CS%diag%axesBL, Time, & - 'stream function', 'None') + 'stream function', 'm2 s-1', conversion=US%L_T_to_m_s*US%L_to_m) CS%id_skeb_taperu = register_static_field('ocean_model', 'skeb_taper_u', CS%diag%axesCu1, & - 'SKEB taper u', 'None', interp_method='none') + 'SKEB taper u', 'None', conversion=1.0, interp_method='none') CS%id_skeb_taperv = register_static_field('ocean_model', 'skeb_taper_v', CS%diag%axesCv1, & - 'SKEB taper v', 'None', interp_method='none') + 'SKEB taper v', 'None', conversion=1.0, interp_method='none') ! Initialize the "taper" fields. These fields multiply the components of the stochastic ! velocity increment in such a way as to smoothly taper them to zero at land boundaries. @@ -259,37 +276,45 @@ subroutine update_stochastics(CS) call callTree_enter("update_stochastics(), MOM_stochastics.F90") ! update stochastic physics patterns before running next time-step - call run_stochastic_physics_ocn(CS%sppt_wts,CS%skeb_wts,CS%epbl1_wts,CS%epbl2_wts) + call run_stochastic_physics_ocn(CS%sppt_wts, CS%skeb_wts, CS%epbl1_wts, CS%epbl2_wts) call callTree_leave("update_stochastics(), MOM_stochastics.F90") end subroutine update_stochastics -subroutine apply_skeb(grid,GV,CS,uc,vc,thickness,tv,dt,Time_end) +subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) type(ocean_grid_type), intent(in) :: grid !< ocean grid structure type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type type(stochastic_CS), intent(inout) :: CS !< stochastic control structure - real, dimension(SZIB_(grid),SZJ_(grid),SZK_(GV)), intent(inout) :: uc !< zonal velocity [L T-1 ~> m s-1] real, dimension(SZI_(grid),SZJB_(grid),SZK_(GV)), intent(inout) :: vc !< meridional velocity [L T-1 ~> m s-1] real, dimension(SZI_(grid),SZJ_(grid),SZK_(GV)), intent(in) :: thickness !< thickness [H ~> m or kg m-2] type(thermo_var_ptrs), intent(in) :: tv !< points to thermodynamic fields real, intent(in) :: dt !< time increment [T ~> s] type(time_type), intent(in) :: Time_end !< Time at the end of the interval -! locals - - real, dimension(SZIB_(grid),SZJB_(grid),SZK_(GV)) :: psi !< Streamfunction for stochastic velocity increments - !! [L2 T-1 ~> m2 s-1] - real, dimension(SZIB_(grid),SZJ_(grid) ,SZK_(GV)) :: ustar !< Stochastic u velocity increment [L T-1 ~> m s-1] - real, dimension(SZI_(grid) ,SZJB_(grid),SZK_(GV)) :: vstar !< Stochastic v velocity increment [L T-1 ~> m s-1] - real, dimension(SZI_(grid),SZJ_(grid)) :: diss_tmp !< Temporary array used in smoothing skeb_diss - !! [L2 T-3 ~> m2 s-2] - real, dimension(3,3) :: local_weights !< 3x3 stencil weights used in smoothing skeb_diss - !! [L2 ~> m2] - - real :: shr,ten,tot,kh - integer :: i,j,k,iter + + ! local variables + real, dimension(SZIB_(grid),SZJB_(grid),SZK_(GV)) :: psi !< Streamfunction for stochastic velocity increments + !! [L2 T-1 ~> m2 s-1] + real, dimension(SZIB_(grid),SZJ_(grid) ,SZK_(GV)) :: ustar !< Stochastic u velocity increment [L T-1 ~> m s-1] + real, dimension(SZI_(grid) ,SZJB_(grid),SZK_(GV)) :: vstar !< Stochastic v velocity increment [L T-1 ~> m s-1] + real, dimension(SZI_(grid),SZJ_(grid)) :: diss_tmp !< Temporary array used in smoothing skeb_diss + !! [L2 T-3 ~> m2 s-2] + real, dimension(SZI_(grid),SZJ_(grid)) :: area_wt !< Masked cell areas used in spatial filter [L2 ~> m2] + real, dimension(3,3) :: local_weights !< 3x3 stencil weights used in smoothing skeb_diss + !! [L2 ~> m2] + + real :: shr ! Horizonal shear [T-1 ~> s-1] + real :: ten ! Horizonal tension of the flow [T-1 ~> s-1] + real :: tot ! The magnitude of the combined shear and tension [T-1 ~> s-1] + real :: kh ! A smooothing factor [nondim] + real :: sum_wtd_skeb_diss ! The rotationally symmetric sum of the surrounding values of skeb times + ! the area weights used to filter skeb_diss [L4 T-3 ~> m4 s-3] + real :: sum_area_wts ! A rotationally symmetric sum of the surrounding area weights + ! that are used to filter skeb_diss [L2 ~> m2] + integer :: i, j, k, iter integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state call callTree_enter("apply_skeb(), MOM_stochastics.F90") @@ -302,53 +327,90 @@ subroutine apply_skeb(grid,GV,CS,uc,vc,thickness,tv,dt,Time_end) enddo ; enddo enddo - !kh needs to be scaled + ! kh needs to be scaled + kh = 1.0 !(120*111)**2 + if (CS%answer_date < 20250701) then + do k=1,GV%ke + do j=grid%jsc,grid%jec ; do i=grid%isc,grid%iec + ! Shear in [T-1 ~> s-1] + shr = (vc(i,J,k)-vc(i-1,J,k)) * grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdxCv(i,J) + & + (uc(I,j,k)-uc(I,j-1,k)) * grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdyCu(I,j) + ! Tension in [T-1 ~> s-1] + ten = (vc(i,J,k)-vc(i-1,J,k)) * grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdyCv(i,J) + & + (uc(I,j,k)-uc(I,j-1,k)) * grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdxCu(I,j) + + tot = sqrt( shr**2 + ten**2 ) * grid%mask2dT(i,j) + CS%skeb_diss(i,j,k) = tot**3 * kh * grid%areaT(i,j) !!**2 + enddo ; enddo + enddo + else ! This version has parentheses to preserve rotational symmetry when FMAs are enabled. + do k=1,GV%ke + do j=grid%jsc,grid%jec ; do i=grid%isc,grid%iec + ! Shear in [T-1 ~> s-1] + shr = ((vc(i,J,k)-vc(i-1,J,k)) * grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdxCv(i,J)) + & + ((uc(I,j,k)-uc(I,j-1,k)) * grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdyCu(I,j)) + ! Tension in [T-1 ~> s-1] + ten = ((vc(i,J,k)-vc(i-1,J,k)) * grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdyCv(i,J)) + & + ((uc(I,j,k)-uc(I,j-1,k)) * grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdxCu(I,j)) + + tot = sqrt( shr**2 + ten**2 ) * grid%mask2dT(i,j) + CS%skeb_diss(i,j,k) = tot**3 * kh * grid%areaT(i,j) !!**2 + enddo ; enddo + enddo + endif + endif ! Sets CS%skeb_diss in [L2 T-3 ~> m2 s-3] without GM or FrictWork - kh=1!(120*111)**2 - do k=1,GV%ke - do j=grid%jsc,grid%jec ; do i=grid%isc,grid%iec - ! Shear - shr = (vc(i,J,k)-vc(i-1,J,k))*grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdxCv(i,J)+& - (uc(I,j,k)-uc(I,j-1,k))*grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdyCu(I,j) - ! Tension - ten = (vc(i,J,k)-vc(i-1,J,k))*grid%mask2dCv(i,J)*grid%mask2dCv(i-1,J)*grid%IdyCv(i,J)+& - (uc(I,j,k)-uc(I,j-1,k))*grid%mask2dCu(I,j)*grid%mask2dCu(I,j-1)*grid%IdxCu(I,j) - - tot = sqrt( shr**2 + ten**2 ) * grid%mask2dT(i,j) - CS%skeb_diss(i,j,k) = tot**3 * kh * grid%areaT(i,j)!!**2 - enddo ; enddo - enddo - endif ! Sets CS%skeb_diss without GM or FrictWork + if (CS%skeb_npass >= 1) then + do j=grid%jsc-2,grid%jec+2 ; do i=grid%isc-2,grid%iec+2 + area_wt(i,j) = grid%mask2dT(i,j)*grid%areaT(i,j) + enddo ; enddo + endif ! smooth dissipation skeb_npass times do iter=1,CS%skeb_npass if (mod(iter,2) == 1) call pass_var(CS%skeb_diss, grid%domain) do k=1,GV%ke + if (CS%answer_date < 20250701) then + ! Do the filter with expressions that do not preserve rotational symmetry. + do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 + local_weights(:,:) = area_wt(i-1:i+1,j-1:j+1) + diss_tmp(i,j) = sum(local_weights(:,:)*CS%skeb_diss(i-1:i+1,j-1:j+1,k)) / & + (sum(local_weights) + 1.e-16*US%m_to_L**2) + enddo ; enddo + else + ! This spatial filter preserves rotational symmeetry (including with FMAs), but is + ! mathematically equivalent to the older sum-based form above + do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 + sum_area_wts = area_wt(i,j) + & + (((area_wt(i-1,j) + area_wt(i+1,j)) + (area_wt(i,j-1) + area_wt(i,j+1))) + & + ((area_wt(i-1,j-1) + area_wt(i+1,j+1)) + (area_wt(i-1,j+1) + area_wt(i+1,j-1)))) + sum_wtd_skeb_diss = CS%skeb_diss(i,j,k) * area_wt(i+1,j) + & + ((( (CS%skeb_diss(i-1,j,k) * area_wt(i-1,j)) + (CS%skeb_diss(i+1,j,k) * area_wt(i+1,j)) ) + & + ( (CS%skeb_diss(i,j-1,k) * area_wt(i,j-1)) + (CS%skeb_diss(i,j+1,k) * area_wt(i,j+1)) )) + & + (( (CS%skeb_diss(i-1,j-1,k) * area_wt(i-1,j-1)) + (CS%skeb_diss(i-1,j-1,k) * area_wt(i+1,j+1)) ) + & + ( (CS%skeb_diss(i-1,j+1,k) * area_wt(i-1,j+1)) + (CS%skeb_diss(i+1,j-1,k) * area_wt(i+1,j-1)) ))) + diss_tmp(i,j) = sum_wtd_skeb_diss / (sum_area_wts + 1.e-16*US%m_to_L**2) + enddo ; enddo + endif do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 - ! This does not preserve rotational symmetry - local_weights = grid%mask2dT(i-1:i+1,j-1:j+1)*grid%areaT(i-1:i+1,j-1:j+1) - diss_tmp(i,j) = sum(local_weights*CS%skeb_diss(i-1:i+1,j-1:j+1,k)) / & - (sum(local_weights) + 1.E-16) - enddo ; enddo - do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 - if (grid%mask2dT(i,j)==0.) cycle - CS%skeb_diss(i,j,k) = diss_tmp(i,j) + CS%skeb_diss(i,j,k) = grid%mask2dT(i,j) * diss_tmp(i,j) enddo ; enddo enddo enddo call pass_var(CS%skeb_diss, grid%domain) - ! call hchksum(CS%skeb_diss, "SKEB DISS", grid%HI, haloshift=2) - ! call qchksum(CS%skeb_wts, "SKEB WTS", grid%HI, haloshift=1) + ! call hchksum(CS%skeb_diss, "SKEB DISS", grid%HI, haloshift=2, unscale=US%L_T_to_m_s**2*US%s_to_T) + ! call qchksum(CS%skeb_wts, "SKEB WTS", grid%HI, haloshift=1) ! SKEB_wts comes in from external code in mks units. do k=1,GV%ke do J=grid%jscB-1,grid%jecB ; do I=grid%iscB-1,grid%iecB + ! psi has units of [L2 T-1 ~> m2 s-1] because skeb_wts is in mks units of [m]. psi(I,J,k) = sqrt(0.25 * dt * max((CS%skeb_diss(i ,j ,k) + CS%skeb_diss(i+1,j+1,k)) + & (CS%skeb_diss(i ,j+1,k) + CS%skeb_diss(i+1,j ,k)), 0.) ) & - * CS%skeb_wts(I,J) + * US%m_to_L*CS%skeb_wts(I,J) enddo ; enddo enddo - !call qchksum(psi,"SKEB PSI", grid%HI, haloshift=1) + !call qchksum(psi,"SKEB PSI", grid%HI, haloshift=1, unscale=US%L_T_to_m_s*US%L_to_m) !call pass_var(psi, grid%domain, position=CORNER) do k=1,GV%ke do j=grid%jsc,grid%jec ; do I=grid%iscB,grid%iecB @@ -361,7 +423,7 @@ subroutine apply_skeb(grid,GV,CS,uc,vc,thickness,tv,dt,Time_end) enddo ; enddo enddo - !call uvchksum("SKEB increment [uv]", ustar, vstar, grid%HI) + !call uvchksum("SKEB increment [uv]", ustar, vstar, grid%HI, unscale=US%L_T_to_m_s) call enable_averages(dt, Time_end, CS%diag) if (CS%id_diss > 0) then @@ -393,7 +455,7 @@ end subroutine apply_skeb !! input fields have valid values in the first two halo points upon entry. subroutine smooth_x9_uv(G, field_u, field_v, zero_land) type(ocean_grid_type), intent(in) :: G !< Ocean grid - real, dimension(SZIB_(G),SZJ_(G)), intent(inout) :: field_u !< u-point field to be smoothed[arbitrary] + real, dimension(SZIB_(G),SZJ_(G)), intent(inout) :: field_u !< u-point field to be smoothed [arbitrary] real, dimension(SZI_(G),SZJB_(G)), intent(inout) :: field_v !< v-point field to be smoothed [arbitrary] logical, optional, intent(in) :: zero_land !< If present and false, return the average !! of the surrounding ocean points when From ff7a785b698ec97e17260c99fe9d20c0cdb12c68 Mon Sep 17 00:00:00 2001 From: Robert Hallberg Date: Fri, 25 Jul 2025 12:25:37 -0400 Subject: [PATCH 16/41] +Add post_tracer_integral_diagnostics (#368) Added the new routine post_tracer_integral_diagnostics to calculate vertically integrated tracer diagnostics. This includes properly setting the vertical layer extents from layer thicknesses via a call to thickness_to_dz. This new routine is being called from within step_MOM(), immediately after another closely related call to write out other tracer diagnostics. In so doing, it changes the thicknesses used for these diagnostics to be consistent with the state of the tracers. This commit also sets the appropriate unit conversion factors in the register_diag_field calls for three recently diagnostics of surface tracer concentrations and the integrated tracers amounts in the full water column and in the topmost 100 m. All solutions are bitwise identical, but this will correct the thicknesses used in the calculation of two groups of tracer diagnostics and properly implements the dimensional rescaling of these diagnostics when tracers (like temperature and salinity) when they are being rescaled. --- src/core/MOM.F90 | 3 + src/tracer/MOM_tracer_registry.F90 | 119 +++++++++++++++++++---------- 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index 3856e731cf..06f971a91d 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -139,6 +139,7 @@ module MOM use MOM_tracer_registry, only : tracer_registry_type, register_tracer, tracer_registry_init use MOM_tracer_registry, only : register_tracer_diagnostics, post_tracer_diagnostics_at_sync use MOM_tracer_registry, only : post_tracer_transport_diagnostics, MOM_tracer_chksum +use MOM_tracer_registry, only : post_tracer_integral_diagnostics use MOM_tracer_registry, only : preALE_tracer_diagnostics, postALE_tracer_diagnostics use MOM_tracer_registry, only : lock_tracer_registry, tracer_registry_end use MOM_tracer_flow_control, only : call_tracer_register, tracer_flow_control_CS @@ -1062,6 +1063,8 @@ subroutine step_MOM(forces_in, fluxes_in, sfc_state, Time_start, time_int_in, CS CS%CDp, p_surf, CS%t_dyn_rel_diag, CS%diag_pre_sync,& G, GV, US, CS%diagnostics_CSp) call post_tracer_diagnostics_at_sync(CS%Tracer_reg, h, CS%diag_pre_sync, CS%diag, G, GV, CS%t_dyn_rel_diag) + call post_tracer_integral_diagnostics(G, GV, US, CS%Tracer_reg, h, CS%tv, CS%diag) + call diag_copy_diag_to_storage(CS%diag_pre_sync, h, CS%diag) if (showCallTree) call callTree_waypoint("finished calculate_diagnostic_fields (step_MOM)") call disable_averaging(CS%diag) diff --git a/src/tracer/MOM_tracer_registry.F90 b/src/tracer/MOM_tracer_registry.F90 index 5c78c2c189..c56bcaddb2 100644 --- a/src/tracer/MOM_tracer_registry.F90 +++ b/src/tracer/MOM_tracer_registry.F90 @@ -16,11 +16,13 @@ module MOM_tracer_registry use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_hor_index, only : hor_index_type use MOM_grid, only : ocean_grid_type +use MOM_interface_heights, only : thickness_to_dz use MOM_io, only : vardesc, query_vardesc, cmor_long_std use MOM_restart, only : register_restart_field, MOM_restart_CS use MOM_string_functions, only : lowercase use MOM_time_manager, only : time_type use MOM_unit_scaling, only : unit_scale_type +use MOM_variables, only : thermo_var_ptrs use MOM_verticalGrid, only : verticalGrid_type use MOM_tracer_types, only : tracer_type, tracer_registry_type @@ -32,6 +34,7 @@ module MOM_tracer_registry public MOM_tracer_chksum, MOM_tracer_chkinv public register_tracer_diagnostics public post_tracer_diagnostics_at_sync, post_tracer_transport_diagnostics +public post_tracer_integral_diagnostics public preALE_tracer_diagnostics, postALE_tracer_diagnostics public tracer_registry_init, lock_tracer_registry, tracer_registry_end public tracer_name_lookup @@ -437,13 +440,13 @@ subroutine register_tracer_diagnostics(Reg, h, Time, diag, G, GV, US, use_ALE, u Tr%id_zint = register_diag_field("ocean_model", trim(shortnm)//"_zint", & diag%axesT1, Time, & "Thickness-weighted integral of " // trim(longname), & - trim(units) // " m") + trim(units) // " m", conversion=Tr%conc_scale*US%Z_to_m) Tr%id_zint_100m = register_diag_field("ocean_model", trim(shortnm)//"_zint_100m", & diag%axesT1, Time, & "Thickness-weighted integral of "// trim(longname) // " over top 100m", & - trim(units) // " m") + trim(units) // " m", conversion=Tr%conc_scale*US%Z_to_m) Tr%id_surf = register_diag_field("ocean_model", trim(shortnm)//"_SURF", & - diag%axesT1, Time, "Surface values of "// trim(longname), trim(units)) + diag%axesT1, Time, "Surface values of "// trim(longname), trim(units), conversion=Tr%conc_scale) if (Tr%id_adx > 0) call safe_alloc_ptr(Tr%ad_x,IsdB,IedB,jsd,jed,nz) if (Tr%id_ady > 0) call safe_alloc_ptr(Tr%ad_y,isd,ied,JsdB,JedB,nz) if (Tr%id_adx_resolved > 0) call safe_alloc_ptr(Tr%ad_x_resolved,IsdB,IedB,jsd,jed,nz) @@ -792,45 +795,13 @@ subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) intent(in) :: h_diag !< Layer thicknesses on which to post fields [H ~> m or kg m-2] type(diag_ctrl), intent(in) :: diag !< structure to regulate diagnostic output - integer :: i, j, k, is, ie, js, je, nz, m, khi + integer :: i, j, k, is, ie, js, je, nz, m real :: work2d(SZI_(G),SZJ_(G)) ! The vertically integrated convergence of lateral advective ! tracer fluxes [CU H T-1 ~> conc m s-1 or conc kg m-2 s-1] - real :: frac_under_100m(SZI_(G),SZJ_(G),SZK_(GV)) ! weights used to compute 100m vertical integrals [nondim] - real :: ztop(SZI_(G),SZJ_(G)) ! position of the top interface [H ~> m or kg m-2] - real :: zbot(SZI_(G),SZJ_(G)) ! position of the bottom interface [H ~> m or kg m-2] type(tracer_type), pointer :: Tr=>NULL() is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke - ! If any tracers are posting 100m vertical integrals, compute weights - frac_under_100m(:,:,:) = 0.0 - ! khi will be the largest layer index corresponding where ztop < 100m and ztop >= 100m - ! in any column (we can reduce computation of 100m integrals by only looping through khi - ! rather than GV%ke) - khi = 0 - do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then - Tr => Reg%Tr(m) - if (Tr%id_zint_100m > 0) then - zbot(:,:) = 0.0 - do k=1, nz - do j=js,je ; do i=is,ie - ztop(i,j) = zbot(i,j) - zbot(i,j) = ztop(i,j) + h_diag(i,j,k)*GV%H_to_m - if (zbot(i,j) <= 100.0) then - frac_under_100m(i,j,k) = 1.0 - elseif (ztop(i,j) < 100.0) then - frac_under_100m(i,j,k) = (100.0 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)) - else - frac_under_100m(i,j,k) = 0.0 - endif - ! frac_under_100m(i,j,k) = max(0, min(1.0, (100.0 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)))) - enddo ; enddo - if (any(frac_under_100m(:,:,k) > 0)) khi = k - enddo - exit - endif - endif; enddo - do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then Tr => Reg%Tr(m) if (Tr%id_tr_post_horzn> 0) call post_data(Tr%id_tr_post_horzn, Tr%t, diag) @@ -854,13 +825,83 @@ subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) enddo ; enddo ; enddo call post_data(Tr%id_adv_xy_2d, work2d, diag) endif + endif ; enddo +end subroutine post_tracer_transport_diagnostics + +!> Post diagnostics of vertically integrated tracer amouints +subroutine post_tracer_integral_diagnostics(G, GV, US, Reg, h_diag, tv, diag) + type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure + type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type + type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry + real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & + intent(in) :: h_diag !< Layer thicknesses on which to post fields [H ~> m or kg m-2] + type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various + !! thermodynamic variables. + type(diag_ctrl), intent(in) :: diag !< structure to regulate diagnostic output + + integer :: i, j, k, is, ie, js, je, nz, m, khi + real :: work2d(SZI_(G),SZJ_(G)) ! The vertically integrated tracer amounts [CU Z T-1 ~> conc m] + real :: dz(SZI_(G),SZJ_(G),SZK_(GV)) !< Geometric layer thicknesses in height units [Z ~> m] + real :: frac_under_100m(SZI_(G),SZJ_(G),SZK_(GV)) ! weights used to compute 100m vertical integrals [nondim] + real :: ztop(SZI_(G),SZJ_(G)) ! position of the top interface [Z ~> m] + real :: zbot(SZI_(G),SZJ_(G)) ! position of the bottom interface [Z ~> m] + real :: Z_100 ! 100 m in depth units [Z ~> m] + logical :: dz_needed, dz100_used + type(tracer_type), pointer :: Tr=>NULL() + + is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke + + dz_needed = .false. + dz100_used = .false. + do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then + if (Reg%Tr(m)%id_zint_100m > 0) dz100_used = .true. + if (Reg%Tr(m)%id_zint > 0) dz_needed = .true. + endif ; enddo + if (dz100_used) dz_needed = .true. + + if (dz_needed) then + ! Convert the layer thicknesses into geometric depths, using the pre-stored layer-mean specific + ! volumes when in non-Boussinesq mode. + call thickness_to_dz(h_diag, tv, dz, G, GV, US) + endif + + if (dz100_used) then + ! If any tracers are posting 100m vertical integrals, compute weights + frac_under_100m(:,:,:) = 0.0 + ! khi will be the largest layer index corresponding where ztop < 100m and ztop >= 100m + ! in any column (we can reduce computation of 100m integrals by only looping through khi + ! rather than GV%ke) + khi = 0 + + Z_100 = 100.0*US%m_to_Z + zbot(:,:) = 0.0 + do k=1,nz + do j=js,je ; do i=is,ie + ztop(i,j) = zbot(i,j) + zbot(i,j) = ztop(i,j) + dz(i,j,k) + if (zbot(i,j) <= Z_100) then + frac_under_100m(i,j,k) = 1.0 + elseif (ztop(i,j) < Z_100) then + frac_under_100m(i,j,k) = (Z_100 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)) + else + frac_under_100m(i,j,k) = 0.0 + endif + ! frac_under_100m(i,j,k) = max(0, min(1.0, (Z_100 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)))) + enddo ; enddo + if (any(frac_under_100m(:,:,k) > 0)) khi = k + enddo + endif + + do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then + Tr => Reg%Tr(m) ! A few diagnostics introduce with MARBL driver ! Compute full-depth vertical integral if (Tr%id_zint > 0) then work2d(:,:) = 0.0 do k=1,nz ; do j=js,je ; do i=is,ie - work2d(i,j) = work2d(i,j) + (h_diag(i,j,k)*GV%H_to_m)*tr%t(i,j,k) + work2d(i,j) = work2d(i,j) + dz(i,j,k)*tr%t(i,j,k) enddo ; enddo ; enddo call post_data(Tr%id_zint, work2d, diag) endif @@ -869,7 +910,7 @@ subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) if (Tr%id_zint_100m > 0) then work2d(:,:) = 0.0 do k=1,khi ; do j=js,je ; do i=is,ie - work2d(i,j) = work2d(i,j) + frac_under_100m(i,j,k)*((h_diag(i,j,k)*GV%H_to_m)*tr%t(i,j,k)) + work2d(i,j) = work2d(i,j) + frac_under_100m(i,j,k) * dz(i,j,k)*Tr%t(i,j,k) enddo ; enddo ; enddo call post_data(Tr%id_zint_100m, work2d, diag) endif @@ -878,7 +919,7 @@ subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) if (Tr%id_SURF > 0) call post_data(Tr%id_SURF, Tr%t(:,:,1), diag) endif ; enddo -end subroutine post_tracer_transport_diagnostics +end subroutine post_tracer_integral_diagnostics !> This subroutine writes out chksums for the first ntr registered tracers. subroutine tracer_array_chksum(mesg, Tr, ntr, G) From 02d316332a7e4a632310a88e32e914ee825d71cb Mon Sep 17 00:00:00 2001 From: Paul Hall <45795415+phall-brown@users.noreply.github.com> Date: Mon, 4 Aug 2025 11:08:44 -0700 Subject: [PATCH 17/41] Removed portion of conditional statement that prevent calculation of La_SL if lamult was present (#375) --- src/parameterizations/vertical/MOM_CVMix_KPP.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index 8e42694b36..70b3adabf7 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -1294,7 +1294,7 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl enddo ! k-loop finishes - if ( (CS%LT_K_ENHANCEMENT .or. CS%LT_VT2_ENHANCEMENT) .and. .not. present(lamult)) then + if ( (CS%LT_K_ENHANCEMENT .or. CS%LT_VT2_ENHANCEMENT)) then MLD_guess = max( CS%MLD_guess_min, abs(CS%OBLdepthprev(i,j) ) ) call get_Langmuir_Number(LA, G, GV, US, MLD_guess, uStar(i,j), i, j, & dz=dz(i,j,:), U_H=U_H, V_H=V_H, WAVES=WAVES) From 7e3e27b42b3ceb6dd9c80e36dbd24acce6ef4813 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Fri, 8 Aug 2025 14:18:58 -0600 Subject: [PATCH 18/41] Initialize arrays (#377) --- .../vertical/MOM_vert_friction.F90 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/parameterizations/vertical/MOM_vert_friction.F90 b/src/parameterizations/vertical/MOM_vert_friction.F90 index d3c0099d20..985215c9d3 100644 --- a/src/parameterizations/vertical/MOM_vert_friction.F90 +++ b/src/parameterizations/vertical/MOM_vert_friction.F90 @@ -257,6 +257,13 @@ subroutine vertFPmix(ui, vi, uold, vold, hbl_h, h, forces, dt, lpost, Cemp_NL, G pi = 4. * atan2(1.,1.) Irho0 = 1.0 / GV%Rho0 + ! initialize arrays + uE_h(:,:,:) = 0.0 + vE_h(:,:,:) = 0.0 + uE_u(:,:,:) = 0.0 + vE_v(:,:,:) = 0.0 + vInc_v(:,:,:) = 0.0 + uInc_u(:,:,:) = 0.0 call pass_var(hbl_h , G%Domain, halo=1) ! u-points @@ -350,20 +357,20 @@ subroutine vertFPmix(ui, vi, uold, vold, hbl_h, h, forces, dt, lpost, Cemp_NL, G vInc_h(i,j,k) = (G%mask2dCv(i,j) * vInc_v(i,j,k) + G%mask2dCv(i,j-1) * vInc_v(i,j-1,k)) / tmp_v enddo ! Wind, Stress and Shear align at surface - Omega_tau2w(i,j,1) = 0.0 - Omega_tau2s(i,j,1) = 0.0 + Omega_tau2w(i,j,:) = 0.0 + Omega_tau2s(i,j,:) = 0.0 do k = 1,nz kp1 = min( nz , k+1) du = uE_h(i,j,k) - uE_h(i,j,kp1) dv = vE_h(i,j,k) - vE_h(i,j,kp1) - omega_s2x = atan2( dv , du ) + omega_s2x = atan2(dv, du) du = du + uInc_h(i,j,k) - uInc_h(i,j,kp1) dv = dv + vInc_h(i,j,k) - vInc_h(i,j,kp1) - omega_tau2x = atan2( dv , du ) - + omega_tau2x = atan2(dv, du) omega_tmp = omega_tau2x - forces%omega_w2x(i,j) - if ( (omega_tmp > pi ) ) omega_tmp = omega_tmp - 2.*pi + + if ( (omega_tmp > pi ) ) omega_tmp = omega_tmp - 2.*pi if ( (omega_tmp < (0.-pi)) ) omega_tmp = omega_tmp + 2.*pi Omega_tau2w(i,j,kp1) = omega_tmp From 580279415988a4e57ae48add0dba1dec11433006 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Mon, 25 Aug 2025 18:43:52 -0600 Subject: [PATCH 19/41] Use SST and SSS consistent with MARBL tracers (#374) * Use prediabatic SST and SSS for MARBL surface flux The existing MARBL driver uses T & S from the end of the diabatic routine as inputs into surface_flux_compute() and interior_tendency_compute(). For surface_flux_compute(), there is a discrepancy because we have not yet called tracer_vertdiff for the MARBL tracers but have for T & S. To enforce consistency among all the tracers, we want to use the pre-vertdiff T&S quantities. There is a little bit of infrastructure change -- I added 3D fields for T & S at the beginning of the diabatic subroutine to the diabatic control structure (we will eventually want to call interior_tendency_compute() before tracer_vertdiff as well), and then had to add a routine to MOM_tracer_flow_control.F90 to extract use_MARBL_tracers from the tracer flow control structure. prediabatic_T and prediabatic_S are now optional arguments to call_tracer_column_fns(), but that function will abort if USE_MARBL_TRACERS is true and the arguments are not present because they are required in MARBL_tracers_column_physics() * Clean up comments Fix failing doxygen / style check texts. Also add a long comment to diabatic_ALE explaining why we use prediabatic_T and prediabatic_S (maybe the comment belongs in diabatic_init?) * Use prediabatic T & S for MARBL interior tendency Reordered MARBL_tracers_column_physics so that surface_flux_compute() and interior_tendency_compute() are both called before tracer_vertdiff. Now use prediabatic T & S for interior tendency computation, and also use h_old as dz. Note that this greatly increases the number of warnings from the co2calc routine, and we are not sure why. * Clean up following code review 1. removed spaces from "end if" to match style guide recommendations 2. cleaned up comment in extract_tracer_flow_member (refer to tracer_flow_control_CS rather than diabatic_CS) 3. Consistent capitalization of MARBL in use_MARBL_tracers (and use_MARBL) throughout the codebase --- .../nuopc_cap/mom_ocean_model_nuopc.F90 | 2 +- .../nuopc_cap/mom_surface_forcing_nuopc.F90 | 10 +- .../solo_driver/MOM_surface_forcing.F90 | 10 +- src/core/MOM_forcing_type.F90 | 2 +- src/core/MOM_variables.F90 | 6 +- .../vertical/MOM_diabatic_driver.F90 | 56 ++- src/tracer/MARBL_forcing_mod.F90 | 14 +- src/tracer/MARBL_tracers.F90 | 346 +++++++++--------- src/tracer/MOM_tracer_flow_control.F90 | 42 ++- 9 files changed, 277 insertions(+), 211 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index a83576028a..c29bbc1e4d 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -387,7 +387,7 @@ subroutine ocean_model_init(Ocean_sfc, OS, Time_init, Time_in, gas_fields_ocn, i ! vertical integrals, since the related 3-d sums are not negligible in cost. call allocate_surface_state(OS%sfc_state, OS%grid, use_temperature, & do_integrals=.true., gas_fields_ocn=gas_fields_ocn, & - use_meltpot=use_melt_pot, use_marbl_tracers=OS%use_MARBL) + use_meltpot=use_melt_pot, use_MARBL_tracers=OS%use_MARBL) call surface_forcing_init(Time_in, OS%grid, OS%US, param_file, OS%diag, & OS%forcing_CSp, OS%restore_salinity, OS%restore_temp, OS%use_waves) diff --git a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 index 11f12a0038..a32987e6a2 100644 --- a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 @@ -81,7 +81,7 @@ module MOM_surface_forcing_nuopc !! pressure limited by max_p_surf instead of the !! full atmospheric pressure. The default is true. logical :: use_CFC !< enables the MOM_CFC_cap tracer package. - logical :: use_marbl_tracers !< enables the MARBL tracer package. + logical :: use_MARBL_tracers !< enables the MARBL tracer package. logical :: enthalpy_cpl !< Controls if enthalpy terms are provided by the coupler or computed !! internally. real :: gust_const !< constant unresolved background gustiness for ustar [R L Z T-2 ~> Pa] @@ -326,7 +326,7 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, if (fluxes%dt_buoy_accum < 0) then call allocate_forcing_type(G, fluxes, water=.true., heat=.true., ustar=.true., & press=.true., fix_accum_bug=.not.CS%ustar_gustless_bug, & - cfc=CS%use_CFC, marbl=CS%use_marbl_tracers, hevap=CS%enthalpy_cpl, & + cfc=CS%use_CFC, marbl=CS%use_MARBL_tracers, hevap=CS%enthalpy_cpl, & tau_mag=.true., ice_ncat=IOB%ice_ncat) call safe_alloc_ptr(fluxes%omega_w2x,isd,ied,jsd,jed) call safe_alloc_ptr(fluxes%sw_vis_dir,isd,ied,jsd,jed) @@ -615,7 +615,7 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, ! Copy MARBL-specific IOB fields into fluxes; also set some MARBL-specific forcings to other values ! (constants, values from netCDF, etc) - if (CS%use_marbl_tracers) & + if (CS%use_MARBL_tracers) & call convert_driver_fields_to_forcings(IOB%atm_fine_dust_flux, IOB%atm_coarse_dust_flux, & IOB%seaice_dust_flux, IOB%atm_bc_flux, IOB%seaice_bc_flux, & IOB%nhx_dep, IOB%noy_dep, IOB%atm_co2_prog, IOB%atm_co2_diag, & @@ -1272,7 +1272,7 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, restore_salt, call get_param(param_file, mdl, "USE_CFC_CAP", CS%use_CFC, & default=.false., do_not_log=.true.) - call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_marbl_tracers, & + call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_MARBL_tracers, & default=.false., do_not_log=.true.) call get_param(param_file, mdl, "ENTHALPY_FROM_COUPLER", CS%enthalpy_cpl, & @@ -1483,7 +1483,7 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, restore_salt, endif ! Set up MARBL forcing control structure - call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, & + call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_MARBL_tracers, & CS%marbl_forcing_CSp) if (present(restore_salt)) then ; if (restore_salt) then diff --git a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 index faa94c3bdd..36badbedb0 100644 --- a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 +++ b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 @@ -116,7 +116,7 @@ module MOM_surface_forcing !! rotationally invariant and more likely to be the same between compilers. logical :: ustar_gustless_bug !< If true, include a bug in the time-averaging of the !! gustless wind friction velocity. - logical :: use_marbl_tracers !< If true, allocate memory for forcing needed by MARBL + logical :: use_MARBL_tracers !< If true, allocate memory for forcing needed by MARBL ! if WIND_CONFIG=='scurves' then use the following to define a piecewise scurve profile real :: scurves_ydata(20) = 90. !< Latitudes of scurve nodes [degreesN] real :: scurves_taux(20) = 0. !< Zonal wind stress values at scurve nodes [R L Z T-2 ~> Pa] @@ -287,7 +287,7 @@ subroutine set_forcing(sfc_state, forces, fluxes, day_start, day_interval, G, US ! Allocate memory for the mechanical and thermodynamic forcing fields. call allocate_mech_forcing(G, forces, stress=.true., ustar=.not.CS%nonBous, press=.true., tau_mag=CS%nonBous) - call allocate_forcing_type(G, fluxes, ustar=.not.CS%nonBous, marbl=CS%use_marbl_tracers, tau_mag=CS%nonBous, & + call allocate_forcing_type(G, fluxes, ustar=.not.CS%nonBous, marbl=CS%use_MARBL_tracers, tau_mag=CS%nonBous, & fix_accum_bug=.not.CS%ustar_gustless_bug) if (trim(CS%buoy_config) /= "NONE") then if ( CS%use_temperature ) then @@ -384,7 +384,7 @@ subroutine set_forcing(sfc_state, forces, fluxes, day_start, day_interval, G, US endif endif - if (CS%use_marbl_tracers) then + if (CS%use_MARBL_tracers) then call MARBL_forcing_from_data_override(fluxes, day_center, G, US, CS) endif @@ -2148,7 +2148,7 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, tracer_flow_C call read_netCDF_data(filename, 'gustiness', CS%gust, G%Domain, & rescale=US%Pa_to_RLZ_T2*US%L_to_Z) ! units in file should be [Pa] endif - call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_marbl_tracers, & + call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_MARBL_tracers, & default=.false., do_not_log=.true.) ! All parameter settings are now known. @@ -2181,7 +2181,7 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, tracer_flow_C endif ! Set up MARBL forcing control structure - call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, & + call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_MARBL_tracers, & CS%marbl_forcing_CSp) call register_forcing_type_diags(Time, diag, US, CS%use_temperature, CS%handles) diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index f51ec928b6..1ceaa3988f 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -3526,7 +3526,7 @@ subroutine allocate_forcing_by_group(G, fluxes, water, heat, ustar, press, & if (present(fix_accum_bug)) fluxes%gustless_accum_bug = .not.fix_accum_bug - !These fields should only be allocated when USE_MARBL is activated. + !These fields should only be allocated when USE_MARBL_TRACERS is activated. call myAlloc(fluxes%ice_fraction,isd,ied,jsd,jed, marbl) call myAlloc(fluxes%u10_sqr,isd,ied,jsd,jed, marbl) call myAlloc(fluxes%noy_dep,isd,ied,jsd,jed, marbl) diff --git a/src/core/MOM_variables.F90 b/src/core/MOM_variables.F90 index c6483f8cef..cbb8019aa0 100644 --- a/src/core/MOM_variables.F90 +++ b/src/core/MOM_variables.F90 @@ -365,7 +365,7 @@ module MOM_variables !! the ocean model. Unused fields are unallocated. subroutine allocate_surface_state(sfc_state, G, use_temperature, do_integrals, & gas_fields_ocn, use_meltpot, use_iceshelves, & - omit_frazil, sfc_state_in, turns, use_marbl_tracers) + omit_frazil, sfc_state_in, turns, use_MARBL_tracers) type(ocean_grid_type), intent(in) :: G !< ocean grid structure type(surface), intent(inout) :: sfc_state !< ocean surface state type to be allocated. logical, optional, intent(in) :: use_temperature !< If true, allocate the space for thermodynamic variables. @@ -391,7 +391,7 @@ subroutine allocate_surface_state(sfc_state, G, use_temperature, do_integrals, & !! is present, it is used and tr_fields_in is ignored. integer, optional, intent(in) :: turns !< If present, the number of counterclockwise quarter !! turns to use on the new grid. - logical, optional, intent(in) :: use_marbl_tracers !< If true, allocate the space for CO2 flux from MARBL + logical, optional, intent(in) :: use_MARBL_tracers !< If true, allocate the space for CO2 flux from MARBL ! local variables logical :: use_temp, alloc_integ, use_melt_potential, alloc_iceshelves, alloc_frazil, alloc_fco2 @@ -409,7 +409,7 @@ subroutine allocate_surface_state(sfc_state, G, use_temperature, do_integrals, & use_melt_potential = .false. ; if (present(use_meltpot)) use_melt_potential = use_meltpot alloc_iceshelves = .false. ; if (present(use_iceshelves)) alloc_iceshelves = use_iceshelves alloc_frazil = .true. ; if (present(omit_frazil)) alloc_frazil = .not.omit_frazil - alloc_fco2 = .false. ; if (present(use_marbl_tracers)) alloc_fco2 = use_marbl_tracers + alloc_fco2 = .false. ; if (present(use_MARBL_tracers)) alloc_fco2 = use_MARBL_tracers if (sfc_state%arrays_allocated) return diff --git a/src/parameterizations/vertical/MOM_diabatic_driver.F90 b/src/parameterizations/vertical/MOM_diabatic_driver.F90 index 41520dabf2..0089d17cbf 100644 --- a/src/parameterizations/vertical/MOM_diabatic_driver.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_driver.F90 @@ -67,7 +67,7 @@ module MOM_diabatic_driver use MOM_sponge, only : apply_sponge, sponge_CS use MOM_ALE_sponge, only : apply_ALE_sponge, ALE_sponge_CS use MOM_time_manager, only : time_type, real_to_time, operator(-), operator(<=) -use MOM_tracer_flow_control, only : call_tracer_column_fns, tracer_flow_control_CS +use MOM_tracer_flow_control, only : call_tracer_column_fns, tracer_flow_control_CS, extract_tracer_flow_member use MOM_tracer_diabatic, only : tracer_vertdiff, tracer_vertdiff_Eulerian use MOM_unit_scaling, only : unit_scale_type use MOM_variables, only : thermo_var_ptrs, vertvisc_type, accel_diag_ptrs @@ -186,6 +186,10 @@ module MOM_diabatic_driver logical :: Use_KdWork_diag = .false. !< Logical flag to indicate if any Kd_work diagnostics are on. logical :: Use_N2_diag = .false. !< Logical flag to indicate if any N2 diagnostics are on. + ! MARBL needs T & S from before the tracer_vertdiff call + real, allocatable, dimension(:,:,:) :: prediabatic_T !< Temperature prior to calling diabatic driver [C ~> degC] + real, allocatable, dimension(:,:,:) :: prediabatic_S !< Salinity prior to calling diabatic driver [S ~> ppt] + !>@{ Diagnostic IDs integer :: id_ea = -1, id_eb = -1 ! used by layer diabatic integer :: id_ea_t = -1, id_eb_t = -1, id_ea_s = -1, id_eb_s = -1 @@ -647,6 +651,22 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Tim showCallTree = callTree_showQuery() if (showCallTree) call callTree_enter("diabatic_ALE_legacy(), MOM_diabatic_driver.F90") + ! Some tracer packages require T & S from the beginning of the diabatic step to + ! provide forcing consistent with the passive tracer values. The initialization + ! routine will allocate prediabatic_T and prediabatic_S if the tracer flow control + ! structure indicates it is necessary. If these arrays are allocated, they will store + ! a copy of tv%T & tv%S before this subroutine modifies the tv structure. + if (allocated(CS%prediabatic_T)) then + do k=1,nz ; do j=js,je ; do i=is,ie + CS%prediabatic_T(i,j,k) = tv%T(i,j,k) + enddo ; enddo ; enddo + endif + if (allocated(CS%prediabatic_S)) then + do k=1,nz ; do j=js,je ; do i=is,ie + CS%prediabatic_S(i,j,k) = tv%S(i,j,k) + enddo ; enddo ; enddo + endif + ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep call enable_averages(dt, Time_end, CS%diag) @@ -1202,7 +1222,8 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Tim KPP_CSp=CS%KPP_CSp, & nonLocalTrans=KPP_NLTscalar, & evap_CFL_limit=CS%evap_CFL_limit, & - minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML) + minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML, & + prediabatic_T=CS%prediabatic_T, prediabatic_S=CS%prediabatic_S) call cpu_clock_end(id_clock_tracers) @@ -1363,6 +1384,22 @@ subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, if (.not. (CS%useALEalgorithm)) call MOM_error(FATAL, "MOM_diabatic_driver: "// & "The ALE algorithm must be enabled when using MOM_diabatic_driver.") + ! Some tracer packages require T & S from the beginning of the diabatic step to + ! provide forcing consistent with the passive tracer values. The initialization + ! routine will allocate prediabatic_T and prediabatic_S if the tracer flow control + ! structure indicates it is necessary. If these arrays are allocated, they will store + ! a copy of tv%T & tv%S before this subroutine modifies the tv structure. + if (allocated(CS%prediabatic_T)) then + do k=1,nz ; do j=js,je ; do i=is,ie + CS%prediabatic_T(i,j,k) = tv%T(i,j,k) + enddo ; enddo ; enddo + endif + if (allocated(CS%prediabatic_S)) then + do k=1,nz ; do j=js,je ; do i=is,ie + CS%prediabatic_S(i,j,k) = tv%S(i,j,k) + enddo ; enddo ; enddo + endif + ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep call enable_averages(dt, Time_end, CS%diag) @@ -1829,7 +1866,8 @@ subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, KPP_CSp=CS%KPP_CSp, & nonLocalTrans=KPP_NLTscalar, & evap_CFL_limit=CS%evap_CFL_limit, & - minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML) + minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML, & + prediabatic_T=CS%prediabatic_T, prediabatic_S=CS%prediabatic_S) call cpu_clock_end(id_clock_tracers) @@ -3234,7 +3272,7 @@ subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, di ! Local variables real :: Kd ! A diffusivity used in the default for other tracer diffusivities [Z2 T-1 ~> m2 s-1] - logical :: use_temperature + logical :: use_temperature, use_MARBL_tracers character(len=20) :: EN1, EN2, EN3 ! This "include" declares and sets the variable "version". @@ -3253,7 +3291,12 @@ subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, di CS%diag => diag CS%Time => Time - if (associated(tracer_flow_CSp)) CS%tracer_flow_CSp => tracer_flow_CSp + if (associated(tracer_flow_CSp)) then + CS%tracer_flow_CSp => tracer_flow_CSp + call extract_tracer_flow_member(tracer_flow_CSp, use_MARBL_tracers=use_MARBL_tracers) + if (use_MARBL_tracers) & + allocate(CS%prediabatic_T(SZI_(G),SZJ_(G), SZK_(G)), CS%prediabatic_S(SZI_(G),SZJ_(G), SZK_(G))) + end if if (associated(sponge_CSp)) CS%sponge_CSp => sponge_CSp if (associated(ALE_sponge_CSp)) CS%ALE_sponge_CSp => ALE_sponge_CSp if (associated(oda_incupd_CSp)) CS%oda_incupd_CSp => oda_incupd_CSp @@ -3875,6 +3918,9 @@ subroutine diabatic_driver_end(CS) deallocate(CS%optics) endif + if (allocated(CS%prediabatic_T)) deallocate(CS%prediabatic_T) + if (allocated(CS%prediabatic_S)) deallocate(CS%prediabatic_S) + if (CS%debug_energy_req) & call diapyc_energy_req_end(CS%diapyc_en_rec_CSp) diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index 2705bc1d66..0454c3b061 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -55,7 +55,7 @@ module MARBL_forcing_mod type(marbl_forcing_diag_ids) :: diag_ids !< used for registering and posting some MARBL forcing fields as diagnostics - logical :: use_marbl_tracers !< most functions can return immediately + logical :: use_MARBL_tracers !< most functions can return immediately !! MARBL tracers are turned off integer :: atm_co2_iopt !< Integer version of atm_co2_opt, which determines source of atm_co2 integer :: atm_alt_co2_iopt !< Integer version of atm_alt_co2_opt, which determines source of atm_alt_co2 @@ -69,14 +69,14 @@ module MARBL_forcing_mod contains - subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_marbl, CS) + subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_MARBL_tracers, CS) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters type(diag_ctrl), target, intent(in) :: diag !< Structure used to regulate diagnostic output. type(time_type), target, intent(in) :: day !< Time of the start of the run. character(len=*), intent(in) :: inputdir !< Directory containing input files - logical, intent(in) :: use_marbl !< Is MARBL tracer package active? + logical, intent(in) :: use_MARBL_tracers !< Is MARBL tracer package active? type(marbl_forcing_CS), pointer, intent(inout) :: CS !< A pointer that is set to point to control !! structure for MARBL forcing @@ -92,9 +92,9 @@ subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_marbl, allocate(CS) CS%diag => diag - CS%use_marbl_tracers = .true. - if (.not. use_marbl) then - CS%use_marbl_tracers = .false. + CS%use_MARBL_tracers = .true. + if (.not. use_MARBL_tracers) then + CS%use_MARBL_tracers = .false. return endif @@ -229,7 +229,7 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust real :: ndep_conversion !< Factor to convert nitrogen deposition from kg m-2 s-1 -> mmol m-3 (m s-1) !! [s m2 kg-1 conc Z T-1 ~> mmol kg-1] - if (.not. CS%use_marbl_tracers) return + if (.not. CS%use_MARBL_tracers) return is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ndep_conversion = (1.e6/14.) * (US%m_to_Z * US%T_to_s) diff --git a/src/tracer/MARBL_tracers.F90 b/src/tracer/MARBL_tracers.F90 index 847a174d36..db7edbfa39 100644 --- a/src/tracer/MARBL_tracers.F90 +++ b/src/tracer/MARBL_tracers.F90 @@ -34,7 +34,7 @@ module MARBL_tracers use MOM_tracer_initialization_from_Z, only : MOM_initialize_tracer_from_Z 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 +use MOM_variables, only : surface use MOM_verticalGrid, only : verticalGrid_type use MOM_diag_mediator, only : register_diag_field, post_data!, safe_alloc_ptr @@ -1270,15 +1270,13 @@ end subroutine setup_saved_state !> This subroutine applies diapycnal diffusion and any other column !! tracer physics or chemistry to the tracers from this file. -subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, US, CS, tv, & - KPP_CSp, nonLocalTrans, evap_CFL_limit, minimum_forcing_depth) +subroutine MARBL_tracers_column_physics(h_old, ea, eb, fluxes, dt, G, GV, US, CS, & + prediabatic_T, prediabatic_S, KPP_CSp, nonLocalTrans, evap_CFL_limit, minimum_forcing_depth) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure real, dimension(SZI_(G),SZJ_(G),SZK_(G)), & intent(in) :: h_old !< Layer thickness before entrainment [H ~> m or kg m-2]. - real, dimension(SZI_(G),SZJ_(G),SZK_(G)), & - intent(in) :: h_new !< Layer thickness after entrainment [H ~> m or kg m-2]. real, dimension(SZI_(G),SZJ_(G),SZK_(G)), & intent(in) :: ea !< an array to which the amount of fluid entrained !! from the layer above during this call will be @@ -1293,7 +1291,9 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type type(MARBL_tracers_CS), pointer :: CS !< The control structure returned by a previous !! call to register_MARBL_tracers. - type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various thermodynamic variables + real, dimension(:,:,:), intent(in) :: prediabatic_T !< Temperature prior to calling diabatic driver [C ~> degC] + real, dimension(:,:,:), intent(in) :: prediabatic_S !< Salinity prior to calling diabatic driver [S ~> ppt] + type(KPP_CS), optional, pointer :: KPP_CSp !< KPP control structure real, optional, intent(in) :: nonLocalTrans(:,:,:) !< Non-local transport [1] real, optional, intent(in) :: evap_CFL_limit !< Limit on the fraction of the water that can @@ -1322,11 +1322,13 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, if (.not.associated(CS)) return - ! (1) Compute surface fluxes + ! (1) Compute surface fluxes and interior tendencies ! FIXME: MARBL can handle computing surface fluxes for all columns simultaneously ! I was just thinking going column-by-column at first might be easier + bot_flux_to_tend(:, :, :) = 0. do j=js,je do i=is,ie + ! Surface fluxes ! i. only want ocean points in this loop if (G%mask2dT(i,j) == 0) cycle @@ -1336,9 +1338,9 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, ! TODO: if top layer is vanishly thin, do we actually want (e.g.) top 5m average temp / salinity? ! How does MOM pass SST and SSS to GFDL coupler? (look in core.F90?) if (CS%sss_ind > 0) & - MARBL_instances%surface_flux_forcings(CS%sss_ind)%field_0d(1) = tv%S(i,j,1) * US%S_to_ppt + MARBL_instances%surface_flux_forcings(CS%sss_ind)%field_0d(1) = prediabatic_S(i,j,1) * US%S_to_ppt if (CS%sst_ind > 0) & - MARBL_instances%surface_flux_forcings(CS%sst_ind)%field_0d(1) = tv%T(i,j,1) * US%C_to_degC + MARBL_instances%surface_flux_forcings(CS%sst_ind)%field_0d(1) = prediabatic_T(i,j,1) * US%C_to_degC if (CS%ifrac_ind > 0) & MARBL_instances%surface_flux_forcings(CS%ifrac_ind)%field_0d(1) = fluxes%ice_fraction(i,j) @@ -1404,7 +1406,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, call MARBL_instances%StatusLog%log_error_trace("MARBL_instances%surface_flux_compute()", & "MARBL_tracers_column_physics") endif - call print_marbl_log(MARBL_instances%StatusLog) + call print_marbl_log(MARBL_instances%StatusLog, G, i, j) call MARBL_instances%StatusLog%erase() ! iv. Copy output that MOM6 needs to hold on to @@ -1430,158 +1432,15 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS%SFO(i,j,m) = MARBL_instances%surface_flux_output%outputs_for_GCM(m)%forcing_field_0d(1) enddo - enddo - enddo - - if (associated(fluxes%salt_flux)) then - ! convert salt flux to tracer fluxes and add to STF - do j=js,je ; do i=is,ie - net_salt_rate(i,j) = (1000.0*US%ppt_to_S * fluxes%salt_flux(i,j)) * GV%RZ_to_H - enddo ; enddo - - ! DIC related tracers - do j=js,je ; do i=is,ie - flux_from_salt_flux(i,j) = (CS%DIC_salt_ratio * GV%H_to_Z) * net_salt_rate(i,j) - enddo ; enddo - m = CS%tracer_inds%dic_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - m = CS%tracer_inds%dic_alt_co2_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - m = CS%tracer_inds%abio_dic_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - m = CS%tracer_inds%abio_di14c_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - - ! ALK related tracers - do j=js,je ; do i=is,ie - flux_from_salt_flux(i,j) = (CS%ALK_salt_ratio * GV%H_to_Z) * net_salt_rate(i,j) - enddo ; enddo - m = CS%tracer_inds%alk_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - m = CS%tracer_inds%alk_alt_co2_ind - if (m > 0) then - do j=js,je ; do i=is,ie - CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) - enddo ; enddo - if (CS%id_surface_flux_from_salt_flux(m) > 0) & - call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) - endif - endif - - if (CS%debug) then - do m=1,CS%ntr - call hchksum(CS%STF(:,:,m), & - trim(MARBL_instances%tracer_metadata(m)%short_name)//" sfc_flux", G%HI, & - unscale=US%Z_to_m*US%s_to_T) - enddo - endif - - ! (2) Post surface fluxes and their diagnostics (currently all 2D) - do m=1,CS%ntr - if (CS%id_surface_flux_out(m) > 0) & - call post_data(CS%id_surface_flux_out(m), CS%STF(:,:,m), CS%diag) - enddo - do m=1,size(CS%surface_flux_diags) - if (CS%surface_flux_diags(m)%id > 0) & - call post_data(CS%surface_flux_diags(m)%id, CS%surface_flux_diags(m)%field_2d(:,:), CS%diag) - enddo - - ! (3) Apply surface fluxes via vertical diffusion - ! Compute KPP nonlocal term if necessary - if (present(KPP_CSp)) then - if (associated(KPP_CSp) .and. present(nonLocalTrans)) then - do m=1,CS%ntr - call KPP_NonLocalTransport(KPP_CSp, G, GV, h_old, nonLocalTrans, CS%STF(:,:,m), dt, & - CS%diag, CS%tracer_data(m)%tr_ptr, CS%tracer_data(m)%tr(:,:,:), & - flux_scale=GV%Z_to_H) - enddo - endif - if (CS%debug) then - do m=1,CS%ntr - call hchksum(CS%tracer_data(m)%tr(:,:,m), & - trim(MARBL_instances%tracer_metadata(m)%short_name)//' post KPP', G%HI) - enddo - endif - endif - - if (present(evap_CFL_limit) .and. present(minimum_forcing_depth)) then - do m=1,CS%ntr - do k=1,nz ;do j=js,je ; do i=is,ie - h_work(i,j,k) = h_old(i,j,k) - enddo ; enddo ; enddo - ! CS%RIV_FLUXES is conc m/s, in_flux_optional expects time-integrated flux (conc H) - do j=js,je ; do i=is,ie - riv_flux_loc(i,j) = (CS%RIV_FLUXES(i,j,m) * (dt*US%T_to_s)) * GV%m_to_H - enddo ; enddo - if (CS%debug) & - call hchksum(riv_flux_loc(:,:), & - trim(MARBL_instances%tracer_metadata(m)%short_name)//' riv flux', G%HI, unscale=GV%H_to_m) - call applyTracerBoundaryFluxesInOut(G, GV, CS%tracer_data(m)%tr(:,:,:) , dt, fluxes, h_work, & - evap_CFL_limit, minimum_forcing_depth, in_flux_optional=riv_flux_loc) - call tracer_vertdiff(h_work, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & - sfc_flux=GV%Rho0 * CS%STF(:,:,m)) - enddo - else - do m=1,CS%ntr - call tracer_vertdiff(h_old, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & - sfc_flux=GV%Rho0 * CS%STF(:,:,m)) - enddo - endif - - if (CS%debug) then - do m=1,CS%ntr - call hchksum(CS%tracer_data(m)%tr(:,:,m), & - trim(MARBL_instances%tracer_metadata(m)%short_name)//' post tracer_vertdiff', G%HI) - enddo - endif - - ! (4) Compute interior tendencies - - bot_flux_to_tend(:, :, :) = 0. - do j=js,je - do i=is,ie - ! i. only want ocean points in this loop - if (G%mask2dT(i,j) == 0) cycle - - ! ii. Set up vertical domain and bot_flux_to_tend + ! interior tendencies + ! i. Set up vertical domain and bot_flux_to_tend ! Calculate depth of interface by building up thicknesses from the bottom (top interface is always 0) ! MARBL wants this to be positive-down zi(GV%ke) = G%bathyT(i,j) MARBL_instances%bot_flux_to_tend(:) = 0. cum_bftt_dz = 0. do k = GV%ke, 1, -1 - ! TODO: if we move this above vertical mixing, use h_old - dz(k) = h_new(i,j,k) ! cell thickness + dz(k) = h_old(i,j,k) ! cell thickness zc(k) = zi(k) - 0.5 * (dz(k)*GV%H_to_Z) zi(k-1) = zi(k) - (dz(k)*GV%H_to_Z) if (G%bathyT(i,j) - zi(k-1) <= CS%bot_flux_mix_thickness) then @@ -1603,22 +1462,22 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, MARBL_instances%domain%zt(:) = US%Z_to_m * zc(:) MARBL_instances%domain%delta_z(:) = GV%H_to_m * dz(:) - ! iii. Load proper column data - ! * Forcing Fields + ! ii. Load proper column data + ! * Forcing Fields ! These fields are getting the correct data if (CS%potemp_ind > 0) & - MARBL_instances%interior_tendency_forcings(CS%potemp_ind)%field_1d(1,:) = tv%T(i,j,:) * US%C_to_degC + MARBL_instances%interior_tendency_forcings(CS%potemp_ind)%field_1d(1,:) = prediabatic_T(i,j,:) * US%C_to_degC if (CS%salinity_ind > 0) & - MARBL_instances%interior_tendency_forcings(CS%salinity_ind)%field_1d(1,:) = tv%S(i,j,:) * US%S_to_ppt + MARBL_instances%interior_tendency_forcings(CS%salinity_ind)%field_1d(1,:) = prediabatic_S(i,j,:) * US%S_to_ppt - ! This are okay, but need option to read in from file + ! This is okay, but need option to read in from file ! (Same as dust_dep_ind for surface_flux_forcings) if (CS%dustflux_ind > 0) & MARBL_instances%interior_tendency_forcings(CS%dustflux_ind)%field_0d(1) = & fluxes%dust_flux(i,j) * US%RZ_T_to_kg_m2s - ! TODO: Support PAR (currently just using single subcolumn) - ! (Look for Pen_sw_bnd?) + ! TODO: Support PAR (currently just using single subcolumn) + ! (Look for Pen_sw_bnd?) if (CS%PAR_col_frac_ind > 0) then ! second index is num_subcols, not depth !MARBL_instances%interior_tendency_forcings(CS%PAR_col_frac_ind)%field_1d(1,:) = fluxes%fracr_cat(i,j,:) @@ -1692,7 +1551,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS%interior_tendency_saved_state(m)%field_3d(i,j,:) enddo - ! iv. Compute interior tendencies in MARBL + ! iii. Compute interior tendencies in MARBL call MARBL_instances%interior_tendency_compute() if (MARBL_instances%StatusLog%labort_marbl) then call MARBL_instances%StatusLog%log_error_trace(& @@ -1701,21 +1560,21 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, call print_marbl_log(MARBL_instances%StatusLog, G, i, j) call MARBL_instances%StatusLog%erase() - ! v. Apply tendencies immediately - ! First pass - Euler step; if stability issues, we can do something different (subcycle?) + ! iv. Apply tendencies immediately + ! First pass - Euler step; if stability issues, we can do something different (subcycle?) do m=1,CS%ntr CS%tracer_data(m)%tr(i,j,:) = CS%tracer_data(m)%tr(i,j,:) + (dt * US%T_to_s) * & MARBL_instances%interior_tendencies(m,:) enddo - ! vi. Copy output that MOM6 needs to hold on to - ! * saved state + ! v. Copy output that MOM6 needs to hold on to + ! * saved state do m=1,size(MARBL_instances%interior_tendency_saved_state%state) CS%interior_tendency_saved_state(m)%field_3d(i,j,:) = & MARBL_instances%interior_tendency_saved_state%state(m)%field_3d(:,1) enddo - ! * diagnostics + ! * diagnostics do m=1,size(MARBL_instances%interior_tendency_diags%diags) if (CS%interior_tendency_diags(m)%id > 0) then if (allocated(CS%interior_tendency_diags(m)%field_2d)) then @@ -1731,7 +1590,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, endif enddo - ! * tendency values themselves (and vertical integrals of them) + ! * tendency values themselves (and vertical integrals of them) do m=1,CS%ntr if (allocated(CS%interior_tendency_out(m)%field_3d)) & CS%interior_tendency_out(m)%field_3d(i,j,:) = MARBL_instances%interior_tendencies(m,:) @@ -1759,7 +1618,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, endif enddo - ! * Interior tendency output + ! * Interior tendency output do m=1,CS%ito_cnt CS%ITO(i,j,:,m) = & MARBL_instances%interior_tendency_output%outputs_for_GCM(m)%forcing_field_1d(1,:) @@ -1775,10 +1634,147 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, enddo endif - ! (5) Post diagnostics from our buffer - ! i. Interior tendency diagnostics (mix of 2D and 3D) - ! ii. Interior tendencies themselves - ! iii. Forcing fields + if (associated(fluxes%salt_flux)) then + ! convert salt flux to tracer fluxes and add to STF + do j=js,je ; do i=is,ie + net_salt_rate(i,j) = (1000.0*US%ppt_to_S * fluxes%salt_flux(i,j)) * GV%RZ_to_H + enddo ; enddo + + ! DIC related tracers + do j=js,je ; do i=is,ie + flux_from_salt_flux(i,j) = (CS%DIC_salt_ratio * GV%H_to_Z) * net_salt_rate(i,j) + enddo ; enddo + m = CS%tracer_inds%dic_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + m = CS%tracer_inds%dic_alt_co2_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + m = CS%tracer_inds%abio_dic_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + m = CS%tracer_inds%abio_di14c_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + + ! ALK related tracers + do j=js,je ; do i=is,ie + flux_from_salt_flux(i,j) = (CS%ALK_salt_ratio * GV%H_to_Z) * net_salt_rate(i,j) + enddo ; enddo + m = CS%tracer_inds%alk_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + m = CS%tracer_inds%alk_alt_co2_ind + if (m > 0) then + do j=js,je ; do i=is,ie + CS%STF(i,j,m) = CS%STF(i,j,m) + flux_from_salt_flux(i,j) + enddo ; enddo + if (CS%id_surface_flux_from_salt_flux(m) > 0) & + call post_data(CS%id_surface_flux_from_salt_flux(m), flux_from_salt_flux, CS%diag) + endif + endif + + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%STF(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//" sfc_flux", G%HI, & + unscale=US%Z_to_m*US%s_to_T) + enddo + endif + + ! (2) Apply surface fluxes via vertical diffusion + ! Compute KPP nonlocal term if necessary + if (present(KPP_CSp)) then + if (associated(KPP_CSp) .and. present(nonLocalTrans)) then + do m=1,CS%ntr + call KPP_NonLocalTransport(KPP_CSp, G, GV, h_old, nonLocalTrans, CS%STF(:,:,m), dt, & + CS%diag, CS%tracer_data(m)%tr_ptr, CS%tracer_data(m)%tr(:,:,:), & + flux_scale=GV%Z_to_H) + enddo + endif + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%tracer_data(m)%tr(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' post KPP', G%HI) + enddo + endif + endif + + if (present(evap_CFL_limit) .and. present(minimum_forcing_depth)) then + do m=1,CS%ntr + do k=1,nz ;do j=js,je ; do i=is,ie + h_work(i,j,k) = h_old(i,j,k) + enddo ; enddo ; enddo + ! CS%RIV_FLUXES is conc m/s, in_flux_optional expects time-integrated flux (conc H) + do j=js,je ; do i=is,ie + riv_flux_loc(i,j) = (CS%RIV_FLUXES(i,j,m) * (dt*US%T_to_s)) * GV%m_to_H + enddo ; enddo + if (CS%debug) & + call hchksum(riv_flux_loc(:,:), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' riv flux', G%HI, unscale=GV%H_to_m) + call applyTracerBoundaryFluxesInOut(G, GV, CS%tracer_data(m)%tr(:,:,:) , dt, fluxes, h_work, & + evap_CFL_limit, minimum_forcing_depth, in_flux_optional=riv_flux_loc) + call tracer_vertdiff(h_work, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & + sfc_flux=GV%Rho0 * CS%STF(:,:,m)) + enddo + else + ! TODO: do we want to support these options? does not apply river fluxes! + ! an alternative would be to require evap_CFL_limit and minimum_forcing_depth. + ! Much like we now require prediabatic_T and prediabatic_S, we can abort + ! in tracer flow control if they are not present. + do m=1,CS%ntr + call tracer_vertdiff(h_old, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & + sfc_flux=GV%Rho0 * CS%STF(:,:,m)) + enddo + endif + + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%tracer_data(m)%tr(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' post tracer_vertdiff', G%HI) + enddo + endif + + ! (3) Post diagnostics from our buffer + ! i. surface fluxes and their diagnostics (currently all 2D) + ! ii. Interior tendency diagnostics (mix of 2D and 3D) + ! iii. Interior tendencies themselves + ! iv. Forcing fields + do m=1,CS%ntr + if (CS%id_surface_flux_out(m) > 0) & + call post_data(CS%id_surface_flux_out(m), CS%STF(:,:,m), CS%diag) + enddo + + do m=1,size(CS%surface_flux_diags) + if (CS%surface_flux_diags(m)%id > 0) & + call post_data(CS%surface_flux_diags(m)%id, CS%surface_flux_diags(m)%field_2d(:,:), CS%diag) + enddo + if (CS%bot_flux_to_tend_id > 0) & call post_data(CS%bot_flux_to_tend_id, bot_flux_to_tend(:, :, :), CS%diag) diff --git a/src/tracer/MOM_tracer_flow_control.F90 b/src/tracer/MOM_tracer_flow_control.F90 index e058058bab..2298cb466f 100644 --- a/src/tracer/MOM_tracer_flow_control.F90 +++ b/src/tracer/MOM_tracer_flow_control.F90 @@ -81,7 +81,7 @@ module MOM_tracer_flow_control public call_tracer_register, tracer_flow_control_init, call_tracer_set_forcing public call_tracer_column_fns, call_tracer_surface_state, call_tracer_stocks public call_tracer_flux_init, get_chl_from_model, tracer_flow_control_end -public call_tracer_register_obc_segments +public call_tracer_register_obc_segments, extract_tracer_flow_member !> The control structure for orchestrating the calling of tracer packages type, public :: tracer_flow_control_CS ; private @@ -201,7 +201,7 @@ subroutine call_tracer_register(G, GV, US, param_file, CS, tr_Reg, restart_CS) call get_param(param_file, mdl, "USE_IDEAL_AGE_TRACER", CS%use_ideal_age, & "If true, use the ideal_age_example tracer package.", & default=.false.) - call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_marbl_tracers, & + call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_MARBL_tracers, & "If true, use the MARBL tracer package.", & default=.false.) call get_param(param_file, mdl, "USE_REGIONAL_DYES", CS%use_regional_dyes, & @@ -415,6 +415,17 @@ subroutine get_chl_from_model(Chl_array, G, GV, CS) end subroutine get_chl_from_model +!> Returns pointers or values of members within the tracer_flow_control_CS type. For extensibility, +!! each returned argument is an optional argument +subroutine extract_tracer_flow_member(CS, use_MARBL_tracers) + type(tracer_flow_control_CS), target, intent(in) :: CS !< module control structure + ! All output arguments are optional + logical, optional, intent(out) :: use_MARBL_tracers !< If true, MARBL tracers are active + + ! Constants within tracer_flow_control_CS + if (present(use_MARBL_tracers)) use_MARBL_tracers = CS%use_MARBL_tracers +end subroutine extract_tracer_flow_member + !> This subroutine calls the individual tracer modules' subroutines to !! specify or read quantities related to their surface forcing. subroutine call_tracer_set_forcing(sfc_state, fluxes, day_start, day_interval, G, US, Rho0, CS) @@ -450,7 +461,8 @@ end subroutine call_tracer_set_forcing !> This subroutine calls all registered tracer column physics subroutines. subroutine call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, mld, dt, G, GV, US, tv, optics, CS, & - debug, KPP_CSp, nonLocalTrans, evap_CFL_limit, minimum_forcing_depth, h_BL) + debug, KPP_CSp, nonLocalTrans, evap_CFL_limit, minimum_forcing_depth, & + h_BL, prediabatic_T, prediabatic_S) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure. type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h_old !< Layer thickness before entrainment @@ -486,6 +498,10 @@ subroutine call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, mld, dt, G, GV, real, optional, intent(in) :: minimum_forcing_depth !< The smallest depth over !! which fluxes can be applied [H ~> m or kg m-2] real, dimension(:,:), optional, pointer :: h_BL !< Thickness of active mixing layer [H ~> m or kg m-2] + real, dimension(:,:,:), optional, intent(in) :: prediabatic_T !< Temperature prior to calling + !! diabatic driver [C ~> degC] + real, dimension(:,:,:), optional, intent(in) :: prediabatic_S !< Salinity prior to calling + !! diabatic driver [S ~> ppt] ! Local variables real :: Hbl(SZI_(G),SZJ_(G)) !< Boundary layer thickness [H ~> m or kg m-2] @@ -527,13 +543,17 @@ subroutine call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, mld, dt, G, GV, evap_CFL_limit=evap_CFL_limit, & minimum_forcing_depth=minimum_forcing_depth, Hbl=Hbl) endif - if (CS%use_MARBL_tracers) & - call MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, & - G, GV, US, CS%MARBL_tracers_CSp, tv, & + if (CS%use_MARBL_tracers) then + if ((.not. present(prediabatic_T)) .or. (.not. present(prediabatic_S))) & + call MOM_error(FATAL, 'Must pass prediabatic_T and prediabatic_S when using MARBL') + call MARBL_tracers_column_physics(h_old, ea, eb, fluxes, dt, & + G, GV, US, CS%MARBL_tracers_CSp, & + prediabatic_T, prediabatic_S, & KPP_CSp=KPP_CSp, & nonLocalTrans=nonLocalTrans, & evap_CFL_limit=evap_CFL_limit, & minimum_forcing_depth=minimum_forcing_depth) + endif if (CS%use_regional_dyes) & call dye_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, & G, GV, US, tv, CS%dye_tracer_CSp, & @@ -617,11 +637,15 @@ subroutine call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, mld, dt, G, GV, call ideal_age_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, & G, GV, US, CS%ideal_age_tracer_CSp, Hbl=Hbl) endif - if (CS%use_MARBL_tracers) & - call MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, & - G, GV, US, CS%MARBL_tracers_CSp, tv, & + if (CS%use_MARBL_tracers) then + if ((.not. present(prediabatic_T)) .or. (.not. present(prediabatic_S))) & + call MOM_error(FATAL, 'Must pass prediabatic_T and prediabatic_S when using MARBL') + call MARBL_tracers_column_physics(h_old, ea, eb, fluxes, dt, & + G, GV, US, CS%MARBL_tracers_CSp, & + prediabatic_T, prediabatic_S, & KPP_CSp=KPP_CSp, & nonLocalTrans=nonLocalTrans) + endif if (CS%use_regional_dyes) & call dye_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, & G, GV, US, tv, CS%dye_tracer_CSp) From 52bdeec975e8ed721f51146d0051dc940bcfc90c Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Tue, 26 Aug 2025 08:59:07 -0600 Subject: [PATCH 20/41] Stochastic GM+E Restarts v2 (#376) Updates the NUOPC cap to write the stochastic physics package's restart file in the run directory whenever using the Stochastic GM+E parameterization. When restarting, enables the stochastic physics package to read a restart file from a name/location other than the default. If the new MOM6 namelist parameter CESM_RESTFILE is True then it uses the mom6 restart filename but with .r_stoch. in place of .r.. If CESM_RESTFILE is False (default) it simply uses whatever the default restart file name is in the stochastic physics package. (Edit: This PR no longer uses the CESM_RESTFILE parameter. It just reads the restart file directly from the run directory.) A separate PR to ESCOMP/stochastic_physics updates that package to allow the restart file name to change from its default value, which was originally hard-coded. This partially addresses #360. Changes will be needed in MOM_interface to make the whole thing work; specifically, we should always set CESM_RESTFILE = True in user_nl_mom, and when CONTINUE_RUN is true we need to modify the stochini parameter in the &nam_stochy section of input.nml to take the value .true.. This PR takes an alternate approach to #373, which required the restart file name to be set in the stochastic physics namelist. I've closed #373 in preference to this approach. --- config_src/drivers/nuopc_cap/mom_cap.F90 | 7 +++-- .../nuopc_cap/mom_ocean_model_nuopc.F90 | 28 ++++++++++++++----- .../stochastic_physics/stochy_data_mod.F90 | 10 +++++++ 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 config_src/external/stochastic_physics/stochy_data_mod.F90 diff --git a/config_src/drivers/nuopc_cap/mom_cap.F90 b/config_src/drivers/nuopc_cap/mom_cap.F90 index 2c8271a028..ad49e9d833 100644 --- a/config_src/drivers/nuopc_cap/mom_cap.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap.F90 @@ -1932,9 +1932,12 @@ subroutine ModelAdvance(gcomp, rc) write(restartname,'(A,".mom6.r",A)') & trim(casename), timestamp + write(stoch_restartname,'(A,".mom6.r_stoch",A,".nc")') & + trim(casename), timestamp call ESMF_LogWrite("MOM_cap: Writing restart : "//trim(restartname), ESMF_LOGMSG_INFO) ! write restart file(s) - call ocean_model_restart(ocean_state, restartname=restartname, num_rest_files=num_rest_files) + call ocean_model_restart(ocean_state, restartname=restartname, & + stoch_restartname=stoch_restartname, num_rest_files=num_rest_files) if (localPet == 0) then ! Write name of restart file in the rpointer file - this is currently hard-coded for the ocean open(newunit=writeunit, file=rpointer_filename, form='formatted', status='unknown', iostat=iostat) @@ -1973,7 +1976,7 @@ subroutine ModelAdvance(gcomp, rc) ! write restart file(s) call ocean_model_restart(ocean_state, restartname=restartname, & - stoch_restartname=stoch_restartname) + stoch_restartname='RESTART/'//stoch_restartname) endif diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index c29bbc1e4d..a48ceffd35 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -62,6 +62,7 @@ module MOM_ocean_model_nuopc use MOM_surface_forcing_nuopc, only : ice_ocean_boundary_type, surface_forcing_CS use MOM_surface_forcing_nuopc, only : forcing_save_restart use get_stochy_pattern_mod, only : write_stoch_restart_ocn +use stochy_data_mod, only : stoch_restfile use iso_fortran_env, only : int64 #include @@ -178,11 +179,12 @@ module MOM_ocean_model_nuopc !! steps can span multiple coupled time steps. logical :: diabatic_first !< If true, apply diabatic and thermodynamic !! processes before time stepping the dynamics. - logical :: do_sppt !< If true, stochastically perturb the diabatic and - !! write restarts - logical :: pert_epbl !< If true, then randomly perturb the KE dissipation and - !! genration termsand write restarts - + logical :: do_sppt !< If true, stochastically perturb the diabatic + !! tendencies and write restarts + logical :: pert_epbl !< If true, then randomly perturb the KE dissipation and + !! generation terms and write restarts + logical :: do_skeb !< If true, stochastically perturb the ocean lateral + !! velocity and write restarts real :: eps_omesh !< Max allowable difference between ESMF mesh and MOM6 !! domain coordinates @@ -266,6 +268,7 @@ subroutine ocean_model_init(Ocean_sfc, OS, Time_init, Time_in, gas_fields_ocn, i integer :: secs, days type(param_file_type) :: param_file !< A structure to parse for run-time parameters logical :: use_temperature + integer :: i, k call callTree_enter("ocean_model_init(), ocean_model_MOM.F90") if (associated(OS)) then @@ -281,6 +284,13 @@ subroutine ocean_model_init(Ocean_sfc, OS, Time_init, Time_in, gas_fields_ocn, i call time_interp_external_init OS%Time = Time_in + if(present(input_restart_file)) then + k = len_trim(input_restart_file) + i = index(input_restart_file, '.r.') + if (i>0) then + stoch_restfile = input_restart_file(1:i)//'r_stoch'//input_restart_file(i+2:k) + endif + endif call initialize_MOM(OS%Time, Time_init, param_file, OS%dirs, OS%MOM_CSp, & Time_in, offline_tracer_mode=OS%offline_tracer_mode, & input_restart_file=input_restart_file, & @@ -444,6 +454,10 @@ subroutine ocean_model_init(Ocean_sfc, OS, Time_init, Time_in, gas_fields_ocn, i "production and dissipation terms. Amplitude and correlations are "//& "controlled by the nam_stoch namelist in the UFS model only.", & default=.false.) + call get_param(param_file, mdl, "DO_SKEB", OS%do_skeb, & + "If true, then stochastically perturb the currents "//& + "using the stochastic kinetic energy backscatter scheme.",& + default=.false.) call close_param_file(param_file) call diag_mediator_close_registration(OS%diag) @@ -770,8 +784,8 @@ subroutine ocean_model_restart(OS, timestamp, restartname, stoch_restartname, nu endif endif if (present(stoch_restartname)) then - if (OS%do_sppt .OR. OS%pert_epbl) then - call write_stoch_restart_ocn('RESTART/'//trim(stoch_restartname)) + if (OS%do_sppt .OR. OS%pert_epbl .OR. OS%do_skeb) then + call write_stoch_restart_ocn(trim(stoch_restartname)) endif endif diff --git a/config_src/external/stochastic_physics/stochy_data_mod.F90 b/config_src/external/stochastic_physics/stochy_data_mod.F90 new file mode 100644 index 0000000000..f67513a956 --- /dev/null +++ b/config_src/external/stochastic_physics/stochy_data_mod.F90 @@ -0,0 +1,10 @@ +!>@brief The module 'stochy_data_mod' contains the initilization routine that read the stochastic phyiscs +!! namelist and determins the number of random patterns. +module stochy_data_mod + +implicit none +public :: stoch_restfile + +character(len=128) :: stoch_restfile = './INPUT/ocn_stoch.res.nc' !< default restart file name + +end module stochy_data_mod From 83cd1337e1099250797e2be57aa3ca16240b6e85 Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Wed, 27 Aug 2025 16:42:54 -0600 Subject: [PATCH 21/41] Stochastic GM+E efficiency & docs (#378) This PR does two things It pre-calculates some coefficients in the stochastic GM+E parameterization, which reduces computational cost. This will change answers when stochastic GM+E is in use, but only due to roundoff. It adds docs to the MOM_stochastics module. Originally this was aimed at Bob's fork, to go in with his PR #367 (see comment). Since that PR has been merged, I'm re-directing this PR directly to dev/ncar. --- .../stochastic/MOM_stochastics.F90 | 91 +++++++++++++------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/src/parameterizations/stochastic/MOM_stochastics.F90 b/src/parameterizations/stochastic/MOM_stochastics.F90 index 5cf0de83a7..32f9da0e40 100644 --- a/src/parameterizations/stochastic/MOM_stochastics.F90 +++ b/src/parameterizations/stochastic/MOM_stochastics.F90 @@ -65,7 +65,7 @@ module MOM_stochastics real, allocatable :: sppt_wts(:,:) !< Random pattern for ocean SPPT !! tendencies with a number between 0 and 2 [nondim] real, allocatable :: skeb_wts(:,:) !< Random pattern of lengthscales for ocean SKEB in mks units [m] - ! Note that SKEB_wts is set via external code in mks units. + !! Note that SKEB_wts is set via external code in mks units. real, allocatable :: epbl1_wts(:,:) !< Random pattern for K.E. generation [nondim] real, allocatable :: epbl2_wts(:,:) !< Random pattern for K.E. dissipation [nondim] type(time_type), pointer :: Time !< Pointer to model time (needed for sponges) @@ -77,11 +77,15 @@ module MOM_stochastics real, allocatable :: taperCv(:,:) !< Taper applied to v component of stochastic !! velocity increment range [0,1], [nondim] + ! Weights for smoothing skeb_diss + real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: Isum_area_wts, & !< One over the 3x3 sum of area_wt [L-2 ~> m-2] + area_wt !< Masked h cell areas. [L2 ~> m2] + end type stochastic_CS contains -!! This subroutine initializes the stochastics physics control structure. +!> This subroutine initializes the stochastics physics control structure. subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time) real, intent(in) :: dt !< time step [T ~> s] type(ocean_grid_type), intent(in) :: grid !< horizontal grid information @@ -102,9 +106,11 @@ subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time) integer :: nyT, nyB ! number of y-points including halo integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags. integer :: i, j, k ! loop indices - real :: tmp(grid%isdB:grid%iedB,grid%jsdB:grid%jedB) ! Used to construct tapers + real :: tmp(grid%isdB:grid%iedB,grid%jsdB:grid%jedB) ! Used to construct tapers and weights integer :: taper_width ! Width (in cells) of the taper that brings the stochastic velocity ! increments to 0 at the boundary. + real :: sum_area_wts ! A rotationally symmetric sum of the surrounding area weights + ! that are used to filter skeb_diss [L2 ~> m2] ! This include declares and sets the variable "version". # include "version_variable.h" @@ -257,6 +263,21 @@ subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time) if (CS%id_skeb_taperu > 0) call post_data(CS%id_skeb_taperu, CS%taperCu, CS%diag, .true.) if (CS%id_skeb_taperv > 0) call post_data(CS%id_skeb_taperv, CS%taperCv, CS%diag, .true.) + ! Initialize the smoothing weights + if ((CS%do_skeb) .and. CS%skeb_npass >= 1) then + ALLOC_(CS%area_wt(grid%isd:grid%ied,grid%jsd:grid%jed)) ; CS%area_wt(:,:) = 0.0 + ALLOC_(CS%Isum_area_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) ; CS%Isum_area_wts(:,:) = 0.0 + do j=grid%jsc-2,grid%jec+2 ; do i=grid%isc-2,grid%iec+2 + CS%area_wt(i,j) = grid%mask2dT(i,j)*grid%areaT(i,j) + enddo ; enddo + do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 + sum_area_wts = CS%area_wt(i,j) + & + (((CS%area_wt(i-1,j) + CS%area_wt(i+1,j)) + (CS%area_wt(i,j-1) + CS%area_wt(i,j+1))) + & + ((CS%area_wt(i-1,j-1) + CS%area_wt(i+1,j+1)) + (CS%area_wt(i-1,j+1) + CS%area_wt(i+1,j-1)))) + CS%Isum_area_wts(i,j) = 1.0 / (sum_area_wts + 1.e-16*US%m_to_L**2) + enddo ; enddo + endif + if (CS%do_sppt .OR. CS%pert_epbl .OR. CS%do_skeb) & call MOM_mesg(' === COMPLETED MOM STOCHASTIC INITIALIZATION =====') @@ -264,11 +285,7 @@ subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time) end subroutine stochastics_init -!> update_ocean_model uses the forcing in Ice_ocean_boundary to advance the -!! ocean model's state from the input value of Ocean_state (which must be for -!! time time_start_update) for a time interval of Ocean_coupling_time_step, -!! returning the publicly visible ocean surface properties in Ocean_sfc and -!! storing the new ocean properties in Ocean_state. +!> Advances the stochastic patterns one time step subroutine update_stochastics(CS) type(stochastic_CS), intent(inout) :: CS !< diabatic control structure call callTree_enter("update_stochastics(), MOM_stochastics.F90") @@ -280,6 +297,7 @@ subroutine update_stochastics(CS) end subroutine update_stochastics +!> Adds a stochastic increment (backscatter) to the input velocity field subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) type(ocean_grid_type), intent(in) :: grid !< ocean grid structure @@ -300,7 +318,6 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) real, dimension(SZI_(grid) ,SZJB_(grid),SZK_(GV)) :: vstar !< Stochastic v velocity increment [L T-1 ~> m s-1] real, dimension(SZI_(grid),SZJ_(grid)) :: diss_tmp !< Temporary array used in smoothing skeb_diss !! [L2 T-3 ~> m2 s-2] - real, dimension(SZI_(grid),SZJ_(grid)) :: area_wt !< Masked cell areas used in spatial filter [L2 ~> m2] real, dimension(3,3) :: local_weights !< 3x3 stencil weights used in smoothing skeb_diss !! [L2 ~> m2] @@ -310,8 +327,6 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) real :: kh ! A smooothing factor [nondim] real :: sum_wtd_skeb_diss ! The rotationally symmetric sum of the surrounding values of skeb times ! the area weights used to filter skeb_diss [L4 T-3 ~> m4 s-3] - real :: sum_area_wts ! A rotationally symmetric sum of the surrounding area weights - ! that are used to filter skeb_diss [L2 ~> m2] integer :: i, j, k, iter integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state @@ -358,12 +373,6 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) endif endif ! Sets CS%skeb_diss in [L2 T-3 ~> m2 s-3] without GM or FrictWork - if (CS%skeb_npass >= 1) then - do j=grid%jsc-2,grid%jec+2 ; do i=grid%isc-2,grid%iec+2 - area_wt(i,j) = grid%mask2dT(i,j)*grid%areaT(i,j) - enddo ; enddo - endif - ! smooth dissipation skeb_npass times do iter=1,CS%skeb_npass if (mod(iter,2) == 1) call pass_var(CS%skeb_diss, grid%domain) @@ -371,7 +380,7 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) if (CS%answer_date < 20250701) then ! Do the filter with expressions that do not preserve rotational symmetry. do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 - local_weights(:,:) = area_wt(i-1:i+1,j-1:j+1) + local_weights(:,:) = CS%area_wt(i-1:i+1,j-1:j+1) diss_tmp(i,j) = sum(local_weights(:,:)*CS%skeb_diss(i-1:i+1,j-1:j+1,k)) / & (sum(local_weights) + 1.e-16*US%m_to_L**2) enddo ; enddo @@ -379,15 +388,12 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end) ! This spatial filter preserves rotational symmeetry (including with FMAs), but is ! mathematically equivalent to the older sum-based form above do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 - sum_area_wts = area_wt(i,j) + & - (((area_wt(i-1,j) + area_wt(i+1,j)) + (area_wt(i,j-1) + area_wt(i,j+1))) + & - ((area_wt(i-1,j-1) + area_wt(i+1,j+1)) + (area_wt(i-1,j+1) + area_wt(i+1,j-1)))) - sum_wtd_skeb_diss = CS%skeb_diss(i,j,k) * area_wt(i+1,j) + & - ((( (CS%skeb_diss(i-1,j,k) * area_wt(i-1,j)) + (CS%skeb_diss(i+1,j,k) * area_wt(i+1,j)) ) + & - ( (CS%skeb_diss(i,j-1,k) * area_wt(i,j-1)) + (CS%skeb_diss(i,j+1,k) * area_wt(i,j+1)) )) + & - (( (CS%skeb_diss(i-1,j-1,k) * area_wt(i-1,j-1)) + (CS%skeb_diss(i-1,j-1,k) * area_wt(i+1,j+1)) ) + & - ( (CS%skeb_diss(i-1,j+1,k) * area_wt(i-1,j+1)) + (CS%skeb_diss(i+1,j-1,k) * area_wt(i+1,j-1)) ))) - diss_tmp(i,j) = sum_wtd_skeb_diss / (sum_area_wts + 1.e-16*US%m_to_L**2) + sum_wtd_skeb_diss = CS%skeb_diss(i,j,k) * CS%area_wt(i+1,j) + & + ((( (CS%skeb_diss(i-1,j,k) * CS%area_wt(i-1,j)) + (CS%skeb_diss(i+1,j,k) * CS%area_wt(i+1,j)) ) + & + ( (CS%skeb_diss(i,j-1,k) * CS%area_wt(i,j-1)) + (CS%skeb_diss(i,j+1,k) * CS%area_wt(i,j+1)) )) + & + (( (CS%skeb_diss(i-1,j-1,k) * CS%area_wt(i-1,j-1)) + (CS%skeb_diss(i-1,j-1,k) * CS%area_wt(i+1,j+1)) ) + & + ( (CS%skeb_diss(i-1,j+1,k) * CS%area_wt(i-1,j+1)) + (CS%skeb_diss(i+1,j-1,k) * CS%area_wt(i+1,j-1)) ))) + diss_tmp(i,j) = sum_wtd_skeb_diss * CS%Isum_area_wts(i,j) enddo ; enddo endif do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1 @@ -509,6 +515,33 @@ subroutine smooth_x9_uv(G, field_u, field_v, zero_land) enddo end subroutine smooth_x9_uv - +!> \namespace mom_stochastics +!! +!! This file contains subroutines that implement some stochastic parameterizations in MOM6. +!! SPPT perturbations of the tendencies of S and T are turned on using DO_SPPT=True. +!! Stochastic perturbations in ePBL are turned on using PERT_EPBL=True. +!! Stochastic kinetic energy backscatter (SKEB) via the Stochastic GM+E scheme is turned on using +!! DO_SKEB=True. For all three schemes the spatial and temporal correlation structure +!! of the associated random fields is controlled from the nam_stochy namelist used by +!! the external stochastic_physics package, which is called by subroutines in this +!! module. +!! +!! The SKEB backscatter can be set in a variety of ways. If SKEB_USE_GM=True then +!! SKEB_GM_COEF times the GM work rate will be added to the backscatter rate. (The +!! vertical structure for this component of backscatter is the so-called EBT struct.) If +!! SKEB_USE_FRICT=True then SKEB_FRICT_COEF times the work rate from +!! lateral viscosity will be added to the backscatter rate. The code uses the total contribution +!! from Laplacian and biharmonic viscosities as computed within the horizontal viscosity module. +!! If neither SKEB_USE_GM nor SKEB_USE_FRICT is true, then the code +!! computes the dissipation rate as if it came from a lateral harmonic viscosity with +!! coefficient 1 (MKS units). The only thoroughly tested SKEB option at this point is +!! SKEB_USE_GM. +!! +!! The contributions to the backscatter rate are smoothed before use. One smoothing pass uses a +!! 3x3 moving average with weights proportional to the h-cell areas. The number of smoothing passes +!! is controlled by SKEB_NPASS. +!! +!! A taper is applied to the SKEB velocity increments (equivalently to the SKEB stochastic forcing). +!! The taper zeros out the increments near land cells. The width of this taper can be controlled using +!! SKEB_TAPER_WIDTH. end module MOM_stochastics - From ef88eda97a7d01be7b5a0b2941afc9cfe4522337 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Wed, 17 Sep 2025 12:27:59 -0600 Subject: [PATCH 22/41] Add scaling/mask option for Cr field (#387) - Modified MOM_read_data call to apply conditional scaling depending on CR value. - Updated USE_CR_GRID description to clarify behavior: - If CR=0 (default), field is scaled by 1.0. - If CR>0, field is treated as a mask and scaled by CR. --- .../lateral/MOM_mixed_layer_restrat.F90 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 0f8fe55e73..07b29726c2 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -1762,7 +1762,9 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "depth used for a smoother stream function at the base of "//& "the mixed-layer.", units="nondim", default=0.0) call get_param(param_file, mdl, "USE_CR_GRID", CS%Cr_grid, & - "If true, read in a spatially varying Cr field.", default=.false.) + "If true, read in a spatially varying Cr field." //& + "If CR = 0 (default), this field is scaled by 1.0." //& + "If CR>0., this field works as a mask and is scaled by CR.", default=.false.) call get_param(param_file, mdl, "USE_MLD_GRID", CS%MLD_grid, & "If true, read in a spatially varying MLD_decaying_Tfilt field.", default=.false.) if (CS%MLD_grid) then @@ -1786,7 +1788,13 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "The variable name for Cr field.", & default="Cr") filename = trim(inputdir) // "/" // trim(filename) - call MOM_read_data(filename, varname, CS%Cr_space, G%domain, scale=1.0) + if (CS%Cr > 0.0) then + ! here, the file is working as a mask + call MOM_read_data(filename, varname, CS%Cr_space, G%domain, scale=CS%Cr) + else + ! read actual Cr + call MOM_read_data(filename, varname, CS%Cr_space, G%domain, scale=1.0) + endif call pass_var(CS%Cr_space, G%domain) endif call closeParameterBlock(param_file) ! The remaining parameters do not have MLE% prepended From d01b4594f24127bfc0537abedb29ab31af370b01 Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Wed, 17 Sep 2025 14:49:31 -0600 Subject: [PATCH 23/41] Add depth-based tapering of Leith+E (#388) --- .../lateral/MOM_hor_visc.F90 | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/parameterizations/lateral/MOM_hor_visc.F90 b/src/parameterizations/lateral/MOM_hor_visc.F90 index 77d431442b..62337301a1 100644 --- a/src/parameterizations/lateral/MOM_hor_visc.F90 +++ b/src/parameterizations/lateral/MOM_hor_visc.F90 @@ -87,6 +87,9 @@ module MOM_hor_visc !! that gets backscattered in the Leith+E scheme. [nondim] logical :: smooth_Ah !< If true (default), then Ah and m_leithy are smoothed. !! This smoothing requires a lot of blocking communication. + logical :: taper_leithy !< If true, backscatter coeff is tapered to zero with depth + real :: leithy_depth !< If tapering leith+E, taper is applied below this depth [Z ~> m] + real :: leithy_width !< If tapering leith+E, backscatter is zero below leithy_depth+leithy_width [Z ~> m] logical :: use_QG_Leith_visc !< If true, use QG Leith nonlinear eddy viscosity. !! KH is the background value. logical :: bound_Coriolis !< If true & SMAGORINSKY_AH is used, the biharmonic @@ -471,6 +474,9 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, hrat_min, & ! h_min divided by the thickness at the stress point (h or q) [nondim] visc_bound_rem ! fraction of overall viscous bounds that remain to be applied (h or q) [nondim] + ! Layer depth. Used to taper Leith+E backscatter coefficient with depth + real, allocatable :: zc(:,:,:) ! depth at center of h cell [Z ~> m] + is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB @@ -651,6 +657,16 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, call smooth_x9_uv(CS, G, u_smooth(:,:,k), v_smooth(:,:,k), zero_land=.false.) enddo call pass_vector(u_smooth, v_smooth, G%Domain) + ! If tapering the backscatter, calculate depths now + if (CS%taper_leithy) then + ! allocate zc + allocate(zc(SZI_(G),SZJ_(G),SZK_(GV))) ; zc(:,:,:) = 0.0 + ! Compute zc. Not actual cell centers because it starts at 0 rather than at SSH. + zc(:,:,1) = 0.5 * h(:,:,1) + do k=2,nz + zc(:,:,k) = zc(:,:,k-1) + 0.5 * (h(:,:,k-1) + h(:,:,k)) + enddo + endif endif if (CS%use_QG_Leith_visc .and. ((CS%Leith_Kh) .or. (CS%Leith_Ah))) then @@ -674,7 +690,7 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, !$OMP h_neglect, h_neglect3, inv_PI3, inv_PI6, & !$OMP diffu, diffv, Kh_h, Kh_q, Ah_h, Ah_q, FrictWork, FrictWork_bh, FrictWork_GME, & !$OMP div_xx_h, sh_xx_h, vort_xy_q, sh_xy_q, GME_coeff_h, GME_coeff_q, & - !$OMP KH_u_GME, KH_v_GME, grid_Re_Kh, grid_Re_Ah, NoSt, ShSt, hu_cont, hv_cont, STOCH & + !$OMP KH_u_GME, KH_v_GME, grid_Re_Kh, grid_Re_Ah, NoSt, ShSt, hu_cont, hv_cont, STOCH, zc & !$OMP ) & !$OMP private( & !$OMP i, j, k, n, tmp, & @@ -1320,6 +1336,10 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, m_leithy(i,j) = CS%m_leithy_max(i,j) endif endif + if (CS%taper_leithy) then + ! Multiply m_leithy by taper function of depth + m_leithy(:,:) = m_leithy(:,:) * leithy_taper_function(CS, zc(:,:,k)) + endif enddo ; enddo if (CS%smooth_Ah) then @@ -2286,6 +2306,8 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, CS%dx2h, CS%dy2h, CS%dx2q, CS%dy2q) endif + if (allocated(zc)) deallocate(zc) + end subroutine horizontal_viscosity !> Allocates space for and calculates static variables used by horizontal_viscosity. @@ -2655,6 +2677,19 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) "If true, Ah and m_leithy are smoothed within Leith+E. This requires "//& "lots of blocking communications, which can be expensive", & default=.true., do_not_log=.not.CS%use_Leithy) + call get_param(param_file, mdl, "TAPER_LEITHY", CS%taper_leithy, & + "If true, Leith+E c_K coefficient is tapered to zero"//& + "below a threshold depth", & + default=.false., do_not_log=.not.CS%use_Leithy) + if (CS%taper_leithy) then + call get_param(param_file, mdl, "LEITHY_DEPTH", CS%leithy_depth, & + "Leith+E backscatter starts tapering below this depth.", & + units="m", scale=US%m_to_Z, default=800.0) + call get_param(param_file, mdl, "LEITHY_WIDTH", CS%leithy_width, & + "Leith+E backscatter is zero below LEITHY_DEPTH+LEITHY_WIDTH.", & + units="m", scale=US%m_to_Z, default=400.0) + if (CS%leithy_width <= 0.0) call MOM_error(FATAL,"ERROR: LEITHY_WIDTH must be positive ") + endif if (CS%use_GME .and. .not.split) call MOM_error(FATAL,"ERROR: Currently, USE_GME = True "// & "cannot be used with SPLIT=False.") @@ -3265,6 +3300,26 @@ subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp) end subroutine hor_visc_init +!> leithy_taper_function returns 1 if zc is shallower than leithy_depth; 0 if deeper than +!! leithy_depth+leithy_width; and an interpolating cubic spline in between. +function leithy_taper_function(CS, zc) + type(hor_visc_CS), intent(in) :: CS !< Control structure for horizontal viscosity + real, intent(in) :: zc(:,:) !< depth of h-cell centersi [Z ~> m] + real :: leithy_taper_function(size(zc,dim=1),size(zc,dim=2)) ! Taper function evaluated at zc [nondim] + + ! Local variables + real :: x(size(zc,dim=1),size(zc,dim=2)) ! 0 at top of transition and 1 at bottom [nondim] + + x = (zc - CS%leithy_depth) / CS%leithy_width + where (zc <= CS%leithy_depth) + leithy_taper_function = 1.0 + elsewhere (zc >= CS%leithy_depth + CS%leithy_width) + leithy_taper_function = 0.0 + elsewhere + leithy_taper_function = (x - 1.0)**2 * (1.0 + 2 * x) + end where +end function leithy_taper_function + !> hor_visc_vel_stencil returns the horizontal viscosity input velocity stencil size function hor_visc_vel_stencil(CS) result(stencil) type(hor_visc_CS), intent(in) :: CS !< Control structure for horizontal viscosity From 175047bbcdb6ee839e11a67acfac3d344f2e53bb Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Thu, 18 Sep 2025 12:50:44 -0600 Subject: [PATCH 24/41] Add entrainment rule BLD calculation to KPP (#379) * Add entrainment rule BLD calculation to KPP This commit introduces an alternative method for computing the boundary layer depth (BLD) in KPP, based on the entrainment rule. This method is activated when the non-solar surface buoyancy flux (surfBuoy_NS) is negative and STOKES_MOST = True. In all other cases, the standard Richardson Number-based method is used. The non-solar surface buoyancy flux is estimated internally using an exponential attenuation function, since only the total surface buoyancy flux (solar + non-solar) is currently available to the module. Ideally, the non-solar component should be provided explicitly. Several new diagnostics have been added, and some of the existing ones have been updated. Specifically, the parameterized shear, buoyancy, and Stokes TKE production terms are calculated. We conducted multiple tests where these terms are passed to the MLE module and used in the denominator of the Bodner streamfunction. However, because of the small Cr value we adopted (0.01), this had minimal effect on the solutions, so we decided to keep the original simpler implementation and not pursue this option for now. This commit should be evaluated together with https://github.com/CVMix/CVMix-src/pull/106. * Fix typos * Update CVMix to latest commit Include new entreinment rule depth changes. * Revert unit conversion for Vt2 and GoRho * Update description and remove empty line * Split description of variables * Refactor KPP StokesMOST diagnostics and allocations - Removed unused `ustar` array from KPP_CS type. - Restricted registration, allocation, and posting of StokesMOST diagnostics (`StokesXI`, `Lam2`, `BEdE_ER`, `ERdepth`, `RNdepth`, `PU_TKE`, `PS_TKE`, `PB_TKE`) to cases when `CS%StokesMOST` is enabled. - Moved allocations of related arrays inside StokesMOST conditional block. - Updated condition for calculating `surfBuoy_NS` to avoid division by zero in alog(buoyFlux(i,j,2)/buoyFlux(i,j,3)). - Wrapped diagnostic and debug checks in `if (CS%StokesMOST)` conditions. - Minor cleanup of comments and diagnostic labeling. --- pkg/CVMix-src | 2 +- .../vertical/MOM_CVMix_KPP.F90 | 593 +++++++++++------- 2 files changed, 353 insertions(+), 242 deletions(-) diff --git a/pkg/CVMix-src b/pkg/CVMix-src index 14939c5704..d20b9898f4 160000 --- a/pkg/CVMix-src +++ b/pkg/CVMix-src @@ -1 +1 @@ -Subproject commit 14939c5704d57b4d68d86b57b13161ea59ab6b5c +Subproject commit d20b9898f46d0ec3f5df2eab7f38eb4aac567254 diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index 23a5c5664d..ca274999dc 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -32,6 +32,7 @@ module MOM_CVMix_KPP use CVMix_kpp, only : CVMix_kpp_params_type use CVMix_kpp, only : CVMix_kpp_compute_kOBL_depth use CVMix_kpp, only : CVMix_kpp_compute_StokesXi +use CVMix_kpp, only : CVMix_kpp_compute_ER_depth implicit none ; private @@ -147,39 +148,49 @@ module MOM_CVMix_KPP integer :: id_NLTt = -1 integer :: id_NLTs = -1 integer :: id_EnhK = -1, id_EnhVt2 = -1 - integer :: id_EnhW = -1 integer :: id_La_SL = -1 integer :: id_OBLdepth_original = -1 + integer :: id_ERdepth = -1, id_RNdepth = -1 integer :: id_StokesXI = -1 + integer :: id_BEdE_ER = -1 integer :: id_Lam2 = -1 + integer :: id_PU_TKE = -1 + integer :: id_PS_TKE = -1 + integer :: id_PB_TKE = -1 !>@} ! Diagnostics arrays real, pointer, dimension(:,:) :: OBLdepth !< Depth (positive) of ocean boundary layer (OBL) [Z ~> m] - real, allocatable, dimension(:,:) :: OBLdepth_original !< Depth (positive) of OBL without smoothing [Z ~> m] - real, allocatable, dimension(:,:) :: StokesParXI !< Stokes similarity parameter [nondim] - real, allocatable, dimension(:,:) :: Lam2 !< La^(-2) = Ustk0/u* [nondim] - real, allocatable, dimension(:,:) :: kOBL !< Level (+fraction) of OBL extent [nondim] - real, allocatable, dimension(:,:) :: OBLdepthprev !< previous Depth (positive) of OBL [Z ~> m] - real, allocatable, dimension(:,:) :: La_SL !< Langmuir number used in KPP [nondim] - real, allocatable, dimension(:,:,:) :: dRho !< Bulk difference in density [R ~> kg m-3] - real, allocatable, dimension(:,:,:) :: Uz2 !< Square of bulk difference in resolved velocity [L2 T-2 ~> m2 s-2] real, allocatable, dimension(:,:,:) :: BulkRi !< Bulk Richardson number for each layer [nondim] - real, allocatable, dimension(:,:,:) :: sigma !< Sigma coordinate (dimensionless) [nondim] - real, allocatable, dimension(:,:,:) :: Ws !< Turbulent velocity scale for scalars [Z T-1 ~> m s-1] real, allocatable, dimension(:,:,:) :: N !< Brunt-Vaisala frequency [T-1 ~> s-1] real, allocatable, dimension(:,:,:) :: N2 !< Squared Brunt-Vaisala frequency [T-2 ~> s-2] - real, allocatable, dimension(:,:,:) :: Vt2 !< Unresolved squared turbulence velocity for - !! bulk Ri [Z2 T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: Ws !< Turbulent velocity scale for scalars [Z T-1 ~> m s-1] + real, allocatable, dimension(:,:,:) :: Vt2 !< Unresolved turbulence velocity^2 for bulk Ri [Z2 T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: Uz2 !< Square of bulk difference in resolved velocity [L2 T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: dRho !< Bulk difference in density [R ~> kg m-3] + real, allocatable, dimension(:,:,:) :: sigma !< Sigma coordinate (dimensionless) [nondim] + real, allocatable, dimension(:,:,:) :: Kv_KPP !< Viscosity due to KPP [Z2 T-1 ~> m2 s-1] real, allocatable, dimension(:,:,:) :: Kt_KPP !< Temp diffusivity from KPP [Z2 T-1 ~> m2 s-1] real, allocatable, dimension(:,:,:) :: Ks_KPP !< Scalar diffusivity from KPP [Z2 T-1 ~> m2 s-1] - real, allocatable, dimension(:,:,:) :: Kv_KPP !< Viscosity due to KPP [Z2 T-1 ~> m2 s-1] real, allocatable, dimension(:,:) :: Tsurf !< Temperature of surface layer [C ~> degC] real, allocatable, dimension(:,:) :: Ssurf !< Salinity of surface layer [S ~> ppt] real, allocatable, dimension(:,:) :: Usurf !< i-velocity of surface layer [L T-1 ~> m s-1] real, allocatable, dimension(:,:) :: Vsurf !< j-velocity of surface layer [L T-1 ~> m s-1] real, allocatable, dimension(:,:,:) :: EnhK !< Enhancement for mixing coefficient [nondim] real, allocatable, dimension(:,:,:) :: EnhVt2 !< Enhancement for Vt2 [nondim] + real, allocatable, dimension(:,:) :: La_SL !< Langmuir number used in KPP [nondim] + real, allocatable, dimension(:,:) :: OBLdepth_original !< Depth (positive) of OBL [Z ~> m] without smoothing + real, allocatable, dimension(:,:) :: ERdepth !< Percent use ER boundary layer depth [nondim] + real, allocatable, dimension(:,:) :: RNdepth !< Percent use Ri Number boundary layer depth [nondim] + real, allocatable, dimension(:,:) :: StokesXI !< Stokes similarity parameter [nondim] + real, allocatable, dimension(:,:) :: BEdE_ER !< Enrtainment Rule's Parameterized BEdE [ m3 s-3 ] + real, allocatable, dimension(:,:) :: Lam2 !< La^(-2) = Ustk0/u* + ! Other arrays + real, allocatable, dimension(:,:) :: kOBL !< Level (+fraction) of OBL extent [nondim] + real, allocatable, dimension(:,:) :: OBLdepthprev !< previous Depth (positive) of OBL [Z ~> m] + real, pointer, dimension(:,:) :: PU_TKE !< Parameterized shear TKE Production [ m3 s-3 ] + real, pointer, dimension(:,:) :: PS_TKE !< Parameterized Stokes TKE Production [ m3 s-3 ] + real, pointer, dimension(:,:) :: PB_TKE !< Parameterized buoyancy TKE Production [ m3 s-3 ] end type KPP_CS @@ -516,7 +527,7 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) endif call get_param(paramFile, mdl, "KPP_CVt2", CS%KPP_CVt2, & - 'Parameter for Stokes MOST convection entrainment', & + 'Parameter for Stokes MOST convection entrainment (unresolved shear)', & units="nondim", default=1.6) call get_param(paramFile, mdl, "ANSWER_DATE", CS%answer_date, & @@ -565,51 +576,39 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) cmor_field_name='oml', cmor_long_name='ocean_mixed_layer_thickness_defined_by_mixing_scheme', & cmor_units='m', cmor_standard_name='Ocean Mixed Layer Thickness Defined by Mixing Scheme') endif - if( CS%StokesMOST ) then - CS%id_StokesXI = register_diag_field('ocean_model', 'StokesXI', diag%axesT1, Time, & - 'Stokes Similarity Parameter', 'nondim') - CS%id_Lam2 = register_diag_field('ocean_model', 'Lam2', diag%axesT1, Time, & - 'Ustk0_ustar', 'nondim') - endif - CS%id_BulkDrho = register_diag_field('ocean_model', 'KPP_BulkDrho', diag%axesTL, Time, & - 'Bulk difference in density used in Bulk Richardson number, as used by [CVMix] KPP', & - 'kg/m3', conversion=US%R_to_kg_m3) - CS%id_BulkUz2 = register_diag_field('ocean_model', 'KPP_BulkUz2', diag%axesTL, Time, & - 'Square of bulk difference in resolved velocity used in Bulk Richardson number via [CVMix] KPP', & - 'm2/s2', conversion=US%L_T_to_m_s**2) CS%id_BulkRi = register_diag_field('ocean_model', 'KPP_BulkRi', diag%axesTL, Time, & 'Bulk Richardson number used to find the OBL depth used by [CVMix] KPP', 'nondim') - CS%id_Sigma = register_diag_field('ocean_model', 'KPP_sigma', diag%axesTi, Time, & - 'Sigma coordinate used by [CVMix] KPP', 'nondim') - CS%id_Ws = register_diag_field('ocean_model', 'KPP_Ws', diag%axesTL, Time, & - 'Turbulent vertical velocity scale for scalars used by [CVMix] KPP', & - 'm/s', conversion=US%Z_to_m*US%s_to_T) CS%id_N = register_diag_field('ocean_model', 'KPP_N', diag%axesTi, Time, & '(Adjusted) Brunt-Vaisala frequency used by [CVMix] KPP', '1/s', conversion=US%s_to_T) CS%id_N2 = register_diag_field('ocean_model', 'KPP_N2', diag%axesTi, Time, & 'Square of Brunt-Vaisala frequency used by [CVMix] KPP', '1/s2', conversion=US%s_to_T**2) + CS%id_Ws = register_diag_field('ocean_model', 'KPP_Ws', diag%axesTL, Time, & + 'Turbulent vertical velocity scale for scalars used by [CVMix] KPP', & + 'm/s', conversion=US%Z_to_m*US%s_to_T) CS%id_Vt2 = register_diag_field('ocean_model', 'KPP_Vt2', diag%axesTL, Time, & 'Unresolved shear turbulence used by [CVMix] KPP', 'm2/s2', conversion=US%Z_to_m**2*US%s_to_T**2) + CS%id_BulkUz2 = register_diag_field('ocean_model', 'KPP_BulkUz2', diag%axesTL, Time, & + 'Square of bulk difference in resolved velocity used in Bulk Richardson number via [CVMix] KPP', & + 'm2/s2', conversion=US%L_T_to_m_s**2) + CS%id_BulkDrho = register_diag_field('ocean_model', 'KPP_BulkDrho', diag%axesTL, Time, & + 'Bulk difference in density used in Bulk Richardson number, as used by [CVMix] KPP', & + 'kg/m3', conversion=US%R_to_kg_m3) CS%id_uStar = register_diag_field('ocean_model', 'KPP_uStar', diag%axesT1, Time, & 'Friction velocity, u*, as used by [CVMix] KPP', 'm/s', conversion=US%Z_to_m*US%s_to_T) CS%id_buoyFlux = register_diag_field('ocean_model', 'KPP_buoyFlux', diag%axesTi, Time, & 'Surface (and penetrating) buoyancy flux, as used by [CVMix] KPP', & 'm2/s3', conversion=US%L_to_m**2*US%s_to_T**3) + CS%id_Sigma = register_diag_field('ocean_model', 'KPP_sigma', diag%axesTi, Time, & + 'Sigma coordinate used by [CVMix] KPP', 'nondim') + CS%id_Kv_KPP = register_diag_field('ocean_model', 'KPP_Kv', diag%axesTi, Time, & + 'Vertical viscosity due to KPP, as calculated by [CVMix] KPP', & + 'm2/s', conversion=US%Z2_T_to_m2_s) CS%id_Kt_KPP = register_diag_field('ocean_model', 'KPP_Kheat', diag%axesTi, Time, & 'Heat diffusivity due to KPP, as calculated by [CVMix] KPP', & 'm2/s', conversion=US%Z2_T_to_m2_s) - CS%id_Kd_in = register_diag_field('ocean_model', 'KPP_Kd_in', diag%axesTi, Time, & - 'Diffusivity passed to KPP', 'm2/s', conversion=GV%HZ_T_to_m2_s) CS%id_Ks_KPP = register_diag_field('ocean_model', 'KPP_Ksalt', diag%axesTi, Time, & 'Salt diffusivity due to KPP, as calculated by [CVMix] KPP', & 'm2/s', conversion=US%Z2_T_to_m2_s) - CS%id_Kv_KPP = register_diag_field('ocean_model', 'KPP_Kv', diag%axesTi, Time, & - 'Vertical viscosity due to KPP, as calculated by [CVMix] KPP', & - 'm2/s', conversion=US%Z2_T_to_m2_s) - CS%id_NLTt = register_diag_field('ocean_model', 'KPP_NLtransport_heat', diag%axesTi, Time, & - 'Non-local transport (Cs*G(sigma)) for heat, as calculated by [CVMix] KPP', 'nondim') - CS%id_NLTs = register_diag_field('ocean_model', 'KPP_NLtransport_salt', diag%axesTi, Time, & - 'Non-local tranpsort (Cs*G(sigma)) for scalars, as calculated by [CVMix] KPP', 'nondim') CS%id_Tsurf = register_diag_field('ocean_model', 'KPP_Tsurf', diag%axesT1, Time, & 'Temperature of surface layer (10% of OBL depth) as passed to [CVMix] KPP', & 'C', conversion=US%C_to_degC) @@ -622,6 +621,12 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) CS%id_Vsurf = register_diag_field('ocean_model', 'KPP_Vsurf', diag%axesCv1, Time, & 'j-component flow of surface layer (10% of OBL depth) as passed to [CVMix] KPP', & 'm/s', conversion=US%L_T_to_m_s) + CS%id_Kd_in = register_diag_field('ocean_model', 'KPP_Kd_in', diag%axesTi, Time, & + 'Diffusivity passed to KPP', 'm2/s', conversion=GV%HZ_T_to_m2_s) + CS%id_NLTt = register_diag_field('ocean_model', 'KPP_NLtransport_heat', diag%axesTi, Time, & + 'Non-local transport (Cs*G(sigma)) for heat, as calculated by [CVMix] KPP', 'nondim') + CS%id_NLTs = register_diag_field('ocean_model', 'KPP_NLtransport_salt', diag%axesTi, Time, & + 'Non-local tranpsort (Cs*G(sigma)) for scalars, as calculated by [CVMix] KPP', 'nondim') CS%id_EnhK = register_diag_field('ocean_model', 'EnhK', diag%axesTI, Time, & 'Langmuir number enhancement to K as used by [CVMix] KPP','nondim') CS%id_EnhVt2 = register_diag_field('ocean_model', 'EnhVt2', diag%axesTL, Time, & @@ -629,30 +634,57 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) CS%id_La_SL = register_diag_field('ocean_model', 'KPP_La_SL', diag%axesT1, Time, & 'Surface-layer Langmuir number computed in [CVMix] KPP','nondim') + ! only available when StokesMOST is enabled + if (CS%StokesMOST) then + CS%id_ERdepth = register_diag_field('ocean_model', 'ERdepth', diag%axesT1, Time, & + 'Entrainment Rule Boundary Layer depth percent', 'nondim') + CS%id_RNdepth = register_diag_field('ocean_model', 'RNdepth', diag%axesT1, Time, & + 'Richardson Number Boundary Layer depth percent', 'nondim') + CS%id_StokesXI = register_diag_field('ocean_model', 'StokesXI', diag%axesT1, Time, & + 'Stokes Similarity Parameter', 'nondim') + CS%id_Lam2 = register_diag_field('ocean_model', 'Lam2', diag%axesT1, Time, & + 'Ustk0/ustar', 'nondim') + CS%id_BEdE_ER = register_diag_field('ocean_model', 'BEdE_ER', diag%axesT1, Time, & + 'Entrainment Rule BEdE_ER', 'm3 s-3', conversion=US%L_T_to_m_s**3) + CS%id_PU_TKE = register_diag_field('ocean_model', 'PU_TKE' , diag%axesT1, Time, & + 'Shear production of surface layer TKE', 'm3 s-3') + CS%id_PS_TKE = register_diag_field('ocean_model', 'PS_TKE' , diag%axesT1, Time, & + 'Stokes production of surface layer TKE', 'm3 s-3') + CS%id_PB_TKE = register_diag_field('ocean_model', 'PB_TKE' , diag%axesT1, Time, & + 'Buoyancy production of surface layer TKE', 'm3 s-3') + ! arrays only needed when StokesMOST is enabled + allocate( CS%Lam2 ( SZI_(G), SZJ_(G) ), source=0. ) + allocate( CS%PU_TKE( SZI_(G), SZJ_(G) ), source=0. ) + allocate( CS%PS_TKE( SZI_(G), SZJ_(G) ), source=0. ) + allocate( CS%PB_TKE( SZI_(G), SZJ_(G) ), source=0. ) + endif + allocate( CS%N( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) - allocate( CS%StokesParXI( SZI_(G), SZJ_(G) ), source=0. ) - allocate( CS%Lam2 ( SZI_(G), SZJ_(G) ), source=0. ) - allocate( CS%kOBL( SZI_(G), SZJ_(G) ), source=0. ) + allocate( CS%StokesXI( SZI_(G), SZJ_(G) ), source=0. ) allocate( CS%La_SL( SZI_(G), SZJ_(G) ), source=0. ) allocate( CS%Vt2( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) - if (CS%id_OBLdepth_original > 0) allocate( CS%OBLdepth_original( SZI_(G), SZJ_(G) ) ) - + allocate( CS%kOBL( SZI_(G), SZJ_(G) ), source=0. ) allocate( CS%OBLdepthprev( SZI_(G), SZJ_(G) ), source=0.0 ) - if (CS%id_BulkDrho > 0) allocate( CS%dRho( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) - if (CS%id_BulkUz2 > 0) allocate( CS%Uz2( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) + allocate( CS%ERdepth( SZI_(G), SZJ_(G) ), source=0. ) + allocate( CS%RNdepth( SZI_(G), SZJ_(G) ), source=0. ) + if (CS%id_BulkRi > 0) allocate( CS%BulkRi( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) - if (CS%id_Sigma > 0) allocate( CS%sigma( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) - if (CS%id_Ws > 0) allocate( CS%Ws( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) if (CS%id_N2 > 0) allocate( CS%N2( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) + if (CS%id_Ws > 0) allocate( CS%Ws( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) + if (CS%id_BulkUz2 > 0) allocate( CS%Uz2( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) + if (CS%id_BulkDrho > 0) allocate( CS%dRho( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) + if (CS%id_Sigma > 0) allocate( CS%sigma( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) + if (CS%id_Kv_KPP > 0) allocate( CS%Kv_KPP( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) if (CS%id_Kt_KPP > 0) allocate( CS%Kt_KPP( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) if (CS%id_Ks_KPP > 0) allocate( CS%Ks_KPP( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) - if (CS%id_Kv_KPP > 0) allocate( CS%Kv_KPP( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) if (CS%id_Tsurf > 0) allocate( CS%Tsurf( SZI_(G), SZJ_(G) ), source=0. ) if (CS%id_Ssurf > 0) allocate( CS%Ssurf( SZI_(G), SZJ_(G) ), source=0. ) if (CS%id_Usurf > 0) allocate( CS%Usurf( SZIB_(G), SZJ_(G) ), source=0. ) if (CS%id_Vsurf > 0) allocate( CS%Vsurf( SZI_(G), SZJB_(G) ), source=0. ) if (CS%id_EnhVt2 > 0) allocate( CS%EnhVt2( SZI_(G), SZJ_(G), SZK_(GV) ), source=0. ) if (CS%id_EnhK > 0) allocate( CS%EnhK( SZI_(G), SZJ_(G), SZK_(GV)+1 ), source=0. ) + if (CS%id_OBLdepth_original > 0) allocate( CS%OBLdepth_original( SZI_(G), SZJ_(G) ) ) + if (CS%id_BEdE_ER > 0) allocate( CS%BEdE_ER( SZI_(G), SZJ_(G) ), source=0. ) id_clock_KPP_calc = cpu_clock_id('Ocean KPP calculate)', grain=CLOCK_MODULE) id_clock_KPP_compute_BLD = cpu_clock_id('(Ocean KPP comp BLD)', grain=CLOCK_ROUTINE) @@ -852,7 +884,7 @@ subroutine KPP_calculate(CS, G, GV, US, h, tv, uStar, buoyFlux, Kt, Ks, Kv, & GV%ke, & ! (in) Number of levels to compute coeffs for GV%ke, & ! (in) Number of levels in array shape Langmuir_EFactor=LangEnhK,& ! Langmuir enhancement multiplier - StokesXi = CS%StokesParXI(i,j), & ! Stokes forcing parameter + StokesXi = CS%StokesXI(i,j), & ! Stokes forcing parameter CVMix_kpp_params_user=CS%KPP_params ) ! safety check, Kviscosity and Kdiffusivity must be >= 0 @@ -1025,6 +1057,8 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl real, dimension( GV%ke+1 ) :: N_col ! A column of buoyancy frequencies at interfaces in MKS units [s-1] real :: surfFricVel ! Surface friction velocity in MKS units [m s-1] real :: surfBuoyFlux ! Surface buoyancy flux in MKS units [m2 s-3] + real :: surfBuoy_NS ! Non-solar surface buoyancy flux in MKS units [m2 s-3] + real :: etaDk ! Approximate solar decay from surfBuoyFlux2 (2) and (3) [m-1] real :: Coriolis ! Coriolis parameter at tracer points in MKS units [s-1] real :: KPP_OBL_depth ! Boundary layer depth calculated by CVMix_kpp_compute_OBL_depth in MKS units [m] @@ -1066,18 +1100,22 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl real :: surfHuS, surfHvS ! Stokes drift velocities integrated over the boundary layer [Z L T-1 ~> m2 s-1] real :: surfUs, surfVs ! Stokes drift velocities averaged over the boundary layer [Z T-1 ~> m s-1] - integer :: i, j, k, km1, kk, ksfc, ktmp ! Loop indices - + integer :: i, j, k, km1, kk, ksfc, ktmp ! Loop indices real, dimension(GV%ke) :: uE_H, vE_H ! Eulerian velocities h-points, centers [L T-1 ~> m s-1] real, dimension(GV%ke) :: uS_H, vS_H ! Stokes drift components h-points, centers [L T-1 ~> m s-1] real, dimension(GV%ke) :: uSbar_H, vSbar_H ! Cell Average Stokes drift h-points [L T-1 ~> m s-1] real, dimension(GV%ke+1) :: uS_Hi, vS_Hi ! Stokes Drift components at interfaces [L T-1 ~> m s-1] - real :: uS_SLD , vS_SLD, uS_SLC , vS_SLC, uSbar_SLD, vSbar_SLD ! Stokes at/to to Surface Layer Extent - ! [L T-1 ~> m s-1] + real :: uS_SL, vS_SL ! Stokes at Surface Layer Depth [L T-1 ~> m s-1] + real :: uSb_SL, vSb_SL ! Average Stokes to Surface Layer Depths [L T-1 ~> m s-1] real :: StokesXI ! Stokes similarity parameter [nondim] - real, dimension( GV%ke ) :: StokesXI_1d , StokesVt_1d ! Parameters of TKE production ratio [nondim] - real :: Llimit ! Stable boundary Layer Limit = vonk Lstar [Z ~> m] - integer :: kbl ! index of cell containing boundary layer depth + real :: BEdE_ER ! Entrainment Rule [ m3 s-3 ] + real :: PU_TKE, PS_TKE, PB_TKE ! Shear, Stokes, Buoyancy TKE production rate [ m3 s-3 ] + real, dimension( GV%ke ) :: StokesXI_1d ! Parameters of TKE production ratio [nondim] + real, dimension( GV%ke ) :: BEdE_ER_1d ! Entrainment Rule parameterized [Z^3 T-3 ~> m s-1] + real :: ERdepth ! Entrainment Rule Boundary layer depth CVMix_kpp_compute_ER_depth in MKS units [m] + real :: check ! Entrainment Rule Boundary layer depth CVMix_kpp_compute_ER_depth in MKS units [m] + real :: Llimit ! Stable boundary Layer Limit = vonk Lstar [Z ~> m] + integer :: kbl ! index of cell containing boundary layer depth [nondim] if (CS%Stokes_Mixing .and. .not.associated(Waves)) call MOM_error(FATAL, & "KPP_compute_BLD: The Waves control structure must be associated if STOKES_MIXING is True.") @@ -1094,9 +1132,9 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl ! some constants GoRho = US%Z_to_m*US%s_to_T**2 * (GV%g_Earth_Z_T2 / GV%Rho0) if (GV%Boussinesq) then - GoRho_Z_L2 = GV%Z_to_H * GV%g_Earth_Z_T2 / GV%Rho0 + GoRho_Z_L2 = US%L_to_Z**2 * GV%Z_to_H * GV%g_Earth / GV%Rho0 else - GoRho_Z_L2 = GV%g_Earth_Z_T2 * GV%RZ_to_H + GoRho_Z_L2 = US%L_to_Z**2 * GV%g_Earth * GV%RZ_to_H endif buoy_scale = US%L_to_m**2*US%s_to_T**3 @@ -1112,28 +1150,44 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl !$OMP Temp_1D, salt_1D, surfBuoyFlux2, MLD_guess, LA, rho_1D, & !$OMP deltarho, deltaBuoy, N2_1d, ws_1d, LangEnhVT2,KPP_OBL_depth, z_cell, & !$OMP z_inter, OBL_depth, BulkRi_1d, zBottomMinusOffset, uE_H, vE_H, & - !$OMP uS_H, vS_H, uSbar_H, vSbar_H , uS_Hi, vS_Hi, & - !$OMP uS_SLD, vS_SLD, uS_SLC, vS_SLC, uSbar_SLD, vSbar_SLD, & - !$OMP StokesXI, StokesXI_1d, StokesVt_1d, kbl) & + !$OMP uS_H, vS_H, uSbar_H, vSbar_H , uS_Hi, vS_Hi, uSb_SL, vSb_SL, & + !$OMP uS_SL, vS_SL, StokesXI, StokesXI_1d, surfBuoy_NS, etadk, & + !$OMP BEdE_ER_1d, ERdepth, BEdE_ER, PU_TKE, PS_TKE, PB_TKE, kbl), & !$OMP shared(G, GV, CS, US, uStar, h, dz, buoy_scale, buoyFlux, & - !$OMP Temp, Salt, waves, tv, GoRho, GoRho_Z_L2, u, v, lamult, Vt_layer) + !$OMP Temp, Salt, waves, tv, GoRho, GoRho_Z_L2, u, v, lamult, & + !$OMP Vt_layer) + do j = G%jsc, G%jec do i = G%isc, G%iec ; if (G%mask2dT(i,j) > 0.0) then + iFaceHeight(:) = 0.0 ! BBL is always relative to the surface iFaceHeight(1) + do k=1,GV%ke U_H(k) = 0.5 * (u(I,j,k)+u(I-1,j,k)) V_H(k) = 0.5 * (v(i,J,k)+v(i,J-1,k)) enddo + if (CS%StokesMOST) then - do k=1,GV%ke - uE_H(k) = 0.5 * (u(I,j,k)+u(I-1,j,k)-Waves%US_x(I,j,k)-Waves%US_x(I-1,j,k)) - vE_H(k) = 0.5 * (v(i,J,k)+v(i,J-1,k)-Waves%US_y(i,J,k)-Waves%US_y(i,J-1,k)) - enddo + ! Load surface Stokes uS_Hi(1), vS_Hi(1); 1.0 is a dummy number + call Compute_StokesDrift(i, j, 1.0, iFaceHeight(1), & + 0.5*h(i,j,1), iFaceHeight(1), -h(i,j,1), & ! zBL, zSLtop, zSL + uS_Hi(1), vS_Hi(1), uS_H(1), vS_H(1), uS_SL, vS_SL, & + uSbar_H(1), vSbar_H(1), uSb_SL, vSb_SL, waves) endif + ! things independent of position within the column Coriolis = 0.25*US%s_to_T*( (G%CoriolisBu(i,j) + G%CoriolisBu(i-1,j-1)) + & (G%CoriolisBu(i-1,j) + G%CoriolisBu(i,j-1)) ) surfFricVel = US%Z_to_m*US%s_to_T * uStar(i,j) + ! Estimate non-solar surface buoyancy flux + ! Ideally, this should be provided to this subroutine. However, right now only the + ! total surface flux (solar + non-solar) is provided. + surfBuoy_NS = 0.0 ! temporary surface solar + if ( (buoyFlux(i,j,3) > 0.0) .and. (buoyFlux(i,j,3) < buoyFlux(i,j,2)) ) then + etaDk = alog(buoyFlux(i,j,2)/buoyFlux(i,j,3)) / (dz(i,j,2) + GV%H_subroundoff) ! (z_inter(2)-z_inter(3)) + surfBuoy_NS = buoyFlux(i,j,2) * exp( -etaDk * dz(i,j,1) ) ! Approximate surface solar buoyancy flux + endif + surfBuoy_NS = buoyFlux(i,j,1) - surfBuoy_NS ! Total - solar = non-solar surface buoyancy flux ! Bulk Richardson number computed for each cell in a column, ! assuming OBLdepth = grid cell depth. After Rib(k) is @@ -1141,16 +1195,12 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl ! the actual OBLdepth. This approach avoids need to iterate ! on the OBLdepth calculation. It follows that used in MOM5 ! and POP. - iFaceHeight(1) = 0.0 ! BBL is all relative to the surface pRef = 0. ; if (associated(tv%p_surf)) pRef = tv%p_surf(i,j) hcorr = 0. - if (CS%StokesMOST) call Compute_StokesDrift( i, j, h(i,j,1) , iFaceHeight(1), & - uS_Hi(1), vS_Hi(1), uS_H(1), vS_H(1), uSbar_H(1), vSbar_H(1), Waves) - do k=1,GV%ke ! cell center and cell bottom in meters (negative values in the ocean) - dh = dz(i,j,k) ! Nominal thickness to use for increment + dh = dz(i,j,k) ! Nominal thickness to use for increment dh = dh + hcorr ! Take away the accumulated error (could temporarily make dh<0) hcorr = min( dh - CS%min_thickness, 0. ) ! If inflating then hcorr<0 dh = max( dh, CS%min_thickness ) ! Limit increment dh>=min_thickness @@ -1173,22 +1223,29 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl surfBuoyFlux = buoy_scale * & (buoyFlux(i,j,1) - 0.5*(buoyFlux(i,j,max(2,k))+buoyFlux(i,j,k+1)) ) surfBuoyFlux2(k) = surfBuoyFlux + call Compute_StokesDrift(i,j, iFaceHeight(k),iFaceHeight(k+1), & - uS_Hi(k+1), vS_Hi(k+1), uS_H(k), vS_H(k), uSbar_H(k), vSbar_H(k), Waves) - call Compute_StokesDrift(i,j, iFaceHeight(ksfc) , -SLdepth_0d, & - uS_SLD , vS_SLD, uS_SLC , vS_SLC, uSbar_SLD, vSbar_SLD, Waves) - call cvmix_kpp_compute_StokesXi( iFaceHeight,CellHeight,ksfc ,SLdepth_0d,surfBuoyFlux, & - surfFricVel,waves%omega_w2x(i,j), uE_H, vE_H, uS_Hi, vS_Hi, uSbar_H, vSbar_H, uS_SLD,& - vS_SLD, uSbar_SLD, vSbar_SLD, StokesXI, CVMix_kpp_params_user=CS%KPP_params ) + cellHeight(k),iFaceHeight(ksfc),-SLdepth_0d, & + uS_Hi(k+1), vS_Hi(k+1), uS_H(k), vS_H(k), uS_SL, vS_SL, & + uSbar_H(k), vSbar_H(k), uSb_SL, vSb_SL, waves) + uE_H(k) = U_H(k) - 0.5 * (Waves%US_x(I,j,k)+Waves%US_x(I-1,j,k)) + vE_H(k) = V_H(k) - 0.5 * (Waves%US_y(i,J,k)+Waves%US_y(i,J-1,k)) + + call cvmix_kpp_compute_StokesXi( iFaceHeight, CellHeight, ksfc ,SLdepth_0d, surfBuoyFlux, & + surfBuoy_NS,surfFricVel,waves%omega_w2x(i,j), uE_H, vE_H, uS_Hi, vS_Hi, uSbar_H, vSbar_H, & + uS_SL, vS_SL, uSb_SL, vSb_SL, StokesXI, BEdE_ER, PU_TKE, PS_TKE, PB_TKE, & + CVMix_kpp_params_user=CS%KPP_params ) + + ! Save 1D Stokes XI similarity parameter and entrainment rule StokesXI_1d(k) = StokesXI - StokesVt_1d(k) = 0.0 ! StokesXI + BEdE_ER_1d(k) = BEdE_ER ! average temperature, salinity, u and v over surface layer starting at ksfc delH = SLdepth_0d + iFaceHeight(ksfc) surfHtemp = Temp(i,j,ksfc) * delH surfHsalt = Salt(i,j,ksfc) * delH - surfHu = (uE_H(ksfc) + uSbar_SLD) * delH - surfHv = (vE_H(ksfc) + vSbar_SLD) * delH + surfHu = (uE_H(ksfc) + uSb_SL) * delH + surfHv = (vE_H(ksfc) + vSb_SL) * delH hTot = delH do ktmp = 1,ksfc-1 ! if ksfc >=2 delH = h(i,j,ktmp)*GV%H_to_Z @@ -1204,8 +1261,8 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl surfU = surfHu * I_hTot surfV = surfHv * I_hTot - Uk = uE_H(k) + uS_H(k) - surfU - Vk = vE_H(k) + vS_H(k) - surfV + Uk = u_H(k) - surfU + Vk = v_H(k) - surfV else !not StokesMOST StokesXI_1d(k) = 0.0 @@ -1219,13 +1276,10 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl surfHvS = 0.0 hTot = 0.0 do ktmp = 1,ksfc - ! SLdepth_0d can be between cell interfaces delH = min( max(0.0, SLdepth_0d - hTot), dz(i,j,ktmp) ) - ! surface layer thickness hTot = hTot + delH - ! surface averaged fields surfHtemp = surfHtemp + Temp(i,j,ktmp) * delH surfHsalt = surfHsalt + Salt(i,j,ktmp) * delH @@ -1237,24 +1291,18 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl endif enddo - !I_hTot = 1./hTot - !surfTemp = surfHtemp * I_hTot - !surfSalt = surfHsalt * I_hTot - !surfU = surfHu * I_hTot - !surfV = surfHv * I_hTot - !surfUs = surfHus * I_hTot - !surfVs = surfHvs * I_hTot - - surfTemp = surfHtemp / hTot - surfSalt = surfHsalt / hTot - surfU = surfHu / hTot - surfV = surfHv / hTot - surfUs = surfHus / hTot - surfVs = surfHvs / hTot + I_hTot = 1./hTot + surfTemp = surfHtemp * I_hTot + surfSalt = surfHsalt * I_hTot + surfU = surfHu * I_hTot + surfV = surfHv * I_hTot + surfUs = surfHus * I_hTot + surfVs = surfHvs * I_hTot + ! vertical shear between present layer and surface layer averaged surfU and surfV. ! C-grid average to get Uk and Vk on T-points. - Uk = 0.5*(u(i,j,k)+u(i-1,j,k)) - surfU - Vk = 0.5*(v(i,j,k)+v(i,j-1,k)) - surfV + Uk = 0.5*(u(i,j,k)+u(i-1,j,k)) - surfU + Vk = 0.5*(v(i,j,k)+v(i,j-1,k)) - surfV if (CS%Stokes_Mixing) then ! If momentum is mixed down the Stokes drift gradient, then @@ -1301,7 +1349,6 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl CS%La_SL(i,j) = LA endif - ! compute in-situ density call calculate_density(Temp_1D, Salt_1D, pres_1D, rho_1D, tv%eqn_of_state) @@ -1315,7 +1362,7 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl if (GV%Boussinesq .or. GV%semi_Boussinesq) then deltaBuoy(k) = GoRho*(rho_1D(kk+2) - rho_1D(kk+1)) else - deltaBuoy(k) = (US%Z_to_m*US%s_to_T**2) * GV%g_Earth_Z_T2 * & + deltaBuoy(k) = (US%Z_to_m*US%s_to_T**2) * (US%L_to_Z**2 * GV%g_Earth) * & ( (rho_1D(kk+2) - rho_1D(kk+1)) / (0.5 * (rho_1D(kk+2) + rho_1D(kk+1))) ) endif N2_1d(k) = (GoRho_Z_L2 * (rho_1D(kk+2) - rho_1D(kk+3)) ) / & @@ -1335,45 +1382,73 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl z_inter(K) = US%Z_to_m*iFaceHeight(K) enddo - ! CVMix_kpp_compute_turbulent_scales_1d_OBL computes w_s velocity scale at cell centers for - ! CVmix_kpp_compute_bulk_Richardson call to CVmix_kpp_compute_unresolved_shear - ! at sigma=Vt_layer (CS%surf_layer_ext or 1.0) for this calculation. - ! StokesVt_1d controls Stokes enhancement (= 0 for none) - Vt_layer = 1.0 ! CS%surf_layer_ext - call CVMix_kpp_compute_turbulent_scales( & ! 1d_OBL + ! Use CS%deepOBLoffset (<-0.1*iFaceHeight(GV%ke+1)) to avoid vanishingly small layers near the bottom. + zBottomMinusOffset = iFaceHeight(GV%ke) + min( max(CS%deepOBLoffset,0.0), -0.1*iFaceHeight(GV%ke+1)) + + ! use these to check if all points are convered + CS%ERdepth(i,j) = 0.0 + CS%RNdepth(i,j) = 0.0 + + if (CS%fixedOBLdepth) then + CS%OBLdepth(i,j) = CS%fixedOBLdepth_value + CS%OBLdepth(i,j) = max( CS%OBLdepth(i,j), -iFaceHeight(2) ) ! no shallower than top layer + else + ERdepth = 0.0 + if ( CS%StokesMOST .and. (surfBuoy_NS < 0.0) ) then + ! Search for Entrainment rule depth (ER_depth) + call CVMix_kpp_compute_ER_depth( & + z_inter, & ! (in) Interface heights <= 0 [m] + N2_1d, & ! (in) Column of Buoyancy Gradients at interfaces + OBL_depth, & ! (in) Array of assumed OBL depths [m] + surfFricVel, & ! (in) surface friction velocity [m s-1] + surfBuoy_NS, & ! (in) surface non-solar Buoyancy flux + surfBuoyFlux2, & ! (in) Buoyancy flux surface to OBL_depth + StokesXI_1d, & ! (in) Stokes similarity parameter given OBL_depth + BEdE_ER_1d, & ! (in) Parameterized Entrainment Rule given OBL_depth + ERdepth, & ! (out) Entrainment Rule Boundary Layer Depth + CVMix_kpp_params_user=CS%KPP_params ) ! KPP parameters + + if ( ERdepth > -iFaceHeight(2) ) then ! deeper than top layer + CS%OBLdepth(i,j) = US%m_to_Z * ERdepth ! min( ERdepth , -zBottomMinusOffset ) + CS%ERdepth(i,j) = 100. ! check and diagnostic for ER depth calculated + endif + endif + + ! Original Richardson Number method (always the case with CS%StokesMOST=False) + if (CS%ERdepth(i,j) == 0.) then + Vt_layer = 1.0 ! CS%surf_layer_ext + call CVMix_kpp_compute_turbulent_scales( & ! 1d_OBL Vt_layer, & ! (in) Boundary layer extent contributing to unresolved shear OBL_depth, & ! (in) OBL depth [m] surfBuoyFlux2, & ! (in) Buoyancy flux at surface [m2 s-3] surfFricVel, & ! (in) Turbulent friction velocity at surface [m s-1] - xi=StokesVt_1d, & ! (in) Stokes similarity parameter-->1/CHI(xi) enhance of Vt + xi=StokesXi_1d, & ! (in) Stokes similarity parameter-->1/CHI(xi) enhance of Vt w_s=Ws_1d, & ! (out) Turbulent velocity scale profile [m s-1] CVMix_kpp_params_user=CS%KPP_params ) - ! Determine the enhancement factor for unresolved shear - IF (CS%LT_VT2_ENHANCEMENT) then - IF (CS%LT_VT2_METHOD==LT_VT2_MODE_CONSTANT) then - LangEnhVT2 = CS%KPP_VT2_ENH_FAC - elseif (CS%LT_VT2_METHOD==LT_VT2_MODE_VR12) then - !Introduced minimum value for La_SL, so maximum value for enhvt2 is removed. - if (present(lamult)) then - LangEnhVT2 = lamult(i,j) + ! Determine the enhancement factor for unresolved shear + if (CS%LT_VT2_ENHANCEMENT) then + if (CS%LT_VT2_METHOD==LT_VT2_MODE_CONSTANT) then + LangEnhVT2 = CS%KPP_VT2_ENH_FAC + elseif (CS%LT_VT2_METHOD==LT_VT2_MODE_VR12) then + !Introduced minimum value for La_SL, so maximum value for enhvt2 is removed. + if (present(lamult)) then + LangEnhVT2 = lamult(i,j) + else + LangEnhVT2 = sqrt(1.+(1.5*CS%La_SL(i,j))**(-2) + & + (5.4*CS%La_SL(i,j))**(-4)) + endif + else + ! for other methods (e.g., LT_VT2_MODE_RW16, LT_VT2_MODE_LF17), the enhancement factor is + ! computed internally within CVMix using LaSL, bfsfc, and ustar to be passed to CVMix. + LangEnhVT2 = 1.0 + endif else - LangEnhVT2 = sqrt(1.+(1.5*CS%La_SL(i,j))**(-2) + & - (5.4*CS%La_SL(i,j))**(-4)) + LangEnhVT2 = 1.0 endif - else - ! for other methods (e.g., LT_VT2_MODE_RW16, LT_VT2_MODE_LF17), the enhancement factor is - ! computed internally within CVMix using LaSL, bfsfc, and ustar to be passed to CVMix. - LangEnhVT2 = 1.0 - endif - else - LangEnhVT2 = 1.0 - endif - - surfBuoyFlux = buoy_scale * buoyFlux(i,j,1) - ! Calculate Bulk Richardson number from eq (21) of LMD94 - BulkRi_1d = CVmix_kpp_compute_bulk_Richardson( & + ! Calculate Bulk Richardson number from eq (21) of LMD94 + BulkRi_1d = CVmix_kpp_compute_bulk_Richardson( & zt_cntr=z_cell, & ! Depth of cell center [m] delta_buoy_cntr=deltaBuoy, & ! Bulk buoyancy difference, Br-B(z) [m s-2] delta_Vsqr_cntr=deltaU2, & ! Square of resolved velocity difference [m2 s-2] @@ -1385,86 +1460,65 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl uStar=surfFricVel, & ! surface friction velocity [m s-1] CVMix_kpp_params_user=CS%KPP_params ) ! KPP parameters -! ! A hack to avoid KPP reaching the bottom. It was needed during development -! ! because KPP was unable to handle vanishingly small layers near the bottom. -! if (CS%deepOBLoffset>0.) then -! zBottomMinusOffset = iFaceHeight(GV%ke+1) + min(CS%deepOBLoffset, -0.1*iFaceHeight(GV%ke+1)) -! CS%OBLdepth(i,j) = min( CS%OBLdepth(i,j), -zBottomMinusOffset ) -! endif - zBottomMinusOffset = iFaceHeight(GV%ke+1) + min(CS%deepOBLoffset,-0.1*iFaceHeight(GV%ke+1)) - - call CVMix_kpp_compute_OBL_depth( & - BulkRi_1d, & ! (in) Bulk Richardson number - z_inter, & ! (in) Height of interfaces [m] - KPP_OBL_depth, & ! (out) OBL depth [m] - CS%kOBL(i,j), & ! (out) level (+fraction) of OBL extent - zt_cntr=z_cell, & ! (in) Height of cell centers [m] - surf_fric=surfFricVel, & ! (in) Turbulent friction velocity at surface [m s-1] - surf_buoy=surfBuoyFlux2, & ! (in) Buoyancy flux at surface [m2 s-3] - Coriolis=Coriolis, & ! (in) Coriolis parameter [s-1] - Xi = StokesXI_1d, & ! (in) Stokes similarity parameter Lmob limit (1-Xi) - zBottom = zBottomMinusOffset, & ! (in) Numerical limit on OBLdepth - CVMix_kpp_params_user=CS%KPP_params ) ! KPP parameters - CS%OBLdepth(i,j) = US%m_to_Z * KPP_OBL_depth - - if (CS%StokesMOST) then - kbl = int(CS%kOBL(i,j)) - SLdepth_0d = CS%surf_layer_ext*CS%OBLdepth(i,j) - surfBuoyFlux = surfBuoyFlux2(kbl) - ! find ksfc for cell where "surface layer" sits - ksfc = kbl - do ktmp = 1, kbl - if (-1.0*iFaceHeight(ktmp+1) >= SLdepth_0d) then - ksfc = ktmp - exit - endif - enddo - call Compute_StokesDrift(i,j, iFaceHeight(ksfc) , -SLdepth_0d, & - uS_SLD , vS_SLD, uS_SLC , vS_SLC, uSbar_SLD, vSbar_SLD, Waves) - call cvmix_kpp_compute_StokesXi( iFaceHeight,CellHeight,ksfc ,SLdepth_0d, & - surfBuoyFlux, surfFricVel,waves%omega_w2x(i,j), uE_H, vE_H, uS_Hi, & - vS_Hi, uSbar_H, vSbar_H, uS_SLD, vS_SLD, uSbar_SLD, vSbar_SLD, & - StokesXI, CVMix_kpp_params_user=CS%KPP_params ) - CS%StokesParXI(i,j) = StokesXI - CS%Lam2(i,j) = sqrt(US_Hi(1)**2+VS_Hi(1)**2) / MAX(surfFricVel,0.0002) - - else !.not Stokes_MOST - CS%StokesParXI(i,j) = 10.0 - CS%Lam2(i,j) = sqrt(US_Hi(1)**2+VS_Hi(1)**2) / MAX(surfFricVel,0.0002) - - ! A hack to avoid KPP reaching the bottom. It was needed during development - ! because KPP was unable to handle vanishingly small layers near the bottom. - if (CS%deepOBLoffset>0.) then - zBottomMinusOffset = iFaceHeight(GV%ke+1) + min(CS%deepOBLoffset, -0.1*iFaceHeight(GV%ke+1)) - CS%OBLdepth(i,j) = min( CS%OBLdepth(i,j), -zBottomMinusOffset ) - endif + call CVMix_kpp_compute_OBL_depth( & + BulkRi_1d, & ! (in) Bulk Richardson number + z_inter, & ! (in) Height of interfaces [m] + KPP_OBL_depth, & ! (out) OBL depth [m] + CS%kOBL(i,j), & ! (out) level (+fraction) of OBL extent + zt_cntr=z_cell, & ! (in) Height of cell centers [m] + surf_fric=surfFricVel, & ! (in) Turbulent friction velocity at surface [m s-1] + surf_buoy=surfBuoyFlux2, & ! (in) Buoyancy flux at surface [m2 s-3] + Coriolis=Coriolis, & ! (in) Coriolis parameter [s-1] + Xi = StokesXI_1d, & ! (in) Stokes similarity parameter Lmob limit (1-Xi) + zBottom = zBottomMinusOffset, & ! (in) Numerical limit on OBLdepth + CVMix_kpp_params_user=CS%KPP_params ) ! KPP parameters - ! apply some constraints on OBLdepth - if (CS%fixedOBLdepth) CS%OBLdepth(i,j) = CS%fixedOBLdepth_value - CS%OBLdepth(i,j) = max( CS%OBLdepth(i,j), -iFaceHeight(2) ) ! no shallower than top layer - CS%OBLdepth(i,j) = min( CS%OBLdepth(i,j), -iFaceHeight(GV%ke+1) ) ! no deeper than bottom + CS%OBLdepth(i,j) = US%m_to_Z * KPP_OBL_depth + CS%RNdepth(i,j) = 100. ! check and diagnostic + endif ! KPP_OBL_depth + + endif ! fixedOBLdepth + CS%OBLdepth(i,j) = min( CS%OBLdepth(i,j), -zBottomMinusOffset ) ! no deeper than deepOBLoffset off bottom CS%kOBL(i,j) = CVMix_kpp_compute_kOBL_depth( iFaceHeight, cellHeight, CS%OBLdepth(i,j) ) - endif !Stokes_MOST + if (CS%StokesMOST) then + ! Now we have OBLdepth and need to compute diagnostics + kbl = int(CS%kOBL(i,j)) + SLdepth_0d = CS%surf_layer_ext*CS%OBLdepth(i,j) + surfBuoyFlux = surfBuoyFlux2(kbl) + ! find ksfc for cell where "surface layer" sits + ksfc = kbl + do ktmp = 1, kbl + if (-1.0*iFaceHeight(ktmp+1) >= SLdepth_0d) then + ksfc = ktmp + exit + endif + enddo + + call Compute_StokesDrift(i,j, iFaceHeight(kbl), iFaceHeight(kbl+1), & + -CS%OBLdepth(i,j),iFaceHeight(ksfc),-SLdepth_0d, & + uS_Hi(kbl+1), vS_Hi(kbl+1), uS_H(kbl), vS_H(kbl), uS_SL, vS_SL, & + uSbar_H(kbl), vSbar_H(kbl), uSb_SL, vSb_SL, waves) + + call cvmix_kpp_compute_StokesXi(iFaceHeight, CellHeight, ksfc ,SLdepth_0d, surfBuoyFlux, & + surfBuoy_NS,surfFricVel,waves%omega_w2x(i,j), uE_H, vE_H, uS_Hi, vS_Hi, & + uSbar_H, vSbar_H, uS_SL, vS_SL, uSb_SL, vSb_SL, & + StokesXI,BEdE_ER,PU_TKE,PS_TKE,PB_TKE,CVMix_kpp_params_user=CS%KPP_params ) + + CS%Lam2(i,j) = sqrt(US_Hi(1)**2+VS_Hi(1)**2) / surfFricVel + CS%PU_TKE(i,j) = PU_TKE + CS%PS_TKE(i,j) = PS_TKE + CS%PB_TKE(i,j) = PB_TKE + CS%StokesXI(i,j) = StokesXI ! StokesXI_1d(kbl) - ! compute unresolved squared velocity for diagnostics - if (CS%id_Vt2 > 0) then - Vt2_1d(:) = CVmix_kpp_compute_unresolved_shear( & - z_cell, & ! Depth of cell center [m] - ws_cntr=Ws_1d, & ! Turbulent velocity scale profile, at centers [m s-1] - N_iface=N_col, & ! Buoyancy frequency at interface [s-1] - EFactor=LangEnhVT2, & ! Langmuir enhancement factor [nondim] - LaSL=CS%La_SL(i,j), & ! surface layer averaged Langmuir number [nondim] - bfsfc=surfBuoyFlux2, & ! surface buoyancy flux [m2 s-3] - uStar=surfFricVel, & ! surface friction velocity [m s-1] - CVmix_kpp_params_user=CS%KPP_params ) ! KPP parameters - CS%Vt2(i,j,:) = US%m_to_Z**2*US%T_to_s**2 * Vt2_1d(:) endif - ! recompute wscale for diagnostics, now that we in fact know boundary layer depth + ! recompute unresolved squared velocity, wscale and BulkRi for known boundary layer depth + ! compute unresolved squared velocity for diagnostics + ! recompute wscale for diagnostics, !BGR consider if LTEnhancement is wanted for diagnostics - if (CS%id_Ws > 0) then + if ( (CS%id_Ws > 0) .or. (CS%id_Vt2 > 0) .or. (CS%id_BulkRi > 0) ) then call CVMix_kpp_compute_turbulent_scales( & -cellHeight(:)/CS%OBLdepth(i,j), & ! (in) Normalized boundary layer coordinate [nondim] US%Z_to_m*CS%OBLdepth(i,j), & ! (in) OBL depth [m] @@ -1473,26 +1527,51 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl xi=StokesXI, & ! (in) Stokes similarity parameter-->1/CHI(xi) enhance w_s=Ws_1d, & ! (out) Turbulent velocity scale profile [m s-1] CVMix_kpp_params_user=CS%KPP_params) ! KPP parameters - CS%Ws(i,j,:) = US%m_to_Z*US%T_to_s*Ws_1d(:) + if ( CS%id_Ws > 0 ) CS%Ws(i,j,:) = US%m_to_Z*US%T_to_s*Ws_1d(:) + endif + + if ( (CS%id_Vt2 > 0) .or. (CS%id_BulkRi > 0) ) then + Vt2_1d(:) = CVmix_kpp_compute_unresolved_shear( & + z_cell, & ! Depth of cell center [m] + ws_cntr=Ws_1d, & ! Turbulent velocity scale profile, at centers [m s-1] + N_iface=N_col, & ! Buoyancy frequency at interface [s-1] + EFactor=LangEnhVT2, & ! Langmuir enhancement factor [nondim] + LaSL=CS%La_SL(i,j), & ! surface layer averaged Langmuir number [nondim] + bfsfc=surfBuoyFlux2, & ! surface buoyancy flux [m2 s-3] + uStar=surfFricVel, & ! surface friction velocity [m s-1] + CVmix_kpp_params_user=CS%KPP_params ) ! KPP parameters + if (CS%id_Vt2 > 0) CS%Vt2(i,j,:) = US%m_to_Z**2 * US%T_to_s**2 * Vt2_1d(:) + endif + if (CS%id_BulkRi > 0) then + do k = 1, GV%ke + BulkRi_1d(k) = -z_cell(k) * deltaBuoy(kbl) / ( deltaU2(k) + Vt2_1d(k) ) + CS%BulkRi(i,j,k) = BulkRi_1d(k) + enddo endif - ! Diagnostics + ! Diagnostics if (CS%id_N2 > 0) CS%N2(i,j,:) = N2_1d(:) if (CS%id_BulkDrho > 0) CS%dRho(i,j,:) = deltaRho(:) - if (CS%id_BulkRi > 0) CS%BulkRi(i,j,:) = BulkRi_1d(:) if (CS%id_BulkUz2 > 0) CS%Uz2(i,j,:) = US%m_s_to_L_T**2 * deltaU2(:) if (CS%id_Tsurf > 0) CS%Tsurf(i,j) = surfTemp if (CS%id_Ssurf > 0) CS%Ssurf(i,j) = surfSalt if (CS%id_Usurf > 0) CS%Usurf(i,j) = surfU if (CS%id_Vsurf > 0) CS%Vsurf(i,j) = surfV + if (CS%id_BEdE_ER > 0) CS%BEdE_ER(i,j) = BEdE_ER endif ; enddo enddo call cpu_clock_end(id_clock_KPP_compute_BLD) + if (CS%debug .and. CS%StokesMOST) then + call hchksum(CS%PS_TKE, 'MOM_CVMix_KPP: PS_TKE', G%HI) + call hchksum(CS%PU_TKE, 'MOM_CVMix_KPP: PU_TKE', G%HI) + call hchksum(CS%PB_TKE, 'MOM_CVMix_KPP: PB_TKE', G%HI) + endif + ! send diagnostics to post_data - if (CS%id_BulkRi > 0) call post_data(CS%id_BulkRi, CS%BulkRi, CS%diag) + if (CS%id_BulkRi > 0) call post_data(CS%id_BulkRi, CS%BulkRi, CS%diag) if (CS%id_N > 0) call post_data(CS%id_N, CS%N, CS%diag) if (CS%id_N2 > 0) call post_data(CS%id_N2, CS%N2, CS%diag) if (CS%id_Tsurf > 0) call post_data(CS%id_Tsurf, CS%Tsurf, CS%diag) @@ -1507,8 +1586,14 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl if (CS%id_Vt2 > 0) call post_data(CS%id_Vt2, CS%Vt2, CS%diag) if (CS%StokesMOST) then - if (CS%id_StokesXI > 0) call post_data(CS%id_StokesXI, CS%StokesParXI, CS%diag) - if (CS%id_Lam2 > 0) call post_data(CS%id_Lam2 , CS%Lam2 , CS%diag) + if (CS%id_StokesXI > 0) call post_data(CS%id_StokesXI, CS%StokesXI, CS%diag) + if (CS%id_Lam2 > 0) call post_data(CS%id_Lam2 , CS%Lam2, CS%diag) + if (CS%id_BEdE_ER > 0) call post_data(CS%id_BEdE_ER, CS%BEdE_ER, CS%diag) + if (CS%id_ERdepth > 0) call post_data(CS%id_ERdepth, CS%ERdepth, CS%diag) + if (CS%id_RNdepth > 0) call post_data(CS%id_RNdepth, CS%RNdepth, CS%diag) + if (CS%id_PU_TKE > 0) call post_data(CS%id_PU_TKE, CS%PU_TKE, CS%diag) + if (CS%id_PS_TKE > 0) call post_data(CS%id_PS_TKE, CS%PS_TKE, CS%diag) + if (CS%id_PB_TKE > 0) call post_data(CS%id_PB_TKE, CS%PB_TKE, CS%diag) endif ! BLD smoothing: @@ -1633,7 +1718,6 @@ subroutine KPP_smooth_BLD(CS, G, GV, US, dz) end subroutine KPP_smooth_BLD - !> Copies KPP surface boundary layer depth into BLD, in units of [Z ~> m] unless other units are specified. subroutine KPP_get_BLD(CS, BLD, G, US, m_to_BLD_units) type(KPP_CS), pointer :: CS !< Control structure for @@ -1763,47 +1847,75 @@ subroutine KPP_NonLocalTransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, end subroutine KPP_NonLocalTransport_saln -!> Compute Stokes Drift components at zbot < ztop <= 0 and at k=0.5*(ztop+zbot) and -!! average components from ztop to zbot <= 0 -subroutine Compute_StokesDrift(i ,j, ztop, zbot, uS_i, vS_i, uS_k, vS_k, uSbar, vSbar, waves) - - type(wave_parameters_CS), pointer :: waves !< Wave CS for Langmuir turbulence - real, intent(in) :: ztop !< cell top - real, intent(in) :: zbot !< cell bottom - real, intent(inout) :: uS_i !< Stokes u velocity at zbot interface - real, intent(inout) :: vS_i !< Stokes v velocity at zbot interface - real, intent(inout) :: uS_k !< Stokes u velocity at zk center - real, intent(inout) :: vS_k !< Stokes v at zk =0.5(ztop+zbot) - real, intent(inout) :: uSbar !< mean Stokes u (ztop to zbot) - real, intent(inout) :: vSbar !< mean Stokes v (ztop to zbot) - integer, intent(in) :: i !< Meridional index of H-point - integer, intent(in) :: j !< Zonal index of H-point + +!> Compute Stokes Drift components and integrals needed to compute +!! Stokes TKE production parameters. +subroutine Compute_StokesDrift(i ,j, ztop, zbot, zBL, zSLtop, zSL, uS_i, vS_i, uS_k, vS_k, uS_SL, vS_SL, & + uSbar, vSbar, uSb_SL, vSb_SL, waves) + type(wave_parameters_CS), pointer :: waves !< Wave CS for Langmuir turbulence + real, intent(in) :: ztop !< boundary layer cellheight top (<0) [m] + real, intent(in) :: zbot !< boundary layer cellheight bottom (<0) [m] + real, intent(in) :: zBL !< boundary layer cellheight center (<0) [m] + real, intent(in) :: zSLtop !< surface layer cell top [m] + real, intent(in) :: zSL !< surface layer cell depth [m] + real, intent(inout) :: uS_i !< Zonal Stokes velocity at zbot interface [m s-1] + real, intent(inout) :: vS_i !< Meridional Stokes velocity at zbot interface [m s-1] + real, intent(inout) :: uS_k !< Zonal Stokes velocity at zbl [m s-1] + real, intent(inout) :: vS_k !< Meridional Stokes velocity at zbl [m s-1] + real, intent(inout) :: uS_SL !< Zonal Stokes velocity at zSL [m s-1] + real, intent(inout) :: vS_SL !< Meridional Stokes velocity at zSL [m s-1] + real, intent(inout) :: uSbar !< Mean zonal Stokes velocity at ztop [m s-1] + real, intent(inout) :: vSbar !< Mean meridional Stokes velocity at zbot [m s-1] + real, intent(inout) :: uSb_SL !< Mean zonal Stokes velocity at zSLtop [m s-1] + real, intent(inout) :: vSb_SL !< Mean meridional Stokes velocity at zSL [m s-1] + integer, intent(in) :: i !< Meridional index of H-point [nondim] + integer, intent(in) :: j !< Zonal index of H-point [nondim] ! local variables integer :: b !< wavenumber band index - real :: fexp !< an exponential function + real :: fexp !< dummy exponential function real :: WaveNum !< Wavenumber - uS_i = 0.0 - vS_i = 0.0 - uS_k = 0.0 - vS_k = 0.0 - uSbar = 0.0 - vSbar = 0.0 + ! initialize variables + uS_i = 0.0 + vS_i = 0.0 + uS_k = 0.0 + vS_k = 0.0 + uS_SL = 0.0 + vS_SL = 0.0 + uSbar = 0.0 + vSbar = 0.0 + uSb_SL = 0.0 + vSb_SL = 0.0 + do b = 1, waves%NumBands WaveNum = waves%WaveNum_Cen(b) + fexp = exp(2. * WaveNum * zbot) uS_i = uS_i + waves%Ustk_Hb(i,j,b) * fexp vS_i = vS_i + waves%Vstk_Hb(i,j,b) * fexp - fexp = exp( WaveNum * (ztop + zbot) ) + + fexp = exp(2. * WaveNum * zBL ) uS_k = uS_k+ waves%Ustk_Hb(i,j,b) * fexp vS_k = vS_k+ waves%Vstk_Hb(i,j,b) * fexp - fexp = exp(2. * WaveNum * ztop) - exp(2. * WaveNum * zbot) + + fexp = exp(2. * WaveNum * zSL ) + uS_SL = uS_SL + waves%Ustk_Hb(i,j,b) * fexp + vS_SL = vS_SL + waves%Vstk_Hb(i,j,b) * fexp + + fexp = exp(2. * WaveNum * ztop) - exp(2. * WaveNum * zbot ) uSbar = uSbar + 0.5 * waves%Ustk_Hb(i,j,b) * fexp / WaveNum vSbar = vSbar + 0.5 * waves%Vstk_Hb(i,j,b) * fexp / WaveNum + + fexp = exp(2. * WaveNum * zSLtop) - exp(2. * WaveNum * zSL) + uSb_SL = uSb_SL + 0.5 * waves%Ustk_Hb(i,j,b) * fexp / WaveNum + vSb_SL = vSb_SL + 0.5 * waves%Vstk_Hb(i,j,b) * fexp / WaveNum + enddo - uSbar = uSbar / (ztop-zbot) - vSbar = vSbar / (ztop-zbot) + uSbar = uSbar / (ztop-zbot) + vSbar = vSbar / (ztop-zbot) + uSb_SL = uSb_SL / (zSLtop-zSL) + vSb_SL = vSb_SL / (zSLtop-zSL) end subroutine Compute_StokesDrift @@ -1814,7 +1926,6 @@ subroutine KPP_end(CS) if (.not.associated(CS)) return deallocate(CS) - end subroutine KPP_end end module MOM_CVMix_KPP From edf726b641a5ac00e501e381b7a782ea0a6b0bcd Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Fri, 26 Sep 2025 15:11:21 -0600 Subject: [PATCH 25/41] * Fix bug in pRef used in calculate_CVMix_conv (#390) * Change pref to pRef for consistency with rest of code * * Fix bug in pRef used in calculate_CVMix_conv Corrected reference pressure update to use `h(i,j,k-1)` instead of `h(i,j,k)`. Ensures first layer thickness is properly accounted for in pressure integration. --- src/parameterizations/vertical/MOM_CVMix_conv.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parameterizations/vertical/MOM_CVMix_conv.F90 b/src/parameterizations/vertical/MOM_CVMix_conv.F90 index 74a0305ce1..69d835ae95 100644 --- a/src/parameterizations/vertical/MOM_CVMix_conv.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_conv.F90 @@ -174,7 +174,7 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) integer :: kOBL !< level of ocean boundary layer extent real :: g_o_rho0 ! Gravitational acceleration, perhaps divided by density, times unit conversion factors ! [H s-2 R-1 ~> m4 s-2 kg-1 or m s-2] - real :: pref ! Interface pressures [R L2 T-2 ~> Pa] + real :: pRef ! Interface pressures [R L2 T-2 ~> Pa] real :: rhok, rhokm1 ! In situ densities of the layers above and below at the interface pressure [R ~> kg m-3] real :: dh_int ! The distance between layer centers [H ~> m or kg m-2] real :: dh, hcorr ! Limited thicknesses and a cumulative correction [Z ~> m] @@ -211,7 +211,7 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) do K=2,GV%ke ! pRef is pressure at interface between k and km1 [R L2 T-2 ~> Pa]. - pRef = pRef + (GV%H_to_RZ*GV%g_Earth) * h(i,j,k) + pRef = pRef + (GV%H_to_RZ*GV%g_Earth) * h(i,j,k-1) call calculate_density(tv%t(i,j,k), tv%s(i,j,k), pRef, rhok, tv%eqn_of_state) call calculate_density(tv%t(i,j,k-1), tv%s(i,j,k-1), pRef, rhokm1, tv%eqn_of_state) From cc24bff129b12fd09f351b70513019831f372246 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Sun, 28 Sep 2025 20:50:39 -0600 Subject: [PATCH 26/41] Option to add effects of Lam2 into MLE restratification. (#389) * Add entrainment rule BLD calculation to KPP This commit introduces an alternative method for computing the boundary layer depth (BLD) in KPP, based on the entrainment rule. This method is activated when the non-solar surface buoyancy flux (surfBuoy_NS) is negative and STOKES_MOST = True. In all other cases, the standard Richardson Number-based method is used. The non-solar surface buoyancy flux is estimated internally using an exponential attenuation function, since only the total surface buoyancy flux (solar + non-solar) is currently available to the module. Ideally, the non-solar component should be provided explicitly. Several new diagnostics have been added, and some of the existing ones have been updated. Specifically, the parameterized shear, buoyancy, and Stokes TKE production terms are calculated. We conducted multiple tests where these terms are passed to the MLE module and used in the denominator of the Bodner streamfunction. However, because of the small Cr value we adopted (0.01), this had minimal effect on the solutions, so we decided to keep the original simpler implementation and not pursue this option for now. This commit should be evaluated together with https://github.com/CVMix/CVMix-src/pull/106. * Fix typos * Update CVMix to latest commit Include new entreinment rule depth changes. * Revert unit conversion for Vt2 and GoRho * Update description and remove empty line * Split description of variables * Refactor KPP StokesMOST diagnostics and allocations - Removed unused `ustar` array from KPP_CS type. - Restricted registration, allocation, and posting of StokesMOST diagnostics (`StokesXI`, `Lam2`, `BEdE_ER`, `ERdepth`, `RNdepth`, `PU_TKE`, `PS_TKE`, `PB_TKE`) to cases when `CS%StokesMOST` is enabled. - Moved allocations of related arrays inside StokesMOST conditional block. - Updated condition for calculating `surfBuoy_NS` to avoid division by zero in alog(buoyFlux(i,j,2)/buoyFlux(i,j,3)). - Wrapped diagnostic and debug checks in `if (CS%StokesMOST)` conditions. - Minor cleanup of comments and diagnostic labeling. * Add support for Lam2 in MLE and KPP - Introduced `Lam2` as an optional pointer field in `vertvisc_type` and restart registry. - Extended `mixedlayer_restrat` and `mixedlayer_restrat_Bodner` to accept/use `Lam2` when available, with fallback to equilibrium value. - Added `KPP_get_Lam2` routine to expose Lam2 from KPP control structure. - Connected `Lam2` into `diabatic_ALE_legacy` and `diabatic_ALE` and copied into `visc%Lam2` when allocated. - Enabled allocation and restart registration of `Lam2` when STOKES_MOST and Bodner MLE are used. - Updated MOM.F90 call sites to conditionally pass `Lam2`. This integrates Langmuir turbulence effects via Lam2 into MLE restratification. * Fix duplicate declaration of Lam2 * Change paramFile to param_file * Fixed OMP directive in KPP_get_Lam2 * Defined Lam2 in diabatic_ALE * Add ParameterBlock for KPP so STOKES_MOST can be read * Fix segfault by checking CS%visc before accessing Lam2 Wrapped the mixedlayer_restrat call with an outer check on `associated(CS%visc)` to ensure the derived type is valid before testing `CS%visc%Lam2`. This prevents invalid memory references when `CS%visc` is unassociated. * Replace associated with allocated * Replace associated with allocated * Replace allocated with associated for checking CS%visc%Lam2 * Only call KPP_get_Lam2 if visc%Lam2 is associated * Implement conditional logic for passing Lam2 to MLE. Read `StokesMOST` and `wave_enhanced_ustar` to determine whether Lam2 should be passed to the `mixedlayer_restrat` subroutine. * Safely handle optional Lam2 pointer in mixedlayer_restrat Added local logical flag `haveLam2` to ensure Lam2 is only used when both present and associated. This avoids potential segfaults from evaluating `associated(Lam2)` when Lam2 is not passed. * Improve description of WAVE_ENHANCED_USTAR --- src/core/MOM.F90 | 25 +++++++-- src/core/MOM_variables.F90 | 1 + .../lateral/MOM_mixed_layer_restrat.F90 | 54 +++++++++++++------ .../vertical/MOM_CVMix_KPP.F90 | 22 +++++++- .../vertical/MOM_diabatic_driver.F90 | 13 ++++- .../vertical/MOM_set_viscosity.F90 | 13 ++++- 6 files changed, 105 insertions(+), 23 deletions(-) diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index 5533f4b282..38d426cac4 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -315,6 +315,10 @@ module MOM logical :: useMEKE !< If true, call the MEKE parameterization. logical :: use_stochastic_EOS !< If true, use the stochastic EOS parameterizations. logical :: useWaves !< If true, update Stokes drift + logical :: StokesMOST !< If true, use Stokes Similarity package. Needed to decide if Lam2 should + !! be passed to mixedlayer_restrat. + logical :: wave_enhanced_ustar !< If true, enhance ustar in Bodner23. Needed to decide if Lam2 should + !! be passed to mixedlayer_restrat. real :: dtbt_reset_period !< The time interval between dynamic recalculation of the !! barotropic time step [T ~> s]. If this is negative dtbt is never !! calculated, and if it is 0, dtbt is calculated every step. @@ -1427,8 +1431,17 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_tr_adv, & CS%uhtr, CS%vhtr, G%HI, haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2) endif call cpu_clock_begin(id_clock_ml_restrat) - call mixedlayer_restrat(h, CS%uhtr, CS%vhtr, CS%tv, forces, dt, CS%visc%MLD, CS%visc%h_ML, & - CS%visc%sfc_buoy_flx, CS%VarMix, G, GV, US, CS%mixedlayer_restrat_CSp) + if (CS%wave_enhanced_ustar .and. CS%StokesMOST) then + if (associated(CS%visc%Lam2)) then + call mixedlayer_restrat(h, CS%uhtr, CS%vhtr, CS%tv, forces, dt, CS%visc%MLD, CS%visc%h_ML, & + CS%visc%sfc_buoy_flx, CS%VarMix, G, GV, US, CS%mixedlayer_restrat_CSp, CS%visc%Lam2) + else + call MOM_error(FATAL,'step_MOM_dynamics:CS%visc%Lam2 not associated') + endif + else + call mixedlayer_restrat(h, CS%uhtr, CS%vhtr, CS%tv, forces, dt, CS%visc%MLD, CS%visc%h_ML, & + CS%visc%sfc_buoy_flx, CS%VarMix, G, GV, US, CS%mixedlayer_restrat_CSp) + endif call cpu_clock_end(id_clock_ml_restrat) call pass_var(h, G%Domain, clock=id_clock_pass, halo=max(2,CS%cont_stencil)) if (CS%debug) then @@ -2449,12 +2462,16 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, & call get_param(param_file, '', "FPMIX", fpmix, & "If true, add non-local momentum flux increments and diffuse down the Eulerian gradient.", & default=.false., do_not_log=.true.) - if (fpmix .and. .not. CS%split) then call MOM_error(FATAL, "initialize_MOM: "//& "FPMIX=True only works when SPLIT=True.") endif - + ! STOKES_MOST and needed to + call get_param(param_file, '', 'STOKES_MOST', CS%StokesMOST, & + 'If True, use Stokes Similarity package.', & + default=.False., do_not_log=.true.) + call get_param(param_file, '', "WAVE_ENHANCED_USTAR", CS%wave_enhanced_ustar, & + "If true, enhance ustar in Bodner23.", default=.false., do_not_log=.true.) call get_param(param_file, "MOM", "BOUSSINESQ", Boussinesq, & "If true, make the Boussinesq approximation.", default=.true., do_not_log=.true.) call get_param(param_file, "MOM", "SEMI_BOUSSINESQ", semi_Boussinesq, & diff --git a/src/core/MOM_variables.F90 b/src/core/MOM_variables.F90 index cbb8019aa0..9e727b34bc 100644 --- a/src/core/MOM_variables.F90 +++ b/src/core/MOM_variables.F90 @@ -291,6 +291,7 @@ module MOM_variables ! The following elements are pointers so they can be used as targets for pointers in the restart registry. real, pointer, dimension(:,:) :: MLD => NULL() !< Instantaneous active mixing layer depth [Z ~> m]. + real, pointer, dimension(:,:) :: Lam2 => NULL() !< (Langmuir Number)^-2 [nondim]. real, pointer, dimension(:,:) :: h_ML => NULL() !< Instantaneous active mixing layer thickness [H ~> m or kg m-2]. real, pointer, dimension(:,:) :: sfc_buoy_flx => NULL() !< Surface buoyancy flux (derived) [Z2 T-3 ~> m2 s-3]. real, pointer, dimension(:,:,:) :: Kd_shear => NULL() diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 07b29726c2..951f462705 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -102,8 +102,9 @@ module MOM_mixed_layer_restrat !! front-length scales read from a file. type(time_type), pointer :: Time => NULL() !< A pointer to the ocean model's clock. logical :: use_Stanley_ML !< If true, use the Stanley parameterization of SGS T variance - logical :: wave_enhanced_ustar !< If true, enhance ustar for equilibrium surface waves (La-2=11), - !! following Eq. 28 in Bodner23. + logical :: wave_enhanced_ustar !< If true, enhance ustar using surface waves, following Eq. 28 in Bodner23. + !! Use a Langmuir number if provided. Otherwise, assumes equilibrium + !! surface waves (La-2=11.). real :: ustar_min !< A minimum value of ustar in thickness units to avoid numerical !! problems [H T-1 ~> m s-1 or kg m-2 s-1] @@ -149,7 +150,7 @@ module MOM_mixed_layer_restrat !> Driver for the mixed-layer restratification parameterization. !! The code branches between two different implementations depending !! on whether the bulk-mixed layer or a general coordinate are in use. -subroutine mixedlayer_restrat(h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux, VarMix, G, GV, US, CS) +subroutine mixedlayer_restrat(h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux, VarMix, G, GV, US, CS, Lam2) type(ocean_grid_type), intent(inout) :: G !< Ocean grid structure type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -170,17 +171,29 @@ subroutine mixedlayer_restrat(h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux, !! PBL scheme [Z2 T-3 ~> m2 s-3] type(VarMix_CS), intent(in) :: VarMix !< Variable mixing control structure type(mixedlayer_restrat_CS), intent(inout) :: CS !< Module control structure + real, dimension(:,:), optional, pointer :: Lam2 !< (Langmuir Number)^-2 [nondim] + ! local variables + logical :: haveLam2 !< True if optional Lam2 argument is both present and associated + if (.not. CS%initialized) call MOM_error(FATAL, "mixedlayer_restrat: "// & "Module must be initialized before it is used.") + ! Determine if Lam2 should be used + haveLam2 = .false. + if (present(Lam2)) haveLam2 = associated(Lam2) + if (GV%nkml>0) then ! Original form, written for the isopycnal model with a bulk mixed layer call mixedlayer_restrat_BML(h, uhtr, vhtr, tv, forces, dt, G, GV, US, CS) elseif (CS%use_Bodner) then ! Implementation of Bodner et al., 2023 - call mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux) + if (haveLam2) then + call mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux, Lam2) + else + call mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, dt, MLD, h_MLD, bflux) + endif else ! Implementation of Fox-Kemper et al., 2008, to work in general coordinates call mixedlayer_restrat_OM4(h, uhtr, vhtr, tv, forces, dt, h_MLD, VarMix, G, GV, US, CS) @@ -755,7 +768,7 @@ end function mu !> Calculates a restratifying flow in the mixed layer, following the formulation !! used in Bodner et al., 2023 (B22) -subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, dt, BLD, h_MLD, bflux) +subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, dt, BLD, h_MLD, bflux, Lam2) ! Arguments type(mixedlayer_restrat_CS), intent(inout) :: CS !< Module control structure type(ocean_grid_type), intent(inout) :: G !< Ocean grid structure @@ -776,6 +789,9 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d !! the PBL scheme [H ~> m or kg m-2] real, dimension(:,:), pointer :: bflux !< Surface buoyancy flux provided by the !! PBL scheme [Z2 T-3 ~> m2 s-3] + real, dimension(:,:), optional, pointer :: Lam2 !< (Langmuir Number)^-2, which is defined as + !! Surface Stokes/ustar [nondim] + ! Local variables real :: uhml(SZIB_(G),SZJ_(G),SZK_(GV)) ! zonal mixed layer transport [H L2 T-1 ~> m3 s-1 or kg s-1] real :: vhml(SZI_(G),SZJB_(G),SZK_(GV)) ! merid mixed layer transport [H L2 T-1 ~> m3 s-1 or kg s-1] @@ -809,7 +825,6 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d real :: w_star3 ! Cube of turbulent convective velocity [Z3 T-3 ~> m3 s-3] real :: u_star3 ! Cube of surface friction velocity [Z3 T-3 ~> m3 s-3] real :: E_ustar ! Surface wave ustar enhancement factor [nondim] - real :: Lam2 ! Reciprocal of the squrared turbulent Langmuir number [nondim] real :: r_wpup ! reciprocal of vertical momentum flux [T2 L-1 H-1 ~> s2 m-2 or m s2 kg-1] real :: absf ! absolute value of f, interpolated to velocity points [T-1 ~> s-1] real :: f_h ! Coriolis parameter at h-points [T-1 ~> s-1] @@ -833,6 +848,7 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d ! fractional power [T3 m3 Z-3 s-3 ~> 1] real :: m2_s2_to_Z2_T2 ! Conversion factors to restore scaling after a term is raised to a ! fractional power [Z2 s2 T-2 m-2 ~> 1] + real, parameter :: Lam2_eq = 11. ! (Langmuir Number)^-2 assuming wind wave equilibrium [nondim] real, parameter :: two_thirds = 2./3. ! [nondim] logical :: line_is_empty, keep_going integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state @@ -873,15 +889,20 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d ! Extract the friction velocity from the forcing type. call find_ustar(forces, tv, U_star_2d, G, GV, US, halo=1) - ! wave enhancement of ustar following Eq. 28 in Bodner23 + ! Wave Enhanced of ustar following Eq. 28 in Bodner23 if (CS%wave_enhanced_ustar) then - ! Assuming wind wave equilibrium (Lam2=11) until Lam2 becomes available - Lam2 = 11. - E_ustar = sqrt( 1.0 + (Lam2 * 0.104) + (Lam2 * Lam2 * 0.00118)) - ! Wave Enhanced - do j=js-1,je+1 ; do i=is-1,ie+1 - U_star_2d(i,j) = E_ustar * U_star_2d(i,j) - enddo ; enddo + if (present(Lam2) .and. associated(Lam2)) then + do j=js-1,je+1 ; do i=is-1,ie+1 + E_ustar = sqrt( 1.0 + (Lam2(i,j) * 0.104) + (Lam2(i,j) * Lam2(i,j) * 0.00118)) + U_star_2d(i,j) = E_ustar * U_star_2d(i,j) + enddo ; enddo + else + ! Assuming wind wave equilibrium (Lam2=11) + E_ustar = sqrt( 1.0 + (Lam2_eq * 0.104) + (Lam2_eq * Lam2_eq * 0.00118)) + do j=js-1,je+1 ; do i=is-1,ie+1 + U_star_2d(i,j) = E_ustar * U_star_2d(i,j) + enddo ; enddo + endif endif if (CS%debug) then @@ -1755,8 +1776,9 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS, "parameter a micron away from the equator.", & units="m2 s-2", default=1.0e-24, scale=US%m_to_Z**2*US%T_to_s**2) call get_param(param_file, mdl, "WAVE_ENHANCED_USTAR", CS%wave_enhanced_ustar, & - "If true, enhance ustar for equilibrium surface waves (La-2=11.), "// & - "following Eq. 28 in Bodner23.", default=.false.) + "If true, enhance ustar using surface waves, following Eq. 28 in Bodner23. " //& + "Use a Langmuir number if provided. Otherwise, assumes equilibrium "// & + "surface waves (La-2=11.).", default=.false.) call get_param(param_file, mdl, "TAIL_DH", CS%MLE_tail_dh, & "Fraction by which to extend the mixed-layer restratification "//& "depth used for a smoother stream function at the base of "//& diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index ca274999dc..a7c1b4e610 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -47,6 +47,8 @@ module MOM_CVMix_KPP public :: KPP_NonLocalTransport_saln public :: KPP_NonLocalTransport public :: KPP_get_BLD +public :: KPP_get_Lam2 + ! Enumerated constants integer, private, parameter :: NLT_SHAPE_CVMix = 0 !< Use the CVMix profile @@ -161,6 +163,7 @@ module MOM_CVMix_KPP ! Diagnostics arrays real, pointer, dimension(:,:) :: OBLdepth !< Depth (positive) of ocean boundary layer (OBL) [Z ~> m] + real, pointer, dimension(:,:) :: Lam2 !< La^(-2) = Ustk0/u* [nondim] real, allocatable, dimension(:,:,:) :: BulkRi !< Bulk Richardson number for each layer [nondim] real, allocatable, dimension(:,:,:) :: N !< Brunt-Vaisala frequency [T-1 ~> s-1] real, allocatable, dimension(:,:,:) :: N2 !< Squared Brunt-Vaisala frequency [T-2 ~> s-2] @@ -184,7 +187,6 @@ module MOM_CVMix_KPP real, allocatable, dimension(:,:) :: RNdepth !< Percent use Ri Number boundary layer depth [nondim] real, allocatable, dimension(:,:) :: StokesXI !< Stokes similarity parameter [nondim] real, allocatable, dimension(:,:) :: BEdE_ER !< Enrtainment Rule's Parameterized BEdE [ m3 s-3 ] - real, allocatable, dimension(:,:) :: Lam2 !< La^(-2) = Ustk0/u* ! Other arrays real, allocatable, dimension(:,:) :: kOBL !< Level (+fraction) of OBL extent [nondim] real, allocatable, dimension(:,:) :: OBLdepthprev !< previous Depth (positive) of OBL [Z ~> m] @@ -1740,6 +1742,24 @@ subroutine KPP_get_BLD(CS, BLD, G, US, m_to_BLD_units) end subroutine KPP_get_BLD +!> Copies CS%Lam2 into Lam2. +subroutine KPP_get_Lam2(CS, Lam2, G, US) + type(KPP_CS), pointer :: CS !< Control structure for + !! this module + type(ocean_grid_type), intent(in) :: G !< Grid structure + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type + real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: Lam2 !< (Langmuir Number)^-2 [nondim] + + ! Local variables + integer :: i,j ! Horizontal indices + + !$OMP parallel do default(none) shared(Lam2, CS, G) + do j = G%jsc, G%jec ; do i = G%isc, G%iec + Lam2(i,j) = CS%Lam2(i,j) + enddo ; enddo + +end subroutine KPP_get_Lam2 + !> Apply KPP non-local transport of surface fluxes for a given tracer subroutine KPP_NonLocalTransport(CS, G, GV, h, nonLocalTrans, surfFlux, & dt, diag, tr_ptr, scalar, flux_scale) diff --git a/src/parameterizations/vertical/MOM_diabatic_driver.F90 b/src/parameterizations/vertical/MOM_diabatic_driver.F90 index 0089d17cbf..e60a292a37 100644 --- a/src/parameterizations/vertical/MOM_diabatic_driver.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_driver.F90 @@ -53,7 +53,7 @@ module MOM_diabatic_driver use MOM_internal_tides, only : internal_tides_init, internal_tides_end, int_tide_CS use MOM_kappa_shear, only : kappa_shear_is_used use MOM_CVMix_KPP, only : KPP_CS, KPP_init, KPP_compute_BLD, KPP_calculate -use MOM_CVMix_KPP, only : KPP_end, KPP_get_BLD, register_KPP_restarts +use MOM_CVMix_KPP, only : KPP_end, KPP_get_BLD, register_KPP_restarts, KPP_get_Lam2 use MOM_CVMix_KPP, only : KPP_NonLocalTransport_temp, KPP_NonLocalTransport_saln use MOM_oda_incupd, only : apply_oda_incupd, oda_incupd_CS use MOM_opacity, only : opacity_init, opacity_end, opacity_CS @@ -591,6 +591,7 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Tim real, dimension(SZI_(G),SZJ_(G)) :: & U_star, & ! The friction velocity [Z T-1 ~> m s-1]. + Lam2, & ! (Langmuir Number)^-2 [nondim] KPP_temp_flux, & ! KPP effective temperature flux [C H T-1 ~> degC m s-1 or degC kg m-2 s-1] KPP_salt_flux, & ! KPP effective salt flux [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1] SkinBuoyFlux, & ! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL @@ -784,10 +785,14 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Tim endif call KPP_get_BLD(CS%KPP_CSp, BLD(:,:), G, US) + if (associated(visc%Lam2)) then + call KPP_get_Lam2(CS%KPP_CSp, Lam2(:,:), G, US) + endif ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions. if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV) if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:) if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1) + if (associated(visc%Lam2)) visc%Lam2(:,:) = Lam2(:,:) if (.not.CS%KPPisPassive) then !$OMP parallel do default(shared) @@ -1321,6 +1326,7 @@ subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, real, dimension(SZI_(G),SZJ_(G)) :: & U_star, & ! The friction velocity [Z T-1 ~> m s-1]. + Lam2, & ! (Langmuir Number)^-2 [nondim] KPP_temp_flux, & ! KPP effective temperature flux [C H T-1 ~> degC m s-1 or degC kg m-2 s-1] KPP_salt_flux, & ! KPP effective salt flux [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1] SkinBuoyFlux, & ! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL @@ -1517,11 +1523,16 @@ subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves) endif + call KPP_get_BLD(CS%KPP_CSp, BLD(:,:), G, US) + if (associated(visc%Lam2)) then + call KPP_get_Lam2(CS%KPP_CSp, Lam2(:,:), G, US) + endif ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions. if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV) if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:) if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1) * US%L_to_Z**2 + if (associated(visc%Lam2)) visc%Lam2(:,:) = Lam2(:,:) if (showCallTree) call callTree_waypoint("done with KPP_calculate (diabatic)") if (CS%debug) then diff --git a/src/parameterizations/vertical/MOM_set_viscosity.F90 b/src/parameterizations/vertical/MOM_set_viscosity.F90 index 888bb098c0..499e388d06 100644 --- a/src/parameterizations/vertical/MOM_set_viscosity.F90 +++ b/src/parameterizations/vertical/MOM_set_viscosity.F90 @@ -2712,7 +2712,7 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C ! Local variables logical :: use_kappa_shear, KS_at_vertex logical :: adiabatic, useKPP, useEPBL, use_ideal_age - logical :: do_brine_plume, use_hor_bnd_diff, use_neutral_diffusion, use_fpmix + logical :: do_brine_plume, use_hor_bnd_diff, use_neutral_diffusion, use_fpmix, use_StokesMOST logical :: use_CVMix_shear, MLE_use_PBL_MLD, MLE_use_Bodner, use_CVMix_conv integer :: isd, ied, jsd, jed, nz real :: hfreeze !< If hfreeze > 0 [Z ~> m], melt potential will be computed. @@ -2795,6 +2795,10 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C default=.false., do_not_log=.true.) call get_param(param_file, mdl, "FPMIX", use_fpmix, & default=.false., do_not_log=.true.) + call openParameterBlock(param_file, 'KPP', do_not_log=.true.) + call get_param(param_file, mdl, 'STOKES_MOST', use_StokesMOST, & + default=.false., do_not_log=.true.) + call closeParameterBlock(param_file) call get_param(param_file, mdl, "USE_IDEAL_AGE_TRACER", use_ideal_age, & default=.false., do_not_log=.true.) call openParameterBlock(param_file, 'MLE', do_not_log=.true.) @@ -2805,6 +2809,9 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C if (MLE_use_PBL_MLD .or. MLE_use_Bodner) then call safe_alloc_ptr(visc%MLD, isd, ied, jsd, jed) endif + if (use_StokesMOST .and. MLE_use_Bodner) then + call safe_alloc_ptr(visc%Lam2, isd, ied, jsd, jed) + endif if ((hfreeze >= 0.0) .or. MLE_use_PBL_MLD .or. do_brine_plume .or. use_fpmix .or. & use_neutral_diffusion .or. use_hor_bnd_diff .or. use_ideal_age) then call safe_alloc_ptr(visc%h_ML, isd, ied, jsd, jed) @@ -2814,6 +2821,10 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C call register_restart_field(visc%MLD, "MLD", .false., restart_CS, & "Instantaneous active mixing layer depth", units="m", conversion=US%Z_to_m) endif + if (use_StokesMOST .and. MLE_use_Bodner) then + call register_restart_field(visc%Lam2, "Lam2", .false., restart_CS, & + "(Langmuir Number)^-2", units="" ) + endif if (MLE_use_PBL_MLD .or. do_brine_plume .or. use_fpmix .or. & use_neutral_diffusion .or. use_hor_bnd_diff .or. MLE_use_Bodner) then call register_restart_field(visc%h_ML, "h_ML", .false., restart_CS, & From f4ba4850f13a941fe367020ef043d49f1c200679 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Wed, 22 Oct 2025 15:28:35 -0600 Subject: [PATCH 27/41] Add three new CVMix parameters (#392) * Add three new CVMix parameters CVMix moved three hard-coded fortran parameters to user-defined parameters than can be set via cvmix_init_kpp(). This PR allows users to set those three parameters via MOM_input / MOM_override, but the MOM6 default values match the CVMix default values (which match the previously-hardcoded values) * Update CVMix external in pkg/ Need updated CVMix API that includes ER_Cb, ER_Cs, and ER_Cu arguments to CVMix_init_kpp() * Description comments weren't in right format The comments describing the new variables of the KPP_Cs class were "!" not "!<" so doxygen didn't recognize them --- pkg/CVMix-src | 2 +- src/parameterizations/vertical/MOM_CVMix_KPP.F90 | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/CVMix-src b/pkg/CVMix-src index d20b9898f4..9187de96a4 160000 --- a/pkg/CVMix-src +++ b/pkg/CVMix-src @@ -1 +1 @@ -Subproject commit d20b9898f46d0ec3f5df2eab7f38eb4aac567254 +Subproject commit 9187de96a40ca55ec7b43524a2bf0ace10bcae67 diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index a7c1b4e610..1eb83c3db8 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -125,6 +125,9 @@ module MOM_CVMix_KPP real :: MLD_guess_min !< The minimum estimate of the mixed layer depth used to !! calculate the Langmuir number for Langmuir turbulence !! enhancement with KPP [Z ~> m] + real :: KPP_ER_Cb !< Entrainment Rule TKE buoyancy production weight [nondim] + real :: KPP_ER_Cs !< Entrainment Rule TKE Stokes production weight [nondim] + real :: KPP_ER_Cu !< Entrainment Rule TKE shear production weight [nondim] logical :: STOKES_MIXING !< Flag if model is mixing down Stokes gradient !! This is relevant for which current to use in RiB integer :: answer_date !< The vintage of the order of arithmetic in the CVMix KPP @@ -532,6 +535,16 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) 'Parameter for Stokes MOST convection entrainment (unresolved shear)', & units="nondim", default=1.6) + call get_param(paramFile, mdl, "KPP_ER_Cb", CS%KPP_ER_Cb, & + 'Entrainment Rule TKE buoyancy production weight', & + units="nondim", default=0.96) + call get_param(paramFile, mdl, "KPP_ER_Cs", CS%KPP_ER_Cs, & + 'Entrainment Rule TKE Stokes production weight', & + units="nondim", default=0.038) + call get_param(paramFile, mdl, "KPP_ER_Cu", CS%KPP_ER_Cu, & + 'Entrainment Rule TKE shear production weight', & + units="nondim", default=0.023) + call get_param(paramFile, mdl, "ANSWER_DATE", CS%answer_date, & "The vintage of the order of arithmetic in the CVMix KPP calculations. Values "//& "below 20240501 recover the answers from early in 2024, while higher values "//& @@ -548,6 +561,9 @@ logical function KPP_init(paramFile, G, GV, US, diag, Time, CS, passive) vonKarman=CS%vonKarman, & surf_layer_ext=CS%surf_layer_ext, & CVt2=CS%KPP_CVt2, & + ER_Cb=CS%KPP_ER_Cb, & + ER_Cs=CS%KPP_ER_Cs, & + ER_Cu=CS%KPP_ER_Cu, & interp_type=CS%interpType, & interp_type2=CS%interpType2, & lEkman=CS%computeEkman, & From 75fd563c433b246db364fa81e33c0a7980b24234 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Thu, 23 Oct 2025 13:52:26 -0600 Subject: [PATCH 28/41] Fix scaling of pRef_MLD in diagnoseMLDbyDensityDifference (#396) Also initialize use_OM4_iteration in case OM4_iteration is not present. --- src/diagnostics/MOM_diagnose_MLD.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/diagnostics/MOM_diagnose_MLD.F90 b/src/diagnostics/MOM_diagnose_MLD.F90 index bd1bcc8ab8..e7c08b6d95 100644 --- a/src/diagnostics/MOM_diagnose_MLD.F90 +++ b/src/diagnostics/MOM_diagnose_MLD.F90 @@ -101,7 +101,7 @@ subroutine diagnoseMLDbyDensityDifference(id_MLD, h, tv, densityDiff, G, GV, US, is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke hRef_MLD(:) = ref_h_mld - pRef_MLD(:) = GV%H_to_RZ*GV%g_Earth*ref_h_mld + pRef_MLD(:) = GV%H_to_RZ * GV%Z_to_H * GV%g_Earth * ref_h_mld z_ref_diag(:,:) = 0. EOSdom(:) = EOS_domain(G%HI) @@ -335,6 +335,7 @@ subroutine diagnoseMLDbyEnergy(id_MLD, h, tv, G, GV, US, Mixing_Energy, k_bounds is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke + use_OM4_iteration = .false. if (present(OM4_iteration)) then use_OM4_iteration = OM4_iteration endif From b7bd69273dab83ba31510517d807f5b450891b90 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Fri, 24 Oct 2025 06:36:42 -0600 Subject: [PATCH 29/41] Ensure short-circuiting in Lam2 available check in mixedlayer_restart_Bodner (#395) * Prevent short-circuiting in Lam2 available check in mixedlayer_restrat_Bodner Otherwise, associated(Lam2) may be checked before present(Lam2), which may lead to sigsegv. * don't imlicitly save lam2_available --- src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 951f462705..4eaa726c90 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -853,6 +853,7 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d logical :: line_is_empty, keep_going integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz + logical :: Lam2_available is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB @@ -889,9 +890,12 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d ! Extract the friction velocity from the forcing type. call find_ustar(forces, tv, U_star_2d, G, GV, US, halo=1) + Lam2_available = present(Lam2) + if (Lam2_available) Lam2_available = associated(Lam2) + ! Wave Enhanced of ustar following Eq. 28 in Bodner23 if (CS%wave_enhanced_ustar) then - if (present(Lam2) .and. associated(Lam2)) then + if (Lam2_available) then do j=js-1,je+1 ; do i=is-1,ie+1 E_ustar = sqrt( 1.0 + (Lam2(i,j) * 0.104) + (Lam2(i,j) * Lam2(i,j) * 0.00118)) U_star_2d(i,j) = E_ustar * U_star_2d(i,j) From be25c684ba16e75995d65ff5fdc7e8154cc338ea Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Fri, 24 Oct 2025 10:30:08 -0600 Subject: [PATCH 30/41] initialize kbl regardless of StokesMOST (#398) This fixes an issue caught by the MOM_interface KPP single column CI test: kbl is initialized only if StokesMOST is true, but used regardless. This PR moves the initialization outside the if StokesMOST block. --- src/parameterizations/vertical/MOM_CVMix_KPP.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index 1eb83c3db8..1ad7435cb8 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -1499,10 +1499,10 @@ subroutine KPP_compute_BLD(CS, G, GV, US, h, Temp, Salt, u, v, tv, uStar, buoyFl endif ! fixedOBLdepth CS%OBLdepth(i,j) = min( CS%OBLdepth(i,j), -zBottomMinusOffset ) ! no deeper than deepOBLoffset off bottom CS%kOBL(i,j) = CVMix_kpp_compute_kOBL_depth( iFaceHeight, cellHeight, CS%OBLdepth(i,j) ) + kbl = int(CS%kOBL(i,j)) if (CS%StokesMOST) then ! Now we have OBLdepth and need to compute diagnostics - kbl = int(CS%kOBL(i,j)) SLdepth_0d = CS%surf_layer_ext*CS%OBLdepth(i,j) surfBuoyFlux = surfBuoyFlux2(kbl) ! find ksfc for cell where "surface layer" sits From 312b327ec29f5191de13bc53b0f894ff67963b6b Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Wed, 19 Nov 2025 16:22:01 -0700 Subject: [PATCH 31/41] Get stoch_restfile right with multiple restarts (#401) If MOM6 is writing so many restart fields to disk that FMS splits them across multiple restart files, the logic for determining the name of the restart for the stochastic_physics package needs to be applied to the first file listed (the one without "_N" between the datestamp and the .nc suffix) --- config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index a48ceffd35..6ced654fdb 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -285,10 +285,16 @@ subroutine ocean_model_init(Ocean_sfc, OS, Time_init, Time_in, gas_fields_ocn, i OS%Time = Time_in if(present(input_restart_file)) then - k = len_trim(input_restart_file) + k = index(input_restart_file, ' ') + if (k==0) k = len_trim(input_restart_file) i = index(input_restart_file, '.r.') if (i>0) then stoch_restfile = input_restart_file(1:i)//'r_stoch'//input_restart_file(i+2:k) + + if (is_root_pe()) then + write(stdout,*) 'input_restart_file =', input_restart_file + write(stdout,*) 'stoch_restfile =', stoch_restfile + endif endif endif call initialize_MOM(OS%Time, Time_init, param_file, OS%dirs, OS%MOM_CSp, & From 285fc129e02341ffaa352876c87a89e6fb787992 Mon Sep 17 00:00:00 2001 From: Ian Grooms Date: Wed, 11 Feb 2026 16:15:04 -0700 Subject: [PATCH 32/41] Taper leithy (#403) * Add depth-based tapering of Leith+E * Leithy+E vertical taper bugfix Moves a global computation outside of a do loop so that it doesn't do the global computation over and over. * Replace array syntax with loop --- src/parameterizations/lateral/MOM_hor_visc.F90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/parameterizations/lateral/MOM_hor_visc.F90 b/src/parameterizations/lateral/MOM_hor_visc.F90 index fc1b7ddefb..ff54cd8092 100644 --- a/src/parameterizations/lateral/MOM_hor_visc.F90 +++ b/src/parameterizations/lateral/MOM_hor_visc.F90 @@ -1348,7 +1348,7 @@ subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, endif if (CS%taper_leithy) then ! Multiply m_leithy by taper function of depth - m_leithy(:,:) = m_leithy(:,:) * leithy_taper_function(CS, zc(:,:,k)) + m_leithy(i,j) = m_leithy(i,j) * leithy_taper_function(CS, zc(i,j,k)) endif enddo ; enddo @@ -3318,20 +3318,20 @@ end subroutine hor_visc_init !! leithy_depth+leithy_width; and an interpolating cubic spline in between. function leithy_taper_function(CS, zc) type(hor_visc_CS), intent(in) :: CS !< Control structure for horizontal viscosity - real, intent(in) :: zc(:,:) !< depth of h-cell centersi [Z ~> m] - real :: leithy_taper_function(size(zc,dim=1),size(zc,dim=2)) ! Taper function evaluated at zc [nondim] + real, intent(in) :: zc !< depth of h-cell centersi [Z ~> m] + real :: leithy_taper_function ! Taper function evaluated at zc [nondim] ! Local variables - real :: x(size(zc,dim=1),size(zc,dim=2)) ! 0 at top of transition and 1 at bottom [nondim] + real :: x ! 0 at top of transition and 1 at bottom [nondim] x = (zc - CS%leithy_depth) / CS%leithy_width - where (zc <= CS%leithy_depth) + if (zc <= CS%leithy_depth) then leithy_taper_function = 1.0 - elsewhere (zc >= CS%leithy_depth + CS%leithy_width) + elseif (zc >= CS%leithy_depth + CS%leithy_width) then leithy_taper_function = 0.0 - elsewhere + else leithy_taper_function = (x - 1.0)**2 * (1.0 + 2 * x) - end where + endif end function leithy_taper_function !> hor_visc_vel_stencil returns the horizontal viscosity input velocity stencil size From e8b17da6cd86e22237bd16bf7d1357a046ab25fe Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Tue, 10 Mar 2026 15:54:30 -0600 Subject: [PATCH 33/41] Update fe forcing (#340) * Use updated iron sediment forcing scheme Instead of just fesedflux and feventflux, updates to MARBL from UCI now add an fesedfluxred forcing field. * New MOM_initialize_tracer_from_Z() argument Added optional argument num_pass to MOM_initialize_tracer_from_Z(), which then gets passed down to horiz_interp_and_extrap_tracer() eventually is passed to fill_miss_2d() [where the optional argument is already part of the API but is never used]. I tested this updated by setting num_pass=0 for the MARBL tracers and verifying that the smoothing step was not run, but that was just a test to see if the smoothing was responsible for some unexpected tracer values in the MARBL initial conditions -- in general, we do want to smooth the MARBL tracers after they are initialized. * Use MARBL's autotroph_tracer_consistency_enforce() There was an issue where smoothing the MARBL tracer initial conditions led to some inconsistent tracer values for tracers associated with MARBL's autotrophs. For each autotroph, if any tracer (C, N, P, etc) is 0 we want all of that autotroph's tracers to be 0... but the smoothing algorithm in MOM_initialize_tracer_from_Z() would sometimes leave one tracer at 0 but introduce a nonzero value in a different tracer at the same location. The subroutine on the MARBL interface enforces this consistency. This function is called whenever any MARBL tracer is initialized with MOM_initialize_tracer_from_Z(); if all the tracers are read in from a restart file then this subroutine is skipped. If this function is called, it is noted in the log with the following message: Enforcing consistency across autotroph tracer initial conditions * Dummy MARBL interface missing subroutine Added autotroph_tracer_consistency_enforce() to the dummy MARBL interface so MARBL_tracers.F90 can still be built without MARBL * Remove unnecessary warning messages MARBL_tracers_stock() was writing a list of all tracers from all processors, filling up cesm.log unnecessarily * Updates to iron forcing from K Moore * Revert changes to add num_pass arguments We decided to update the MARBL interface instead of playing with how MOM6 smooths the MARBL ICs, so we don't need to modify src/framework or src/initialization in this PR. Also changed some ".eq." to "==" in MARBL_tracers.F90 * Fix CI build error (hopefully) CI was complaining about dust_ratio**-0.9 ("Unary operator following arithmetic operator (use parentheses)") so I took the message's advice and changed to dust_ratio**(-0.9) --- config_src/external/MARBL/marbl_interface.F90 | 10 +++ src/tracer/MARBL_forcing_mod.F90 | 38 ++++----- src/tracer/MARBL_tracers.F90 | 82 ++++++++++++++++--- 3 files changed, 96 insertions(+), 34 deletions(-) diff --git a/config_src/external/MARBL/marbl_interface.F90 b/config_src/external/MARBL/marbl_interface.F90 index 40ddf17c73..d80ad49586 100644 --- a/config_src/external/MARBL/marbl_interface.F90 +++ b/config_src/external/MARBL/marbl_interface.F90 @@ -37,6 +37,7 @@ module marbl_interface procedure, public :: put_setting !< dummy put_setting routine procedure, public :: get_setting !< dummy get_setting routine procedure, public :: init !< dummy init routine + procedure, public :: autotroph_tracer_consistency_enforce !< dummy consistency enforcement procedure, public :: compute_totChl !< dummy routine to compute total Chlorophyll procedure, public :: surface_flux_compute !< dummy surface flux routine procedure, public :: interior_tendency_compute !< dummy interior tendency routine @@ -91,6 +92,15 @@ subroutine init(self, & call MOM_error(FATAL, error_msg) end subroutine init + !> Dummy version of MARBL's autotroph_tracer_consistency_enforce() function + subroutine autotroph_tracer_consistency_enforce(self) + + class(marbl_interface_class), intent(inout) :: self + + call MOM_error(FATAL, error_msg) + + end subroutine autotroph_tracer_consistency_enforce + !> Dummy version of MARBL's compute_totChl() function subroutine compute_totChl(self) diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index 0454c3b061..7769175e83 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -40,12 +40,9 @@ module MARBL_forcing_mod !! regulate the timing of diagnostic output. real :: dust_ratio_thres !< coarse/fine dust ratio threshold [1] - real :: dust_ratio_to_fe_bioavail_frac !< ratio of dust to iron bioavailability fraction [1] real :: fe_bioavail_frac_offset !< offset for iron bioavailability fraction [1] real :: atm_fe_to_bc_ratio !< atmospheric iron to black carbon ratio [1] - real :: atm_bc_fe_bioavail_frac !< atmospheric black carbon to iron bioavailablity fraction ratio [1] real :: seaice_fe_to_bc_ratio !< sea-ice iron to black carbon ratio [1] - real :: seaice_bc_fe_bioavail_frac !< sea-ice black carbon to iron bioavailablity fraction ratio [1] real :: iron_frac_in_atm_fine_dust !< Fraction of fine dust from the atmosphere that is iron [1] real :: iron_frac_in_atm_coarse_dust !< Fraction of coarse dust from the atmosphere that is iron [1] real :: iron_frac_in_seaice_dust !< Fraction of dust from the sea ice that is iron [1] @@ -99,19 +96,11 @@ subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_MARBL_ endif call get_param(param_file, mdl, "DUST_RATIO_THRES", CS%dust_ratio_thres, & - "coarse/fine dust ratio threshold", units="1", default=69.00594) - call get_param(param_file, mdl, "DUST_RATIO_TO_FE_BIOAVAIL_FRAC", CS%dust_ratio_to_fe_bioavail_frac, & - "ratio of dust to iron bioavailability fraction", units="1", default=1./366.314) - call get_param(param_file, mdl, "FE_BIOAVAIL_FRAC_OFFSET", CS%fe_bioavail_frac_offset, & - "offset for iron bioavailability fraction", units="1", default=0.0146756) + "coarse/fine dust ratio threshold", units="1", default=90.) call get_param(param_file, mdl, "ATM_FE_TO_BC_RATIO", CS%atm_fe_to_bc_ratio, & - "atmospheric iron to black carbon ratio", units="1", default=1.) - call get_param(param_file, mdl, "ATM_BC_FE_BIOAVAIL_FRAC", CS%atm_bc_fe_bioavail_frac, & - "atmospheric black carbon to iron bioavailablity fraction ratio", units="1", default=0.06) + "atmospheric iron to black carbon ratio", units="1", default=1.33) call get_param(param_file, mdl, "SEAICE_FE_TO_BC_RATIO", CS%seaice_fe_to_bc_ratio, & - "sea-ice iron to black carbon ratio", units="1", default=1.) - call get_param(param_file, mdl, "SEAICE_BC_FE_BIOAVAIL_FRAC", CS%seaice_bc_fe_bioavail_frac, & - "sea-ice black carbon to iron bioavailablity fraction ratio", units="1", default=0.06) + "sea-ice iron to black carbon ratio", units="1", default=1.33) call get_param(param_file, mdl, "IRON_FRAC_IN_ATM_FINE_DUST", CS%iron_frac_in_atm_fine_dust, & "Fraction of fine dust from the atmosphere that is iron", units="1", default=0.035) call get_param(param_file, mdl, "IRON_FRAC_IN_ATM_COARSE_DUST", CS%iron_frac_in_atm_coarse_dust, & @@ -221,6 +210,7 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust integer :: i, j, is, ie, js, je, m real :: atm_fe_bioavail_frac !< Fraction of iron from the atmosphere available for biological uptake [1] + real :: dust_ratio !< Ratio of coarse to fine dust from the atmosphere [1] real :: seaice_fe_bioavail_frac !< Fraction of iron from sea ice available for biological uptake [1] ! Note: following two conversion factors are used to both convert from km m-2 s-1 -> mmol m-2 s-1 !! AND cast in MOM6's unique dimensional consistency scaling system [conc Z T-1] @@ -324,13 +314,15 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust do j=js,je ; do i=is,ie ! TODO: abort if atm_fine_dust_flux and atm_coarse_dust_flux are not associated? ! Contribution of atmospheric dust to iron flux - if (atm_coarse_dust_flux(i-i0,j-j0) < & - CS%dust_ratio_thres * atm_fine_dust_flux(i-i0,j-j0)) then - atm_fe_bioavail_frac = CS%fe_bioavail_frac_offset + CS%dust_ratio_to_fe_bioavail_frac * & - (CS%dust_ratio_thres - atm_coarse_dust_flux(i-i0,j-j0) / atm_fine_dust_flux(i-i0,j-j0)) + atm_fe_bioavail_frac = 0.005 + if ((atm_coarse_dust_flux(i-i0,j-j0) > 0.) .and. (atm_fine_dust_flux(i-i0,j-j0)) > 0.) then + dust_ratio = max(atm_coarse_dust_flux(i-i0,j-j0) / atm_fine_dust_flux(i-i0,j-j0), 9.903) else - atm_fe_bioavail_frac = CS%fe_bioavail_frac_offset + dust_ratio = 9.903 endif + dust_ratio = dust_ratio - 5.5 + if (dust_ratio < CS%dust_ratio_thres) & + atm_fe_bioavail_frac = dust_ratio**(-0.9) - 0.0134 ! Contribution of atmospheric dust to iron flux fluxes%iron_flux(i,j) = (atm_fe_bioavail_frac * & @@ -338,8 +330,8 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust CS%iron_frac_in_atm_coarse_dust * atm_coarse_dust_flux(i-i0,j-j0))) ! Contribution of atmospheric black carbon to iron flux - fluxes%iron_flux(i,j) = fluxes%iron_flux(i,j) + (CS%atm_bc_fe_bioavail_frac * & - (CS%atm_fe_to_bc_ratio * atm_bc_flux(i-i0,j-j0))) + fluxes%iron_flux(i,j) = fluxes%iron_flux(i,j) + (atm_bc_flux(i-i0,j-j0) * & + (atm_fe_bioavail_frac * CS%atm_fe_to_bc_ratio)) seaice_fe_bioavail_frac = atm_fe_bioavail_frac ! Contribution of seaice dust to iron flux @@ -347,8 +339,8 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust (CS%iron_frac_in_seaice_dust * seaice_dust_flux(i-i0,j-j0))) ! Contribution of seaice black carbon to iron flux - fluxes%iron_flux(i,j) = fluxes%iron_flux(i,j) + (CS%seaice_bc_fe_bioavail_frac * & - (CS%seaice_fe_to_bc_ratio * seaice_bc_flux(i-i0,j-j0))) + fluxes%iron_flux(i,j) = fluxes%iron_flux(i,j) + (seaice_bc_flux(i-i0,j-j0) * & + (seaice_fe_bioavail_frac * CS%seaice_fe_to_bc_ratio)) ! Unit conversion (kg m-2 s-1 -> conc Z T-1) fluxes%iron_flux(i,j) = (G%mask2dT(i,j) * iron_flux_conversion) * fluxes%iron_flux(i,j) diff --git a/src/tracer/MARBL_tracers.F90 b/src/tracer/MARBL_tracers.F90 index db7edbfa39..c5e0936fe8 100644 --- a/src/tracer/MARBL_tracers.F90 +++ b/src/tracer/MARBL_tracers.F90 @@ -135,8 +135,9 @@ module MARBL_tracers type(vardesc), allocatable :: tr_desc(:) !< Descriptions and metadata for the tracers logical :: tracers_may_reinit !< If true the tracers may be initialized if not found in a restart file - character(len=200) :: fesedflux_file !< name of [netCDF] file containing iron sediment flux - character(len=200) :: feventflux_file !< name of [netCDF] file containing iron vent flux + character(len=200) :: fesedflux_file !< name of [netCDF] file containing iron sediment flux + character(len=200) :: fesedfluxred_file !< name of [netCDF] file containing reduced iron sediment flux + character(len=200) :: feventflux_file !< name of [netCDF] file containing iron vent flux type(forcing_timeseries_dataset) :: d14c_dataset(3) !< File and time axis information for d14c forcing real, dimension(3) :: d14c_bands !< forcing is organized into bands: [30 N, 90 N]; [30 S, 30 N]; [90 S, 30 S] !! This variable contains D14C for each band [CU ~> conc] @@ -259,7 +260,9 @@ module MARBL_tracers integer :: potemp_ind !< index of MARBL forcing field array to copy potential temperature into integer :: salinity_ind !< index of MARBL forcing field array to copy salinity into integer :: pressure_ind !< index of MARBL forcing field array to copy pressure into - integer :: fesedflux_ind !< index of MARBL forcing field array to copy iron sediment flux into + integer :: fesedflux_ind !< index of MARBL forcing field array to copy iron sediment flux into + integer :: fesedfluxred_ind !< index of MARBL forcing field array to copy reduced iron sediment flux into + integer :: feventflux_ind !< index of MARBL forcing field array to copy iron vent flux into integer :: o2_scalef_ind !< index of MARBL forcing field array to copy O2 scale length into integer :: remin_scalef_ind !< index of MARBL forcing field array to copy remin scale length into type(external_field), allocatable :: id_tracer_restoring(:) !< id number for time_interp_external @@ -288,8 +291,9 @@ module MARBL_tracers ! TODO: create generic 3D forcing input type to read z coordinate + values real :: fesedflux_scale_factor !< scale factor for iron sediment flux [mmol umol-1 d s-1] integer :: fesedflux_nz !< number of levels in iron sediment flux file - real, allocatable, dimension(:,:,:) :: fesedflux_in !< Field to read iron sediment flux into [conc m s-1] - real, allocatable, dimension(:,:,:) :: feventflux_in !< Field to read iron vent flux into [conc m s-1] + real, allocatable, dimension(:,:,:) :: fesedflux_in !< Field to read iron sediment flux into [conc m s-1] + real, allocatable, dimension(:,:,:) :: fesedfluxred_in !< Field to read reduced iron sediment flux into [conc m s-1] + real, allocatable, dimension(:,:,:) :: feventflux_in !< Field to read iron vent flux into [conc m s-1] real, allocatable, dimension(:) :: & fesedflux_z_edges !< The depths of the cell interfaces in the input data [Z ~> m] ! TODO: this thickness does not need to be 3D, but it is easier to make thickness 0 @@ -498,6 +502,8 @@ subroutine configure_MARBL_tracers(GV, US, param_file, CS) CS%salinity_ind = -1 CS%pressure_ind = -1 CS%fesedflux_ind = -1 + CS%fesedfluxred_ind = -1 + CS%feventflux_ind = -1 CS%o2_scalef_ind = -1 CS%remin_scalef_ind = -1 CS%d14c_ind = -1 @@ -524,6 +530,10 @@ subroutine configure_MARBL_tracers(GV, US, param_file, CS) CS%pressure_ind = m case('Iron Sediment Flux') CS%fesedflux_ind = m + case('Iron Red Sediment Flux') + CS%fesedfluxred_ind = m + case('Iron Vent Flux') + CS%feventflux_ind = m case('O2 Consumption Scale Factor') CS%o2_scalef_ind = m case('Particulate Remin Scale Factor') @@ -629,16 +639,25 @@ function register_MARBL_tracers(HI, GV, US, param_file, CS, tr_Reg, restart_CS, ! ** FESEDFLUX call get_param(param_file, mdl, "MARBL_FESEDFLUX_FILE", CS%fesedflux_file, & "The file in which the iron sediment flux forcing field can be found.", & - default="fesedflux_total_reduce_oxic_tx0.66v1.c230817.nc") + default="fesedflux.nc") if (scan(CS%fesedflux_file,'/') == 0) then ! Add the directory if CS%fesedflux_file is not already a complete path. CS%fesedflux_file = trim(slasher(inputdir))//trim(CS%fesedflux_file) call log_param(param_file, mdl, "INPUTDIR/MARBL_TRACERS_FESEDFLUX_FILE", CS%fesedflux_file) endif + ! ** FESEDFLUXRED + call get_param(param_file, mdl, "MARBL_FESEDFLUXRED_FILE", CS%fesedfluxred_file, & + "The file in which the iron sediment flux forcing field can be found.", & + default="fesedfluxred.nc") + if (scan(CS%fesedfluxred_file,'/') == 0) then + ! Add the directory if CS%fesedflux_file is not already a complete path. + CS%fesedfluxred_file = trim(slasher(inputdir))//trim(CS%fesedfluxred_file) + call log_param(param_file, mdl, "INPUTDIR/MARBL_TRACERS_FESEDFLUXRED_FILE", CS%fesedfluxred_file) + endif ! ** FEVENTFLUX call get_param(param_file, mdl, "MARBL_FEVENTFLUX_FILE", CS%feventflux_file, & "The file in which the iron vent flux forcing field can be found.", & - default="feventflux_5gmol_tx0.66v1.c230817.nc") + default="feventflux.nc") if (scan(CS%feventflux_file,'/') == 0) then ! Add the directory if CS%feventflux_file is not already a complete path. CS%feventflux_file = trim(slasher(inputdir))//trim(CS%feventflux_file) @@ -874,7 +893,7 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag character(len=48) :: flux_units ! The units for age tracer fluxes, either ! years m3 s-1 or years kg s-1. character(len=48) :: tracer_name - logical :: fesedflux_has_edges, fesedflux_use_missing + logical :: fesedflux_has_edges, fesedflux_use_missing, tracer_init_from_Z real :: fesedflux_missing ! required argument for read_Z_edges() [CU ~> conc] integer :: i, j, k, kbot, m, diag_size @@ -953,6 +972,7 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag day, "Conversion Factor for Bottom Flux -> Tend", "1/m") ! Initialize tracers (if they weren't initialized from restart file) + tracer_init_from_Z = .false. do m=1,CS%ntr call query_vardesc(CS%tr_desc(m), name=name, caller="initialize_MARBL_tracers") if ((.not. restart) .or. & @@ -961,12 +981,30 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag ! TODO: added the ongrid optional argument, but is there a good way to detect if the file is on grid? call MOM_initialize_tracer_from_Z(h, CS%tracer_data(m)%tr, G, GV, US, param_file, & CS%IC_file, name, ongrid=CS%ongrid) + tracer_init_from_Z = .true. do k=1,GV%ke ; do j=G%jsc, G%jec ; do i=G%isc, G%iec ! Ensure tracer concentrations are at / above minimum value if (CS%tracer_data(m)%tr(i,j,k) < CS%IC_min) CS%tracer_data(m)%tr(i,j,k) = CS%IC_min enddo ; enddo ; enddo endif enddo + if (tracer_init_from_Z) then + ! For each column, enforce consistency in MARBL tracers + ! (no negative concentrations; for a given autotroph, if one tracer is 0 they all are) + call MOM_error(NOTE, 'Enforcing consistency across autotroph tracer initial conditions') + do j=G%jsc, G%jec ; do i=G%isc, G%iec + ! Copy tracer data into flat array + do k=1,GV%ke; do m=1, CS%ntr + MARBL_instances%tracers(m,k) = CS%tracer_data(m)%tr(i,j,k) + end do ; end do + ! call consistency enforcement + call MARBL_instances%autotroph_tracer_consistency_enforce() + ! Copy tracer data out of flat array + do k=1,GV%ke; do m=1, CS%ntr + CS%tracer_data(m)%tr(i,j,k) = MARBL_instances%tracers(m,k) + end do ; end do + end do ; end do + end if ! Initialize total chlorophyll to get SW Pen correct (if it wasn't initialized from restart file) if ((CS%total_Chl_ind > 0) .and. & @@ -1072,6 +1110,7 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag ! (2) Allocate memory for fesedflux and feventflux allocate(CS%fesedflux_in(SZI_(G), SZJ_(G), CS%fesedflux_nz)) + allocate(CS%fesedfluxred_in(SZI_(G), SZJ_(G), CS%fesedflux_nz)) allocate(CS%feventflux_in(SZI_(G), SZJ_(G), CS%fesedflux_nz)) allocate(CS%fesedflux_dz(SZI_(G), SZJ_(G), CS%fesedflux_nz)) @@ -1079,6 +1118,8 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag ! TODO: Add US term to scale call MOM_read_data(CS%fesedflux_file, "FESEDFLUXIN", CS%fesedflux_in(:,:,:), G%Domain, & scale=CS%fesedflux_scale_factor) + call MOM_read_data(CS%fesedfluxred_file, "FESEDFLUXIN", CS%fesedfluxred_in(:,:,:), G%Domain, & + scale=CS%fesedflux_scale_factor) call MOM_read_data(CS%feventflux_file, "FESEDFLUXIN", CS%feventflux_in(:,:,:), G%Domain, & scale=CS%fesedflux_scale_factor) @@ -1102,6 +1143,8 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag if (G%bathyT(i,j) + CS%fesedflux_z_edges(k) < 1e-8 * US%m_to_Z) then CS%fesedflux_in(i,j,k-1) = CS%fesedflux_in(i,j,k-1) + CS%fesedflux_in(i,j,k) CS%fesedflux_in(i,j,k) = 0. + CS%fesedfluxred_in(i,j,k-1) = CS%fesedfluxred_in(i,j,k-1) + CS%fesedfluxred_in(i,j,k) + CS%fesedfluxred_in(i,j,k) = 0. CS%feventflux_in(i,j,k-1) = CS%feventflux_in(i,j,k-1) + CS%feventflux_in(i,j,k) CS%feventflux_in(i,j,k) = 0. CS%fesedflux_dz(i,j,k) = 0. @@ -1183,7 +1226,7 @@ subroutine register_MARBL_diags(MARBL_diags, diag, day, G, id_diags) allocate(id_diags(diag_size)) do m = 1, diag_size id_diags(m)%id = -1 - if (trim(MARBL_diags%diags(m)%vertical_grid) .eq. "none") then ! 2D field + if (trim(MARBL_diags%diags(m)%vertical_grid) == "none") then ! 2D field id_diags(m)%id = register_diag_field("ocean_model", & trim(MARBL_diags%diags(m)%short_name), & diag%axesT1, & ! T => tracer grid? 1 => no vertical grid @@ -1196,7 +1239,9 @@ subroutine register_MARBL_diags(MARBL_diags, diag, day, G, id_diags) ! (for now, FESEDFLUX is the only one that should be true) ! Also, known issue where passing v_extensive=.false. isn't ! treated the same as not passing v_extensive - if (trim(MARBL_diags%diags(m)%short_name).eq."FESEDFLUX") then + if ((trim(MARBL_diags%diags(m)%short_name) == "FESEDFLUX") .or. & + (trim(MARBL_diags%diags(m)%short_name) == "FEREDSEDFLUX") .or. & + (trim(MARBL_diags%diags(m)%short_name) == "FEVENTFLUX")) then id_diags(m)%id = register_diag_field("ocean_model", & trim(MARBL_diags%diags(m)%short_name), & diag%axesTL, & ! T=> tracer grid? L => layer center @@ -1528,9 +1573,23 @@ subroutine MARBL_tracers_column_physics(h_old, ea, eb, fluxes, dt, G, GV, US, CS MARBL_instances%interior_tendency_forcings(CS%fesedflux_ind)%field_1d(1,:) = 0. call reintegrate_column(CS%fesedflux_nz, & CS%fesedflux_dz(i,j,:) * (sum(dz(:) * GV%H_to_Z) / G%bathyT(i,j)), & - CS%fesedflux_in(i,j,:) + CS%feventflux_in(i,j,:), GV%ke, dz(:), & + CS%fesedflux_in(i,j,:), GV%ke, dz(:), & MARBL_instances%interior_tendency_forcings(CS%fesedflux_ind)%field_1d(1,:)) endif + if (CS%fesedfluxred_ind > 0) then + MARBL_instances%interior_tendency_forcings(CS%fesedfluxred_ind)%field_1d(1,:) = 0. + call reintegrate_column(CS%fesedflux_nz, & + CS%fesedflux_dz(i,j,:) * (sum(dz(:) * GV%H_to_Z) / G%bathyT(i,j)), & + CS%fesedfluxred_in(i,j,:), GV%ke, dz(:), & + MARBL_instances%interior_tendency_forcings(CS%fesedfluxred_ind)%field_1d(1,:)) + endif + if (CS%feventflux_ind > 0) then + MARBL_instances%interior_tendency_forcings(CS%feventflux_ind)%field_1d(1,:) = 0. + call reintegrate_column(CS%fesedflux_nz, & + CS%fesedflux_dz(i,j,:) * (sum(dz(:) * GV%H_to_Z) / G%bathyT(i,j)), & + CS%feventflux_in(i,j,:), GV%ke, dz(:), & + MARBL_instances%interior_tendency_forcings(CS%feventflux_ind)%field_1d(1,:)) + endif ! TODO: add ability to read these fields from file ! also, add constant values to CS @@ -2164,6 +2223,7 @@ subroutine MARBL_tracers_end(CS) if (allocated(CS%tracer_restoring_ind)) deallocate(CS%tracer_restoring_ind) if (allocated(CS%tracer_I_tau_ind)) deallocate(CS%tracer_I_tau_ind) if (allocated(CS%fesedflux_in)) deallocate(CS%fesedflux_in) + if (allocated(CS%fesedfluxred_in)) deallocate(CS%fesedfluxred_in) if (allocated(CS%feventflux_in)) deallocate(CS%feventflux_in) if (allocated(CS%I_tau)) deallocate(CS%I_tau) deallocate(CS) From b15bc9780bc630236b048fcfd27b5ad177f55abe Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Wed, 11 Mar 2026 19:52:28 -0600 Subject: [PATCH 34/41] Ensemble filename and stoch restart fixes (#409) Introduce append_ensemble_appendix To eliminate code duplication, this commit introduces insert_ensemble_appendix, a routine to insert the ensemble appendix to i/o filenames. If provided, the appendix is inserted after the last occurrence of ENSEMBLE_APPENDIX_PREFIX, a new runtime parameter (initially called RESTARTFILE_APPENDIX_PREFIX). Also, fix stoch restart file handling in NUOPC cap: - append ensemble instance suffix in multi-instance runs - add it to CESM rpointer files. --- config_src/drivers/nuopc_cap/mom_cap.F90 | 32 ++++++----- .../nuopc_cap/mom_ocean_model_nuopc.F90 | 16 ++++-- src/framework/MOM_io.F90 | 42 ++++++++++++++ src/framework/MOM_restart.F90 | 56 ++++--------------- .../MOM_shared_initialization.F90 | 19 +++---- 5 files changed, 91 insertions(+), 74 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_cap.F90 b/config_src/drivers/nuopc_cap/mom_cap.F90 index 0eb0c8c290..1f7e3b3cf7 100644 --- a/config_src/drivers/nuopc_cap/mom_cap.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap.F90 @@ -4,6 +4,7 @@ module MOM_cap_mod use MOM_domains, only: get_domain_extent use MOM_io, only: stdout, io_infra_end +use MOM_io, only: insert_ensemble_appendix use mpp_domains_mod, only: mpp_get_compute_domains use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_pelist, mpp_get_global_domain use mpp_domains_mod, only: mpp_get_domain_npes @@ -24,6 +25,7 @@ module MOM_cap_mod use MOM_ocean_model_nuopc, only: ocean_model_init_sfc, ocean_model_flux_init use MOM_ocean_model_nuopc, only: ocean_model_init, update_ocean_model, ocean_model_end use MOM_ocean_model_nuopc, only: get_ocean_grid, get_eps_omesh, query_ocean_state +use MOM_ocean_model_nuopc, only: stoch_restart_needed use MOM_cap_time, only: AlarmInit use MOM_cap_methods, only: mom_import, mom_export, mom_set_geomtype, mod2med_areacor use MOM_cap_methods, only: med2mod_areacor, state_diagnose @@ -1728,7 +1730,7 @@ subroutine ModelAdvance(gcomp, rc) character(240) :: msgString character(ESMF_MAXSTR) :: casename integer :: iostat - integer :: writeunit + integer :: rpointer_unit integer :: localPet type(ESMF_VM) :: vm integer :: n, i @@ -1940,30 +1942,27 @@ subroutine ModelAdvance(gcomp, rc) rpointer_filename = trim(rpointer_filename//timestamp) endif - write(restartname,'(A,".mom6.r",A)') & - trim(casename), timestamp - write(stoch_restartname,'(A,".mom6.r_stoch",A,".nc")') & - trim(casename), timestamp + write(restartname,'(A,".mom6.r",A)') trim(casename), timestamp + write(stoch_restartname,'(A,".mom6.r_stoch",A,".nc")') trim(casename), timestamp + + call insert_ensemble_appendix(stoch_restartname, ".mom6") + call ESMF_LogWrite("MOM_cap: Writing restart : "//trim(restartname), ESMF_LOGMSG_INFO) ! write restart file(s) call ocean_model_restart(ocean_state, restartname=restartname, & stoch_restartname=stoch_restartname, num_rest_files=num_rest_files) if (localPet == 0) then ! Write name of restart file in the rpointer file - this is currently hard-coded for the ocean - open(newunit=writeunit, file=rpointer_filename, form='formatted', status='unknown', iostat=iostat) + open(newunit=rpointer_unit, file=rpointer_filename, form='formatted', status='unknown', iostat=iostat) if (iostat /= 0) then call ESMF_LogSetError(ESMF_RC_FILE_OPEN, & msg=subname//' ERROR opening '//rpointer_filename, line=__LINE__, file=u_FILE_u, rcToReturn=rc) return endif - ! update restart file name to include the instance suffix - if (len_trim(inst_suffix) > 0) then - write(restartname, '(A,".mom6",A,".r",A)') trim(casename), trim(inst_suffix), timestamp - endif - - write(writeunit,'(a)') trim(restartname)//'.nc' + call insert_ensemble_appendix(restartname, ".mom6") + write(rpointer_unit,'(a)') trim(restartname)//'.nc' if (num_rest_files > 1) then ! append i.th restart file name to rpointer do i=1, num_rest_files-1 @@ -1972,10 +1971,15 @@ subroutine ModelAdvance(gcomp, rc) else write(suffix,'("_",I2)') i endif - write(writeunit,'(a)') trim(restartname) // trim(suffix) // '.nc' + write(rpointer_unit,'(a)') trim(restartname) // trim(suffix) // '.nc' enddo endif - close(writeunit) + + if (stoch_restart_needed(ocean_state)) then + write(rpointer_unit,'(a)') trim(stoch_restartname) + endif + + close(rpointer_unit) endif else ! not cesm_coupled write(restartname,'(i4.4,2(i2.2),A,3(i2.2),A)') year, month, day,".", hour, minute, seconds, & diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index 6ced654fdb..87a16300ee 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -82,6 +82,7 @@ module MOM_ocean_model_nuopc public ocean_public_type_chksum public get_ocean_grid, query_ocean_state public get_eps_omesh +public stoch_restart_needed !> This type is used for communication with other components via the FMS coupler. !! The element names and types can be changed only with great deliberation, hence @@ -790,7 +791,7 @@ subroutine ocean_model_restart(OS, timestamp, restartname, stoch_restartname, nu endif endif if (present(stoch_restartname)) then - if (OS%do_sppt .OR. OS%pert_epbl .OR. OS%do_skeb) then + if (stoch_restart_needed(OS)) then call write_stoch_restart_ocn(trim(stoch_restartname)) endif endif @@ -1148,7 +1149,6 @@ end subroutine Ocean_stock_pe !> Write out checksums for fields from the ocean surface state subroutine ocean_public_type_chksum(id, timestep, ocn) - character(len=*), intent(in) :: id !< An identifying string for this call integer, intent(in) :: timestep !< The number of elapsed timesteps type(ocean_public_type), intent(in) :: ocn !< A structure containing various publicly @@ -1174,8 +1174,8 @@ end subroutine ocean_public_type_chksum subroutine get_ocean_grid(OS, Gridp) ! Obtain the ocean grid. - type(ocean_state_type) :: OS - type(ocean_grid_type) , pointer :: Gridp + type(ocean_state_type), intent(in) :: OS + type(ocean_grid_type) , pointer, intent(out) :: Gridp Gridp => OS%grid return @@ -1183,8 +1183,14 @@ end subroutine get_ocean_grid !> Returns eps_omesh read from param file real function get_eps_omesh(OS) - type(ocean_state_type) :: OS + type(ocean_state_type), intent(in) :: OS get_eps_omesh = OS%eps_omesh; return end function +!> Returns true if a stochastic restart file is needed +logical function stoch_restart_needed(OS) + type(ocean_state_type), intent(in) :: OS + stoch_restart_needed = OS%do_sppt .OR. OS%pert_epbl .OR. OS%do_skeb +end function stoch_restart_needed + end module MOM_ocean_model_nuopc diff --git a/src/framework/MOM_io.F90 b/src/framework/MOM_io.F90 index a74a9316c5..6c2b469f9d 100644 --- a/src/framework/MOM_io.F90 +++ b/src/framework/MOM_io.F90 @@ -58,6 +58,7 @@ module MOM_io public :: file_exists, open_ASCII_file, close_file public :: MOM_file, MOM_infra_file, MOM_netcdf_file public :: field_exists, get_filename_appendix +public :: insert_ensemble_appendix public :: fieldtype, field_size, get_field_atts public :: axistype, get_axis_data public :: MOM_read_data, MOM_read_vector, read_field_chksum @@ -2997,6 +2998,47 @@ subroutine MOM_write_field_0d(IO_handle, field_md, field, tstamp, fill_value, sc call IO_handle%write_field(field_md, scaled_val, tstamp=tstamp) end subroutine MOM_write_field_0d +!> Insert the ensemble appendix into a filename. If provided, the appendix is inserted after +!! the last occurrence of the insert_after substring in the filename. +subroutine insert_ensemble_appendix(filename, insert_after) + character(len=*), intent(inout) :: filename !< The filename to which the appendix is inserted + character(len=*), optional, intent(in) :: insert_after !< The string after which the appendix is inserted. + !! If not provided or found, the appendix is inserted + !! at the end of the filename. + ! Local variables + character(len=32) :: filename_appendix ! ensemble appendix to be inserted into the filename + character(len=:), allocatable :: filename_tr ! trimmed filename + character(len=:), allocatable :: insert_after_tr ! trimmed insert_after + integer :: pos ! The filename string index after which the appendix is to be inserted + + call get_filename_appendix(filename_appendix) + if (len_trim(filename_appendix) == 0) return + + filename_tr = trim(adjustl(filename)) + pos = len(filename_tr) + + ! If insert_after is provided, find the last occurrence of insert_after in the filename and set pos accordingly. + if (present(insert_after)) then + insert_after_tr = trim(adjustl(insert_after)) + pos = index(filename_tr, insert_after_tr, back=.true.) + if (pos == 0) then + call MOM_error(FATAL, "insert_ensemble_appendix: The string " // insert_after_tr // & + " was not found in the filename " // filename_tr) + endif + pos = pos + len(insert_after_tr) - 1 + endif + + ! Insert the ensemble appendix into the filename. If the appendix is to be added to + ! the end of the filename, do so before the .nc extension if it exists. + if (pos>3 .and. pos == len(filename_tr)) then + if (filename_tr(pos-2:pos) == ".nc") then + pos = pos - 3 ! Position before the .nc extension + endif + endif + filename = filename_tr(1:pos) // trim(filename_appendix) // filename_tr(pos+1:) + +end subroutine insert_ensemble_appendix + !> Given filename and fieldname, this subroutine returns the size of the field in the file subroutine field_size(filename, fieldname, sizes, field_found, no_domain, ndims, ncid_in) character(len=*), intent(in) :: filename !< The name of the file to read diff --git a/src/framework/MOM_restart.F90 b/src/framework/MOM_restart.F90 index 19d1950bd1..d7b4b31d1a 100644 --- a/src/framework/MOM_restart.F90 +++ b/src/framework/MOM_restart.F90 @@ -13,10 +13,11 @@ module MOM_restart use MOM_io, only : create_MOM_file, file_exists use MOM_io, only : MOM_infra_file, MOM_field use MOM_io, only : MOM_read_data, read_data, MOM_write_field, field_exists -use MOM_io, only : vardesc, var_desc, query_vardesc, modify_vardesc, get_filename_appendix +use MOM_io, only : vardesc, var_desc, query_vardesc, modify_vardesc use MOM_io, only : MULTIPLE, READONLY_FILE, SINGLE_FILE use MOM_io, only : CENTER, CORNER, NORTH_FACE, EAST_FACE use MOM_io, only : axis_info, get_axis_info +use MOM_io, only : insert_ensemble_appendix use MOM_string_functions, only : lowercase use MOM_time_manager, only : time_type, time_type_to_real, real_to_time use MOM_time_manager, only : days_in_month, get_date, set_date @@ -132,7 +133,8 @@ module MOM_restart type(p4d), pointer :: var_ptr4d(:) => NULL() !>@} integer :: max_fields !< The maximum number of restart fields - character(len=32) :: restartfile_appx_prefix !< The prefix for the restart file appendix (i.e., ensemble id) + character(len=32) :: ensemble_appendix_prefix !< The prefix after which the ensemble id appendix is added + !! in output file names. end type MOM_restart_CS !> Register fields for restarts @@ -1614,8 +1616,6 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_ integer :: turns ! Number of quarter turns from input to model domain integer, parameter :: nmax_extradims = 5 type(axis_info), dimension(:), allocatable :: extra_axes - integer :: prefix_index ! The index of the first occurrence of prefix in the restart filename. - integer :: prefix_length ! The length of the prefix string. turns = CS%turns @@ -1654,31 +1654,7 @@ subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV, num_ endif ; endif ! Determine if there is a filename_appendix (used for ensemble runs). - call get_filename_appendix(filename_appendix) - if (len_trim(filename_appendix) > 0) then - length = len_trim(restartname) - - ! Determine if a valid prefix for appendix is provided. - prefix_index = 0 - prefix_length = len_trim(CS%restartfile_appx_prefix) - if (prefix_length > 0) prefix_index = index(restartname, trim(CS%restartfile_appx_prefix)) - - if (prefix_index == 0) then ! No prefix is found - if (restartname(length-2:length) == '.nc') then - restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc' - else - restartname = restartname(1:length) //'.'//trim(filename_appendix) - endif - else ! Prefix is found - if (restartname(length-2:length) == '.nc') then - restartname = restartname(1:prefix_index-1+prefix_length) // & - trim(filename_appendix) // restartname(prefix_index+prefix_length:length-3) // '.nc' - else - restartname = restartname(1:prefix_index-1+prefix_length) // & - trim(filename_appendix) // restartname(prefix_index+prefix_length:) - endif - endif - endif + call insert_ensemble_appendix(restartname, CS%ensemble_appendix_prefix) next_var = 1 do while (next_var <= CS%novars ) @@ -2150,17 +2126,7 @@ function open_restart_units(filename, directory, G, CS, IO_handles, file_paths, still_looking = (num_restart <= 0) ! Avoid going through the file list twice. do while (still_looking) restartname = trim(CS%restartfile) - - ! Determine if there is a filename_appendix (used for ensemble runs). - call get_filename_appendix(filename_appendix) - if (len_trim(filename_appendix) > 0) then - length = len_trim(restartname) - if (restartname(length-2:length) == '.nc') then - restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc' - else - restartname = restartname(1:length) //'.'//trim(filename_appendix) - endif - endif + call insert_ensemble_appendix(restartname, CS%ensemble_appendix_prefix) filepath = trim(directory) // trim(restartname) write(suffix,'("_",I0)') num_restart @@ -2314,11 +2280,11 @@ subroutine restart_init(param_file, CS, restart_root) "made from a run with a different mask_table than the current run, "//& "in which case the checksums will not match and cause crash.",& default=.true.) - call get_param(param_file, mdl, "RESTARTFILE_APPENDIX_PREFIX", CS%restartfile_appx_prefix, & - "The prefix for the restart file appendix (i.e., ensemble id for ensemble runs). "// & - "If this prefix is found in the restart file name, the appendix is added right after the "// & - "first occurrence of the prefix. If not found, the appendix is added to the end of the "// & - "file name. This parameter is ignored for non-ensemble runs.", & + call get_param(param_file, mdl, "ENSEMBLE_APPENDIX_PREFIX", CS%ensemble_appendix_prefix, & + "If set to a non-empty string, this value specifies the substring after which "//& + "the ensemble appendix is inserted in restart, initial conditions, and ocean "//& + "geometry file names. If the specified substring is not found in any of those "//& + "output file names, the model terminates with an error.", & default="") call get_param(param_file, mdl, "RESTART_SYMMETRIC_CHECKSUMS", CS%symmetric_checksums, & "If true, do the restart checksums on all the edge points for a non-reentrant "//& diff --git a/src/initialization/MOM_shared_initialization.F90 b/src/initialization/MOM_shared_initialization.F90 index 08465659a6..cbb966c43d 100644 --- a/src/initialization/MOM_shared_initialization.F90 +++ b/src/initialization/MOM_shared_initialization.F90 @@ -16,6 +16,7 @@ module MOM_shared_initialization use MOM_io, only : MOM_read_data, MOM_read_vector, read_variable, stdout use MOM_io, only : open_file_to_read, close_file_to_read, SINGLE_FILE, MULTIPLE use MOM_io, only : slasher, vardesc, MOM_write_field, var_desc +use MOM_io, only : insert_ensemble_appendix use MOM_string_functions, only : uppercase use MOM_unit_scaling, only : unit_scale_type @@ -1342,6 +1343,7 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file) character(len=240) :: filepath ! The full path to the file to write character(len=40) :: mdl = "write_ocean_geometry_file" character(len=32) :: filename_appendix = '' ! Appendix to geom filename for ensemble runs + character(len=32) :: ensemble_appendix_prefix ! The prefix after which the ensemble id appendix is added type(vardesc), dimension(:), allocatable :: & vars ! Types with metadata about the variables and their staggering type(MOM_field), dimension(:), allocatable :: & @@ -1407,16 +1409,13 @@ subroutine write_ocean_geometry_file(G, param_file, directory, US, geom_file) filepath = trim(directory) // "ocean_geometry" endif - ! Append ensemble run number to filename if it is an ensemble run - call get_filename_appendix(filename_appendix) - if (len_trim(filename_appendix) > 0) then - geom_file_len = len_trim(filepath) - if (filepath(geom_file_len-2:geom_file_len) == ".nc") then - filepath = filepath(1:geom_file_len-3) // '.' // trim(filename_appendix) // ".nc" - else - filepath = filepath // '.' // trim(filename_appendix) - endif - endif + call get_param(param_file, mdl, "ENSEMBLE_APPENDIX_PREFIX", ensemble_appendix_prefix, & + "If set to a non-empty string, this value specifies the substring after which "//& + "the ensemble appendix is inserted in restart, initial conditions, and ocean "//& + "geometry file names. If the specified substring is not found in any of those "//& + "output file names, the model terminates with an error.", & + default="", do_not_log=.true.) + call insert_ensemble_appendix(filepath, ensemble_appendix_prefix) call get_param(param_file, mdl, "PARALLEL_RESTARTFILES", multiple_files, & "If true, the IO layout is used to group processors that write to the same "//& From d2279c8cd2ed05437fe700ef67af13b62faf7c1a Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Thu, 2 Apr 2026 09:17:34 -0600 Subject: [PATCH 35/41] Fix spurious restart writes caused by incorrect stop_alarm ring time (#414) In ModelSetRunClock, the stop_alarm was created using the driver clock's stopTime, which is just one coupling step ahead (currTime + driver_timestep), not the end of the simulation. This caused the alarm to ring on the first ocean coupling step, triggering spurious restart and rpointer file writes whenever write_restart_at_endofrun was enabled. The bug manifests in fully coupled (B) cases where the driver timestep (set by the fastest component, e.g., atmosphere at 1800s) differs from the ocean coupling interval (3600s). Fix: For CESM-coupled runs, use the model clock's stopTime (captured before ModelSetRunClock overwrites it), which holds the NUOPC-initialized end-of-run time. The non-CESM path is left unchanged for NOAA-EMC to address independently, preferably by removing the cesm_coupled branching this commit adds. --- config_src/drivers/nuopc_cap/mom_cap.F90 | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_cap.F90 b/config_src/drivers/nuopc_cap/mom_cap.F90 index 1f7e3b3cf7..a4c9a68a44 100644 --- a/config_src/drivers/nuopc_cap/mom_cap.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap.F90 @@ -2039,6 +2039,7 @@ subroutine ModelSetRunClock(gcomp, rc) type(ESMF_Clock) :: mclock, dclock type(ESMF_Time) :: mcurrtime, dcurrtime type(ESMF_Time) :: mstoptime, dstoptime + type(ESMF_Time) :: mstoptime_prev ! model stop time before it is updated by this routine type(ESMF_TimeInterval) :: mtimestep, dtimestep character(len=128) :: mtimestring, dtimestring character(len=256) :: cvalue @@ -2064,7 +2065,8 @@ subroutine ModelSetRunClock(gcomp, rc) stopTime=dstoptime, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_ClockGet(mclock, currTime=mcurrtime, timeStep=mtimestep, rc=rc) + call ESMF_ClockGet(mclock, currTime=mcurrtime, timeStep=mtimestep, & + stopTime=mstoptime_prev, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return !-------------------------------- @@ -2188,12 +2190,21 @@ subroutine ModelSetRunClock(gcomp, rc) endif ! create a 1-shot alarm at the driver stop time - stop_alarm = ESMF_AlarmCreate(mclock, ringtime=dstopTime, name = "stop_alarm", rc=rc) - call ESMF_LogWrite(subname//" Create Stop alarm", ESMF_LOGMSG_INFO) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (cesm_coupled) then + stop_alarm = ESMF_AlarmCreate(mclock, ringtime=mstoptime_prev, name = "stop_alarm", rc=rc) + call ESMF_LogWrite(subname//" Create Stop alarm", ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_TimeGet(dstoptime, timestring=timestr, rc=rc) - call ESMF_LogWrite("Stop Alarm will ring at : "//trim(timestr), ESMF_LOGMSG_INFO) + call ESMF_TimeGet(mstoptime_prev, timestring=timestr, rc=rc) + call ESMF_LogWrite("Stop Alarm will ring at : "//trim(timestr), ESMF_LOGMSG_INFO) + else + stop_alarm = ESMF_AlarmCreate(mclock, ringtime=dstopTime, name = "stop_alarm", rc=rc) + call ESMF_LogWrite(subname//" Create Stop alarm", ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet(dstoptime, timestring=timestr, rc=rc) + call ESMF_LogWrite("Stop Alarm will ring at : "//trim(timestr), ESMF_LOGMSG_INFO) + endif first_time = .false. From e6fdf98c5074926b5cc4cac785b9fcc64a759371 Mon Sep 17 00:00:00 2001 From: Gustavo Marques Date: Thu, 2 Apr 2026 12:03:53 -0600 Subject: [PATCH 36/41] Enforce tracer diffusivity minimum (KHTR_MIN) at all depths (#415) Enforce the minimum tracer diffusivity throughout the entire water column when using a vertically varying diffusivity structure (KHTR_USE_EBT_STRUCT=True). Parameter, FULL_DEPTH_KHTR_MIN (default: .false.), controls whether KHTR_MIN is applied as a lower bound at all depths. When FULL_DEPTH_KHTR_MIN=True, KHTR_MIN is enforced at every depth level for Coef_x, Coef_y, Kh_u, Kh_v, and Kh_h. When FULL_DEPTH_KHTR_MIN=False (default), the previous behavior is retained: the vertical structure uses VarMix%ebt_struct instead of VarMix%khtr_struct for Coef_x/Coef_y, and KHTR_MIN is only enforced at the surface. Motivation: When using vertically varying tracer diffusivity (KHTR_USE_EBT_STRUCT=True), KHTR_MIN was previously enforced only in the surface layer. This could result in very weak or near-zero diffusivity in the ocean interior. The new option allows users to enforce a minimum diffusivity throughout the water column. FULL_DEPTH_KHTR_MIN is only read and applied when both KHTR_USE_EBT_STRUCT=True and KHTR_MIN > 0. --- src/tracer/MOM_tracer_hor_diff.F90 | 101 ++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/src/tracer/MOM_tracer_hor_diff.F90 b/src/tracer/MOM_tracer_hor_diff.F90 index 9a10826627..02aa597a7e 100644 --- a/src/tracer/MOM_tracer_hor_diff.F90 +++ b/src/tracer/MOM_tracer_hor_diff.F90 @@ -505,21 +505,43 @@ subroutine tracer_hordiff(h, dt, MEKE, VarMix, visc, G, GV, US, CS, Reg, tv, do_ enddo enddo enddo + if (CS%KhTr_use_vert_struct) then - do K=2,nz+1 - do J=js-1,je - do i=is,ie - Coef_y(i,J,K) = Coef_y(i,J,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i,j+1,k-1) ) + if (CS%full_depth_khtr_min) then + do K=2,nz+1 + do J=js-1,je + do i=is,ie + Coef_y(i,J,K) = Coef_y(i,J,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i,j+1,k-1) ) + Coef_min = I_numitts * dt * (CS%KhTr_min*(G%dx_Cv(i,J)*G%IdyCv(i,J))) + Coef_y(i,J,K) = max(Coef_y(i,J,K), Coef_min) + enddo enddo enddo - enddo - do k=2,nz+1 - do j=js,je - do I=is-1,ie - Coef_x(I,j,K) = Coef_x(I,j,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i+1,j,k-1) ) + do k=2,nz+1 + do j=js,je + do I=is-1,ie + Coef_x(I,j,K) = Coef_x(I,j,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i+1,j,k-1) ) + Coef_min = I_numitts * dt * (CS%KhTr_min*(G%dy_Cu(I,j)*G%IdxCu(I,j))) + Coef_x(I,j,K) = max(Coef_x(I,j,K), Coef_min) + enddo enddo enddo - enddo + else + do K=2,nz+1 + do J=js-1,je + do i=is,ie + Coef_y(i,J,K) = Coef_y(i,J,1) * 0.5 * ( VarMix%ebt_struct(i,j,k-1) + VarMix%ebt_struct(i,j+1,k-1) ) + enddo + enddo + enddo + do k=2,nz+1 + do j=js,je + do I=is-1,ie + Coef_x(I,j,K) = Coef_x(I,j,1) * 0.5 * ( VarMix%ebt_struct(i,j,k-1) + VarMix%ebt_struct(i+1,j,k-1) ) + enddo + enddo + enddo + endif endif do itt=1,num_itts @@ -633,13 +655,24 @@ subroutine tracer_hordiff(h, dt, MEKE, VarMix, visc, G, GV, US, CS, Reg, tv, do_ Kh_u(I,j,:) = G%mask2dCu(I,j)*Kh_u(I,j,1) enddo ; enddo if (CS%KhTr_use_vert_struct) then - do K=2,nz+1 - do j=js,je - do I=is-1,ie - Kh_u(I,j,K) = Kh_u(I,j,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i+1,j,k-1) ) + if (CS%full_depth_khtr_min) then + do K=2,nz+1 + do j=js,je + do I=is-1,ie + Kh_u(I,j,K) = Kh_u(I,j,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i+1,j,k-1) ) + Kh_u(I,j,K) = max(Kh_u(I,j,K), CS%KhTr_min) + enddo enddo enddo - enddo + else + do K=2,nz+1 + do j=js,je + do I=is-1,ie + Kh_u(I,j,K) = Kh_u(I,j,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i+1,j,k-1) ) + enddo + enddo + enddo + endif endif !call post_data(CS%id_KhTr_u, Kh_u, CS%diag, is_static=.false., mask=G%mask2dCu) call post_data(CS%id_KhTr_u, Kh_u, CS%diag) @@ -649,13 +682,24 @@ subroutine tracer_hordiff(h, dt, MEKE, VarMix, visc, G, GV, US, CS, Reg, tv, do_ Kh_v(i,J,:) = G%mask2dCv(i,J)*Kh_v(i,J,1) enddo ; enddo if (CS%KhTr_use_vert_struct) then - do K=2,nz+1 - do J=js-1,je - do i=is,ie - Kh_v(i,J,K) = Kh_v(i,J,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i,j+1,k-1) ) + if (CS%full_depth_khtr_min) then + do K=2,nz+1 + do J=js-1,je + do i=is,ie + Kh_v(i,J,K) = Kh_v(i,J,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i,j+1,k-1) ) + Kh_v(i,J,K) = max(Kh_v(i,J,K), CS%KhTr_min) + enddo enddo enddo - enddo + else + do K=2,nz+1 + do J=js-1,je + do i=is,ie + Kh_v(i,J,K) = Kh_v(i,J,1) * 0.5 * ( VarMix%khtr_struct(i,j,k-1) + VarMix%khtr_struct(i,j+1,k-1) ) + enddo + enddo + enddo + endif endif !call post_data(CS%id_KhTr_v, Kh_v, CS%diag, is_static=.false., mask=G%mask2dCv) call post_data(CS%id_KhTr_v, Kh_v, CS%diag) @@ -675,10 +719,19 @@ subroutine tracer_hordiff(h, dt, MEKE, VarMix, visc, G, GV, US, CS, Reg, tv, do_ Kh_h(i,j,:) = normalize*G%mask2dT(i,j)*((Kh_u(I-1,j,1)+Kh_u(I,j,1)) + & (Kh_v(i,J-1,1)+Kh_v(i,J,1))) if (CS%KhTr_use_vert_struct) then - do K=2,nz+1 - Kh_h(i,j,K) = normalize*G%mask2dT(i,j)*VarMix%khtr_struct(i,j,k-1)*((Kh_u(I-1,j,1)+Kh_u(I,j,1)) + & - (Kh_v(i,J-1,1)+Kh_v(i,J,1))) - enddo + if (CS%full_depth_khtr_min) then + do K=2,nz+1 + Kh_h(i,j,K) = normalize*G%mask2dT(i,j)*VarMix%khtr_struct(i,j,k-1)*((Kh_u(I-1,j,1)+Kh_u(I,j,1)) + & + (Kh_v(i,J-1,1)+Kh_v(i,J,1))) + Kh_h(i,j,K) = max(Kh_h(i,j,K), CS%KhTr_min) + enddo + + else + do K=2,nz+1 + Kh_h(i,j,K) = normalize*G%mask2dT(i,j)*VarMix%khtr_struct(i,j,k-1)*((Kh_u(I-1,j,1)+Kh_u(I,j,1)) + & + (Kh_v(i,J-1,1)+Kh_v(i,J,1))) + enddo + endif endif enddo ; enddo !call post_data(CS%id_KhTr_h, Kh_h, CS%diag, is_static=.false., mask=G%mask2dT) From 258d4e988fb75edbf62b46a686a10bd23ed1734c Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Thu, 9 Apr 2026 14:28:53 -0600 Subject: [PATCH 37/41] Merge main 260408 (#417) * Fix divide by zero fpe in apply_oda_incupd (#164) Move computation of tmp_h inside the if G%mask2dT test to avoid divide by zero error * Add mom_cap_outputlog.F90 that enables output logging diagnostics at a given hourly output frequency Author: Denise Worthen This feature is required for UFS operational configurations and is used to determine when MOM6 output (diagnostics and restart) have been completed. The log files created by this feature can be queried by the Global Workflow to either trigger downstream jobs or to ensure that if a run fails and a restart is required, model output is available consistent with a given restart file. * Adds the ability to read a CDEPS configuration file to provide in-line forcing. * Adds the ability to read a CDEPS configuration file to provide in-line forcing. Currently this is set up to read a non-climatological lrunoff data stream only. * Add tracing instrumentation to nuopc driver (#162) * adds calls to ufs tracing routines that will create a trace file which can then be visualized, which is found to be useful in identifying various performance issues. * Update CVMix to Apache-2.0 based release This patch updates the CVMix submodule to a more recent version that is licensed under the Apache 2.0 license. There are no code changes to CVMix relative to the current version. * Relicense code to Apache License, Version 2.0 This PR re-licenses the MOM6 source code from the Lesser GNU Public License, version 3 to Apache License, Version 2.0. This is done with the consent of all contributors to the source code. All source files are now tagged with the following disclaimer. ``` This file is part of MOM6, the Modular Ocean Model version 6. See the LICENSE file for licensing information. SPDX-License-Identifier: Apache-2.0 ``` All relevent source code, scripts, and macros are now explicitly identified as part of MOM6. Configuration files containing scripts, such as GitHub Actions, have also been tagged. Any other configurations, such as model inputs, have been excluded. * Address reviewer comments (#14) In mom_cap.F90 rename module variable 'mype' to 'localPet' Rename mom_ufs_trace_wrapper module to mom_cap_profiling Add docstrings * address reviewers comments (#15) * indenting for mom_inline_mod and mom_cap_outputlog.F90 made consistent w/ MOM6 style * several docstrings added or moved; spurious whitespace and comments removed * two word end if and end do changed to one word * Fixes for flang * Change variable not type --------- Co-authored-by: jiandewang Co-authored-by: Dusan Jovic <48258889+DusanJovic-NOAA@users.noreply.github.com> Co-authored-by: Denise Worthen Co-authored-by: Marshall Ward Co-authored-by: Matthew Thompson --- .github/actions/macos-setup/action.yml | 4 + .github/actions/ubuntu-setup/action.yml | 4 + .github/workflows/verify-linux.yml | 4 + .github/workflows/verify-macos.yml | 4 + .gitlab-ci.yml | 4 + .gitlab/mom6-ci-run-gnu-restarts-script.sh | 3 + .gitlab/mom6-ci-run-gnu-script.sh | 3 + .gitlab/mom6-ci-run-intel-script.sh | 3 + .gitlab/mom6-ci-run-pgi-script.sh | 3 + .gitlab/pipeline-ci-tool.sh | 3 + .testing/Makefile | 4 + .testing/tc4/Makefile.in | 4 + .testing/tc4/configure.ac | 4 + .testing/tc4/gen_data.F90 | 4 + .testing/tc4/gen_grid.F90 | 4 + .testing/tools/cmp_diag.sh | 3 + .testing/tools/compare_clocks.py | 4 + .testing/tools/compare_perf.py | 4 + .testing/tools/diff_diag.sh | 3 + .testing/tools/disp_timing.py | 3 + .testing/tools/parse_fms_clocks.py | 4 + .testing/tools/parse_perf.py | 4 + .testing/tools/report_test_results.sh | 4 + .testing/trailer.py | 4 + LICENSE | 177 +++++ LICENSE.md | 173 ----- ac/Makefile.in | 4 + ac/configure.ac | 4 + ac/deps/Makefile | 4 + ac/deps/Makefile.fms.in | 4 + ac/deps/configure.fms.ac | 4 + ac/deps/m4/ax_fc_allow_arg_mismatch.m4 | 4 + ac/deps/m4/ax_fc_allow_invalid_boz.m4 | 4 + ac/deps/m4/ax_fc_check_c_lib.m4 | 4 + ac/deps/m4/ax_fc_check_lib.m4 | 4 + ac/deps/m4/ax_fc_check_module.m4 | 4 + ac/deps/m4/ax_fc_cray_pointer.m4 | 4 + ac/deps/m4/ax_fc_line_length.m4 | 4 + ac/deps/m4/ax_fc_real8.m4 | 4 + ac/m4/ax_fc_check_bind_c.m4 | 4 + ac/m4/ax_fc_check_c_lib.m4 | 4 + ac/m4/ax_fc_check_lib.m4 | 4 + ac/m4/ax_fc_check_module.m4 | 4 + ac/m4/ax_fc_real8.m4 | 4 + .../FMS_cap/MOM_surface_forcing_gfdl.F90 | 6 +- .../drivers/FMS_cap/ocean_model_MOM.F90 | 6 +- .../STALE_mct_cap/mom_ocean_model_mct.F90 | 6 +- .../STALE_mct_cap/mom_surface_forcing_mct.F90 | 6 +- .../drivers/STALE_mct_cap/ocn_cap_methods.F90 | 4 + .../drivers/STALE_mct_cap/ocn_comp_mct.F90 | 6 +- .../drivers/STALE_mct_cap/ocn_cpl_indices.F90 | 4 + .../ice_solo_driver/atmos_ocean_fluxes.F90 | 6 +- .../ice_solo_driver/ice_shelf_driver.F90 | 6 +- config_src/drivers/nuopc_cap/mom_cap.F90 | 121 +++- .../drivers/nuopc_cap/mom_cap_methods.F90 | 4 + .../drivers/nuopc_cap/mom_cap_outputlog.F90 | 623 ++++++++++++++++++ .../drivers/nuopc_cap/mom_cap_profiling.F90 | 45 ++ config_src/drivers/nuopc_cap/mom_cap_time.F90 | 4 + .../drivers/nuopc_cap/mom_inline_mod.F90 | 218 ++++++ .../nuopc_cap/mom_ocean_model_nuopc.F90 | 6 +- .../nuopc_cap/mom_surface_forcing_nuopc.F90 | 6 +- .../drivers/nuopc_cap/ocn_comp_NUOPC.F90 | 4 + config_src/drivers/nuopc_cap/time_utils.F90 | 4 + .../solo_driver/MESO_surface_forcing.F90 | 6 +- config_src/drivers/solo_driver/MOM_driver.F90 | 6 +- .../solo_driver/MOM_surface_forcing.F90 | 6 +- .../solo_driver/atmos_ocean_fluxes.F90 | 6 +- .../solo_driver/user_surface_forcing.F90 | 6 +- .../drivers/timing_tests/time_MOM_ANN.F90 | 6 +- .../drivers/timing_tests/time_MOM_EOS.F90 | 6 +- .../timing_tests/time_MOM_remapping.F90 | 6 +- .../timing_tests/time_reproducing_sum.F90 | 6 +- .../drivers/unit_tests/test_MOM_ANN.F90 | 4 + .../drivers/unit_tests/test_MOM_EOS.F90 | 4 + .../unit_tests/test_MOM_file_parser.F90 | 4 + .../test_MOM_mixedlayer_restrat.F90 | 4 + .../drivers/unit_tests/test_MOM_remapping.F90 | 4 + .../unit_tests/test_MOM_string_functions.F90 | 4 + .../test_numerical_testing_type.F90 | 4 + .../unit_tests/test_reproducing_sum.F90 | 6 +- .../GFDL_ocean_BGC/MOM_generic_tracer.F90 | 6 +- .../external/MARBL/marbl_constants_mod.F90 | 4 + config_src/external/MARBL/marbl_interface.F90 | 4 + .../MARBL/marbl_interface_public_types.F90 | 6 +- config_src/external/MARBL/marbl_logging.F90 | 6 +- config_src/external/ODA_hooks/kdtree.f90 | 4 + .../external/ODA_hooks/ocean_da_core.F90 | 4 + .../external/ODA_hooks/ocean_da_types.F90 | 4 + .../external/ODA_hooks/write_ocean_obs.F90 | 4 + .../database_comms/MOM_database_comms.F90 | 5 +- .../database_client_interface.F90 | 5 +- .../external/drifters/MOM_particles.F90 | 6 +- .../external/drifters/MOM_particles_types.F90 | 6 +- .../stochastic_physics/get_stochy_pattern.F90 | 6 +- .../stochastic_physics/stochastic_physics.F90 | 6 +- config_src/infra/FMS1/MOM_coms_infra.F90 | 6 +- config_src/infra/FMS1/MOM_constants.F90 | 6 +- .../infra/FMS1/MOM_couplertype_infra.F90 | 6 +- config_src/infra/FMS1/MOM_cpu_clock_infra.F90 | 6 +- .../infra/FMS1/MOM_data_override_infra.F90 | 6 +- .../infra/FMS1/MOM_diag_manager_infra.F90 | 6 +- config_src/infra/FMS1/MOM_domain_infra.F90 | 6 +- .../infra/FMS1/MOM_ensemble_manager_infra.F90 | 6 +- config_src/infra/FMS1/MOM_error_infra.F90 | 6 +- config_src/infra/FMS1/MOM_interp_infra.F90 | 6 +- config_src/infra/FMS1/MOM_io_infra.F90 | 6 +- config_src/infra/FMS1/MOM_time_manager.F90 | 6 +- config_src/infra/FMS2/MOM_coms_infra.F90 | 6 +- config_src/infra/FMS2/MOM_constants.F90 | 6 +- .../infra/FMS2/MOM_couplertype_infra.F90 | 6 +- config_src/infra/FMS2/MOM_cpu_clock_infra.F90 | 6 +- .../infra/FMS2/MOM_data_override_infra.F90 | 6 +- .../infra/FMS2/MOM_diag_manager_infra.F90 | 6 +- config_src/infra/FMS2/MOM_domain_infra.F90 | 6 +- .../infra/FMS2/MOM_ensemble_manager_infra.F90 | 6 +- config_src/infra/FMS2/MOM_error_infra.F90 | 6 +- config_src/infra/FMS2/MOM_interp_infra.F90 | 6 +- config_src/infra/FMS2/MOM_io_infra.F90 | 6 +- config_src/infra/FMS2/MOM_time_manager.F90 | 6 +- .../memory/dynamic_nonsymmetric/MOM_memory.h | 4 + .../memory/dynamic_symmetric/MOM_memory.h | 4 + docs/postProcessEquations.py | 4 + src/ALE/MOM_ALE.F90 | 6 +- src/ALE/MOM_hybgen_regrid.F90 | 6 +- src/ALE/MOM_hybgen_remap.F90 | 6 +- src/ALE/MOM_hybgen_unmix.F90 | 6 +- src/ALE/MOM_regridding.F90 | 6 +- src/ALE/MOM_remapping.F90 | 69 +- src/ALE/P1M_functions.F90 | 6 +- src/ALE/P3M_functions.F90 | 6 +- src/ALE/PCM_functions.F90 | 6 +- src/ALE/PLM_functions.F90 | 6 +- src/ALE/PPM_functions.F90 | 6 +- src/ALE/PQM_functions.F90 | 6 +- src/ALE/Recon1d_EMPLM_CWK.F90 | 6 +- src/ALE/Recon1d_EMPLM_WA.F90 | 6 +- src/ALE/Recon1d_EMPLM_WA_poly.F90 | 6 +- src/ALE/Recon1d_EPPM_CWK.F90 | 6 +- src/ALE/Recon1d_MPLM_CWK.F90 | 6 +- src/ALE/Recon1d_MPLM_WA.F90 | 6 +- src/ALE/Recon1d_MPLM_WA_poly.F90 | 6 +- src/ALE/Recon1d_PCM.F90 | 6 +- src/ALE/Recon1d_PLM_CW.F90 | 6 +- src/ALE/Recon1d_PLM_CWK.F90 | 6 +- src/ALE/Recon1d_PLM_hybgen.F90 | 6 +- src/ALE/Recon1d_PPM_CW.F90 | 6 +- src/ALE/Recon1d_PPM_CWK.F90 | 6 +- src/ALE/Recon1d_PPM_H4_2018.F90 | 6 +- src/ALE/Recon1d_PPM_H4_2019.F90 | 6 +- src/ALE/Recon1d_PPM_hybgen.F90 | 6 +- src/ALE/Recon1d_type.F90 | 6 +- src/ALE/coord_adapt.F90 | 6 +- src/ALE/coord_hycom.F90 | 6 +- src/ALE/coord_rho.F90 | 6 +- src/ALE/coord_sigma.F90 | 6 +- src/ALE/coord_zlike.F90 | 6 +- src/ALE/polynomial_functions.F90 | 6 +- src/ALE/regrid_consts.F90 | 6 +- src/ALE/regrid_edge_values.F90 | 6 +- src/ALE/regrid_interp.F90 | 6 +- src/ALE/regrid_solvers.F90 | 6 +- src/core/MOM.F90 | 6 +- src/core/MOM_CoriolisAdv.F90 | 6 +- src/core/MOM_PressureForce.F90 | 6 +- src/core/MOM_PressureForce_FV.F90 | 6 +- src/core/MOM_PressureForce_Montgomery.F90 | 6 +- src/core/MOM_barotropic.F90 | 6 +- src/core/MOM_boundary_update.F90 | 7 +- src/core/MOM_check_scaling.F90 | 6 +- src/core/MOM_checksum_packages.F90 | 6 +- src/core/MOM_continuity.F90 | 6 +- src/core/MOM_continuity_PPM.F90 | 6 +- src/core/MOM_density_integrals.F90 | 6 +- src/core/MOM_dynamics_split_RK2.F90 | 6 +- src/core/MOM_dynamics_split_RK2b.F90 | 6 +- src/core/MOM_dynamics_unsplit.F90 | 6 +- src/core/MOM_dynamics_unsplit_RK2.F90 | 6 +- src/core/MOM_forcing_type.F90 | 6 +- src/core/MOM_grid.F90 | 6 +- src/core/MOM_interface_heights.F90 | 6 +- src/core/MOM_isopycnal_slopes.F90 | 6 +- src/core/MOM_open_boundary.F90 | 6 +- src/core/MOM_porous_barriers.F90 | 6 +- src/core/MOM_stoch_eos.F90 | 5 +- src/core/MOM_transcribe_grid.F90 | 6 +- src/core/MOM_unit_tests.F90 | 6 +- src/core/MOM_variables.F90 | 6 +- src/core/MOM_verticalGrid.F90 | 6 +- src/diagnostics/MOM_PointAccel.F90 | 6 +- src/diagnostics/MOM_debugging.F90 | 6 +- src/diagnostics/MOM_diagnose_KdWork.F90 | 6 +- src/diagnostics/MOM_diagnose_MLD.F90 | 6 +- src/diagnostics/MOM_diagnostics.F90 | 6 +- src/diagnostics/MOM_harmonic_analysis.F90 | 4 + src/diagnostics/MOM_obsolete_diagnostics.F90 | 6 +- src/diagnostics/MOM_obsolete_params.F90 | 5 +- src/diagnostics/MOM_spatial_means.F90 | 6 +- src/diagnostics/MOM_sum_output.F90 | 6 +- src/diagnostics/MOM_wave_speed.F90 | 6 +- src/equation_of_state/MOM_EOS.F90 | 6 +- src/equation_of_state/MOM_EOS_Jackett06.F90 | 6 +- src/equation_of_state/MOM_EOS_Roquet_SpV.F90 | 6 +- src/equation_of_state/MOM_EOS_Roquet_rho.F90 | 6 +- src/equation_of_state/MOM_EOS_TEOS10.F90 | 6 +- src/equation_of_state/MOM_EOS_UNESCO.F90 | 6 +- src/equation_of_state/MOM_EOS_Wright.F90 | 6 +- src/equation_of_state/MOM_EOS_Wright_full.F90 | 6 +- src/equation_of_state/MOM_EOS_Wright_red.F90 | 6 +- src/equation_of_state/MOM_EOS_base_type.F90 | 6 +- src/equation_of_state/MOM_EOS_linear.F90 | 6 +- src/equation_of_state/MOM_TFreeze.F90 | 6 +- .../MOM_temperature_convert.F90 | 6 +- src/framework/MOM_ANN.F90 | 4 + src/framework/MOM_array_transform.F90 | 4 + src/framework/MOM_checksums.F90 | 6 +- src/framework/MOM_coms.F90 | 6 +- src/framework/MOM_coupler_types.F90 | 6 +- src/framework/MOM_cpu_clock.F90 | 6 +- src/framework/MOM_data_override.F90 | 6 +- src/framework/MOM_diag_mediator.F90 | 6 +- src/framework/MOM_diag_remap.F90 | 6 +- src/framework/MOM_document.F90 | 6 +- src/framework/MOM_domains.F90 | 6 +- src/framework/MOM_dyn_horgrid.F90 | 6 +- src/framework/MOM_ensemble_manager.F90 | 6 +- src/framework/MOM_error_handler.F90 | 6 +- src/framework/MOM_file_parser.F90 | 6 +- src/framework/MOM_get_input.F90 | 6 +- src/framework/MOM_hor_index.F90 | 6 +- src/framework/MOM_horizontal_regridding.F90 | 6 +- src/framework/MOM_interpolate.F90 | 6 +- src/framework/MOM_intrinsic_functions.F90 | 6 +- src/framework/MOM_io.F90 | 6 +- src/framework/MOM_io_file.F90 | 6 +- src/framework/MOM_memory_macros.h | 4 + src/framework/MOM_murmur_hash.F90 | 4 + src/framework/MOM_netcdf.F90 | 6 +- src/framework/MOM_random.F90 | 6 +- src/framework/MOM_restart.F90 | 6 +- src/framework/MOM_safe_alloc.F90 | 6 +- src/framework/MOM_string_functions.F90 | 6 +- src/framework/MOM_unique_scales.F90 | 6 +- src/framework/MOM_unit_scaling.F90 | 6 +- src/framework/MOM_unit_testing.F90 | 4 + src/framework/MOM_write_cputime.F90 | 6 +- src/framework/numerical_testing_type.F90 | 6 +- src/framework/posix.F90 | 4 + src/framework/posix.h | 4 + .../testing/MOM_file_parser_tests.F90 | 4 + src/framework/version_variable.h | 4 + src/ice_shelf/MOM_ice_shelf.F90 | 5 +- src/ice_shelf/MOM_ice_shelf_diag_mediator.F90 | 4 + src/ice_shelf/MOM_ice_shelf_dynamics.F90 | 6 +- src/ice_shelf/MOM_ice_shelf_initialize.F90 | 6 +- src/ice_shelf/MOM_ice_shelf_state.F90 | 6 +- src/ice_shelf/MOM_marine_ice.F90 | 6 +- src/ice_shelf/user_shelf_init.F90 | 6 +- .../MOM_coord_initialization.F90 | 6 +- .../MOM_fixed_initialization.F90 | 6 +- src/initialization/MOM_grid_initialize.F90 | 6 +- .../MOM_shared_initialization.F90 | 6 +- .../MOM_state_initialization.F90 | 6 +- .../MOM_tracer_initialization_from_Z.F90 | 6 +- src/ocean_data_assim/MOM_oda_driver.F90 | 4 + src/ocean_data_assim/MOM_oda_incupd.F90 | 29 +- src/parameterizations/lateral/MOM_MEKE.F90 | 5 +- .../lateral/MOM_MEKE_types.F90 | 6 +- .../lateral/MOM_Zanna_Bolton.F90 | 5 +- .../lateral/MOM_hor_visc.F90 | 7 +- .../lateral/MOM_interface_filter.F90 | 6 +- .../lateral/MOM_internal_tides.F90 | 6 +- .../lateral/MOM_lateral_mixing_coeffs.F90 | 6 +- .../lateral/MOM_load_love_numbers.F90 | 4 + .../lateral/MOM_mixed_layer_restrat.F90 | 6 +- .../lateral/MOM_self_attr_load.F90 | 4 + .../lateral/MOM_spherical_harmonics.F90 | 4 + .../lateral/MOM_streaming_filter.F90 | 4 + .../lateral/MOM_thickness_diffuse.F90 | 6 +- .../lateral/MOM_tidal_forcing.F90 | 6 +- .../lateral/MOM_wave_drag.F90 | 4 + .../stochastic/MOM_stochastics.F90 | 6 +- .../vertical/MOM_ALE_sponge.F90 | 5 +- .../vertical/MOM_CVMix_KPP.F90 | 6 +- .../vertical/MOM_CVMix_conv.F90 | 6 +- .../vertical/MOM_CVMix_ddiff.F90 | 6 +- .../vertical/MOM_CVMix_shear.F90 | 6 +- .../vertical/MOM_bkgnd_mixing.F90 | 6 +- .../vertical/MOM_bulk_mixed_layer.F90 | 6 +- .../vertical/MOM_diabatic_aux.F90 | 6 +- .../vertical/MOM_diabatic_driver.F90 | 6 +- .../vertical/MOM_diapyc_energy_req.F90 | 6 +- .../vertical/MOM_energetic_PBL.F90 | 6 +- .../vertical/MOM_entrain_diffusive.F90 | 6 +- .../vertical/MOM_full_convection.F90 | 6 +- .../vertical/MOM_geothermal.F90 | 6 +- .../vertical/MOM_internal_tide_input.F90 | 6 +- .../vertical/MOM_kappa_shear.F90 | 6 +- .../vertical/MOM_opacity.F90 | 6 +- .../vertical/MOM_regularize_layers.F90 | 6 +- .../vertical/MOM_set_diffusivity.F90 | 6 +- .../vertical/MOM_set_viscosity.F90 | 6 +- src/parameterizations/vertical/MOM_sponge.F90 | 6 +- .../vertical/MOM_tidal_mixing.F90 | 6 +- .../vertical/MOM_vert_friction.F90 | 5 +- src/tracer/DOME_tracer.F90 | 6 +- src/tracer/ISOMIP_tracer.F90 | 6 +- src/tracer/MARBL_forcing_mod.F90 | 4 + src/tracer/MARBL_tracers.F90 | 6 +- src/tracer/MOM_CFC_cap.F90 | 6 +- src/tracer/MOM_OCMIP2_CFC.F90 | 6 +- src/tracer/MOM_hor_bnd_diffusion.F90 | 6 +- src/tracer/MOM_neutral_diffusion.F90 | 6 +- src/tracer/MOM_offline_aux.F90 | 6 +- src/tracer/MOM_offline_main.F90 | 6 +- src/tracer/MOM_tracer_Z_init.F90 | 6 +- src/tracer/MOM_tracer_advect.F90 | 6 +- src/tracer/MOM_tracer_advect_schemes.F90 | 6 +- src/tracer/MOM_tracer_diabatic.F90 | 6 +- src/tracer/MOM_tracer_flow_control.F90 | 6 +- src/tracer/MOM_tracer_hor_diff.F90 | 6 +- src/tracer/MOM_tracer_registry.F90 | 6 +- src/tracer/MOM_tracer_types.F90 | 4 + src/tracer/RGC_tracer.F90 | 6 +- src/tracer/advection_test_tracer.F90 | 6 +- src/tracer/boundary_impulse_tracer.F90 | 6 +- src/tracer/dye_example.F90 | 6 +- src/tracer/dyed_obc_tracer.F90 | 6 +- src/tracer/ideal_age_example.F90 | 6 +- src/tracer/nw2_tracers.F90 | 6 +- src/tracer/oil_tracer.F90 | 6 +- src/tracer/pseudo_salt_tracer.F90 | 6 +- src/tracer/tracer_example.F90 | 6 +- src/user/BFB_initialization.F90 | 6 +- src/user/BFB_surface_forcing.F90 | 6 +- src/user/DOME2d_initialization.F90 | 6 +- src/user/DOME_initialization.F90 | 6 +- src/user/ISOMIP_initialization.F90 | 6 +- src/user/Idealized_Hurricane.F90 | 6 +- src/user/Kelvin_initialization.F90 | 6 +- src/user/MOM_controlled_forcing.F90 | 6 +- src/user/MOM_wave_interface.F90 | 6 +- src/user/Neverworld_initialization.F90 | 6 +- src/user/Phillips_initialization.F90 | 6 +- src/user/RGC_initialization.F90 | 6 +- src/user/Rossby_front_2d_initialization.F90 | 6 +- src/user/SCM_CVMix_tests.F90 | 6 +- src/user/adjustment_initialization.F90 | 6 +- src/user/baroclinic_zone_initialization.F90 | 6 +- src/user/basin_builder.F90 | 6 +- src/user/benchmark_initialization.F90 | 6 +- src/user/circle_obcs_initialization.F90 | 6 +- src/user/dense_water_initialization.F90 | 6 +- src/user/dumbbell_initialization.F90 | 6 +- src/user/dumbbell_surface_forcing.F90 | 6 +- src/user/dyed_channel_initialization.F90 | 6 +- src/user/dyed_obcs_initialization.F90 | 6 +- src/user/external_gwave_initialization.F90 | 6 +- src/user/lock_exchange_initialization.F90 | 6 +- src/user/seamount_initialization.F90 | 6 +- src/user/shelfwave_initialization.F90 | 6 +- src/user/sloshing_initialization.F90 | 6 +- src/user/soliton_initialization.F90 | 6 +- src/user/supercritical_initialization.F90 | 6 +- src/user/tidal_bay_initialization.F90 | 6 +- src/user/user_change_diffusivity.F90 | 6 +- src/user/user_initialization.F90 | 6 +- src/user/user_revise_forcing.F90 | 6 +- 367 files changed, 2645 insertions(+), 783 deletions(-) create mode 100644 LICENSE delete mode 100644 LICENSE.md create mode 100644 config_src/drivers/nuopc_cap/mom_cap_outputlog.F90 create mode 100644 config_src/drivers/nuopc_cap/mom_cap_profiling.F90 create mode 100644 config_src/drivers/nuopc_cap/mom_inline_mod.F90 diff --git a/.github/actions/macos-setup/action.yml b/.github/actions/macos-setup/action.yml index caa6f193bb..0c1116f25b 100644 --- a/.github/actions/macos-setup/action.yml +++ b/.github/actions/macos-setup/action.yml @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + name: 'install-macos-prerequisites' description: 'Install prerequisites for Mac OS compilation' diff --git a/.github/actions/ubuntu-setup/action.yml b/.github/actions/ubuntu-setup/action.yml index 0f53a68c70..22d8ae897a 100644 --- a/.github/actions/ubuntu-setup/action.yml +++ b/.github/actions/ubuntu-setup/action.yml @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + name: 'install-ubuntu-prerequisites' description: 'Install prerequisites for Ubuntu Linux compilation' diff --git a/.github/workflows/verify-linux.yml b/.github/workflows/verify-linux.yml index 4c2817f4ee..2bc7a66255 100644 --- a/.github/workflows/verify-linux.yml +++ b/.github/workflows/verify-linux.yml @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + name: Linux verification on: [push, pull_request] diff --git a/.github/workflows/verify-macos.yml b/.github/workflows/verify-macos.yml index d058336053..5ba0669b7a 100644 --- a/.github/workflows/verify-macos.yml +++ b/.github/workflows/verify-macos.yml @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + name: MacOS verification on: [push, pull_request] diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5aa48ae919..b1f7f4bf4d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + stages: - setup - builds diff --git a/.gitlab/mom6-ci-run-gnu-restarts-script.sh b/.gitlab/mom6-ci-run-gnu-restarts-script.sh index 02af3460b4..104dc40567 100644 --- a/.gitlab/mom6-ci-run-gnu-restarts-script.sh +++ b/.gitlab/mom6-ci-run-gnu-restarts-script.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 sect=none clean_stats () { # fn to clean up stats files diff --git a/.gitlab/mom6-ci-run-gnu-script.sh b/.gitlab/mom6-ci-run-gnu-script.sh index 8577eff6d2..13dfe00111 100644 --- a/.gitlab/mom6-ci-run-gnu-script.sh +++ b/.gitlab/mom6-ci-run-gnu-script.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 sect=none clean_stats () { # fn to clean up stats files diff --git a/.gitlab/mom6-ci-run-intel-script.sh b/.gitlab/mom6-ci-run-intel-script.sh index 875d60c191..01a2888e80 100644 --- a/.gitlab/mom6-ci-run-intel-script.sh +++ b/.gitlab/mom6-ci-run-intel-script.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 sect=none clean_stats () { # fn to clean up stats files diff --git a/.gitlab/mom6-ci-run-pgi-script.sh b/.gitlab/mom6-ci-run-pgi-script.sh index 27216e4a9f..4e55b5ced8 100644 --- a/.gitlab/mom6-ci-run-pgi-script.sh +++ b/.gitlab/mom6-ci-run-pgi-script.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 sect=none clean_stats () { # fn to clean up stats files diff --git a/.gitlab/pipeline-ci-tool.sh b/.gitlab/pipeline-ci-tool.sh index d948b72008..a6948c765e 100755 --- a/.gitlab/pipeline-ci-tool.sh +++ b/.gitlab/pipeline-ci-tool.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 # Environment variables set by gitlab (the CI environment) if [ -z $JOB_DIR ]; then diff --git a/.testing/Makefile b/.testing/Makefile index 71d5b464f0..4e6827da2f 100644 --- a/.testing/Makefile +++ b/.testing/Makefile @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # MOM6 Test suite Makefile # # Usage: diff --git a/.testing/tc4/Makefile.in b/.testing/tc4/Makefile.in index 714a8f19f1..4d2e40a1bb 100644 --- a/.testing/tc4/Makefile.in +++ b/.testing/tc4/Makefile.in @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + FC = @FC@ LD = @LD@ FCFLAGS = @FCFLAGS@ diff --git a/.testing/tc4/configure.ac b/.testing/tc4/configure.ac index c431ad65ef..d5dc142e85 100644 --- a/.testing/tc4/configure.ac +++ b/.testing/tc4/configure.ac @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # tc4 preprocessor configuration AC_PREREQ([2.63]) AC_INIT([], []) diff --git a/.testing/tc4/gen_data.F90 b/.testing/tc4/gen_data.F90 index 8f44aa1465..406d44e54a 100644 --- a/.testing/tc4/gen_data.F90 +++ b/.testing/tc4/gen_data.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + use netcdf implicit none diff --git a/.testing/tc4/gen_grid.F90 b/.testing/tc4/gen_grid.F90 index e76a681924..4ddabb7846 100644 --- a/.testing/tc4/gen_grid.F90 +++ b/.testing/tc4/gen_grid.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + use netcdf implicit none diff --git a/.testing/tools/cmp_diag.sh b/.testing/tools/cmp_diag.sh index 03f29a5fd2..8bf0fd806f 100755 --- a/.testing/tools/cmp_diag.sh +++ b/.testing/tools/cmp_diag.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 for chk in $1 $2; do awk '{print $(NF-2) " " $(NF-1) " " $(NF),$0}' ${chk} | sort > ${chk}.sorted diff --git a/.testing/tools/compare_clocks.py b/.testing/tools/compare_clocks.py index 77198fda6a..09e6fe2439 100755 --- a/.testing/tools/compare_clocks.py +++ b/.testing/tools/compare_clocks.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + import argparse import json diff --git a/.testing/tools/compare_perf.py b/.testing/tools/compare_perf.py index 7b1f3fda8d..65afc58c01 100755 --- a/.testing/tools/compare_perf.py +++ b/.testing/tools/compare_perf.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + import argparse import json diff --git a/.testing/tools/diff_diag.sh b/.testing/tools/diff_diag.sh index de9745df6a..edbd0c934f 100755 --- a/.testing/tools/diff_diag.sh +++ b/.testing/tools/diff_diag.sh @@ -1,4 +1,7 @@ #!/bin/bash +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 for chk in $1 $2; do awk '{print $(NF-2) " " $(NF-1) " " $(NF),$0}' ${chk} | sort > ${chk}.sorted diff --git a/.testing/tools/disp_timing.py b/.testing/tools/disp_timing.py index 0b3163625a..55637abbef 100755 --- a/.testing/tools/disp_timing.py +++ b/.testing/tools/disp_timing.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 from __future__ import print_function diff --git a/.testing/tools/parse_fms_clocks.py b/.testing/tools/parse_fms_clocks.py index fd3e7179d7..4125f09475 100755 --- a/.testing/tools/parse_fms_clocks.py +++ b/.testing/tools/parse_fms_clocks.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + import argparse import collections import json diff --git a/.testing/tools/parse_perf.py b/.testing/tools/parse_perf.py index efcfa13b4f..4673022756 100755 --- a/.testing/tools/parse_perf.py +++ b/.testing/tools/parse_perf.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + import argparse import collections import json diff --git a/.testing/tools/report_test_results.sh b/.testing/tools/report_test_results.sh index 24bab45507..bc5376a837 100755 --- a/.testing/tools/report_test_results.sh +++ b/.testing/tools/report_test_results.sh @@ -1,4 +1,8 @@ #!/bin/sh +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + RESULTS=${1:-${PWD}/results} GREEN="\033[0;32m" diff --git a/.testing/trailer.py b/.testing/trailer.py index 64f016275f..495f1cc6e3 100755 --- a/.testing/trailer.py +++ b/.testing/trailer.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + """Subroutines for Validating the whitespace of the source code.""" import argparse diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..f433b1a53f --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 5528208587..0000000000 --- a/LICENSE.md +++ /dev/null @@ -1,173 +0,0 @@ -This file is part of the Modular Ocean Model, referred to as MOM, which is made -available under version 3 of the Gnu Lesser General Public License, which is -provided below. - -The intent of this license is to ensure free and unrestricted access to the MOM -software, and to pass on those rights to modified versions this software. - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/ac/Makefile.in b/ac/Makefile.in index c4d23efdfb..da321067b2 100644 --- a/ac/Makefile.in +++ b/ac/Makefile.in @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # Makefile template for MOM6 # # Compiler flags are configured by autoconf's configure script. diff --git a/ac/configure.ac b/ac/configure.ac index 071f43f5a9..201bb262c4 100644 --- a/ac/configure.ac +++ b/ac/configure.ac @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # Autoconf configuration # NOTE: diff --git a/ac/deps/Makefile b/ac/deps/Makefile index 01431cef8c..00aeedd238 100644 --- a/ac/deps/Makefile +++ b/ac/deps/Makefile @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + SHELL = bash # Disable implicit rules diff --git a/ac/deps/Makefile.fms.in b/ac/deps/Makefile.fms.in index e4617f1428..05680c5af1 100644 --- a/ac/deps/Makefile.fms.in +++ b/ac/deps/Makefile.fms.in @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # Makefile template for FMS # # Compiler flags are configured by autoconf's configure script. diff --git a/ac/deps/configure.fms.ac b/ac/deps/configure.fms.ac index 7d68daa3c7..8aef4eaccf 100644 --- a/ac/deps/configure.fms.ac +++ b/ac/deps/configure.fms.ac @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + # Autoconf configuration AC_PREREQ([2.63]) diff --git a/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 b/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 index cffa302c66..a525e4f28a 100644 --- a/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 +++ b/ac/deps/m4/ax_fc_allow_arg_mismatch.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl Test if mismatched function arguments are permitted. dnl dnl This macro tests if a flag is required to enable mismatched functions in diff --git a/ac/deps/m4/ax_fc_allow_invalid_boz.m4 b/ac/deps/m4/ax_fc_allow_invalid_boz.m4 index 5d4521b5fb..ef2b20342f 100644 --- a/ac/deps/m4/ax_fc_allow_invalid_boz.m4 +++ b/ac/deps/m4/ax_fc_allow_invalid_boz.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl Test if BOZ literal assignment is supported. dnl dnl This macro tests if a flag is required to enable BOZ literal assignments diff --git a/ac/deps/m4/ax_fc_check_c_lib.m4 b/ac/deps/m4/ax_fc_check_c_lib.m4 index af5765282a..692fe722df 100644 --- a/ac/deps/m4/ax_fc_check_c_lib.m4 +++ b/ac/deps/m4/ax_fc_check_c_lib.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_C_LIB(LIBRARY, FUNCTION, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LDFLAGS], [OTHER-LIBS]) diff --git a/ac/deps/m4/ax_fc_check_lib.m4 b/ac/deps/m4/ax_fc_check_lib.m4 index a7f848cd60..4074b52e46 100644 --- a/ac/deps/m4/ax_fc_check_lib.m4 +++ b/ac/deps/m4/ax_fc_check_lib.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_LIB(LIBRARY, FUNCTION, dnl [MODULE], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LDFLAGS], [OTHER-LIBS]) diff --git a/ac/deps/m4/ax_fc_check_module.m4 b/ac/deps/m4/ax_fc_check_module.m4 index 1cfd0c5a5d..e902882524 100644 --- a/ac/deps/m4/ax_fc_check_module.m4 +++ b/ac/deps/m4/ax_fc_check_module.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_MODULE(MODULE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-FCFLAGS]) diff --git a/ac/deps/m4/ax_fc_cray_pointer.m4 b/ac/deps/m4/ax_fc_cray_pointer.m4 index 57ed186afa..aef870c75d 100644 --- a/ac/deps/m4/ax_fc_cray_pointer.m4 +++ b/ac/deps/m4/ax_fc_cray_pointer.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CRAY_POINTER([ACTION-IF-SUCCESS], [ACTION-IF-FAILURE]) dnl dnl This macro tests if any flags are required to enable Cray pointers. diff --git a/ac/deps/m4/ax_fc_line_length.m4 b/ac/deps/m4/ax_fc_line_length.m4 index 97271da1f6..90770469da 100644 --- a/ac/deps/m4/ax_fc_line_length.m4 +++ b/ac/deps/m4/ax_fc_line_length.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl # AX_FC_LINE_LENGTH([LENGTH], [ACTION-IF-SUCCESS], # [ACTION-IF-FAILURE = FAILURE]) # ------------------------------------------------ diff --git a/ac/deps/m4/ax_fc_real8.m4 b/ac/deps/m4/ax_fc_real8.m4 index 565018a984..15f0acda22 100644 --- a/ac/deps/m4/ax_fc_real8.m4 +++ b/ac/deps/m4/ax_fc_real8.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl Determine the flag required to force 64-bit reals. dnl dnl Many applications do not specify the kind of its real variables, even diff --git a/ac/m4/ax_fc_check_bind_c.m4 b/ac/m4/ax_fc_check_bind_c.m4 index 9b9f821d4c..e2a42f1bfb 100644 --- a/ac/m4/ax_fc_check_bind_c.m4 +++ b/ac/m4/ax_fc_check_bind_c.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_C_LIB(FUNCTION, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LDFLAGS], [OTHER-LIBS]) diff --git a/ac/m4/ax_fc_check_c_lib.m4 b/ac/m4/ax_fc_check_c_lib.m4 index af5765282a..692fe722df 100644 --- a/ac/m4/ax_fc_check_c_lib.m4 +++ b/ac/m4/ax_fc_check_c_lib.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_C_LIB(LIBRARY, FUNCTION, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LDFLAGS], [OTHER-LIBS]) diff --git a/ac/m4/ax_fc_check_lib.m4 b/ac/m4/ax_fc_check_lib.m4 index a7f848cd60..4074b52e46 100644 --- a/ac/m4/ax_fc_check_lib.m4 +++ b/ac/m4/ax_fc_check_lib.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_LIB(LIBRARY, FUNCTION, dnl [MODULE], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LDFLAGS], [OTHER-LIBS]) diff --git a/ac/m4/ax_fc_check_module.m4 b/ac/m4/ax_fc_check_module.m4 index 1cfd0c5a5d..e902882524 100644 --- a/ac/m4/ax_fc_check_module.m4 +++ b/ac/m4/ax_fc_check_module.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl AX_FC_CHECK_MODULE(MODULE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-FCFLAGS]) diff --git a/ac/m4/ax_fc_real8.m4 b/ac/m4/ax_fc_real8.m4 index 565018a984..15f0acda22 100644 --- a/ac/m4/ax_fc_real8.m4 +++ b/ac/m4/ax_fc_real8.m4 @@ -1,3 +1,7 @@ +dnl This file is part of MOM6, the Modular Ocean Model version 6. +dnl See the LICENSE file for licensing information. +dnl SPDX-License-Identifier: Apache-2.0 +dnl dnl Determine the flag required to force 64-bit reals. dnl dnl Many applications do not specify the kind of its real variables, even diff --git a/config_src/drivers/FMS_cap/MOM_surface_forcing_gfdl.F90 b/config_src/drivers/FMS_cap/MOM_surface_forcing_gfdl.F90 index 07bff26395..1a4981ccee 100644 --- a/config_src/drivers/FMS_cap/MOM_surface_forcing_gfdl.F90 +++ b/config_src/drivers/FMS_cap/MOM_surface_forcing_gfdl.F90 @@ -1,6 +1,8 @@ -module MOM_surface_forcing_gfdl +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +module MOM_surface_forcing_gfdl !#CTRL# use MOM_controlled_forcing, only : apply_ctrl_forcing, register_ctrl_forcing_restarts !#CTRL# use MOM_controlled_forcing, only : controlled_forcing_init, controlled_forcing_end diff --git a/config_src/drivers/FMS_cap/ocean_model_MOM.F90 b/config_src/drivers/FMS_cap/ocean_model_MOM.F90 index e3b7b0cec7..110415c6e0 100644 --- a/config_src/drivers/FMS_cap/ocean_model_MOM.F90 +++ b/config_src/drivers/FMS_cap/ocean_model_MOM.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Top-level module for the MOM6 ocean model in coupled mode. module ocean_model_mod -! This file is part of MOM6. See LICENSE.md for the license. - ! This is the top level module for the MOM6 ocean model. It contains routines ! for initialization, termination and update of ocean model state. This ! particular version wraps all of the calls for MOM6 in the calls that had diff --git a/config_src/drivers/STALE_mct_cap/mom_ocean_model_mct.F90 b/config_src/drivers/STALE_mct_cap/mom_ocean_model_mct.F90 index d1c46f4254..6e1545efe1 100644 --- a/config_src/drivers/STALE_mct_cap/mom_ocean_model_mct.F90 +++ b/config_src/drivers/STALE_mct_cap/mom_ocean_model_mct.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Top-level module for the MOM6 ocean model in coupled mode. module MOM_ocean_model_mct -! This file is part of MOM6. See LICENSE.md for the license. - ! This is the top level module for the MOM6 ocean model. It contains routines ! for initialization, termination and update of ocean model state. This ! particular version wraps all of the calls for MOM6 in the calls that had diff --git a/config_src/drivers/STALE_mct_cap/mom_surface_forcing_mct.F90 b/config_src/drivers/STALE_mct_cap/mom_surface_forcing_mct.F90 index e5c5943d4f..5df0d2a3f6 100644 --- a/config_src/drivers/STALE_mct_cap/mom_surface_forcing_mct.F90 +++ b/config_src/drivers/STALE_mct_cap/mom_surface_forcing_mct.F90 @@ -1,6 +1,8 @@ -module MOM_surface_forcing_mct +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +module MOM_surface_forcing_mct use MOM_coms, only : reproducing_sum, field_chksum use MOM_constants, only : hlv, hlf diff --git a/config_src/drivers/STALE_mct_cap/ocn_cap_methods.F90 b/config_src/drivers/STALE_mct_cap/ocn_cap_methods.F90 index 0b7a331458..a2d6ad29c8 100644 --- a/config_src/drivers/STALE_mct_cap/ocn_cap_methods.F90 +++ b/config_src/drivers/STALE_mct_cap/ocn_cap_methods.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module ocn_cap_methods use ESMF, only: ESMF_clock, ESMF_time, ESMF_ClockGet, ESMF_TimeGet diff --git a/config_src/drivers/STALE_mct_cap/ocn_comp_mct.F90 b/config_src/drivers/STALE_mct_cap/ocn_comp_mct.F90 index 85b7350b77..c7d758c8de 100644 --- a/config_src/drivers/STALE_mct_cap/ocn_comp_mct.F90 +++ b/config_src/drivers/STALE_mct_cap/ocn_comp_mct.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This is the main driver for MOM6 in CIME module ocn_comp_mct -! This file is part of MOM6. See LICENSE.md for the license. - ! mct modules use ESMF, only: ESMF_clock, ESMF_time, ESMF_timeInterval use ESMF, only: ESMF_ClockGet, ESMF_TimeGet, ESMF_TimeIntervalGet diff --git a/config_src/drivers/STALE_mct_cap/ocn_cpl_indices.F90 b/config_src/drivers/STALE_mct_cap/ocn_cpl_indices.F90 index 3f47c01903..68b6537662 100644 --- a/config_src/drivers/STALE_mct_cap/ocn_cpl_indices.F90 +++ b/config_src/drivers/STALE_mct_cap/ocn_cpl_indices.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module ocn_cpl_indices use mct_mod, only: mct_avect_init, mct_avect_indexra, mct_aVect_clean, mct_aVect 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 fb9fbe3e22..a8e11fbe34 100644 --- a/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 +++ b/config_src/drivers/ice_solo_driver/atmos_ocean_fluxes.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A dummy version of atmos_ocean_fluxes_mod module for !! use when the vastly larger FMS package is not needed. module atmos_ocean_fluxes_mod -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public :: aof_set_coupler_flux 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 bc95633af8..b12b1abd1a 100644 --- a/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 +++ b/config_src/drivers/ice_solo_driver/ice_shelf_driver.F90 @@ -1,6 +1,8 @@ -program Shelf_main +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program Shelf_main !********+*********+*********+*********+*********+*********+*********+** !* * diff --git a/config_src/drivers/nuopc_cap/mom_cap.F90 b/config_src/drivers/nuopc_cap/mom_cap.F90 index a4c9a68a44..a70232cba6 100644 --- a/config_src/drivers/nuopc_cap/mom_cap.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains a set of subroutines that are required by NUOPC. module MOM_cap_mod @@ -33,11 +37,13 @@ module MOM_cap_mod use MOM_ensemble_manager, only: ensemble_manager_init use MOM_coms, only: sum_across_PEs +! stub routines for CESMCOUPLED +use mom_cap_outputlog, only: outputlog_init, outputlog_run, outputlog_restart #ifdef CESMCOUPLED use shr_log_mod, only: shr_log_setLogUnit use nuopc_shr_methods, only: get_component_instance #endif -use time_utils_mod, only: esmf2fms_time +use time_utils_mod, only: esmf2fms_time use, intrinsic :: iso_fortran_env, only: output_unit @@ -93,9 +99,11 @@ module MOM_cap_mod use NUOPC_Model, only: model_label_Finalize => label_Finalize use NUOPC_Model, only: SetVM +use mom_inline_mod, only : mom_inline_init, mom_inline_run #ifndef CESMCOUPLED - use shr_is_restart_fh_mod, only : init_is_restart_fh, is_restart_fh, is_restart_fh_type +use shr_is_restart_fh_mod, only : init_is_restart_fh, is_restart_fh, is_restart_fh_type #endif +use mom_cap_profiling, only: cap_profiling_init, cap_profiling implicit none; private @@ -144,6 +152,7 @@ module MOM_cap_mod logical :: use_mommesh = .true. logical :: set_missing_stks_to_zero = .false. logical :: restart_eor = .false. +logical :: use_cdeps_inline = .false. character(len=128) :: scalar_field_name = '' integer :: scalar_field_count = 0 integer :: scalar_field_idx_grid_nx = 0 @@ -163,6 +172,7 @@ module MOM_cap_mod character(len=16) :: inst_suffix = '' logical :: pointer_date = .true. ! append date to rpointer real(8) :: timere +integer :: localPet = -1 contains @@ -180,8 +190,18 @@ subroutine SetServices(gcomp, rc) ! local variables character(len=*),parameter :: subname='(MOM_cap:SetServices)' + type(ESMF_VM) :: vm + rc = ESMF_SUCCESS + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMGet(vm, localpet=localPet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (localPet == 0) call cap_profiling_init() + if (localPet == 0) call cap_profiling("mom", "SetServices", "B") + ! the NUOPC model component will register the generic methods call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -221,6 +241,8 @@ subroutine SetServices(gcomp, rc) specRoutine=ocean_model_finalize, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (localPet == 0) call cap_profiling("mom", "SetServices", "E") + end subroutine SetServices !> First initialize subroutine called by NUOPC. The purpose @@ -247,10 +269,11 @@ subroutine InitializeP0(gcomp, importState, exportState, clock, rc) character(len=64) :: value, logmsg character(len=*),parameter :: subname='(MOM_cap:InitializeP0)' type(ESMF_VM) :: vm - integer :: mype rc = ESMF_SUCCESS + if (localPet == 0) call cap_profiling("mom", "InitializeP0", "B") + ! Switch to IPDv03 by filtering all other phaseMap entries call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, & acceptStringList=(/"IPDv03p"/), rc=rc) @@ -397,6 +420,13 @@ subroutine InitializeP0(gcomp, importState, exportState, clock, rc) geomtype = ESMF_GEOMTYPE_GRID endif + call NUOPC_CompAttributeGet(gcomp, name="use_cdeps_inline", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) use_cdeps_inline=(trim(value)=="true") + write(logmsg,*) use_cdeps_inline + call ESMF_LogWrite('MOM_cap:use_cdeps_inline = '//trim(logmsg), ESMF_LOGMSG_INFO) + ! Read end of run restart config option call NUOPC_CompAttributeGet(gcomp, name="write_restart_at_endofrun", value=value, & isPresent=isPresent, isSet=isSet, rc=rc) @@ -405,6 +435,8 @@ subroutine InitializeP0(gcomp, importState, exportState, clock, rc) if (trim(value) .eq. '.true.') restart_eor = .true. end if + if (localPet == 0) call cap_profiling("mom", "InitializeP0", "E") + end subroutine !> Called by NUOPC to advertise import and export fields. "Advertise" @@ -456,7 +488,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) character(len=40) :: wave_method ! Wave coupling method. logical :: use_MARBL ! If true, MARBL tracers are being used. integer :: userRc - integer :: localPet integer :: localPeCount integer :: iostat integer :: readunit @@ -474,6 +505,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !-------------------------------- rc = ESMF_SUCCESS + + if (localPet == 0) call cap_profiling("mom", "InitializeAdvertise", "B") + if(write_runtimelog) timeiads = MPI_Wtime() call ESMF_LogWrite(subname//' enter', ESMF_LOGMSG_INFO) @@ -489,7 +523,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call ESMF_VMGetCurrent(vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMGet(VM, mpiCommunicator=mpi_comm_mom, localPet=localPet, rc=rc) + call ESMF_VMGet(VM, mpiCommunicator=mpi_comm_mom, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_ClockGet(CLOCK, currTIME=MyTime, TimeStep=TINT, RC=rc) @@ -514,7 +548,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) rpointer_filename = 'rpointer.ocn'//trim(inst_suffix) if (pointer_date) then - write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)'),year,month,day,hour*3600+minute*60+second + write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)')year,month,day,hour*3600+minute*60+second inquire(file=trim(rpointer_filename//timestamp), exist=found) ! for backward compatibility if (found) then @@ -679,8 +713,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call ESMF_LogWrite('MOM_cap: restart requested, using '//trim(rpointer_filename), ESMF_LOGMSG_WARNING) call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMGet(vm, localPet=localPet, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return if (localPet == 0) then open(newunit=readunit, file=rpointer_filename, form='formatted', status='old', iostat=iostat) @@ -917,6 +949,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) enddo if(write_runtimelog .and. is_root_pe()) write(stdout,*) 'In ',trim(subname),' time ', MPI_Wtime()-timeiads + if (localPet == 0) call cap_profiling("mom", "InitializeAdvertise", "E") + end subroutine InitializeAdvertise !> Called by NUOPC to realize import and export fields. "Realizing" a field @@ -971,7 +1005,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) real(ESMF_KIND_R8), pointer :: dataPtr_xcor(:,:) real(ESMF_KIND_R8), pointer :: dataPtr_ycor(:,:) integer :: mpicom - integer :: localPet integer :: localPeCount integer :: lsize integer :: ig,jg, ni,nj,k @@ -1010,6 +1043,9 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) !-------------------------------- rc = ESMF_SUCCESS + + if (localPet == 0) call cap_profiling("mom", "InitializeRealize", "B") + if(write_runtimelog) timeirls = MPI_Wtime() call shr_log_setLogUnit (stdout) @@ -1032,7 +1068,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) call ESMF_VMGetCurrent(vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMGet(vm, petCount=npet, mpiCommunicator=mpicom, localPet=localPet, rc=rc) + call ESMF_VMGet(vm, petCount=npet, mpiCommunicator=mpicom, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return !--------------------------------- @@ -1584,6 +1620,11 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) !--------------------------------- call mom_set_geomtype(geomtype) + if (use_cdeps_inline) then + call mom_inline_init(gcomp, clock, eMesh, localPet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + !--------------------------------- ! write out diagnostics !--------------------------------- @@ -1595,6 +1636,8 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) timere = 0. if(write_runtimelog .and. is_root_pe()) write(stdout,*) 'In ',trim(subname),' time ', MPI_Wtime()-timeirls + if (localPet == 0) call cap_profiling("mom", "InitializeRealize", "E") + end subroutine InitializeRealize !> TODO @@ -1626,6 +1669,8 @@ subroutine DataInitialize(gcomp, rc) real(8) :: MPI_Wtime, timedis !-------------------------------- + if (localPet == 0) call cap_profiling("mom", "DataInitialize", "B") + if(write_runtimelog) timedis = MPI_Wtime() ! query the Component for its clock, importState and exportState @@ -1690,6 +1735,8 @@ subroutine DataInitialize(gcomp, rc) if(write_runtimelog .and. is_root_pe()) write(stdout,*) 'In ',trim(subname),' time ', MPI_Wtime()-timedis + if (localPet == 0) call cap_profiling("mom", "DataInitialize", "E") + end subroutine DataInitialize !> Called by NUOPC to advance the model a single timestep. @@ -1731,7 +1778,6 @@ subroutine ModelAdvance(gcomp, rc) character(ESMF_MAXSTR) :: casename integer :: iostat integer :: rpointer_unit - integer :: localPet type(ESMF_VM) :: vm integer :: n, i character(240) :: import_timestr, export_timestr @@ -1746,6 +1792,9 @@ subroutine ModelAdvance(gcomp, rc) logical :: write_restart_eor rc = ESMF_SUCCESS + + if (localPet == 0) call cap_profiling("mom", "ModelAdvance", "B") + if(profile_memory) call ESMF_VMLogMemInfo("Entering MOM Model_ADVANCE: ") if(write_runtimelog) then timers = MPI_Wtime() @@ -1776,7 +1825,9 @@ subroutine ModelAdvance(gcomp, rc) call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) call ESMF_TimeGet(currTime, timestring=import_timestr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_TimeGet(currTime+timestep, timestring=export_timestr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return Time_step_coupled = esmf2fms_time(timeStep) Time = esmf2fms_time(currTime) @@ -1859,6 +1910,11 @@ subroutine ModelAdvance(gcomp, rc) set_missing_stks_to_zero, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (use_cdeps_inline) then + call mom_inline_run(clock, ocean_public, ocean_grid, ice_ocean_boundary, dbug, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + !--------------- ! Update MOM6 !--------------- @@ -1879,7 +1935,7 @@ subroutine ModelAdvance(gcomp, rc) call state_diagnose(exportState,subname//':ES ',rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return endif - endif + endif ! do_advance !--------------- ! Get the stop alarm @@ -1907,12 +1963,12 @@ subroutine ModelAdvance(gcomp, rc) write_restart_eor = .false. if (restart_eor) then if (ESMF_AlarmIsRinging(stop_alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - write_restart_eor = .true. - ! turn off the alarm - call ESMF_AlarmRingerOff(stop_alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - end if + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write_restart_eor = .true. + ! turn off the alarm + call ESMF_AlarmRingerOff(stop_alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if end if #ifndef CESMCOUPLED @@ -1932,10 +1988,8 @@ subroutine ModelAdvance(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMGet(vm, localPet=localPet, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)'),year,month,day,hour*3600+minute*60+seconds + write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)')year,month,day,hour*3600+minute*60+seconds rpointer_filename = 'rpointer.ocn'//trim(inst_suffix) if (pointer_date) then @@ -1990,8 +2044,10 @@ subroutine ModelAdvance(gcomp, rc) ! write restart file(s) call ocean_model_restart(ocean_state, restartname=restartname, & - stoch_restartname='RESTART/'//stoch_restartname) + stoch_restartname=stoch_restartname, num_rest_files=num_rest_files) + call outputlog_restart(clock, num_rest_files, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return endif if (is_root_pe()) then @@ -2000,6 +2056,9 @@ subroutine ModelAdvance(gcomp, rc) endif endif ! restart_mode + call outputlog_run(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + !--------------- ! Write diagnostics !--------------- @@ -2028,6 +2087,8 @@ subroutine ModelAdvance(gcomp, rc) if(profile_memory) call ESMF_VMLogMemInfo("Leaving MOM Model_ADVANCE: ") + if (localPet == 0) call cap_profiling("mom", "ModelAdvance", "E") + end subroutine ModelAdvance @@ -2057,6 +2118,8 @@ subroutine ModelSetRunClock(gcomp, rc) rc = ESMF_SUCCESS + if (localPet == 0) call cap_profiling("mom", "ModelSetRunClock", "B") + ! query the Component for its clock, importState and exportState call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -2206,6 +2269,8 @@ subroutine ModelSetRunClock(gcomp, rc) call ESMF_LogWrite("Stop Alarm will ring at : "//trim(timestr), ESMF_LOGMSG_INFO) endif + call outputlog_init(gcomp, mclock, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return first_time = .false. endif @@ -2220,6 +2285,8 @@ subroutine ModelSetRunClock(gcomp, rc) call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (localPet == 0) call cap_profiling("mom", "ModelSetRunClock", "E") + end subroutine ModelSetRunClock !=============================================================================== @@ -2246,6 +2313,8 @@ subroutine ocean_model_finalize(gcomp, rc) character(len=*),parameter :: subname='(MOM_cap:ocean_model_finalize)' real(8) :: MPI_Wtime, timefs + if (localPet == 0) call cap_profiling("mom", "ocean_model_finalize", "B") + if (is_root_pe()) then write(stdout,*) 'MOM: --- finalize called ---' endif @@ -2279,8 +2348,16 @@ subroutine ocean_model_finalize(gcomp, rc) call io_infra_end() call MOM_infra_end() + ! need to call twice to force logging of last output file + call outputlog_run(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call outputlog_run(clock, .true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if(write_runtimelog .and. is_root_pe()) write(stdout,*) 'In ',trim(subname),' time ', MPI_Wtime()-timefs + if (localPet == 0) call cap_profiling("mom", "ocean_model_finalize", "E") + end subroutine ocean_model_finalize diff --git a/config_src/drivers/nuopc_cap/mom_cap_methods.F90 b/config_src/drivers/nuopc_cap/mom_cap_methods.F90 index 8a7a1b3942..2b686fcd52 100644 --- a/config_src/drivers/nuopc_cap/mom_cap_methods.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap_methods.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Contains import/export methods for CMEPS. module MOM_cap_methods diff --git a/config_src/drivers/nuopc_cap/mom_cap_outputlog.F90 b/config_src/drivers/nuopc_cap/mom_cap_outputlog.F90 new file mode 100644 index 0000000000..ef62ac0cda --- /dev/null +++ b/config_src/drivers/nuopc_cap/mom_cap_outputlog.F90 @@ -0,0 +1,623 @@ +!> This module contains a set of subroutines that check if MOM restart and history files +!! have been written and closed. This file is specific to UWM operational requirements +!! and configurations (eg specific output frequencies in hours) and may break if used outside +!! the scope of intended use. +!! This module is a stub when CESMCOUPLED is defined +module MOM_cap_outputlog + +#ifdef CESMCOUPLED +use ESMF , only : ESMF_GridComp, ESMF_Clock, ESMF_SUCCESS +implicit none; private + +public :: outputlog_init, outputlog_run, outputlog_restart +contains +subroutine outputlog_init(gcomp, mclock, rc) + type(ESMF_GridComp) :: gcomp !< an ESMF_GridComp object + type(ESMF_Clock) :: mclock !< the ESMF_clock for the model + integer, intent(out) :: rc !< return code + rc = ESMF_SUCCESS +end subroutine outputlog_init +subroutine outputlog_run(mclock, atStopTime, rc) + type(ESMF_Clock) :: mclock !< the ESMF_clock for the model + logical, intent(in), optional :: atStopTime !< if true, checks for final output file + integer, intent(out) :: rc !< return code + rc = ESMF_SUCCESS +end subroutine outputlog_run +subroutine outputlog_restart(mclock, num_rest_files, rc) + type(ESMF_Clock) :: mclock !< the ESMF_clock for the model + integer, intent(in) :: num_rest_files !< the number of restart files + integer, intent(out) :: rc !< return code + rc = ESMF_SUCCESS +end subroutine outputlog_restart +#else +use MOM_error_handler , only : is_root_pe, MOM_error, FATAL +use NUOPC , only : NUOPC_CompAttributeGet +use ESMF , only : ESMF_GridComp, ESMF_GridCompGet, ESMF_VM, ESMF_VMGet +use ESMF , only : ESMF_Time, ESMF_Clock, ESMF_ClockGet, ESMF_Alarm, ESMF_AlarmSet +use ESMF , only : ESMF_ClockGetAlarm, ESMF_AlarmIsRinging, ESMF_AlarmRingerOff +use ESMF , only : ESMF_ClockGetNextTime, ESMF_TimeGet, ESMF_TimeInterval +use ESMF , only : ESMF_AlarmGet, ESMF_TimeIntervalSet, ESMF_TimeIntervalPrint +use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_VMBroadCast +use ESMF , only : ESMF_LogSetError, ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU +use ESMF , only : operator(*), operator(+), operator(-), operator(>), operator(==) +use MOM_cap_methods , only : ChkErr +use MOM_cap_time , only : AlarmInit +use shr_is_restart_fh_mod , only : log_restart_fh +use netcdf + +implicit none; private + +public :: outputlog_init, outputlog_run, outputlog_restart + +! the allowable output frequency for MOM6 history, in hours only +integer, parameter :: n_freq = 3 +integer, parameter, dimension(n_freq) :: freq = (/3, 6, 24/) +! TODO: for multiple output freq in same run, a different known filename +! root for different freqs needs to be read in, consistent with the diag table + +! the tincrement interval (defined in minutes) is used to construct the output filename +! the file name must be set as the mid-point of the averaging period via the diagtable +! and the output filename timestrings are given by +! T - (interval * 60 * increment + interval/2 * 60 * increment ) +! where T is the time when the file is closed +! +! 00 . 03 . 06 . 09 +! 1:30 = 6 - (3 + 1:30) +! 4:30 = 9 - (3 + 1:30) +! +! 00 . 06 . 12 . 18 +! 03 = 12 - (6 + 3) +! 09 = 18 - (6 + 3) +! +! 00 . 24 . 48 . 72 +! 12 = 48 - (24 + 12) +! 36 = 72 - (24 + 12) +! +! when the model reaches the stop time, any 'pending' output file is closed, and the final +! interval output is also closed +! +! stop +! 18 . 24 . 30 +! 21 = 30 - (12 + 3) +! 03 = 30 - (3) +! +! since both the final interval and the next-to-final interval can be closed at the stop time, +! a different log file name is required for the final log file, otherwise the next-to-final +! log is overwritten +! +! Depending on configuration, the output file can have an unlimited dimension >0 at creation time. +! This necessitates checking for an additional criteria using the filesize at creation. An output file +! is declared complete either when the unlimited dimension in the file is >0 or when the unlimited +! dimension is >0 and the filesize is larger than the initial size. + +! When a file is determined to be complete, a log file is recorded containing the forecast hour, the valid +! time, the name of the output file and the last completed restart file. + +type(ESMF_VM) :: vm +type(ESMF_TimeInterval) :: tincrement +type(ESMF_Time) :: lastrestart + +type :: outputlog_type + character(len=14) :: alarm_name + integer :: opt_n + logical :: chkfile_nextAdvance + logical :: use_filesize + character(len=256) :: filename + integer :: createsize + type(ESMF_Alarm) :: alarm + type(ESMF_TimeInterval) :: fhoffset + type(ESMF_TimeInterval) :: filename_fhoffset + type(ESMF_Time) :: time_lastrestart +end type outputlog_type + +type(outputlog_type) :: olog(n_freq) + +integer :: toffset +logical :: debug +logical :: existflag +character(len=256) :: restartdir +character(len=256) :: outputdir +character(len=2) :: output_fh +character(len=*), parameter :: u_FILE_u = & + __FILE__ + +contains +!> Initialize a set of Alarms at the allowed output frequencies +!! +!! @param gcomp an ESMF_GridComp object +!! @param clock an ESMF_Clock object +!! @param rc return code +subroutine outputlog_init(gcomp, mclock, rc) + type(ESMF_GridComp) :: gcomp + type(ESMF_Clock) :: mclock + integer, intent(out) :: rc + + ! local variables + type(ESMF_Time) :: mcurrTime + type(ESMF_TimeInterval) :: alarmoffset + logical :: isPresent, isSet + integer :: n + integer :: year, month, day, hour + character(len=3) :: chour + character(len=256) :: msgString + character(len=256) :: value + character(len=256) :: subname='MOM_cap:(outputlog_init)' + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="mom6_restart_dir", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + restartdir = trim(value) + else + restartdir = './' + endif + if (restartdir(len_trim(restartdir):len_trim(restartdir)) /= '/') then + restartdir = trim(restartdir)//'/' + endif + write(msgString,'(A)')'MOM_cap:MOM6 restart directory = '//trim(restartdir) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + + call NUOPC_CompAttributeGet(gcomp, name="mom6_output_dir", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + outputdir = trim(value) + else + outputdir = './' + endif + if (outputdir(len_trim(outputdir):len_trim(outputdir)) /= '/') then + outputdir = trim(outputdir)//'/' + endif + write(msgString,'(A)')'MOM_cap:MOM6 output directory = '//trim(outputdir) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + + call NUOPC_CompAttributeGet(gcomp, name="mom6_output_fh", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + if (len_trim(value) == 1) then + output_fh = '0'//trim(value) + else + output_fh = trim(value) + endif + else + output_fh = '06' + endif + write(msgString,'(A)')'MOM_cap:MOM6 output frequency = '//trim(output_fh) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + + debug = .false. + call NUOPC_CompAttributeGet(gcomp, name="debug_outputlog", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) debug=(trim(value)=="true") + if (debug) call ESMF_LogWrite('MOM_cap:MOM6 output debug ON', ESMF_LOGMSG_INFO) + + call ESMF_ClockGet(mclock, currTime=mcurrTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeIntervalSet(tincrement, m=1, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get start hour time offset (ie, fhrot) + call ESMF_TimeGet(mcurrTime, yy=year, mm=month, dd=day, h=hour, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (mod(hour,6) /= 0) then + toffset = hour - 6 + else + toffset = 0 + endif + if (debug .and. is_root_pe()) then + print '(A,i8)',trim(subname)//' toffset = ',toffset + endif + ! initialize + lastrestart = mcurrTime + + do n = 1,n_freq + write(chour,'(I2.2,A)')freq(n),'h' + olog(n)%alarm_name = 'output_alarm'//trim(chour) + olog(n)%opt_n = freq(n) + olog(n)%chkfile_nextAdvance = .false. + olog(n)%use_filesize = .false. + olog(n)%filename = '' + olog(n)%createsize = 0 + olog(n)%time_lastrestart = lastrestart + olog(n)%fhoffset = 60*freq(n)*tincrement + olog(n)%filename_fhoffset = 90*freq(n)*tincrement + + ! the time offset in hours required to ensure the alarm rings at multiples of 6 + if (freq(n) >= 6) then + alarmoffset = toffset*60*tincrement + else + alarmoffset = 0*tincrement + endif + + call AlarmInit(mclock, & + alarm = olog(n)%alarm, & + option = 'nhours', & + opt_n = olog(n)%opt_n, & + opt_ymd = -999, & + RefTime = mcurrTime+alarmoffset, & + alarmname = olog(n)%alarm_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(olog(n)%alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(msgString,'(A)')trim(subname)//' Output alarm '//trim(olog(n)%alarm_name)//' Created & Set' + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + if (debug .and. is_root_pe()) then + call ESMF_TimeIntervalPrint(olog(n)%filename_fhoffset, options="string", rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + enddo +end subroutine outputlog_init + +!> Write a log file denoting that an output file is complete +!! +!! @param clock an ESMF_Clock object +!! @param atStopTime when present, checks for final output file +!! @param rc return code +subroutine outputlog_run(mclock, atStopTime, rc) + type(ESMF_Clock) :: mclock + logical, intent(in), optional :: atStopTime + integer, intent(out) :: rc + + ! local variables + type(ESMF_Time) :: nextTime, currTime, startTime, prevRing + logical :: lstop + logical :: filecomplete + integer :: n, nlen(1), fsize(1) + character(len=3) :: chour + character(len=40) :: importexport + character(len=16) :: timestr + character(len=256) :: fname + character(len=256) :: subname='MOM_cap:(outputlog_run)' + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_ClockGet(mclock, startTime=startTime, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGetNextTime(mclock, nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + importexport = get_importexport(currTime, nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + lstop = .false. + if (present(atStopTime)) then + lstop = atStopTime + endif + + filecomplete = .false. + fsize(1) = nf90_fill_int + nlen(1) = nf90_fill_int + + do n = 1,n_freq + write(chour,'(I2.2,A)')freq(n),'h' + if (chour(1:2) == output_fh(1:2)) then + call ESMF_ClockGetAlarm(mclock, alarmname=trim(olog(n)%alarm_name), alarm=olog(n)%alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! when the alarm rings, set file check on next advance and construct the filename + if (ESMF_AlarmIsRinging(olog(n)%alarm, rc=rc)) then + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_AlarmRingerOff(olog(n)%alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + olog(n)%chkfile_nextAdvance = .true. + + timestr = get_timestr(nextTime-olog(n)%filename_fhoffset, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(olog(n)%filename,'(A)')trim(outputdir)//'ocn_'//trim(timestr)//'.nc' + + fname = trim(olog(n)%filename) + inquire(file=fname, exist=existflag) + if (existflag) then + if (is_root_pe()) then + nlen(1) = get_unlimited_len(trim(fname)) + inquire(file=fname, size=fsize(1)) + endif + call ESMF_VMBroadCast(vm, nlen, 1, 0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadCast(vm, fsize, 1, 0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + olog(n)%createsize = fsize(1) + + if (nlen(1) == 0) then + olog(n)%use_filesize = .false. + else + olog(n)%use_filesize = .true. + endif + endif + if (debug .and. is_root_pe()) then + print '(A,2(A,L),A,2i16)',trim(subname)//' fname '//trim(olog(n)%filename)//' '//trim(importexport), & + ' checkflag ',olog(n)%chkfile_nextAdvance,' use_filesize ',olog(n)%use_filesize, & + ' ',olog(n)%createsize,nlen(1) + endif + endif + + if (olog(n)%chkfile_nextAdvance) then + fname = trim(olog(n)%filename) + filecomplete = file_is_complete(fname, olog(n)%use_filesize, olog(n)%createsize, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (filecomplete) then + olog(n)%chkfile_nextAdvance = .false. + olog(n)%time_lastrestart = lastrestart + if (is_root_pe()) then + call log_restart_fh(currTime-olog(n)%fhoffset, startTime, 'mom6.'//chour, prefixtime=.true., & + lastrestart=olog(n)%time_lastrestart, lastoutput=olog(n)%filename, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + endif + endif + if (debug .and. is_root_pe()) call debug_info(trim(subname)//' ',trim(olog(n)%filename), & + olog(n)%chkfile_nextAdvance, olog(n)%createsize, importexport) + + if (lstop) then + ! use prevRing in place of currTime to allow for stopping between averaging intervals + ! prevring == currTime if stopping on intervals + call ESMF_AlarmGet(olog(n)%alarm, prevRingTime=prevring, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + timestr = get_timestr(prevring-30*freq(n)*tincrement, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(olog(n)%filename,'(A)')trim(outputdir)//'ocn_'//trim(timestr)//'.nc' + + fname = trim(olog(n)%filename) + filecomplete = file_is_complete(fname, olog(n)%use_filesize, olog(n)%createsize, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (filecomplete) then + olog(n)%chkfile_nextAdvance = .false. + olog(n)%time_lastrestart = lastrestart + if (is_root_pe()) then + call log_restart_fh(prevring, startTime, 'mom6.lstop.'//chour, prefixtime=.true., & + lastrestart=olog(n)%time_lastrestart, lastoutput=olog(n)%filename, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + endif + if (debug .and. is_root_pe()) call debug_info(trim(subname)//' lstop ',trim(olog(n)%filename), & + olog(n)%chkfile_nextAdvance, olog(n)%createsize, importexport) + + endif ! lstop + endif ! chour = output_fh + enddo +end subroutine outputlog_run + +!> Check all restart files to determine if output has been completed +!! +!! @param[in] clock an ESMF_Clock object +!! @param[in] num_rest_files the number of restart files +!! @param[out] rc return code +subroutine outputlog_restart(mclock, num_rest_files, rc) + type(ESMF_Clock) :: mclock + integer, intent(in) :: num_rest_files + integer, intent(out) :: rc + + ! local variables + type(ESMF_Time) :: startTime, currTime, nextTime + integer :: n, nlen(1) + integer :: year, month, day, hour, minute, seconds + character(len=256) :: fname + character(len=15) :: timestr + character(len=40) :: importexport + logical, allocatable :: allDone(:) + character(len=8) :: suffix + character(len=256) :: subname='MOM_cap:(outputlog_restart)' + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_ClockGet(mclock, startTime=startTime, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGetNextTime(mclock, nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + importexport = get_importexport(currTime, nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet(nextTime, yy=year, mm=month, dd=day, h=hour, m=minute, s=seconds, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(timestr,'(I4.4,2(I2.2),A,3(I2.2))') year, month, day,".", hour, minute, seconds + + allocate(allDone(1:num_rest_files)) + allDone = .false. + + do n = 1,num_rest_files + if (n == 1) then + suffix = '' + else if (n-1 < 10) then + write(suffix,'("_",I1)') n-1 + else + write(suffix,'("_",I2)') n-1 + endif + if (len_trim(suffix) == 0) then + fname = trim(restartdir)//trim(timestr)//'.MOM.res.nc' + else + fname = trim(restartdir)//trim(timestr)//'.MOM.res'//trim(suffix)//'.nc' + endif + + ! check if file is written + inquire(file=trim(fname), exist=existflag) + if (existflag) then + if (is_root_pe())then + nlen(1) = get_unlimited_len(trim(fname)) + endif + call ESMF_VMBroadCast(vm, nlen, 1, 0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (nlen(1) > 0) allDone(n) = .true. + if (debug .and. is_root_pe()) then + if (nlen(1) > 0) then + print '(A)',trim(subname)//' restart '//trim(fname)//' '//trim(importexport)//' complete' + else + print '(A)',trim(subname)//' restart '//trim(fname)//' '//trim(importexport)//' still 0' + endif + endif + endif + enddo ! num_rest_files + + if (all(allDone) .eqv. .true.) then + lastrestart = nextTime + if (is_root_pe()) then + call log_restart_fh(nextTime, startTime, 'mom6.res', prefixtime=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + endif +end subroutine outputlog_restart + +!> Determine if the netcdf output file is complete +!! +!! @param[in] fname the file name +!! @param[in] chk4size logical flag for check method in use +!! @param[in] createsize the filesize at creation +!! @param[out] rc return code +!! @return logical flag, true if the file is complete +logical function file_is_complete(fname, chk4size, createsize, rc) result(filecomplete) + character(len=*), intent(in) :: fname + logical, intent(in) :: chk4size + integer, intent(in) :: createsize + integer, intent(out) :: rc + + integer :: nlen(1), fsize(1) + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + filecomplete = .false. + nlen(1) = nf90_fill_int + fsize(1) = nf90_fill_int + + inquire(file=fname, exist=existflag) + if (existflag) then + if (is_root_pe()) then + nlen(1) = get_unlimited_len(fname) + inquire(file=fname, size=fsize(1)) + endif + call ESMF_VMBroadCast(vm, nlen, 1, 0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadCast(vm, fsize, 1, 0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + + if (chk4size) then + filecomplete = (nlen(1) > 0 .and. fsize(1) > createsize) + else + filecomplete = (nlen(1) > 0) + endif +end function file_is_complete + +!> Return the length of the unlimited dimension +!! +!! @param[in] fname the file name +!! @return unlimited dimension length +integer function get_unlimited_len(fname) result(unlen) + character(len=*), intent(in) :: fname + + integer :: ncid, dimid + !---------------------------------------------------------------------------- + + unlen = 0 + call nf90_err(nf90_open(trim(fname), nf90_nowrite, ncid), 'nf90_open: '//trim(fname)) + call nf90_err(nf90_inquire(ncid, unlimiteddimid=dimid), 'inquire unlimiteddimid') + call nf90_err(nf90_inquire_dimension(ncid, dimid, len=unlen), 'inquire unlimited dimension') + call nf90_err(nf90_close(ncid), 'close: '//trim(fname)) +end function get_unlimited_len + +!> Convenience function to return a 16-character time string +!! +!! @param[in] MyTime an ESMF_Time object +!! @param[out] rc return code +!! @return 16-character formatted time string (YYYY_MM_DD_HH_MM) +character(len=16) function get_timestr(MyTime, rc) result(timestr) + type(ESMF_Time), intent(in) :: MyTime + integer, intent(out) :: rc + + integer :: year, month, day, hour, minute + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TimeGet(MyTime, yy=year, mm=month, dd=day, h=hour, m=minute, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(timestr,'(I4.4,4(A,I2.2))')year,'_',month,'_',day,'_',hour,'_',minute +end function get_timestr + +!> Convenience function to return import/export timestring +!! +!! @param[in] currTime an ESMF_Time object +!! @param[in] nextTime an ESMF_Time object +!! @param[out] rc return code +!! @return 40-character string +character(len=40) function get_importexport(currTime, nextTime, rc) result(importexport) + + type(ESMF_Time), intent(in) :: currTime, nextTime + integer, intent(out) :: rc + + character(len=19) :: import_timestr, export_timestr + !---------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TimeGet(currTime, timestring=import_timestr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(nextTime, timestring=export_timestr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + importexport = trim(import_timestr)//' '//trim(export_timestr) +end function get_importexport + +!> Write debug info to stdout, only called on root pe +!! +!! @param[in] tag an information tag +!! @param[in] fname the filename to check +!! @param[in] filesize the filesize at creation time +!! @param[in] chkflag logical flag for checking next Advance +!! @param[in] timestring a timestring +subroutine debug_info(tag,fname,chkflag,filesize,timestring) + character(len=*), intent(in) :: tag + character(len=*), intent(in) :: fname + integer, intent(in) :: filesize + logical, intent(in) :: chkflag + character(len=*), intent(in) :: timestring + + integer :: fsize + character(len=256) :: msgString + !---------------------------------------------------------------------------- + + inquire(file=fname, exist=existflag) + if (existflag) then + inquire(file=fname, size=fsize) + write(msgString,'(A)')tag//' '//fname//' exists '//timestring + if (chkflag) then + print '(A,L,2i16)',trim(msgString)//' not complete, chkflag ',chkflag,filesize,fsize + else + print '(A,L,2i16)',trim(msgString)//' complete, chkflag ',chkflag,filesize,fsize + endif + else + write(msgString,'(A)')tag//' '//fname//' does not exist '//timestring + print '(A)',trim(msgString) + endif +end subroutine debug_info + +!> Handle netcdf errors +!! +!! @param[in] ierr the error code +!! @param[in] string the error message +subroutine nf90_err(ierr, string) + integer, intent(in) :: ierr + character(len=*), intent(in) :: string + !---------------------------------------------------------------------------- + + if (ierr /= nf90_noerr) then + write(0, '(A)') 'FATAL ERROR: ' // trim(string)// ' : ' // trim(nf90_strerror(ierr)) + ! This fails on WCOSS2 with Intel 19 compiler. See https://community.intel.com/ + ! Search term "STOP and ERROR STOP with variable stop codes" + ! When WCOSS2 moves to Intel 2020+, uncomment the next line and remove stop 99 + !stop ierr + stop 99 + endif +end subroutine nf90_err +#endif +end module MOM_cap_outputlog diff --git a/config_src/drivers/nuopc_cap/mom_cap_profiling.F90 b/config_src/drivers/nuopc_cap/mom_cap_profiling.F90 new file mode 100644 index 0000000000..4e3e387e2d --- /dev/null +++ b/config_src/drivers/nuopc_cap/mom_cap_profiling.F90 @@ -0,0 +1,45 @@ +!> Contains wrapper routines that call the ufs tracing routines +module mom_cap_profiling + +#ifdef UFS_TRACING + use ufs_trace_mod, only: ufs_trace_init, ufs_trace, ufs_trace_finalize +#endif + + implicit none + + private + + public cap_profiling_init + public cap_profiling + public cap_profiling_finalize + +contains + +!> Wrapper routine that calls ufs_trace_init + subroutine cap_profiling_init() +#ifdef UFS_TRACING + call ufs_trace_init() +#endif + return + end subroutine cap_profiling_init + +!> Wrapper routine that calls ufs_trace + subroutine cap_profiling(component, routine, ph) + character(len=*), intent(in) :: component !< Name of the component, 'mom' + character(len=*), intent(in) :: routine !< Name of the profiled subroutine + character(len=*), intent(in) :: ph !< Duration event phase type. 'B' or 'E' for begin/end +#ifdef UFS_TRACING + call ufs_trace(component, routine, ph) +#endif + return + end subroutine cap_profiling + +!> Wrapper routine that calls ufs_trace_finalize + subroutine cap_profiling_finalize() +#ifdef UFS_TRACING + call ufs_trace_finalize() +#endif + return + end subroutine cap_profiling_finalize + +end module mom_cap_profiling diff --git a/config_src/drivers/nuopc_cap/mom_cap_time.F90 b/config_src/drivers/nuopc_cap/mom_cap_time.F90 index d8ae6892a9..f49ea133ff 100644 --- a/config_src/drivers/nuopc_cap/mom_cap_time.F90 +++ b/config_src/drivers/nuopc_cap/mom_cap_time.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This was originally share code in CIME, but required CIME as a !! dependency to build the MOM cap. The options here for setting !! a restart alarm are useful for all caps, so a second step is to diff --git a/config_src/drivers/nuopc_cap/mom_inline_mod.F90 b/config_src/drivers/nuopc_cap/mom_inline_mod.F90 new file mode 100644 index 0000000000..8b8b544f2f --- /dev/null +++ b/config_src/drivers/nuopc_cap/mom_inline_mod.F90 @@ -0,0 +1,218 @@ +!> This module contains a set of subroutines that enables inline CDEPS capability + +module mom_inline_mod + +use NUOPC , only: NUOPC_CompAttributeGet +use ESMF , only: ESMF_GridComp, ESMF_Mesh +use ESMF , only: ESMF_Clock, ESMF_Time, ESMF_TimeGet, ESMF_ClockGet +use ESMF , only: ESMF_KIND_R8, ESMF_SUCCESS, ESMF_LogFoundError +use ESMF , only: ESMF_LOGERR_PASSTHRU, ESMF_LOGMSG_INFO, ESMF_LOGWRITE +use ESMF , only: ESMF_END_ABORT, ESMF_Finalize, ESMF_MAXSTR +use dshr_mod , only: dshr_pio_init +use dshr_strdata_mod , only: shr_strdata_type, shr_strdata_print +use dshr_strdata_mod , only: shr_strdata_init_from_inline +use dshr_strdata_mod , only: shr_strdata_advance +use dshr_methods_mod , only: dshr_fldbun_getfldptr, dshr_fldbun_Field_diagnose +use dshr_stream_mod , only: shr_stream_init_from_esmfconfig +use MOM_cap_methods , only: ChkErr + +implicit none +private + +public mom_inline_init +public mom_inline_run + +type(shr_strdata_type), allocatable :: sdat(:) + +integer :: logunit ! the logunit on the root task +character(len=ESMF_MAXSTR) :: stream_name ! generic identifier + +character(len=*), parameter :: u_FILE_u = __FILE__ +contains + +!=============================================================================== +subroutine mom_inline_init(gcomp, model_clock, model_mesh, mytask, rc) + type(ESMF_GridComp) , intent(in) :: gcomp !< ESMF_GridComp object + type(ESMF_Clock) , intent(in) :: model_clock !< ESMF_Clock object + type(ESMF_Mesh) , intent(in) :: model_mesh !< ESMF mesh + integer , intent(in) :: mytask !< the current task + integer , intent(out) :: rc !< Return code + + ! local variables + logical :: isPresent, isSet + integer :: ns, l + integer :: nstreams, nvars + type(shr_strdata_type) :: sdatconfig !< stream data from config (xml or esmf), one or more streams + + character(len=ESMF_MAXSTR) :: value, streamfilename + character(len=ESMF_MAXSTR), allocatable :: filelist(:) + character(len=ESMF_MAXSTR), allocatable :: filevars(:,:) + + character(len=*), parameter :: subname='(mom_inline_init)' + !---------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call NUOPC_CompAttributeGet(gcomp, name="streamfilename", value=value, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + streamfilename = value + else + call ESMF_LogWrite(trim(subname)//': streamfilename must be provided', ESMF_LOGMSG_INFO) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + return + endif + +#ifndef CESMCOUPLED + if (mytask == 0) then + open (newunit=logunit, file='log.mom6.cdeps') + else + logunit = 6 + endif + + ! CMEPS Init PIO + call dshr_pio_init(gcomp, sdatconfig, logunit, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! read the available stream definitions, each data stream is one or more data_files + ! which have the same spatial and temporal coordinates + call shr_stream_init_from_esmfconfig(trim(streamfilename), sdatconfig%stream, logunit, & + sdatconfig%pio_subsystem, sdatconfig%io_type, sdatconfig%io_format, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return +#else + !TODO: CESM logunit, configuration via xml etc + !call shr_stream_init_from_xml(trim(streamfilename) .... +#endif + + nstreams = size(sdatconfig%stream) + ! allocate stream data type + if (.not. allocated(sdat)) allocate(sdat(nstreams)) + + ! set the model clock and mesh + sdat(:)%model_clock = model_clock + sdat(:)%model_mesh = model_mesh + + ! loop over streams and initialize + do ns = 1, nstreams + sdat(ns)%pio_subsystem => sdatconfig%pio_subsystem + sdat(ns)%io_type = sdatconfig%io_type + sdat(ns)%io_format = sdatconfig%io_format + + allocate(filelist(sdatconfig%stream(ns)%nfiles)) + allocate(filevars(sdatconfig%stream(ns)%nvars,2)) + + ! fill stream info + do l = 1, sdatconfig%stream(ns)%nfiles + filelist(l) = trim(sdatconfig%stream(ns)%file(l)%name) + enddo + do l = 1, sdatconfig%stream(ns)%nvars + filevars(l,1) = trim(sdatconfig%stream(ns)%varlist(l)%nameinfile) + filevars(l,2) = trim(sdatconfig%stream(ns)%varlist(l)%nameinmodel) + enddo + + write(stream_name,fmt='(a,i2.2)') 'stream_', ns + call shr_strdata_init_from_inline(sdat(ns), & + my_task = mytask, & + logunit = logunit, & + compname = 'OCN', & + model_clock = sdat(ns)%model_clock, & + model_mesh = sdat(ns)%model_mesh, & + stream_name = trim(stream_name), & + stream_meshfile = trim(sdatconfig%stream(ns)%meshfile), & + stream_filenames = filelist, & + stream_yearFirst = sdatconfig%stream(ns)%yearFirst, & + stream_yearLast = sdatconfig%stream(ns)%yearLast, & + stream_yearAlign = sdatconfig%stream(ns)%yearAlign, & + stream_fldlistFile = filevars(:,1), & + stream_fldListModel = filevars(:,2), & + stream_lev_dimname = trim(sdatconfig%stream(ns)%lev_dimname), & + stream_mapalgo = trim(sdatconfig%stream(ns)%mapalgo), & + stream_offset = sdatconfig%stream(ns)%offset, & + stream_taxmode = trim(sdatconfig%stream(ns)%taxmode), & + stream_dtlimit = sdatconfig%stream(ns)%dtlimit, & + stream_tintalgo = trim(sdatconfig%stream(ns)%tInterpAlgo), & + stream_src_mask = sdatconfig%stream(ns)%src_mask_val, & + stream_dst_mask = sdatconfig%stream(ns)%dst_mask_val, & + rc = rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + deallocate(filelist) + deallocate(filevars) + enddo + +end subroutine mom_inline_init +!=============================================================================== +subroutine mom_inline_run(clock, ocean_public, ocean_grid, ice_ocean_boundary, dbug, rc) + use MOM_ocean_model_nuopc, only: ocean_public_type + use MOM_surface_forcing_nuopc, only: ice_ocean_boundary_type + use MOM_grid, only: ocean_grid_type + use mpp_domains_mod, only: mpp_get_compute_domain + + type(ESMF_Clock) , intent(in) :: clock !< ESMF_Clock object + type(ocean_public_type) , intent(in) :: ocean_public !< Ocean surface state + type(ocean_grid_type) , intent(in) :: ocean_grid !< Ocean model grid + type(ice_ocean_boundary_type) , intent(inout) :: ice_ocean_boundary !< Ocean boundary forcing + integer , intent(in) :: dbug !< Integer debug flag + integer , intent(out) :: rc !< Return code + + ! local variables + type(ESMF_Time) :: date + integer :: nstreams, nflds + integer :: ns,nf,n,i,j + integer :: isc, iec, jsc, jec + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + character(len=ESMF_MAXSTR) :: fldname + real(ESMF_KIND_R8), pointer :: dataPtr1d(:) + character(len=*), parameter :: subname='(mom_inline_run)' + !----------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! The following are global indices without halos + call mpp_get_compute_domain(ocean_public%domain, isc, iec, jsc, jec) + + ! Current model date + call ESMF_ClockGet( clock, currTime=date, rc=rc ) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(date, yy=year, mm=mon, dd=day, s=sec, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + mcdate = year*10000 + mon*100 + day + + nstreams = size(sdat) + ! Advance the streams + do ns = 1,nstreams + write(stream_name,fmt='(a,i2.2)') 'stream_', ns + call shr_strdata_advance(sdat(ns), ymd=mcdate, tod=sec, logunit=logunit, istr=trim(stream_name),rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + nflds = size(sdat(ns)%pstrm(1)%fldlist_model) + do nf = 1,nflds + fldname = trim(sdat(ns)%pstrm(1)%fldlist_model(nf)) + + if (fldname == 'lrunoff') then + ! Get pointer for stream data that is time and spatially interpolated to model time and grid + call dshr_fldbun_getFldPtr(sdat(ns)%pstrm(1)%fldbun_model, trim(fldname), dataPtr1d, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + n = 0 + do j = jsc,jec + do i = isc,iec + n = n + 1 + ice_ocean_boundary%lrunoff(i,j) = dataPtr1d(n) + enddo + enddo + endif + + if (dbug > 1) then + call dshr_fldbun_Field_diagnose(sdat(ns)%pstrm(1)%fldbun_model, trim(fldname), 'inline_run ', rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + endif + enddo !nf + enddo !ns + +end subroutine mom_inline_run +end module mom_inline_mod diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index 87a16300ee..3c29db32b4 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Top-level module for the MOM6 ocean model in coupled mode. module MOM_ocean_model_nuopc -! This file is part of MOM6. See LICENSE.md for the license. - ! This is the top level module for the MOM6 ocean model. It contains routines ! for initialization, termination and update of ocean model state. This ! particular version wraps all of the calls for MOM6 in the calls that had diff --git a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 index a32987e6a2..10aa31ee19 100644 --- a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Converts the input ESMF data (import data) to a MOM-specific data type (surface_forcing_CS). module MOM_surface_forcing_nuopc -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : reproducing_sum, field_chksum use MOM_constants, only : hlv, hlf use MOM_coupler_types, only : coupler_2d_bc_type, coupler_type_write_chksums diff --git a/config_src/drivers/nuopc_cap/ocn_comp_NUOPC.F90 b/config_src/drivers/nuopc_cap/ocn_comp_NUOPC.F90 index 6d25b9a1ae..bb41084b65 100644 --- a/config_src/drivers/nuopc_cap/ocn_comp_NUOPC.F90 +++ b/config_src/drivers/nuopc_cap/ocn_comp_NUOPC.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module ocn_comp_NUOPC use MOM_cap_mod end module ocn_comp_NUOPC diff --git a/config_src/drivers/nuopc_cap/time_utils.F90 b/config_src/drivers/nuopc_cap/time_utils.F90 index 46f922d5bf..e2912206d1 100644 --- a/config_src/drivers/nuopc_cap/time_utils.F90 +++ b/config_src/drivers/nuopc_cap/time_utils.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Set of time utilities for converting between FMS and ESMF time type. module time_utils_mod diff --git a/config_src/drivers/solo_driver/MESO_surface_forcing.F90 b/config_src/drivers/solo_driver/MESO_surface_forcing.F90 index f1f3daa52e..7fee056ec6 100644 --- a/config_src/drivers/solo_driver/MESO_surface_forcing.F90 +++ b/config_src/drivers/solo_driver/MESO_surface_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Sets forcing for the MESO configuration module MESO_surface_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled use MOM_diag_mediator, only : register_diag_field, diag_ctrl, safe_alloc_ptr use MOM_domains, only : pass_var, pass_vector, AGRID diff --git a/config_src/drivers/solo_driver/MOM_driver.F90 b/config_src/drivers/solo_driver/MOM_driver.F90 index 9b85fafb8d..b1d1487bb1 100644 --- a/config_src/drivers/solo_driver/MOM_driver.F90 +++ b/config_src/drivers/solo_driver/MOM_driver.F90 @@ -1,6 +1,8 @@ -program MOM6 +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program MOM6 !********+*********+*********+*********+*********+*********+*********+** !* * diff --git a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 index 36badbedb0..660f4d84e6 100644 --- a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 +++ b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Functions that calculate the surface wind stresses and fluxes of buoyancy !! or temperature/salinity and fresh water, in ocean-only (solo) mode. !! @@ -7,8 +11,6 @@ !! fields is controlled by surface_forcing_init, located in this file. module MOM_surface_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_constants, only : hlv, hlf use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE diff --git a/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 b/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 index fb9fbe3e22..a8e11fbe34 100644 --- a/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 +++ b/config_src/drivers/solo_driver/atmos_ocean_fluxes.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A dummy version of atmos_ocean_fluxes_mod module for !! use when the vastly larger FMS package is not needed. module atmos_ocean_fluxes_mod -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public :: aof_set_coupler_flux diff --git a/config_src/drivers/solo_driver/user_surface_forcing.F90 b/config_src/drivers/solo_driver/user_surface_forcing.F90 index 55b1be1172..109e0364ce 100644 --- a/config_src/drivers/solo_driver/user_surface_forcing.F90 +++ b/config_src/drivers/solo_driver/user_surface_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Template for user to code up surface forcing. module user_surface_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled use MOM_diag_mediator, only : register_diag_field, diag_ctrl, safe_alloc_ptr use MOM_domains, only : pass_var, pass_vector, AGRID diff --git a/config_src/drivers/timing_tests/time_MOM_ANN.F90 b/config_src/drivers/timing_tests/time_MOM_ANN.F90 index a399835d89..dc079d4cff 100644 --- a/config_src/drivers/timing_tests/time_MOM_ANN.F90 +++ b/config_src/drivers/timing_tests/time_MOM_ANN.F90 @@ -1,6 +1,8 @@ -program time_MOM_ANN +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program time_MOM_ANN use MOM_ANN, only : ANN_CS use MOM_ANN, only : ANN_allocate, ANN_apply, ANN_end diff --git a/config_src/drivers/timing_tests/time_MOM_EOS.F90 b/config_src/drivers/timing_tests/time_MOM_EOS.F90 index 94e3282511..b8a3f5d27d 100644 --- a/config_src/drivers/timing_tests/time_MOM_EOS.F90 +++ b/config_src/drivers/timing_tests/time_MOM_EOS.F90 @@ -1,6 +1,8 @@ -program time_MOM_EOS +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program time_MOM_EOS use MOM_EOS, only : EOS_type use MOM_EOS, only : EOS_manual_init diff --git a/config_src/drivers/timing_tests/time_MOM_remapping.F90 b/config_src/drivers/timing_tests/time_MOM_remapping.F90 index e752686040..684abe2e2c 100644 --- a/config_src/drivers/timing_tests/time_MOM_remapping.F90 +++ b/config_src/drivers/timing_tests/time_MOM_remapping.F90 @@ -1,6 +1,8 @@ -program time_MOM_remapping +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program time_MOM_remapping use MOM_remapping, only : remapping_CS use MOM_remapping, only : initialize_remapping diff --git a/config_src/drivers/timing_tests/time_reproducing_sum.F90 b/config_src/drivers/timing_tests/time_reproducing_sum.F90 index de9a3ef63f..2851550d21 100644 --- a/config_src/drivers/timing_tests/time_reproducing_sum.F90 +++ b/config_src/drivers/timing_tests/time_reproducing_sum.F90 @@ -1,6 +1,8 @@ -program time_reproducing_sum +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program time_reproducing_sum use MOM_coms, only : PE_here, root_PE, num_PEs, reproducing_sum use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end diff --git a/config_src/drivers/unit_tests/test_MOM_ANN.F90 b/config_src/drivers/unit_tests/test_MOM_ANN.F90 index 2bdf7c14fe..345b6ee6e9 100644 --- a/config_src/drivers/unit_tests/test_MOM_ANN.F90 +++ b/config_src/drivers/unit_tests/test_MOM_ANN.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_ANN use MOM_ANN, only : ANN_unit_tests diff --git a/config_src/drivers/unit_tests/test_MOM_EOS.F90 b/config_src/drivers/unit_tests/test_MOM_EOS.F90 index 070bec04f6..90fe5b95e0 100644 --- a/config_src/drivers/unit_tests/test_MOM_EOS.F90 +++ b/config_src/drivers/unit_tests/test_MOM_EOS.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_EOS use MOM_EOS, only : EOS_unit_tests diff --git a/config_src/drivers/unit_tests/test_MOM_file_parser.F90 b/config_src/drivers/unit_tests/test_MOM_file_parser.F90 index 55f57d5fc2..1b3e52259c 100644 --- a/config_src/drivers/unit_tests/test_MOM_file_parser.F90 +++ b/config_src/drivers/unit_tests/test_MOM_file_parser.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_file_parser use MPI diff --git a/config_src/drivers/unit_tests/test_MOM_mixedlayer_restrat.F90 b/config_src/drivers/unit_tests/test_MOM_mixedlayer_restrat.F90 index 3e5eec64fc..60c6e72de4 100644 --- a/config_src/drivers/unit_tests/test_MOM_mixedlayer_restrat.F90 +++ b/config_src/drivers/unit_tests/test_MOM_mixedlayer_restrat.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_mixedlayer_restrat use MOM_mixed_layer_restrat, only : mixedlayer_restrat_unit_tests diff --git a/config_src/drivers/unit_tests/test_MOM_remapping.F90 b/config_src/drivers/unit_tests/test_MOM_remapping.F90 index 4c6fe4f750..4869e57965 100644 --- a/config_src/drivers/unit_tests/test_MOM_remapping.F90 +++ b/config_src/drivers/unit_tests/test_MOM_remapping.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_remapping use MOM_remapping, only : remapping_unit_tests diff --git a/config_src/drivers/unit_tests/test_MOM_string_functions.F90 b/config_src/drivers/unit_tests/test_MOM_string_functions.F90 index 2376afbbae..47da9d0411 100644 --- a/config_src/drivers/unit_tests/test_MOM_string_functions.F90 +++ b/config_src/drivers/unit_tests/test_MOM_string_functions.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_MOM_string_functions use MOM_string_functions, only : string_functions_unit_tests diff --git a/config_src/drivers/unit_tests/test_numerical_testing_type.F90 b/config_src/drivers/unit_tests/test_numerical_testing_type.F90 index 77216219fa..532d7ca960 100644 --- a/config_src/drivers/unit_tests/test_numerical_testing_type.F90 +++ b/config_src/drivers/unit_tests/test_numerical_testing_type.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + program test_numerical_testing_type use numerical_testing_type, only : numerical_testing_type_unit_tests diff --git a/config_src/drivers/unit_tests/test_reproducing_sum.F90 b/config_src/drivers/unit_tests/test_reproducing_sum.F90 index 0afd138138..2a9af42538 100644 --- a/config_src/drivers/unit_tests/test_reproducing_sum.F90 +++ b/config_src/drivers/unit_tests/test_reproducing_sum.F90 @@ -1,6 +1,8 @@ -program test_reproducing_sum +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +program test_reproducing_sum use MOM_coms, only : PE_here, root_PE, num_PEs, reproducing_sum use MOM_coms, only : sum_across_PEs, max_across_PEs, max_count_prec diff --git a/config_src/external/GFDL_ocean_BGC/MOM_generic_tracer.F90 b/config_src/external/GFDL_ocean_BGC/MOM_generic_tracer.F90 index 808cace1e2..4111bf020f 100644 --- a/config_src/external/GFDL_ocean_BGC/MOM_generic_tracer.F90 +++ b/config_src/external/GFDL_ocean_BGC/MOM_generic_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Drives the generic version of tracers TOPAZ and CFC and other GFDL BGC components module MOM_generic_tracer -! This file is part of MOM6. See LICENSE.md for the license. - #include ! The following macro is usually defined in but since MOM6 should not directly diff --git a/config_src/external/MARBL/marbl_constants_mod.F90 b/config_src/external/MARBL/marbl_constants_mod.F90 index 7a1d44ba97..1181a50e31 100644 --- a/config_src/external/MARBL/marbl_constants_mod.F90 +++ b/config_src/external/MARBL/marbl_constants_mod.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A non-functioning template of the MARBL constants module module marbl_constants_mod diff --git a/config_src/external/MARBL/marbl_interface.F90 b/config_src/external/MARBL/marbl_interface.F90 index d80ad49586..e4f4f51cfb 100644 --- a/config_src/external/MARBL/marbl_interface.F90 +++ b/config_src/external/MARBL/marbl_interface.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A non-functioning template of the MARBL interface module marbl_interface diff --git a/config_src/external/MARBL/marbl_interface_public_types.F90 b/config_src/external/MARBL/marbl_interface_public_types.F90 index 3955faf73a..98f83b529b 100644 --- a/config_src/external/MARBL/marbl_interface_public_types.F90 +++ b/config_src/external/MARBL/marbl_interface_public_types.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A non-functioning template of the public structures provided through MARBL interface module marbl_interface_public_types @@ -87,4 +91,4 @@ module marbl_interface_public_types type(marbl_single_output_type), dimension(:), pointer :: outputs_for_GCM => NULL() !< dummy outputs_for_GCM end type marbl_output_for_GCM_type -end module marbl_interface_public_types \ No newline at end of file +end module marbl_interface_public_types diff --git a/config_src/external/MARBL/marbl_logging.F90 b/config_src/external/MARBL/marbl_logging.F90 index 906d881f0e..8310d3746b 100644 --- a/config_src/external/MARBL/marbl_logging.F90 +++ b/config_src/external/MARBL/marbl_logging.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A non-functioning template of the MARBL logging module module marbl_logging @@ -35,4 +39,4 @@ subroutine erase(self) class(marbl_log_type), intent(inout) :: self end subroutine erase -end module marbl_logging \ No newline at end of file +end module marbl_logging diff --git a/config_src/external/ODA_hooks/kdtree.f90 b/config_src/external/ODA_hooks/kdtree.f90 index a27716dde1..75558c94fa 100644 --- a/config_src/external/ODA_hooks/kdtree.f90 +++ b/config_src/external/ODA_hooks/kdtree.f90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A null version of K-d tree from geoKdTree module kdtree implicit none diff --git a/config_src/external/ODA_hooks/ocean_da_core.F90 b/config_src/external/ODA_hooks/ocean_da_core.F90 index 769e44b2aa..a2fba2b7b0 100644 --- a/config_src/external/ODA_hooks/ocean_da_core.F90 +++ b/config_src/external/ODA_hooks/ocean_da_core.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A set of dummy interfaces for compiling the MOM6 DA driver code. module ocean_da_core_mod ! MOM modules diff --git a/config_src/external/ODA_hooks/ocean_da_types.F90 b/config_src/external/ODA_hooks/ocean_da_types.F90 index a99f1ae669..82e1a28e6e 100644 --- a/config_src/external/ODA_hooks/ocean_da_types.F90 +++ b/config_src/external/ODA_hooks/ocean_da_types.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Dummy aata structures and methods for ocean data assimilation. module ocean_da_types_mod diff --git a/config_src/external/ODA_hooks/write_ocean_obs.F90 b/config_src/external/ODA_hooks/write_ocean_obs.F90 index 51b5d2a1d7..6766a391ca 100644 --- a/config_src/external/ODA_hooks/write_ocean_obs.F90 +++ b/config_src/external/ODA_hooks/write_ocean_obs.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Dummy interfaces for writing ODA data module write_ocean_obs_mod diff --git a/config_src/external/database_comms/MOM_database_comms.F90 b/config_src/external/database_comms/MOM_database_comms.F90 index 4c3eb38b5c..90f866186a 100644 --- a/config_src/external/database_comms/MOM_database_comms.F90 +++ b/config_src/external/database_comms/MOM_database_comms.F90 @@ -1,6 +1,9 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Contains routines necessary to initialize communication with a database module MOM_database_comms -! This file is part of MOM6. See LICENSE.md for the license. use MOM_file_parser, only : param_file_type use MOM_error_handler, only : MOM_error, WARNING use database_client_interface, only : dbclient_type diff --git a/config_src/external/database_comms/database_client_interface.F90 b/config_src/external/database_comms/database_client_interface.F90 index 8b05b83daf..3997fe8baf 100644 --- a/config_src/external/database_comms/database_client_interface.F90 +++ b/config_src/external/database_comms/database_client_interface.F90 @@ -1,6 +1,9 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module database_client_interface -! This file is part of MOM6. See LICENSE.md for the license. use iso_fortran_env, only : int8, int16, int32, int64, real32, real64 implicit none; private diff --git a/config_src/external/drifters/MOM_particles.F90 b/config_src/external/drifters/MOM_particles.F90 index 1c41170582..543efeaf1d 100644 --- a/config_src/external/drifters/MOM_particles.F90 +++ b/config_src/external/drifters/MOM_particles.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A set of dummy interfaces for compiling the MOM6 drifters code module MOM_particles_mod -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_grid, only : ocean_grid_type use MOM_time_manager, only : time_type, get_date, operator(-) use MOM_variables, only : thermo_var_ptrs diff --git a/config_src/external/drifters/MOM_particles_types.F90 b/config_src/external/drifters/MOM_particles_types.F90 index 30fecad7a2..ffa9158e69 100644 --- a/config_src/external/drifters/MOM_particles_types.F90 +++ b/config_src/external/drifters/MOM_particles_types.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Dummy data structures and methods for drifters package module particles_types_mod -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : int64 use MOM_grid, only : ocean_grid_type use MOM_domains, only: domain2D diff --git a/config_src/external/stochastic_physics/get_stochy_pattern.F90 b/config_src/external/stochastic_physics/get_stochy_pattern.F90 index c3e23cd1a4..4d4c5c9bec 100644 --- a/config_src/external/stochastic_physics/get_stochy_pattern.F90 +++ b/config_src/external/stochastic_physics/get_stochy_pattern.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + ! The are stubs for ocean stochastic physics ! the fully functional code is available at ! http://github.com/noaa-psd/stochastic_physics module get_stochy_pattern_mod -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public :: write_stoch_restart_ocn diff --git a/config_src/external/stochastic_physics/stochastic_physics.F90 b/config_src/external/stochastic_physics/stochastic_physics.F90 index 196468e317..718e80ab8a 100644 --- a/config_src/external/stochastic_physics/stochastic_physics.F90 +++ b/config_src/external/stochastic_physics/stochastic_physics.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + ! The are stubs for ocean stochastic physics ! the fully functional code is available at ! http://github.com/noaa-psd/stochastic_physics module stochastic_physics -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, WARNING implicit none ; private diff --git a/config_src/infra/FMS1/MOM_coms_infra.F90 b/config_src/infra/FMS1/MOM_coms_infra.F90 index 13f8006184..a9395440bd 100644 --- a/config_src/infra/FMS1/MOM_coms_infra.F90 +++ b/config_src/infra/FMS1/MOM_coms_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Thin interfaces to non-domain-oriented mpp communication subroutines module MOM_coms_infra -! This file is part of MOM6. See LICENSE.md for the license. - use iso_fortran_env, only : int32, int64 use mpp_mod, only : mpp_pe, mpp_root_pe, mpp_npes, mpp_set_root_pe diff --git a/config_src/infra/FMS1/MOM_constants.F90 b/config_src/infra/FMS1/MOM_constants.F90 index a632267a7f..ad44ba4f85 100644 --- a/config_src/infra/FMS1/MOM_constants.F90 +++ b/config_src/infra/FMS1/MOM_constants.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a few physical constants module MOM_constants -! This file is part of MOM6. See LICENSE.md for the license. - use constants_mod, only : FMS_HLV => HLV use constants_mod, only : FMS_HLF => HLF diff --git a/config_src/infra/FMS1/MOM_couplertype_infra.F90 b/config_src/infra/FMS1/MOM_couplertype_infra.F90 index 637f2b5ebf..e196b7e147 100644 --- a/config_src/infra/FMS1/MOM_couplertype_infra.F90 +++ b/config_src/infra/FMS1/MOM_couplertype_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module wraps the FMS coupler types module module MOM_couplertype_infra -! This file is part of MOM6. See LICENSE.md for the license. - use coupler_types_mod, only : coupler_type_spawn, coupler_type_initialized, coupler_type_destructor use coupler_types_mod, only : coupler_type_set_diags, coupler_type_send_data, coupler_type_copy_data use coupler_types_mod, only : coupler_type_write_chksums, coupler_type_redistribute_data diff --git a/config_src/infra/FMS1/MOM_cpu_clock_infra.F90 b/config_src/infra/FMS1/MOM_cpu_clock_infra.F90 index 0c42c577b4..aeca65b863 100644 --- a/config_src/infra/FMS1/MOM_cpu_clock_infra.F90 +++ b/config_src/infra/FMS1/MOM_cpu_clock_infra.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Wraps the MPP cpu clock functions !! !! The functions and constants should be accessed via mom_cpu_clock module MOM_cpu_clock_infra -! This file is part of MOM6. See LICENSE.md for the license. - ! These interfaces and constants from MPP/FMS will not be directly exposed outside of this module use fms_mod, only : clock_flag_default use mpp_mod, only : mpp_clock_begin diff --git a/config_src/infra/FMS1/MOM_data_override_infra.F90 b/config_src/infra/FMS1/MOM_data_override_infra.F90 index 1484f0c128..57311710c8 100644 --- a/config_src/infra/FMS1/MOM_data_override_infra.F90 +++ b/config_src/infra/FMS1/MOM_data_override_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> These interfaces allow for ocean or sea-ice variables to be replaced with data. module MOM_data_override_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, domain2d use MOM_domain_infra, only : get_simple_array_i_ind, get_simple_array_j_ind use MOM_time_manager, only : time_type diff --git a/config_src/infra/FMS1/MOM_diag_manager_infra.F90 b/config_src/infra/FMS1/MOM_diag_manager_infra.F90 index d9be18d33f..2031487389 100644 --- a/config_src/infra/FMS1/MOM_diag_manager_infra.F90 +++ b/config_src/infra/FMS1/MOM_diag_manager_infra.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A wrapper for the FMS diag_manager routines. This module should be the !! only MOM6 module which imports the FMS shared infrastructure for !! diagnostics. Pass through interfaces are being documented @@ -6,8 +10,6 @@ !! those APIs would be applied here). module MOM_diag_manager_infra -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : real64 use diag_axis_mod, only : fms_axis_init=>diag_axis_init use diag_axis_mod, only : fms_get_diag_axis_name => get_diag_axis_name diff --git a/config_src/infra/FMS1/MOM_domain_infra.F90 b/config_src/infra/FMS1/MOM_domain_infra.F90 index fdffef9d60..1031f07d56 100644 --- a/config_src/infra/FMS1/MOM_domain_infra.F90 +++ b/config_src/infra/FMS1/MOM_domain_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Describes the decomposed MOM domain and has routines for communications across PEs module MOM_domain_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms_infra, only : PE_here, root_PE, num_PEs use MOM_cpu_clock_infra, only : cpu_clock_begin, cpu_clock_end use MOM_error_infra, only : MOM_error=>MOM_err, NOTE, WARNING, FATAL diff --git a/config_src/infra/FMS1/MOM_ensemble_manager_infra.F90 b/config_src/infra/FMS1/MOM_ensemble_manager_infra.F90 index 3ab9d591da..436cf28654 100644 --- a/config_src/infra/FMS1/MOM_ensemble_manager_infra.F90 +++ b/config_src/infra/FMS1/MOM_ensemble_manager_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A simple (very thin) wrapper for managing ensemble member layout information module MOM_ensemble_manager_infra -! This file is part of MOM6. See LICENSE.md for the license. - use ensemble_manager_mod, only : FMS_ensemble_manager_init => ensemble_manager_init use ensemble_manager_mod, only : FMS_ensemble_pelist_setup => ensemble_pelist_setup use ensemble_manager_mod, only : FMS_get_ensemble_id => get_ensemble_id diff --git a/config_src/infra/FMS1/MOM_error_infra.F90 b/config_src/infra/FMS1/MOM_error_infra.F90 index e5a8b8dc68..7db14bc127 100644 --- a/config_src/infra/FMS1/MOM_error_infra.F90 +++ b/config_src/infra/FMS1/MOM_error_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines for error handling and I/O management module MOM_error_infra -! This file is part of MOM6. See LICENSE.md for the license. - use mpp_mod, only : mpp_error, mpp_pe, mpp_root_pe, mpp_stdlog=>stdlog, mpp_stdout=>stdout use mpp_mod, only : NOTE, WARNING, FATAL diff --git a/config_src/infra/FMS1/MOM_interp_infra.F90 b/config_src/infra/FMS1/MOM_interp_infra.F90 index 70bc99827e..3069f1c644 100644 --- a/config_src/infra/FMS1/MOM_interp_infra.F90 +++ b/config_src/infra/FMS1/MOM_interp_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module wraps the FMS temporal and spatial interpolation routines module MOM_interp_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, domain2d use MOM_io, only : axis_info use MOM_io, only : set_axis_info diff --git a/config_src/infra/FMS1/MOM_io_infra.F90 b/config_src/infra/FMS1/MOM_io_infra.F90 index e37e5db3cb..9bff64363a 100644 --- a/config_src/infra/FMS1/MOM_io_infra.F90 +++ b/config_src/infra/FMS1/MOM_io_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains a thin inteface to mpp and fms I/O code module MOM_io_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, rescale_comp_data, AGRID, BGRID_NE, CGRID_NE use MOM_domain_infra, only : domain2d, domain1d, CENTER, CORNER, NORTH_FACE, EAST_FACE use MOM_error_infra, only : MOM_error=>MOM_err, NOTE, FATAL, WARNING diff --git a/config_src/infra/FMS1/MOM_time_manager.F90 b/config_src/infra/FMS1/MOM_time_manager.F90 index 5f3279b713..7ec71cc37c 100644 --- a/config_src/infra/FMS1/MOM_time_manager.F90 +++ b/config_src/infra/FMS1/MOM_time_manager.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Wraps the FMS time manager functions module MOM_time_manager -! This file is part of MOM6. See LICENSE.md for the license. - use time_manager_mod, only : time_type, get_time, set_time use time_manager_mod, only : time_type_to_real, real_to_time_type use time_manager_mod, only : operator(+), operator(-), operator(*), operator(/) diff --git a/config_src/infra/FMS2/MOM_coms_infra.F90 b/config_src/infra/FMS2/MOM_coms_infra.F90 index 06a9b9f343..1112f932d2 100644 --- a/config_src/infra/FMS2/MOM_coms_infra.F90 +++ b/config_src/infra/FMS2/MOM_coms_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Thin interfaces to non-domain-oriented mpp communication subroutines module MOM_coms_infra -! This file is part of MOM6. See LICENSE.md for the license. - use iso_fortran_env, only : int32, int64 use mpp_mod, only : mpp_pe, mpp_root_pe, mpp_npes, mpp_set_root_pe diff --git a/config_src/infra/FMS2/MOM_constants.F90 b/config_src/infra/FMS2/MOM_constants.F90 index a632267a7f..ad44ba4f85 100644 --- a/config_src/infra/FMS2/MOM_constants.F90 +++ b/config_src/infra/FMS2/MOM_constants.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a few physical constants module MOM_constants -! This file is part of MOM6. See LICENSE.md for the license. - use constants_mod, only : FMS_HLV => HLV use constants_mod, only : FMS_HLF => HLF diff --git a/config_src/infra/FMS2/MOM_couplertype_infra.F90 b/config_src/infra/FMS2/MOM_couplertype_infra.F90 index 3bcccc1dc7..b8dbc1be82 100644 --- a/config_src/infra/FMS2/MOM_couplertype_infra.F90 +++ b/config_src/infra/FMS2/MOM_couplertype_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module wraps the FMS coupler types module module MOM_couplertype_infra -! This file is part of MOM6. See LICENSE.md for the license. - use coupler_types_mod, only : coupler_type_spawn, coupler_type_initialized, coupler_type_destructor use coupler_types_mod, only : coupler_type_set_diags, coupler_type_send_data, coupler_type_copy_data use coupler_types_mod, only : coupler_type_write_chksums, coupler_type_redistribute_data diff --git a/config_src/infra/FMS2/MOM_cpu_clock_infra.F90 b/config_src/infra/FMS2/MOM_cpu_clock_infra.F90 index 0c42c577b4..aeca65b863 100644 --- a/config_src/infra/FMS2/MOM_cpu_clock_infra.F90 +++ b/config_src/infra/FMS2/MOM_cpu_clock_infra.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Wraps the MPP cpu clock functions !! !! The functions and constants should be accessed via mom_cpu_clock module MOM_cpu_clock_infra -! This file is part of MOM6. See LICENSE.md for the license. - ! These interfaces and constants from MPP/FMS will not be directly exposed outside of this module use fms_mod, only : clock_flag_default use mpp_mod, only : mpp_clock_begin diff --git a/config_src/infra/FMS2/MOM_data_override_infra.F90 b/config_src/infra/FMS2/MOM_data_override_infra.F90 index 1484f0c128..57311710c8 100644 --- a/config_src/infra/FMS2/MOM_data_override_infra.F90 +++ b/config_src/infra/FMS2/MOM_data_override_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> These interfaces allow for ocean or sea-ice variables to be replaced with data. module MOM_data_override_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, domain2d use MOM_domain_infra, only : get_simple_array_i_ind, get_simple_array_j_ind use MOM_time_manager, only : time_type diff --git a/config_src/infra/FMS2/MOM_diag_manager_infra.F90 b/config_src/infra/FMS2/MOM_diag_manager_infra.F90 index 57f92c2046..2648900493 100644 --- a/config_src/infra/FMS2/MOM_diag_manager_infra.F90 +++ b/config_src/infra/FMS2/MOM_diag_manager_infra.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A wrapper for the FMS diag_manager routines. This module should be the !! only MOM6 module which imports the FMS shared infrastructure for !! diagnostics. Pass through interfaces are being documented @@ -6,8 +10,6 @@ !! those APIs would be applied here). module MOM_diag_manager_infra -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : real64 use diag_axis_mod, only : fms_axis_init=>diag_axis_init use diag_axis_mod, only : fms_get_diag_axis_name => get_diag_axis_name diff --git a/config_src/infra/FMS2/MOM_domain_infra.F90 b/config_src/infra/FMS2/MOM_domain_infra.F90 index 91c62f7d08..4065628635 100644 --- a/config_src/infra/FMS2/MOM_domain_infra.F90 +++ b/config_src/infra/FMS2/MOM_domain_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Describes the decomposed MOM domain and has routines for communications across PEs module MOM_domain_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms_infra, only : PE_here, root_PE, num_PEs use MOM_cpu_clock_infra, only : cpu_clock_begin, cpu_clock_end use MOM_error_infra, only : MOM_error=>MOM_err, NOTE, WARNING, FATAL diff --git a/config_src/infra/FMS2/MOM_ensemble_manager_infra.F90 b/config_src/infra/FMS2/MOM_ensemble_manager_infra.F90 index f4028f7af7..8285eefd57 100644 --- a/config_src/infra/FMS2/MOM_ensemble_manager_infra.F90 +++ b/config_src/infra/FMS2/MOM_ensemble_manager_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A simple (very thin) wrapper for managing ensemble member layout information module MOM_ensemble_manager_infra -! This file is part of MOM6. See LICENSE.md for the license. - use ensemble_manager_mod, only : FMS_ensemble_manager_init => ensemble_manager_init use ensemble_manager_mod, only : FMS_ensemble_pelist_setup => ensemble_pelist_setup use ensemble_manager_mod, only : FMS_get_ensemble_id => get_ensemble_id diff --git a/config_src/infra/FMS2/MOM_error_infra.F90 b/config_src/infra/FMS2/MOM_error_infra.F90 index e5a8b8dc68..7db14bc127 100644 --- a/config_src/infra/FMS2/MOM_error_infra.F90 +++ b/config_src/infra/FMS2/MOM_error_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines for error handling and I/O management module MOM_error_infra -! This file is part of MOM6. See LICENSE.md for the license. - use mpp_mod, only : mpp_error, mpp_pe, mpp_root_pe, mpp_stdlog=>stdlog, mpp_stdout=>stdout use mpp_mod, only : NOTE, WARNING, FATAL diff --git a/config_src/infra/FMS2/MOM_interp_infra.F90 b/config_src/infra/FMS2/MOM_interp_infra.F90 index 0b45b752ae..9b745ad001 100644 --- a/config_src/infra/FMS2/MOM_interp_infra.F90 +++ b/config_src/infra/FMS2/MOM_interp_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module wraps the FMS temporal and spatial interpolation routines module MOM_interp_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, domain2d use MOM_io, only : axis_info use MOM_io, only : get_var_axes_info diff --git a/config_src/infra/FMS2/MOM_io_infra.F90 b/config_src/infra/FMS2/MOM_io_infra.F90 index a43b4e9344..3e69d110ff 100644 --- a/config_src/infra/FMS2/MOM_io_infra.F90 +++ b/config_src/infra/FMS2/MOM_io_infra.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains a thin inteface to mpp and fms I/O code module MOM_io_infra -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domain_infra, only : MOM_domain_type, rescale_comp_data, AGRID, BGRID_NE, CGRID_NE use MOM_domain_infra, only : domain2d, domain1d, CENTER, CORNER, NORTH_FACE, EAST_FACE use MOM_error_infra, only : MOM_error=>MOM_err, NOTE, FATAL, WARNING, is_root_PE diff --git a/config_src/infra/FMS2/MOM_time_manager.F90 b/config_src/infra/FMS2/MOM_time_manager.F90 index 5f3279b713..7ec71cc37c 100644 --- a/config_src/infra/FMS2/MOM_time_manager.F90 +++ b/config_src/infra/FMS2/MOM_time_manager.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Wraps the FMS time manager functions module MOM_time_manager -! This file is part of MOM6. See LICENSE.md for the license. - use time_manager_mod, only : time_type, get_time, set_time use time_manager_mod, only : time_type_to_real, real_to_time_type use time_manager_mod, only : operator(+), operator(-), operator(*), operator(/) diff --git a/config_src/memory/dynamic_nonsymmetric/MOM_memory.h b/config_src/memory/dynamic_nonsymmetric/MOM_memory.h index c3385b8b9a..0d5f44d6be 100644 --- a/config_src/memory/dynamic_nonsymmetric/MOM_memory.h +++ b/config_src/memory/dynamic_nonsymmetric/MOM_memory.h @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !/// \brief Compile-time memory settings !/// \details This include file determines the compile-time memory settings. !/// There are several variants of this file and only one should be in the search path for compilation. diff --git a/config_src/memory/dynamic_symmetric/MOM_memory.h b/config_src/memory/dynamic_symmetric/MOM_memory.h index 4188663a2c..e1557b6ac7 100644 --- a/config_src/memory/dynamic_symmetric/MOM_memory.h +++ b/config_src/memory/dynamic_symmetric/MOM_memory.h @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !/// \brief Compile-time memory settings !/// \details This include file determines the compile-time memory settings. !/// There are several variants of this file and only one should be in the search path for compilation. diff --git a/docs/postProcessEquations.py b/docs/postProcessEquations.py index 396c41b507..59bceb15d0 100644 --- a/docs/postProcessEquations.py +++ b/docs/postProcessEquations.py @@ -1,3 +1,7 @@ +# This file is part of MOM6, the Modular Ocean Model version 6. +# See the LICENSE file for licensing information. +# SPDX-License-Identifier: Apache-2.0 + import os, sys, pathlib, re import itertools from lxml import html diff --git a/src/ALE/MOM_ALE.F90 b/src/ALE/MOM_ALE.F90 index ab9b7405ee..e319b71ddc 100644 --- a/src/ALE/MOM_ALE.F90 +++ b/src/ALE/MOM_ALE.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the main regridding routines. !! !! Regridding comprises two steps: @@ -8,8 +12,6 @@ !! Original module written by Laurent White, 2008.06.09 module MOM_ALE -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : check_column_integrals use MOM_diag_mediator, only : register_diag_field, post_data, diag_ctrl use MOM_diag_mediator, only : time_type, diag_update_remap_grids, query_averaging_enabled diff --git a/src/ALE/MOM_hybgen_regrid.F90 b/src/ALE/MOM_hybgen_regrid.F90 index 396fa65ed2..d3a889ed99 100644 --- a/src/ALE/MOM_hybgen_regrid.F90 +++ b/src/ALE/MOM_hybgen_regrid.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the hybgen regridding routines from HYCOM, with minor !! modifications to follow the MOM6 coding conventions module MOM_hybgen_regrid -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS, only : EOS_type, calculate_density use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, assert use MOM_file_parser, only : get_param, param_file_type, log_param diff --git a/src/ALE/MOM_hybgen_remap.F90 b/src/ALE/MOM_hybgen_remap.F90 index f97b0e9c62..68a193cebe 100644 --- a/src/ALE/MOM_hybgen_remap.F90 +++ b/src/ALE/MOM_hybgen_remap.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the hybgen remapping routines from HYCOM, with minor !! modifications to follow the MOM6 coding conventions module MOM_hybgen_remap -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public hybgen_plm_coefs, hybgen_ppm_coefs, hybgen_weno_coefs diff --git a/src/ALE/MOM_hybgen_unmix.F90 b/src/ALE/MOM_hybgen_unmix.F90 index bb6f64c4d7..1dfae7a167 100644 --- a/src/ALE/MOM_hybgen_unmix.F90 +++ b/src/ALE/MOM_hybgen_unmix.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the hybgen unmixing routines from HYCOM, with !! modifications to follow the MOM6 coding conventions and several bugs fixed module MOM_hybgen_unmix -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS, only : EOS_type, calculate_density, calculate_density_derivs use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING use MOM_file_parser, only : get_param, param_file_type, log_param diff --git a/src/ALE/MOM_regridding.F90 b/src/ALE/MOM_regridding.F90 index 9f36ae9d89..7e24d80a21 100644 --- a/src/ALE/MOM_regridding.F90 +++ b/src/ALE/MOM_regridding.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Generates vertical grids as part of the ALE algorithm module MOM_regridding -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL, WARNING, NOTE, assert use MOM_file_parser, only : param_file_type, get_param, log_param use MOM_io, only : file_exists, field_exists, field_size, MOM_read_data diff --git a/src/ALE/MOM_remapping.F90 b/src/ALE/MOM_remapping.F90 index c47ab73b77..e22b148c23 100644 --- a/src/ALE/MOM_remapping.F90 +++ b/src/ALE/MOM_remapping.F90 @@ -1,7 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides column-wise vertical remapping functions module MOM_remapping -! This file is part of MOM6. See LICENSE.md for the license. ! Original module written by Laurent White, 2008.06.09 use MOM_error_handler, only : MOM_error, FATAL @@ -2095,22 +2098,22 @@ logical function remapping_unit_tests(verbose, num_comp_samp) integer :: om4 ! Loop parameter, 0 or 1 integer :: ntests ! Number of iterations when brute force testing character(len=4) :: om4_tag ! Generated label - type(PCM) :: PCM - type(PLM_CW) :: PLM_CW - type(PLM_hybgen) :: PLM_hybgen - type(MPLM_WA) :: MPLM_WA - type(EMPLM_WA) :: EMPLM_WA - type(MPLM_WA_poly) :: MPLM_WA_poly - type(EMPLM_WA_poly) :: EMPLM_WA_poly - type(PLM_CWK) :: PLM_CWK - type(MPLM_CWK) :: MPLM_CWK - type(EMPLM_CWK) :: EMPLM_CWK - type(PPM_H4_2019) :: PPM_H4_2019 - type(PPM_H4_2018) :: PPM_H4_2018 - type(PPM_CW) :: PPM_CW - type(PPM_hybgen) :: PPM_hybgen - type(PPM_CWK) :: PPM_CWK - type(EPPM_CWK) :: EPPM_CWK + type(PCM) :: PCM_instance + type(PLM_CW) :: PLM_CW_instance + type(PLM_hybgen) :: PLM_hybgen_instance + type(MPLM_WA) :: MPLM_WA_instance + type(EMPLM_WA) :: EMPLM_WA_instance + type(MPLM_WA_poly) :: MPLM_WA_poly_instance + type(EMPLM_WA_poly) :: EMPLM_WA_poly_instance + type(PLM_CWK) :: PLM_CWK_instance + type(MPLM_CWK) :: MPLM_CWK_instance + type(EMPLM_CWK) :: EMPLM_CWK_instance + type(PPM_H4_2019) :: PPM_H4_2019_instance + type(PPM_H4_2018) :: PPM_H4_2018_instance + type(PPM_CW) :: PPM_CW_instance + type(PPM_hybgen) :: PPM_hybgen_instance + type(PPM_CWK) :: PPM_CWK_instance + type(EPPM_CWK) :: EPPM_CWK_instance call test%set( verbose=verbose ) ! Sets the verbosity flag in test ! call test%set( stop_instantly=.true. ) ! While debugging @@ -2724,22 +2727,22 @@ logical function remapping_unit_tests(verbose, num_comp_samp) 3, (/0.,0.,0./), (/0.,0.,0./) ) if (verbose) write(test%stdout,*) '- - - - - - - - - - Recon1d PCM tests - - - - - - - - -' - call test%test( PCM%unit_tests(verbose, test%stdout, test%stderr), 'PCM unit test') - call test%test( MPLM_WA%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_WA unit test') - call test%test( EMPLM_WA%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_WA unit test') - call test%test( MPLM_WA_poly%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_WA_poly unit test') - call test%test( EMPLM_WA_poly%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_WA_poly unit test') - call test%test( PLM_hybgen%unit_tests(verbose, test%stdout, test%stderr), 'PLM_hybgen unit test') - call test%test( PLM_CW%unit_tests(verbose, test%stdout, test%stderr), 'PLM_CW unit test') - call test%test( PLM_CWK%unit_tests(verbose, test%stdout, test%stderr), 'PLM_CWK unit test') - call test%test( MPLM_CWK%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_CWK unit test') - call test%test( EMPLM_CWK%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_CWK unit test') - call test%test( PPM_H4_2019%unit_tests(verbose, test%stdout, test%stderr), 'PPM_H4_2019 unit test') - call test%test( PPM_H4_2018%unit_tests(verbose, test%stdout, test%stderr), 'PPM_H4_2018 unit test') - call test%test( PPM_hybgen%unit_tests(verbose, test%stdout, test%stderr), 'PPM_hybgen unit test') - call test%test( PPM_CW%unit_tests(verbose, test%stdout, test%stderr), 'PPM_CW unit test') - call test%test( PPM_CWK%unit_tests(verbose, test%stdout, test%stderr), 'PPM_CWK unit test') - call test%test( EPPM_CWK%unit_tests(verbose, test%stdout, test%stderr), 'EPPM_CWK unit test') + call test%test( PCM_instance%unit_tests(verbose, test%stdout, test%stderr), 'PCM unit test') + call test%test( MPLM_WA_instance%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_WA unit test') + call test%test( EMPLM_WA_instance%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_WA unit test') + call test%test( MPLM_WA_poly_instance%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_WA_poly unit test') + call test%test( EMPLM_WA_poly_instance%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_WA_poly unit test') + call test%test( PLM_hybgen_instance%unit_tests(verbose, test%stdout, test%stderr), 'PLM_hybgen unit test') + call test%test( PLM_CW_instance%unit_tests(verbose, test%stdout, test%stderr), 'PLM_CW unit test') + call test%test( PLM_CWK_instance%unit_tests(verbose, test%stdout, test%stderr), 'PLM_CWK unit test') + call test%test( MPLM_CWK_instance%unit_tests(verbose, test%stdout, test%stderr), 'MPLM_CWK unit test') + call test%test( EMPLM_CWK_instance%unit_tests(verbose, test%stdout, test%stderr), 'EMPLM_CWK unit test') + call test%test( PPM_H4_2019_instance%unit_tests(verbose, test%stdout, test%stderr), 'PPM_H4_2019 unit test') + call test%test( PPM_H4_2018_instance%unit_tests(verbose, test%stdout, test%stderr), 'PPM_H4_2018 unit test') + call test%test( PPM_hybgen_instance%unit_tests(verbose, test%stdout, test%stderr), 'PPM_hybgen unit test') + call test%test( PPM_CW_instance%unit_tests(verbose, test%stdout, test%stderr), 'PPM_CW unit test') + call test%test( PPM_CWK_instance%unit_tests(verbose, test%stdout, test%stderr), 'PPM_CWK unit test') + call test%test( EPPM_CWK_instance%unit_tests(verbose, test%stdout, test%stderr), 'EPPM_CWK unit test') ! Randomized, brute force tests ntests = 3000 diff --git a/src/ALE/P1M_functions.F90 b/src/ALE/P1M_functions.F90 index d2051cc702..510ebde12c 100644 --- a/src/ALE/P1M_functions.F90 +++ b/src/ALE/P1M_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Linear interpolation functions module P1M_functions -! This file is part of MOM6. See LICENSE.md for the license. - use regrid_edge_values, only : bound_edge_values, average_discontinuous_edge_values implicit none ; private diff --git a/src/ALE/P3M_functions.F90 b/src/ALE/P3M_functions.F90 index e9c234db32..e07cd9640f 100644 --- a/src/ALE/P3M_functions.F90 +++ b/src/ALE/P3M_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Cubic interpolation functions module P3M_functions -! This file is part of MOM6. See LICENSE.md for the license. - use regrid_edge_values, only : bound_edge_values, average_discontinuous_edge_values implicit none ; private diff --git a/src/ALE/PCM_functions.F90 b/src/ALE/PCM_functions.F90 index f5899339e4..dff25e5fc6 100644 --- a/src/ALE/PCM_functions.F90 +++ b/src/ALE/PCM_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise constant reconstruction functions module PCM_functions -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public PCM_reconstruction diff --git a/src/ALE/PLM_functions.F90 b/src/ALE/PLM_functions.F90 index 6d6afd3885..ab70541747 100644 --- a/src/ALE/PLM_functions.F90 +++ b/src/ALE/PLM_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise linear reconstruction functions module PLM_functions -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public PLM_boundary_extrapolation diff --git a/src/ALE/PPM_functions.F90 b/src/ALE/PPM_functions.F90 index c11ec6e741..ad8fe2adb6 100644 --- a/src/ALE/PPM_functions.F90 +++ b/src/ALE/PPM_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides functions used with the Piecewise-Parabolic-Method in the vertical ALE algorithm. module PPM_functions -! This file is part of MOM6. See LICENSE.md for the license. - ! First version was created by Laurent White, June 2008. ! Substantially re-factored January 2016. diff --git a/src/ALE/PQM_functions.F90 b/src/ALE/PQM_functions.F90 index 418a4b47a2..d0bd58a9fe 100644 --- a/src/ALE/PQM_functions.F90 +++ b/src/ALE/PQM_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise quartic reconstruction functions module PQM_functions -! This file is part of MOM6. See LICENSE.md for the license. - use regrid_edge_values, only : bound_edge_values, check_discontinuous_edge_values implicit none ; private diff --git a/src/ALE/Recon1d_EMPLM_CWK.F90 b/src/ALE/Recon1d_EMPLM_CWK.F90 index 01d97058a9..bcd06c3f6f 100644 --- a/src/ALE/Recon1d_EMPLM_CWK.F90 +++ b/src/ALE/Recon1d_EMPLM_CWK.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Linear Method 1D reconstruction in index space and boundary extrapolation !! !! This implementation of PLM follows Colella and Woodward, 1984 \cite colella1984, except for assuming @@ -7,8 +11,6 @@ !! cell (i.e. extrapolates from the interior). module Recon1d_EMPLM_CWK -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : testing use Recon1d_MPLM_CWK, only : MPLM_CWK diff --git a/src/ALE/Recon1d_EMPLM_WA.F90 b/src/ALE/Recon1d_EMPLM_WA.F90 index fc46cf74f6..b72203e0f0 100644 --- a/src/ALE/Recon1d_EMPLM_WA.F90 +++ b/src/ALE/Recon1d_EMPLM_WA.F90 @@ -1,11 +1,13 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Extrapolated-Monotonized Piecewise Linear Method 1D reconstruction !! !! This extends MPLM_WA, following White and Adcroft, 2008 \cite white2008, by extrapolating for the slopes of the !! first and last cells. This extrapolation is used by White et al., 2009, during grid-generation. module Recon1d_EMPLM_WA -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_MPLM_WA, only : MPLM_WA, testing implicit none ; private diff --git a/src/ALE/Recon1d_EMPLM_WA_poly.F90 b/src/ALE/Recon1d_EMPLM_WA_poly.F90 index bcfc398cf9..8aa06a883a 100644 --- a/src/ALE/Recon1d_EMPLM_WA_poly.F90 +++ b/src/ALE/Recon1d_EMPLM_WA_poly.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Extrapolated-Monotonized Piecewise Linear Method 1D reconstruction !! !! This extends MPLM_poly, following White and Adcroft, 2008 \cite white2008, by extraplating for the slopes of the @@ -7,8 +11,6 @@ !! but was the form used in OM4. module Recon1d_EMPLM_WA_poly -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_MPLM_WA_poly, only : MPLM_WA_poly, testing implicit none ; private diff --git a/src/ALE/Recon1d_EPPM_CWK.F90 b/src/ALE/Recon1d_EPPM_CWK.F90 index 2b9ed9853d..e39bf557e0 100644 --- a/src/ALE/Recon1d_EPPM_CWK.F90 +++ b/src/ALE/Recon1d_EPPM_CWK.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction in model index space with linear !! extrapolation for first and last cells !! @@ -6,8 +10,6 @@ !! representation with slope set by matching the edge of the first interior cell. module Recon1d_EPPM_CWK -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing use Recon1d_PPM_CWK, only : PPM_CWK diff --git a/src/ALE/Recon1d_MPLM_CWK.F90 b/src/ALE/Recon1d_MPLM_CWK.F90 index dc401a8440..87d623cf53 100644 --- a/src/ALE/Recon1d_MPLM_CWK.F90 +++ b/src/ALE/Recon1d_MPLM_CWK.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Linear Method 1D reconstruction in index space !! !! This implementation of PLM follows Colella and Woodward, 1984 \cite colella1984, except for assuming @@ -6,8 +10,6 @@ !! The first and last cells are always limited to PCM. module Recon1d_MPLM_CWK -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : testing use Recon1d_PLM_CWK, only : PLM_CWK diff --git a/src/ALE/Recon1d_MPLM_WA.F90 b/src/ALE/Recon1d_MPLM_WA.F90 index b9fa635063..29b54ccdeb 100644 --- a/src/ALE/Recon1d_MPLM_WA.F90 +++ b/src/ALE/Recon1d_MPLM_WA.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Monotonized Piecewise Linear Method 1D reconstruction !! !! This implementation of PLM follows White and Adcroft, 2008 \cite white2008. @@ -9,8 +13,6 @@ !! are referred to. module Recon1d_MPLM_WA -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_PLM_CW, only : PLM_CW, testing implicit none ; private diff --git a/src/ALE/Recon1d_MPLM_WA_poly.F90 b/src/ALE/Recon1d_MPLM_WA_poly.F90 index 4a4bdc95bb..333377f726 100644 --- a/src/ALE/Recon1d_MPLM_WA_poly.F90 +++ b/src/ALE/Recon1d_MPLM_WA_poly.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Monotonized Piecewise Linear Method 1D reconstruction using polynomial representation !! !! This implementation of PLM follows White and Adcroft, 2008 \cite white2008. @@ -9,8 +13,6 @@ !! not preferred but was the form used in OM4. module Recon1d_MPLM_WA_poly -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_MPLM_WA, only : MPLM_WA, testing implicit none ; private diff --git a/src/ALE/Recon1d_PCM.F90 b/src/ALE/Recon1d_PCM.F90 index 3b64844983..3225e25985 100644 --- a/src/ALE/Recon1d_PCM.F90 +++ b/src/ALE/Recon1d_PCM.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> 1D reconstructions using the Piecewise Constant Method (PCM) module Recon1d_PCM -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing implicit none ; private diff --git a/src/ALE/Recon1d_PLM_CW.F90 b/src/ALE/Recon1d_PLM_CW.F90 index 0c53246286..0e966d2e48 100644 --- a/src/ALE/Recon1d_PLM_CW.F90 +++ b/src/ALE/Recon1d_PLM_CW.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Linear Method 1D reconstruction !! !! This implementation of PLM follows Colella and Woodward, 1984 \cite colella1984, with cells @@ -7,8 +11,6 @@ !! This does not yield monotonic profiles for the general remapping problem. module Recon1d_PLM_CW -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing implicit none ; private diff --git a/src/ALE/Recon1d_PLM_CWK.F90 b/src/ALE/Recon1d_PLM_CWK.F90 index b30af80aa1..b5a6266f0e 100644 --- a/src/ALE/Recon1d_PLM_CWK.F90 +++ b/src/ALE/Recon1d_PLM_CWK.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Linear Method 1D reconstruction !! !! This implementation of PLM follows Colella and Woodward, 1984, except for assuming @@ -10,8 +14,6 @@ !! resulting calculations are properly bounded. module Recon1d_PLM_CWK -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : testing use Recon1d_PLM_CW, only : PLM_CW diff --git a/src/ALE/Recon1d_PLM_hybgen.F90 b/src/ALE/Recon1d_PLM_hybgen.F90 index 0cf2e8e001..aa33ce7443 100644 --- a/src/ALE/Recon1d_PLM_hybgen.F90 +++ b/src/ALE/Recon1d_PLM_hybgen.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Linear Method 1D reconstruction ported from "hybgen" module in Hycom. !! !! This implementation of PLM follows Colella and Woodward, 1984, with cells resorting to PCM for @@ -11,8 +15,6 @@ !! equiavalent to the recon1d_plm_hybgen module (this implementation). module Recon1d_PLM_hybgen -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing implicit none ; private diff --git a/src/ALE/Recon1d_PPM_CW.F90 b/src/ALE/Recon1d_PPM_CW.F90 index 9523ad46ea..27be489b7f 100644 --- a/src/ALE/Recon1d_PPM_CW.F90 +++ b/src/ALE/Recon1d_PPM_CW.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction following Colella and Woodward, 1984 !! !! This is a near faithful implementation of PPM following Colella and Woodward, 1984, with @@ -9,8 +13,6 @@ !! set to PCM. The reconstructions are grid-spacing dependent, and so quasi-forth order in h. module Recon1d_PPM_CW -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing use Recon1d_PLM_CW, only : PLM_CW diff --git a/src/ALE/Recon1d_PPM_CWK.F90 b/src/ALE/Recon1d_PPM_CWK.F90 index a0cbce5877..07256b4372 100644 --- a/src/ALE/Recon1d_PPM_CWK.F90 +++ b/src/ALE/Recon1d_PPM_CWK.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction in model index space !! !! This implementation of PPM follows Colella and Woodward, 1984, using uniform thickness @@ -10,8 +14,6 @@ !! when the grid spacing is variable. module Recon1d_PPM_CWK -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing use Recon1d_PLM_CWK, only : PLM_CWK diff --git a/src/ALE/Recon1d_PPM_H4_2018.F90 b/src/ALE/Recon1d_PPM_H4_2018.F90 index d668b70ace..401c95e504 100644 --- a/src/ALE/Recon1d_PPM_H4_2018.F90 +++ b/src/ALE/Recon1d_PPM_H4_2018.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction with h4 interpolation for edges (2018 version) !! !! This implementation of PPM follows White and Adcroft 2008 \cite white2008, with cells @@ -8,8 +12,6 @@ !! The first and last cells are always limited to PCM. module Recon1d_PPM_H4_2018 -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_PPM_H4_2019, only : PPM_H4_2019, testing use regrid_edge_values, only : bound_edge_values, check_discontinuous_edge_values use regrid_solvers, only : solve_linear_system diff --git a/src/ALE/Recon1d_PPM_H4_2019.F90 b/src/ALE/Recon1d_PPM_H4_2019.F90 index d01ff3fb2b..26985be644 100644 --- a/src/ALE/Recon1d_PPM_H4_2019.F90 +++ b/src/ALE/Recon1d_PPM_H4_2019.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction with h4 interpolation for edges !! !! This implementation of PPM follows White and Adcroft 2008 \cite white2008, with cells @@ -8,8 +12,6 @@ !! The first and last cells are always limited to PCM. module Recon1d_PPM_H4_2019 -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : Recon1d, testing implicit none ; private diff --git a/src/ALE/Recon1d_PPM_hybgen.F90 b/src/ALE/Recon1d_PPM_hybgen.F90 index 2978dd9269..72fc374be4 100644 --- a/src/ALE/Recon1d_PPM_hybgen.F90 +++ b/src/ALE/Recon1d_PPM_hybgen.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Piecewise Parabolic Method 1D reconstruction following Colella and Woodward, 1984 !! !! This implementation of PPM follows Colella and Woodward, 1984 \cite colella1984, with @@ -10,8 +14,6 @@ !! (reached with "PPM_CW"), are equivalent. Similarly recon1d_ppm_hybgen (this implementation) is equivalent also. module Recon1d_PPM_hybgen -! This file is part of MOM6. See LICENSE.md for the license. - use Recon1d_type, only : testing use Recon1d_PPM_CW, only : PPM_CW diff --git a/src/ALE/Recon1d_type.F90 b/src/ALE/Recon1d_type.F90 index 4411e1288e..a98eb80434 100644 --- a/src/ALE/Recon1d_type.F90 +++ b/src/ALE/Recon1d_type.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A generic type for vertical 1D reconstructions module Recon1d_type -! This file is part of MOM6. See LICENSE.md for the license. - use numerical_testing_type, only : testing implicit none ; private diff --git a/src/ALE/coord_adapt.F90 b/src/ALE/coord_adapt.F90 index 0e28ae0395..3b6a068f66 100644 --- a/src/ALE/coord_adapt.F90 +++ b/src/ALE/coord_adapt.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Regrid columns for the adaptive coordinate module coord_adapt -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS, only : calculate_density_derivs use MOM_error_handler, only : MOM_error, FATAL use MOM_unit_scaling, only : unit_scale_type diff --git a/src/ALE/coord_hycom.F90 b/src/ALE/coord_hycom.F90 index f5062d6f68..2036e61c1e 100644 --- a/src/ALE/coord_hycom.F90 +++ b/src/ALE/coord_hycom.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Regrid columns for the HyCOM coordinate module coord_hycom -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, is_root_pe, FATAL, NOTE use MOM_variables, only : ocean_grid_type, thermo_var_ptrs use MOM_EOS, only : EOS_type, calculate_density diff --git a/src/ALE/coord_rho.F90 b/src/ALE/coord_rho.F90 index c967687dc8..904517ef15 100644 --- a/src/ALE/coord_rho.F90 +++ b/src/ALE/coord_rho.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Regrid columns for the continuous isopycnal (rho) coordinate module coord_rho -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL use MOM_remapping, only : remapping_CS, remapping_core_h use MOM_EOS, only : EOS_type, calculate_density diff --git a/src/ALE/coord_sigma.F90 b/src/ALE/coord_sigma.F90 index a2a5820487..60e05654d9 100644 --- a/src/ALE/coord_sigma.F90 +++ b/src/ALE/coord_sigma.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Regrid columns for the sigma coordinate module coord_sigma -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL implicit none ; private diff --git a/src/ALE/coord_zlike.F90 b/src/ALE/coord_zlike.F90 index 7f284217b2..ad7772d7ae 100644 --- a/src/ALE/coord_zlike.F90 +++ b/src/ALE/coord_zlike.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Regrid columns for a z-like coordinate (z-star, z-level) module coord_zlike -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL implicit none ; private diff --git a/src/ALE/polynomial_functions.F90 b/src/ALE/polynomial_functions.F90 index b01e097b83..0b232dc359 100644 --- a/src/ALE/polynomial_functions.F90 +++ b/src/ALE/polynomial_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Polynomial functions module polynomial_functions -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public :: evaluation_polynomial, integration_polynomial, first_derivative_polynomial diff --git a/src/ALE/regrid_consts.F90 b/src/ALE/regrid_consts.F90 index 0c5ccf268f..b3ca485f0a 100644 --- a/src/ALE/regrid_consts.F90 +++ b/src/ALE/regrid_consts.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Contains constants for interpreting input parameters that control regridding. module regrid_consts -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL use MOM_string_functions, only : uppercase diff --git a/src/ALE/regrid_edge_values.F90 b/src/ALE/regrid_edge_values.F90 index 54cec45cba..f9a0bacd25 100644 --- a/src/ALE/regrid_edge_values.F90 +++ b/src/ALE/regrid_edge_values.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Edge value estimation for high-order reconstruction module regrid_edge_values -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL use regrid_solvers, only : solve_linear_system, linear_solver use regrid_solvers, only : solve_tridiagonal_system, solve_diag_dominant_tridiag diff --git a/src/ALE/regrid_interp.F90 b/src/ALE/regrid_interp.F90 index 6e0be9ebba..84b94684ea 100644 --- a/src/ALE/regrid_interp.F90 +++ b/src/ALE/regrid_interp.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Vertical interpolation for regridding module regrid_interp -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL use MOM_string_functions, only : uppercase diff --git a/src/ALE/regrid_solvers.F90 b/src/ALE/regrid_solvers.F90 index 6e5b3a0cb0..2ac2230ec4 100644 --- a/src/ALE/regrid_solvers.F90 +++ b/src/ALE/regrid_solvers.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Solvers of linear systems. module regrid_solvers -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL implicit none ; private diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index 5657bdbaf1..60834838fc 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The central module of the MOM6 ocean model module MOM -! This file is part of MOM6. See LICENSE.md for the license. - ! Infrastructure modules use MOM_array_transform, only : rotate_array, rotate_vector use MOM_debugging, only : MOM_debugging_init, hchksum, uvchksum, totalTandS diff --git a/src/core/MOM_CoriolisAdv.F90 b/src/core/MOM_CoriolisAdv.F90 index 5495164782..af85ae3889 100644 --- a/src/core/MOM_CoriolisAdv.F90 +++ b/src/core/MOM_CoriolisAdv.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Accelerations due to the Coriolis force and momentum advection module MOM_CoriolisAdv -! This file is part of MOM6. See LICENSE.md for the license. - !> \author Robert Hallberg, April 1994 - June 2002 use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl diff --git a/src/core/MOM_PressureForce.F90 b/src/core/MOM_PressureForce.F90 index 191ee439c9..133de90434 100644 --- a/src/core/MOM_PressureForce.F90 +++ b/src/core/MOM_PressureForce.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A thin wrapper for Boussinesq/non-Boussinesq forms of the pressure force calculation. module MOM_PressureForce -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, time_type use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/core/MOM_PressureForce_FV.F90 b/src/core/MOM_PressureForce_FV.F90 index 58b3a68a5d..b0e1934229 100644 --- a/src/core/MOM_PressureForce_FV.F90 +++ b/src/core/MOM_PressureForce_FV.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Finite volume pressure gradient (integrated by quadrature or analytically) module MOM_PressureForce_FV -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, uvchksum use MOM_diag_mediator, only : post_data, register_diag_field use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl, time_type diff --git a/src/core/MOM_PressureForce_Montgomery.F90 b/src/core/MOM_PressureForce_Montgomery.F90 index 1529af9d83..19aa7b2aaa 100644 --- a/src/core/MOM_PressureForce_Montgomery.F90 +++ b/src/core/MOM_PressureForce_Montgomery.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides the Montgomery potential form of pressure gradient module MOM_PressureForce_Mont -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_density_integrals, only : int_specific_vol_dp use MOM_diag_mediator, only : post_data, register_diag_field use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl, time_type diff --git a/src/core/MOM_barotropic.F90 b/src/core/MOM_barotropic.F90 index ac2e668f8e..3cc0dd560b 100644 --- a/src/core/MOM_barotropic.F90 +++ b/src/core/MOM_barotropic.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Barotropic solver module MOM_barotropic -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_checksums, only : chksum0 use MOM_coms, only : any_across_PEs use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE diff --git a/src/core/MOM_boundary_update.F90 b/src/core/MOM_boundary_update.F90 index 8d8c4e1f5f..9caf549de7 100644 --- a/src/core/MOM_boundary_update.F90 +++ b/src/core/MOM_boundary_update.F90 @@ -1,9 +1,10 @@ -! This file is part of MOM6. See LICENSE.md for the license. +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Controls where open boundary conditions are applied module MOM_boundary_update -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_diag_mediator, only : time_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING diff --git a/src/core/MOM_check_scaling.F90 b/src/core/MOM_check_scaling.F90 index 2841514924..d04a6b3934 100644 --- a/src/core/MOM_check_scaling.F90 +++ b/src/core/MOM_check_scaling.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module is used to check the dimensional scaling factors used by the MOM6 ocean model module MOM_check_scaling -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, assert, MOM_get_verbosity use MOM_unique_scales, only : check_scaling_uniqueness, scales_to_powers use MOM_unit_scaling, only : unit_scale_type diff --git a/src/core/MOM_checksum_packages.F90 b/src/core/MOM_checksum_packages.F90 index c226f5309d..ecb8f7edb3 100644 --- a/src/core/MOM_checksum_packages.F90 +++ b/src/core/MOM_checksum_packages.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides routines that do checksums of groups of MOM variables module MOM_checksum_packages -! This file is part of MOM6. See LICENSE.md for the license. - ! This module provides several routines that do check-sums of groups ! of variables in the various dynamic solver routines. diff --git a/src/core/MOM_continuity.F90 b/src/core/MOM_continuity.F90 index 14582d1eb5..27d69fc3d8 100644 --- a/src/core/MOM_continuity.F90 +++ b/src/core/MOM_continuity.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Solve the layer continuity equation. module MOM_continuity -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_continuity_PPM, only : continuity=>continuity_PPM use MOM_continuity_PPM, only : continuity_stencil=>continuity_PPM_stencil use MOM_continuity_PPM, only : continuity_init=>continuity_PPM_init diff --git a/src/core/MOM_continuity_PPM.F90 b/src/core/MOM_continuity_PPM.F90 index d5e380391c..bbfe1cc75d 100644 --- a/src/core/MOM_continuity_PPM.F90 +++ b/src/core/MOM_continuity_PPM.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Solve the layer continuity equation using the PPM method for layer fluxes. module MOM_continuity_PPM -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_diag_mediator, only : time_type, diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/core/MOM_density_integrals.F90 b/src/core/MOM_density_integrals.F90 index 2638718594..19cad281e8 100644 --- a/src/core/MOM_density_integrals.F90 +++ b/src/core/MOM_density_integrals.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides integrals of density module MOM_density_integrals -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS, only : EOS_type use MOM_EOS, only : EOS_quadrature, EOS_domain use MOM_EOS, only : analytic_int_density_dz diff --git a/src/core/MOM_dynamics_split_RK2.F90 b/src/core/MOM_dynamics_split_RK2.F90 index 2f345ff9e9..8588a0c41e 100644 --- a/src/core/MOM_dynamics_split_RK2.F90 +++ b/src/core/MOM_dynamics_split_RK2.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Time step the adiabatic dynamic core of MOM using RK2 method. module MOM_dynamics_split_RK2 -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_variables, only : vertvisc_type, thermo_var_ptrs, porous_barrier_type use MOM_variables, only : BT_cont_type, alloc_bt_cont_type, dealloc_bt_cont_type use MOM_variables, only : accel_diag_ptrs, ocean_internal_state, cont_diag_ptrs diff --git a/src/core/MOM_dynamics_split_RK2b.F90 b/src/core/MOM_dynamics_split_RK2b.F90 index 9835c0c02e..dcdfd9b834 100644 --- a/src/core/MOM_dynamics_split_RK2b.F90 +++ b/src/core/MOM_dynamics_split_RK2b.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Time step the adiabatic dynamic core of MOM using RK2 method with greater use of the !! time-filtered velocities and less inheritance of tedencies from the previous step in the !! predictor step than in the original MOM_dyanmics_split_RK2. module MOM_dynamics_split_RK2b -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_variables, only : vertvisc_type, thermo_var_ptrs, porous_barrier_type use MOM_variables, only : BT_cont_type, alloc_bt_cont_type, dealloc_bt_cont_type use MOM_variables, only : accel_diag_ptrs, ocean_internal_state, cont_diag_ptrs diff --git a/src/core/MOM_dynamics_unsplit.F90 b/src/core/MOM_dynamics_unsplit.F90 index 71ffac8fec..c560ba07a8 100644 --- a/src/core/MOM_dynamics_unsplit.F90 +++ b/src/core/MOM_dynamics_unsplit.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Time steps the ocean dynamics with an unsplit quasi 3rd order scheme module MOM_dynamics_unsplit -! This file is part of MOM6. See LICENSE.md for the license. - !********+*********+*********+*********+*********+*********+*********+** !* * !* By Robert Hallberg, 1993-2012 * diff --git a/src/core/MOM_dynamics_unsplit_RK2.F90 b/src/core/MOM_dynamics_unsplit_RK2.F90 index 66c58439b3..0f2274c445 100644 --- a/src/core/MOM_dynamics_unsplit_RK2.F90 +++ b/src/core/MOM_dynamics_unsplit_RK2.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Time steps the ocean dynamics with an unsplit quasi 2nd order Runge-Kutta scheme module MOM_dynamics_unsplit_RK2 -! This file is part of MOM6. See LICENSE.md for the license. - !********+*********+*********+*********+*********+*********+*********+** !* * !* By Alistair Adcroft and Robert Hallberg, 2010-2012 * diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index 1ceaa3988f..2059e8eb8f 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module implements boundary forcing for MOM6. module MOM_forcing_type -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_vector, rotate_array_pair use MOM_coupler_types, only : coupler_2d_bc_type, coupler_type_destructor use MOM_coupler_types, only : coupler_type_increment_data, coupler_type_initialized diff --git a/src/core/MOM_grid.F90 b/src/core/MOM_grid.F90 index 94583673c2..eb6e0eeeee 100644 --- a/src/core/MOM_grid.F90 +++ b/src/core/MOM_grid.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides the ocean grid type module MOM_grid -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_hor_index, only : hor_index_type, hor_index_init use MOM_domains, only : MOM_domain_type, get_domain_extent, compute_block_extent use MOM_domains, only : get_global_shape, deallocate_MOM_domain diff --git a/src/core/MOM_interface_heights.F90 b/src/core/MOM_interface_heights.F90 index c9e4bc015e..6da95df2c9 100644 --- a/src/core/MOM_interface_heights.F90 +++ b/src/core/MOM_interface_heights.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Functions for calculating interface heights, including free surface height. module MOM_interface_heights -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_density_integrals, only : int_specific_vol_dp, avg_specific_vol, int_density_dz use MOM_debugging, only : hchksum use MOM_error_handler, only : MOM_error, FATAL diff --git a/src/core/MOM_isopycnal_slopes.F90 b/src/core/MOM_isopycnal_slopes.F90 index 372ed8701d..1dd1d92bf2 100644 --- a/src/core/MOM_isopycnal_slopes.F90 +++ b/src/core/MOM_isopycnal_slopes.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculations of isoneutral slopes and stratification. module MOM_isopycnal_slopes -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, uvchksum use MOM_error_handler, only : MOM_error, FATAL use MOM_grid, only : ocean_grid_type diff --git a/src/core/MOM_open_boundary.F90 b/src/core/MOM_open_boundary.F90 index 2ebbce6475..aa309fd56a 100644 --- a/src/core/MOM_open_boundary.F90 +++ b/src/core/MOM_open_boundary.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Controls where open boundary conditions are applied module MOM_open_boundary -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_array_pair use MOM_coms, only : sum_across_PEs, Set_PElist, Get_PElist, PE_here, num_PEs use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE diff --git a/src/core/MOM_porous_barriers.F90 b/src/core/MOM_porous_barriers.F90 index e24d4954cb..53f8ea406b 100644 --- a/src/core/MOM_porous_barriers.F90 +++ b/src/core/MOM_porous_barriers.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Module for calculating curve fit for porous topography. !written by sjd module MOM_porous_barriers -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_MODULE use MOM_error_handler, only : MOM_error, FATAL use MOM_grid, only : ocean_grid_type diff --git a/src/core/MOM_stoch_eos.F90 b/src/core/MOM_stoch_eos.F90 index 8db35c72e7..b312cc3a39 100644 --- a/src/core/MOM_stoch_eos.F90 +++ b/src/core/MOM_stoch_eos.F90 @@ -1,7 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides the ocean stochastic equation of state module MOM_stoch_eos -! This file is part of MOM6. See LICENSE.md for the license. use MOM_diag_mediator, only : register_diag_field, post_data, diag_ctrl use MOM_error_handler, only : MOM_error, FATAL use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/core/MOM_transcribe_grid.F90 b/src/core/MOM_transcribe_grid.F90 index d9ca19985f..f227cfc5a5 100644 --- a/src/core/MOM_transcribe_grid.F90 +++ b/src/core/MOM_transcribe_grid.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Module with routines for copying information from a shared dynamic horizontal !! grid to an ocean-specific horizontal grid and the reverse. module MOM_transcribe_grid -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_array_pair use MOM_domains, only : pass_var, pass_vector use MOM_domains, only : To_All, SCALAR_PAIR, CGRID_NE, AGRID, BGRID_NE, CORNER diff --git a/src/core/MOM_unit_tests.F90 b/src/core/MOM_unit_tests.F90 index bd449d0b39..e47242711a 100644 --- a/src/core/MOM_unit_tests.F90 +++ b/src/core/MOM_unit_tests.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Invokes unit tests in all modules that have them module MOM_unit_tests -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL, is_root_pe use MOM_hor_bnd_diffusion, only : near_boundary_unit_tests use MOM_intrinsic_functions, only : intrinsic_functions_unit_tests diff --git a/src/core/MOM_variables.F90 b/src/core/MOM_variables.F90 index 9e727b34bc..c43f71481e 100644 --- a/src/core/MOM_variables.F90 +++ b/src/core/MOM_variables.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides transparent structures with groups of MOM6 variables and supporting routines module MOM_variables -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_vector use MOM_coupler_types, only : coupler_1d_bc_type, coupler_2d_bc_type use MOM_coupler_types, only : coupler_type_spawn, coupler_type_destructor, coupler_type_initialized diff --git a/src/core/MOM_verticalGrid.F90 b/src/core/MOM_verticalGrid.F90 index 4713fb6797..a4b3dbbffb 100644 --- a/src/core/MOM_verticalGrid.F90 +++ b/src/core/MOM_verticalGrid.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a transparent vertical ocean grid type and supporting routines module MOM_verticalGrid -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL use MOM_file_parser, only : get_param, log_param, log_version, param_file_type use MOM_unit_scaling, only : unit_scale_type diff --git a/src/diagnostics/MOM_PointAccel.F90 b/src/diagnostics/MOM_PointAccel.F90 index 9b09e3d6af..b1db788b90 100644 --- a/src/diagnostics/MOM_PointAccel.F90 +++ b/src/diagnostics/MOM_PointAccel.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Debug accelerations at a given point !! !! The two subroutines in this file write out all of the terms @@ -7,8 +11,6 @@ !! often this is done for debugging purposes. module MOM_PointAccel -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl use MOM_domains, only : pe_here use MOM_error_handler, only : MOM_error, NOTE diff --git a/src/diagnostics/MOM_debugging.F90 b/src/diagnostics/MOM_debugging.F90 index 5e3ee191d5..a8ded110f0 100644 --- a/src/diagnostics/MOM_debugging.F90 +++ b/src/diagnostics/MOM_debugging.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides checksumming functions for debugging !! !! This module contains subroutines that perform various error checking and @@ -6,8 +10,6 @@ !! separate we retain the ability to set up MOM6 and SIS2 debugging separately. module MOM_debugging -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_checksums, only : hchksum, Bchksum, qchksum, uvchksum, hchksum_pair use MOM_checksums, only : is_NaN, chksum, MOM_checksums_init use MOM_coms, only : PE_here, root_PE, num_PEs diff --git a/src/diagnostics/MOM_diagnose_KdWork.F90 b/src/diagnostics/MOM_diagnose_KdWork.F90 index 8b89933169..999002b5d1 100644 --- a/src/diagnostics/MOM_diagnose_KdWork.F90 +++ b/src/diagnostics/MOM_diagnose_KdWork.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides diagnostics of work due to a given diffusivity module MOM_diagnose_kdwork -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, time_type, post_data, register_diag_field use MOM_diag_mediator, only : register_scalar_field use MOM_error_handler, only : MOM_error, FATAL, WARNING diff --git a/src/diagnostics/MOM_diagnose_MLD.F90 b/src/diagnostics/MOM_diagnose_MLD.F90 index e7c08b6d95..b24714ba69 100644 --- a/src/diagnostics/MOM_diagnose_MLD.F90 +++ b/src/diagnostics/MOM_diagnose_MLD.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides functions for some diabatic processes such as fraxil, brine rejection, !! tendency due to surface flux divergence. module MOM_diagnose_mld -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data use MOM_diag_mediator, only : diag_ctrl use MOM_EOS, only : calculate_density, calculate_TFreeze, EOS_domain diff --git a/src/diagnostics/MOM_diagnostics.F90 b/src/diagnostics/MOM_diagnostics.F90 index 6c220c79cf..8bb85762bb 100644 --- a/src/diagnostics/MOM_diagnostics.F90 +++ b/src/diagnostics/MOM_diagnostics.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates any requested diagnostic quantities !! that are not calculated in the various subroutines. !! Diagnostic quantities are requested by allocating them memory. module MOM_diagnostics -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : reproducing_sum use MOM_coupler_types, only : coupler_type_send_data use MOM_density_integrals, only : int_density_dz diff --git a/src/diagnostics/MOM_harmonic_analysis.F90 b/src/diagnostics/MOM_harmonic_analysis.F90 index 9a15867631..1ff0b4bacc 100644 --- a/src/diagnostics/MOM_harmonic_analysis.F90 +++ b/src/diagnostics/MOM_harmonic_analysis.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Inline harmonic analysis (conventional) module MOM_harmonic_analysis diff --git a/src/diagnostics/MOM_obsolete_diagnostics.F90 b/src/diagnostics/MOM_obsolete_diagnostics.F90 index ddfe0452a0..642f10f74e 100644 --- a/src/diagnostics/MOM_obsolete_diagnostics.F90 +++ b/src/diagnostics/MOM_obsolete_diagnostics.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a mechanism for recording diagnostic variables that are no longer !! valid, along with their replacement name if appropriate. module MOM_obsolete_diagnostics -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, found_in_diagtable use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : param_file_type, log_version, get_param diff --git a/src/diagnostics/MOM_obsolete_params.F90 b/src/diagnostics/MOM_obsolete_params.F90 index bfb621c95c..012fcff931 100644 --- a/src/diagnostics/MOM_obsolete_params.F90 +++ b/src/diagnostics/MOM_obsolete_params.F90 @@ -1,7 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Methods for testing for, and list of, obsolete run-time parameters. module MOM_obsolete_params -! This file is part of MOM6. See LICENSE.md for the license. ! This module was first conceived and written by Robert Hallberg, July 2010. use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/diagnostics/MOM_spatial_means.F90 b/src/diagnostics/MOM_spatial_means.F90 index bc0b05b477..1d63334a23 100644 --- a/src/diagnostics/MOM_spatial_means.F90 +++ b/src/diagnostics/MOM_spatial_means.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Functions and routines to take area, volume, mass-weighted, layerwise, zonal or meridional means module MOM_spatial_means -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type, operator(+), operator(-), assignment(=) use MOM_coms, only : EFP_to_real, real_to_EFP, EFP_sum_across_PEs use MOM_coms, only : reproducing_sum, reproducing_sum_EFP, EFP_to_real diff --git a/src/diagnostics/MOM_sum_output.F90 b/src/diagnostics/MOM_sum_output.F90 index 40e58808fb..9f37965874 100644 --- a/src/diagnostics/MOM_sum_output.F90 +++ b/src/diagnostics/MOM_sum_output.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Reports integrated quantities for monitoring the model state module MOM_sum_output -! This file is part of MOM6. See LICENSE.md for the license. - use iso_fortran_env, only : int64 use MOM_checksums, only : is_NaN, field_checksum use MOM_coms, only : sum_across_PEs, PE_here, root_PE, num_PEs, max_across_PEs diff --git a/src/diagnostics/MOM_wave_speed.F90 b/src/diagnostics/MOM_wave_speed.F90 index 7abdab0a90..f6a884004f 100644 --- a/src/diagnostics/MOM_wave_speed.F90 +++ b/src/diagnostics/MOM_wave_speed.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines for calculating baroclinic wave speeds module MOM_wave_speed -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING use MOM_file_parser, only : log_version diff --git a/src/equation_of_state/MOM_EOS.F90 b/src/equation_of_state/MOM_EOS.F90 index ee49bd282d..e716d9221f 100644 --- a/src/equation_of_state/MOM_EOS.F90 +++ b/src/equation_of_state/MOM_EOS.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides subroutines for quantities specific to the equation of state module MOM_EOS -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base use MOM_EOS_linear, only : linear_EOS, avg_spec_vol_linear use MOM_EOS_linear, only : int_density_dz_linear, int_spec_vol_dp_linear diff --git a/src/equation_of_state/MOM_EOS_Jackett06.F90 b/src/equation_of_state/MOM_EOS_Jackett06.F90 index 1ef7456e96..4c0705f717 100644 --- a/src/equation_of_state/MOM_EOS_Jackett06.F90 +++ b/src/equation_of_state/MOM_EOS_Jackett06.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the Jackett et al 2006 expressions that are often used in Hycom module MOM_EOS_Jackett06 -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base implicit none ; private diff --git a/src/equation_of_state/MOM_EOS_Roquet_SpV.F90 b/src/equation_of_state/MOM_EOS_Roquet_SpV.F90 index 205b6e2b55..852f62fb73 100644 --- a/src/equation_of_state/MOM_EOS_Roquet_SpV.F90 +++ b/src/equation_of_state/MOM_EOS_Roquet_SpV.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state for specific volume (SpV) using the expressions of Roquet et al. 2015 module MOM_EOS_Roquet_Spv -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base implicit none ; private diff --git a/src/equation_of_state/MOM_EOS_Roquet_rho.F90 b/src/equation_of_state/MOM_EOS_Roquet_rho.F90 index 1a5cc7b49c..1e80c63c5a 100644 --- a/src/equation_of_state/MOM_EOS_Roquet_rho.F90 +++ b/src/equation_of_state/MOM_EOS_Roquet_rho.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the expressions of Roquet et al. (2015) that are used in NEMO module MOM_EOS_Roquet_rho -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base implicit none ; private diff --git a/src/equation_of_state/MOM_EOS_TEOS10.F90 b/src/equation_of_state/MOM_EOS_TEOS10.F90 index b65e887694..9f63dd9b3b 100644 --- a/src/equation_of_state/MOM_EOS_TEOS10.F90 +++ b/src/equation_of_state/MOM_EOS_TEOS10.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the TEOS10 expressions module MOM_EOS_TEOS10 -! This file is part of MOM6. See LICENSE.md for the license. - use gsw_mod_toolbox, only : gsw_sp_from_sr, gsw_pt_from_ct, gsw_sr_from_sp, gsw_ct_from_pt use gsw_mod_toolbox, only : gsw_rho, gsw_specvol use gsw_mod_toolbox, only : gsw_rho_first_derivatives, gsw_specvol_first_derivatives diff --git a/src/equation_of_state/MOM_EOS_UNESCO.F90 b/src/equation_of_state/MOM_EOS_UNESCO.F90 index 6051c0fb0a..93ac54d0ac 100644 --- a/src/equation_of_state/MOM_EOS_UNESCO.F90 +++ b/src/equation_of_state/MOM_EOS_UNESCO.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the Jackett and McDougall fits to the UNESCO EOS module MOM_EOS_UNESCO -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base implicit none ; private diff --git a/src/equation_of_state/MOM_EOS_Wright.F90 b/src/equation_of_state/MOM_EOS_Wright.F90 index 874d3e784e..89dbe9630b 100644 --- a/src/equation_of_state/MOM_EOS_Wright.F90 +++ b/src/equation_of_state/MOM_EOS_Wright.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using a poor implementation (missing parenthesis and bugs) of the !! reduced range Wright 1997 expressions module MOM_EOS_Wright -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base use MOM_hor_index, only : hor_index_type diff --git a/src/equation_of_state/MOM_EOS_Wright_full.F90 b/src/equation_of_state/MOM_EOS_Wright_full.F90 index 4be5f2940e..ec910e8233 100644 --- a/src/equation_of_state/MOM_EOS_Wright_full.F90 +++ b/src/equation_of_state/MOM_EOS_Wright_full.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the Wright 1997 expressions with full range of data. module MOM_EOS_Wright_full -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base use MOM_hor_index, only : hor_index_type diff --git a/src/equation_of_state/MOM_EOS_Wright_red.F90 b/src/equation_of_state/MOM_EOS_Wright_red.F90 index 1635f9e809..5a2898ae49 100644 --- a/src/equation_of_state/MOM_EOS_Wright_red.F90 +++ b/src/equation_of_state/MOM_EOS_Wright_red.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The equation of state using the Wright 1997 expressions with reduced range of data. module MOM_EOS_Wright_red -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base use MOM_hor_index, only : hor_index_type diff --git a/src/equation_of_state/MOM_EOS_base_type.F90 b/src/equation_of_state/MOM_EOS_base_type.F90 index a6e5a21309..5728dfa2f2 100644 --- a/src/equation_of_state/MOM_EOS_base_type.F90 +++ b/src/equation_of_state/MOM_EOS_base_type.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A generic type for equations of state module MOM_EOS_base_type -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public EOS_base diff --git a/src/equation_of_state/MOM_EOS_linear.F90 b/src/equation_of_state/MOM_EOS_linear.F90 index 7737004ea7..28d3ba68a0 100644 --- a/src/equation_of_state/MOM_EOS_linear.F90 +++ b/src/equation_of_state/MOM_EOS_linear.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A simple linear equation of state for sea water with constant coefficients module MOM_EOS_linear -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_EOS_base_type, only : EOS_base use MOM_hor_index, only : hor_index_type diff --git a/src/equation_of_state/MOM_TFreeze.F90 b/src/equation_of_state/MOM_TFreeze.F90 index faa103d094..d55fd0a2b0 100644 --- a/src/equation_of_state/MOM_TFreeze.F90 +++ b/src/equation_of_state/MOM_TFreeze.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Freezing point expressions module MOM_TFreeze -! This file is part of MOM6. See LICENSE.md for the license. - !********+*********+*********+*********+*********+*********+*********+** !* The subroutines in this file determine the potential temperature * !* or conservative temperature at which sea-water freezes. * diff --git a/src/equation_of_state/MOM_temperature_convert.F90 b/src/equation_of_state/MOM_temperature_convert.F90 index ee4bc21e62..e1cc3b899d 100644 --- a/src/equation_of_state/MOM_temperature_convert.F90 +++ b/src/equation_of_state/MOM_temperature_convert.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Functions to convert between conservative and potential temperature module MOM_temperature_convert -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public poTemp_to_consTemp, consTemp_to_poTemp diff --git a/src/framework/MOM_ANN.F90 b/src/framework/MOM_ANN.F90 index 4e921ccd48..e14ca23747 100644 --- a/src/framework/MOM_ANN.F90 +++ b/src/framework/MOM_ANN.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements the general purpose Artificial Neural Network (ANN). module MOM_ANN diff --git a/src/framework/MOM_array_transform.F90 b/src/framework/MOM_array_transform.F90 index 66c9925f11..30aeadcdf1 100644 --- a/src/framework/MOM_array_transform.F90 +++ b/src/framework/MOM_array_transform.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Module for supporting the rotation of a field's index map. !! The implementation of each angle is described below. !! diff --git a/src/framework/MOM_checksums.F90 b/src/framework/MOM_checksums.F90 index 9177eb8965..4683dabfac 100644 --- a/src/framework/MOM_checksums.F90 +++ b/src/framework/MOM_checksums.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines to calculate checksums of various array and vector types module MOM_checksums -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_array_pair, rotate_vector use MOM_array_transform, only : allocate_rotated_array use MOM_coms, only : PE_here, root_PE, num_PEs, sum_across_PEs diff --git a/src/framework/MOM_coms.F90 b/src/framework/MOM_coms.F90 index be9c9d9586..97b93d8bfe 100644 --- a/src/framework/MOM_coms.F90 +++ b/src/framework/MOM_coms.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interfaces to non-domain-oriented communication subroutines, including the !! MOM6 reproducing sums facility module MOM_coms -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : int64 use MOM_coms_infra, only : PE_here, root_PE, num_PEs, set_rootPE, Set_PElist, Get_PElist use MOM_coms_infra, only : broadcast, field_chksum, MOM_infra_init, MOM_infra_end diff --git a/src/framework/MOM_coupler_types.F90 b/src/framework/MOM_coupler_types.F90 index 25a2937aaa..cc8b2427da 100644 --- a/src/framework/MOM_coupler_types.F90 +++ b/src/framework/MOM_coupler_types.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module provides coupler type interfaces for use by MOM6 module MOM_coupler_types -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : allocate_rotated_array, rotate_array use MOM_couplertype_infra, only : CT_spawn, CT_initialized, CT_destructor, atmos_ocn_coupler_flux use MOM_couplertype_infra, only : CT_set_diags, CT_send_data, CT_write_chksums, CT_data_override diff --git a/src/framework/MOM_cpu_clock.F90 b/src/framework/MOM_cpu_clock.F90 index f4e605a06c..91d1c2085a 100644 --- a/src/framework/MOM_cpu_clock.F90 +++ b/src/framework/MOM_cpu_clock.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides cpu clock functions module MOM_cpu_clock -! This file is part of MOM6. See LICENSE.md for the license. - ! These interfaces and constants from MPP/FMS will not be directly exposed outside of this module use MOM_cpu_clock_infra, only : cpu_clock_begin use MOM_cpu_clock_infra, only : cpu_clock_end diff --git a/src/framework/MOM_data_override.F90 b/src/framework/MOM_data_override.F90 index 39841913e1..1ff145c0d7 100644 --- a/src/framework/MOM_data_override.F90 +++ b/src/framework/MOM_data_override.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> These interfaces allow for ocean or sea-ice variables to be replaced with data. module MOM_data_override -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_data_override_infra, only : data_override_init => impose_data_init use MOM_data_override_infra, only : data_override => impose_data use MOM_data_override_infra, only : data_override_unset_domains => impose_data_unset_domains diff --git a/src/framework/MOM_diag_mediator.F90 b/src/framework/MOM_diag_mediator.F90 index 58b7d39a4c..a464137aa1 100644 --- a/src/framework/MOM_diag_mediator.F90 +++ b/src/framework/MOM_diag_mediator.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The subroutines here provide convenient wrappers to the fms diag_manager !! interfaces with additional diagnostic capabilies. module MOM_diag_mediator -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_checksums, only : chksum0, zchksum use MOM_checksums, only : hchksum, uchksum, vchksum, Bchksum use MOM_coms, only : PE_here diff --git a/src/framework/MOM_diag_remap.F90 b/src/framework/MOM_diag_remap.F90 index 8fa523924c..c63e50ef9b 100644 --- a/src/framework/MOM_diag_remap.F90 +++ b/src/framework/MOM_diag_remap.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> provides runtime remapping of diagnostics to z star, sigma and !! rho vertical coordinates. !! @@ -27,8 +31,6 @@ module MOM_diag_remap -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : reproducing_sum_EFP, EFP_to_real use MOM_coms, only : EFP_type, assignment(=), EFP_sum_across_PEs use MOM_error_handler, only : MOM_error, FATAL, assert, WARNING diff --git a/src/framework/MOM_document.F90 b/src/framework/MOM_document.F90 index d999e1e680..ef7d22596a 100644 --- a/src/framework/MOM_document.F90 +++ b/src/framework/MOM_document.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The subroutines here provide hooks for document generation functions at !! various levels of granularity. module MOM_document -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_time_manager, only : time_type, operator(==), get_time, get_ticks_per_second use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/framework/MOM_domains.F90 b/src/framework/MOM_domains.F90 index 194d9f10c5..859072c9d6 100644 --- a/src/framework/MOM_domains.F90 +++ b/src/framework/MOM_domains.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Describes the decomposed MOM domain and has routines for communications across PEs module MOM_domains -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms_infra, only : MOM_infra_init, MOM_infra_end use MOM_coms_infra, only : PE_here, root_PE, num_PEs, broadcast use MOM_coms_infra, only : sum_across_PEs, min_across_PEs, max_across_PEs diff --git a/src/framework/MOM_dyn_horgrid.F90 b/src/framework/MOM_dyn_horgrid.F90 index 2e183cdbef..edbf022fe7 100644 --- a/src/framework/MOM_dyn_horgrid.F90 +++ b/src/framework/MOM_dyn_horgrid.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Contains a shareable dynamic type for describing horizontal grids and metric data !! and utilty routines that work on this type. module MOM_dyn_horgrid -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : rotate_array, rotate_array_pair use MOM_domains, only : MOM_domain_type, deallocate_MOM_domain use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING diff --git a/src/framework/MOM_ensemble_manager.F90 b/src/framework/MOM_ensemble_manager.F90 index e431212524..62fb32a9dd 100644 --- a/src/framework/MOM_ensemble_manager.F90 +++ b/src/framework/MOM_ensemble_manager.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Manages ensemble member layout information module MOM_ensemble_manager -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ensemble_manager_infra, only : ensemble_manager_init use MOM_ensemble_manager_infra, only : ensemble_pelist_setup use MOM_ensemble_manager_infra, only : get_ensemble_id diff --git a/src/framework/MOM_error_handler.F90 b/src/framework/MOM_error_handler.F90 index b113050572..eb097b32f0 100644 --- a/src/framework/MOM_error_handler.F90 +++ b/src/framework/MOM_error_handler.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines for error handling and I/O management module MOM_error_handler -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms_infra, only : num_PEs use MOM_error_infra, only : MOM_err, is_root_pe, stdlog, stdout, NOTE, WARNING, FATAL use posix, only : getpid, getppid, handler_interface diff --git a/src/framework/MOM_file_parser.F90 b/src/framework/MOM_file_parser.F90 index 291d44492d..1504fc67d5 100644 --- a/src/framework/MOM_file_parser.F90 +++ b/src/framework/MOM_file_parser.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The MOM6 facility to parse input files for runtime parameters module MOM_file_parser -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : root_PE, broadcast use MOM_coms, only : any_across_PEs use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg, assert diff --git a/src/framework/MOM_get_input.F90 b/src/framework/MOM_get_input.F90 index 6ecc3ef3f9..8000558b06 100644 --- a/src/framework/MOM_get_input.F90 +++ b/src/framework/MOM_get_input.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> \brief Reads the only Fortran name list needed to boot-strap the model. !! !! The name list parameters indicate which directories to use for @@ -5,8 +9,6 @@ !! the full parsable input parameter file(s). module MOM_get_input -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : open_param_file, param_file_type use MOM_io, only : file_exists, close_file, slasher, ensembler diff --git a/src/framework/MOM_hor_index.F90 b/src/framework/MOM_hor_index.F90 index 2ce2808692..efd8731d0d 100644 --- a/src/framework/MOM_hor_index.F90 +++ b/src/framework/MOM_hor_index.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Defines the horizontal index type (hor_index_type) used for providing index ranges module MOM_hor_index -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : MOM_domain_type, get_domain_extent, get_global_shape use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL use MOM_file_parser, only : get_param, log_param, log_version, param_file_type diff --git a/src/framework/MOM_horizontal_regridding.F90 b/src/framework/MOM_horizontal_regridding.F90 index 3b296e8b65..4af288ae1d 100644 --- a/src/framework/MOM_horizontal_regridding.F90 +++ b/src/framework/MOM_horizontal_regridding.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Horizontal interpolation module MOM_horizontal_regridding -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum use MOM_coms, only : max_across_PEs, min_across_PEs, sum_across_PEs, broadcast use MOM_coms, only : reproducing_sum diff --git a/src/framework/MOM_interpolate.F90 b/src/framework/MOM_interpolate.F90 index 5a830fb028..074b00c3a8 100644 --- a/src/framework/MOM_interpolate.F90 +++ b/src/framework/MOM_interpolate.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module provides added functionality to the FMS temporal and spatial interpolation routines module MOM_interpolate -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : allocate_rotated_array, rotate_array use MOM_error_handler, only : MOM_error, FATAL use MOM_interp_infra, only : time_interp_extern, init_external_field=>init_extern_field diff --git a/src/framework/MOM_intrinsic_functions.F90 b/src/framework/MOM_intrinsic_functions.F90 index fdafa8503d..a66e007a7b 100644 --- a/src/framework/MOM_intrinsic_functions.F90 +++ b/src/framework/MOM_intrinsic_functions.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A module with intrinsic functions that are used by MOM but are not supported !! by some compilers. module MOM_intrinsic_functions -! This file is part of MOM6. See LICENSE.md for the license. - use iso_fortran_env, only : stdout => output_unit, stderr => error_unit use iso_fortran_env, only : int64, real64 diff --git a/src/framework/MOM_io.F90 b/src/framework/MOM_io.F90 index 6c2b469f9d..a2632c7562 100644 --- a/src/framework/MOM_io.F90 +++ b/src/framework/MOM_io.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains I/O framework code module MOM_io -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_array_transform, only : allocate_rotated_array, rotate_array use MOM_array_transform, only : rotate_array_pair, rotate_vector use MOM_domains, only : MOM_domain_type, domain1D, broadcast, get_domain_components diff --git a/src/framework/MOM_io_file.F90 b/src/framework/MOM_io_file.F90 index 682f967099..9da83fd338 100644 --- a/src/framework/MOM_io_file.F90 +++ b/src/framework/MOM_io_file.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the MOM file handler types module MOM_io_file -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : int64 use MOM_domains, only : MOM_domain_type, domain1D diff --git a/src/framework/MOM_memory_macros.h b/src/framework/MOM_memory_macros.h index 6ac3e7566b..4919fe4123 100644 --- a/src/framework/MOM_memory_macros.h +++ b/src/framework/MOM_memory_macros.h @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !//! \brief Memory macros !//! \details This is a header file to define macros for static and dynamic memory allocation. !//! Define STATIC_MEMORY_ in MOM_memory.h for static memory allocation. diff --git a/src/framework/MOM_murmur_hash.F90 b/src/framework/MOM_murmur_hash.F90 index 16283f61e3..1016fa0ee4 100644 --- a/src/framework/MOM_murmur_hash.F90 +++ b/src/framework/MOM_murmur_hash.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> MurmurHash is a non-cryptographic hash function developed by Austin Appleby. !! !! This module provides an implementation of the 32-bit MurmurHash3 algorithm. diff --git a/src/framework/MOM_netcdf.F90 b/src/framework/MOM_netcdf.F90 index 4a7a61ec1c..66ec1e194c 100644 --- a/src/framework/MOM_netcdf.F90 +++ b/src/framework/MOM_netcdf.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> MOM6 interface to netCDF operations module MOM_netcdf -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : real32, real64 use netcdf, only : nf90_create, nf90_open, nf90_close diff --git a/src/framework/MOM_random.F90 b/src/framework/MOM_random.F90 index 6fcc6903c9..e21bbcae61 100644 --- a/src/framework/MOM_random.F90 +++ b/src/framework/MOM_random.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides gridded random number capability module MOM_random -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_hor_index, only : hor_index_type use MOM_time_manager, only : time_type, set_date, get_date diff --git a/src/framework/MOM_restart.F90 b/src/framework/MOM_restart.F90 index d7b4b31d1a..47731ab1c0 100644 --- a/src/framework/MOM_restart.F90 +++ b/src/framework/MOM_restart.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The MOM6 facility for reading and writing restart files, and querying what has been read. module MOM_restart -! This file is part of MOM6. See LICENSE.md for the license. - use, intrinsic :: iso_fortran_env, only : int64 use MOM_array_transform, only : rotate_array, rotate_vector, rotate_array_pair use MOM_checksums, only : chksum => field_checksum diff --git a/src/framework/MOM_safe_alloc.F90 b/src/framework/MOM_safe_alloc.F90 index 8960e8e358..3b5b2b397e 100644 --- a/src/framework/MOM_safe_alloc.F90 +++ b/src/framework/MOM_safe_alloc.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Convenience functions for safely allocating memory without !! accidentally reallocating pointer and causing memory leaks. module MOM_safe_alloc -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public safe_alloc_ptr, safe_alloc_alloc diff --git a/src/framework/MOM_string_functions.F90 b/src/framework/MOM_string_functions.F90 index cabe0f6e40..10671c135d 100644 --- a/src/framework/MOM_string_functions.F90 +++ b/src/framework/MOM_string_functions.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Handy functions for manipulating strings module MOM_string_functions -! This file is part of MOM6. See LICENSE.md for the license. - use iso_fortran_env, only : stdout=>output_unit, stderr=>error_unit implicit none ; private diff --git a/src/framework/MOM_unique_scales.F90 b/src/framework/MOM_unique_scales.F90 index afc7b6b0ed..e61a339c8b 100644 --- a/src/framework/MOM_unique_scales.F90 +++ b/src/framework/MOM_unique_scales.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module provides tools that can be used to check the uniqueness of the dimensional !! scaling factors used by the MOM6 ocean model or other models module MOM_unique_scales -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, assert, MOM_get_verbosity implicit none ; private diff --git a/src/framework/MOM_unit_scaling.F90 b/src/framework/MOM_unit_scaling.F90 index 8b4f9266a8..96814d3220 100644 --- a/src/framework/MOM_unit_scaling.F90 +++ b/src/framework/MOM_unit_scaling.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a transparent unit rescaling type to facilitate dimensional consistency testing module MOM_unit_scaling -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL use MOM_file_parser, only : get_param, log_param, log_version, param_file_type diff --git a/src/framework/MOM_unit_testing.F90 b/src/framework/MOM_unit_testing.F90 index 312914933c..aeef8aa882 100644 --- a/src/framework/MOM_unit_testing.F90 +++ b/src/framework/MOM_unit_testing.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module MOM_unit_testing use posix, only : chmod diff --git a/src/framework/MOM_write_cputime.F90 b/src/framework/MOM_write_cputime.F90 index 025dcad2ac..52cc924574 100644 --- a/src/framework/MOM_write_cputime.F90 +++ b/src/framework/MOM_write_cputime.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A module to monitor the overall CPU time used by MOM6 and project when to stop the model module MOM_write_cputime -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : sum_across_PEs, num_pes use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, is_root_pe use MOM_io, only : open_ASCII_file, close_file, APPEND_FILE, WRITEONLY_FILE diff --git a/src/framework/numerical_testing_type.F90 b/src/framework/numerical_testing_type.F90 index 22b069491c..23ed4630f0 100644 --- a/src/framework/numerical_testing_type.F90 +++ b/src/framework/numerical_testing_type.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A simple type for keeping track of numerical tests module numerical_testing_type -! This file is part of MOM6. See LICENSE.md for the license. - implicit none ; private public testing diff --git a/src/framework/posix.F90 b/src/framework/posix.F90 index a9829c510e..4eb5969b3a 100644 --- a/src/framework/posix.F90 +++ b/src/framework/posix.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to the libc POSIX API #include "posix.h" diff --git a/src/framework/posix.h b/src/framework/posix.h index c4b09e1285..2ccdfde126 100644 --- a/src/framework/posix.h +++ b/src/framework/posix.h @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + #ifndef MOM6_POSIX_H_ #define MOM6_POSIX_H_ diff --git a/src/framework/testing/MOM_file_parser_tests.F90 b/src/framework/testing/MOM_file_parser_tests.F90 index c0a31c39c4..586037f5d9 100644 --- a/src/framework/testing/MOM_file_parser_tests.F90 +++ b/src/framework/testing/MOM_file_parser_tests.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module MOM_file_parser_tests use posix, only : chmod diff --git a/src/framework/version_variable.h b/src/framework/version_variable.h index 7cccf999fe..f60afdfc69 100644 --- a/src/framework/version_variable.h +++ b/src/framework/version_variable.h @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + #ifdef _FILE_VERSION character(len=*), parameter :: version = _FILE_VERSION #else diff --git a/src/ice_shelf/MOM_ice_shelf.F90 b/src/ice_shelf/MOM_ice_shelf.F90 index 2def8097ea..bdde9ba6e4 100644 --- a/src/ice_shelf/MOM_ice_shelf.F90 +++ b/src/ice_shelf/MOM_ice_shelf.F90 @@ -1,9 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements the thermodynamic aspects of ocean / ice-shelf interactions, !! along with a crude placeholder for a later implementation of full !! ice shelf dynamics, all using the MOM framework and coding style. module MOM_ice_shelf -! This file is part of MOM6. See LICENSE.md for the license. use MOM_array_transform, only : rotate_array use MOM_constants, only : hlf use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end diff --git a/src/ice_shelf/MOM_ice_shelf_diag_mediator.F90 b/src/ice_shelf/MOM_ice_shelf_diag_mediator.F90 index fe54dd6533..fc728e5d14 100644 --- a/src/ice_shelf/MOM_ice_shelf_diag_mediator.F90 +++ b/src/ice_shelf/MOM_ice_shelf_diag_mediator.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Convenient wrappers to the FMS diag_manager interfaces with additional diagnostic capabilies. module MOM_IS_diag_mediator diff --git a/src/ice_shelf/MOM_ice_shelf_dynamics.F90 b/src/ice_shelf/MOM_ice_shelf_dynamics.F90 index 5c9b0b306d..9ad992bb97 100644 --- a/src/ice_shelf/MOM_ice_shelf_dynamics.F90 +++ b/src/ice_shelf/MOM_ice_shelf_dynamics.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements a crude placeholder for a later implementation of full !! ice shelf dynamics. module MOM_ice_shelf_dynamics -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_COMPONENT, CLOCK_ROUTINE use MOM_IS_diag_mediator, only : post_data=>post_IS_data diff --git a/src/ice_shelf/MOM_ice_shelf_initialize.F90 b/src/ice_shelf/MOM_ice_shelf_initialize.F90 index ec24aef2d0..ee089706b7 100644 --- a/src/ice_shelf/MOM_ice_shelf_initialize.F90 +++ b/src/ice_shelf/MOM_ice_shelf_initialize.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialize ice shelf variables module MOM_ice_shelf_initialize -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_grid, only : ocean_grid_type use MOM_array_transform, only : rotate_array use MOM_hor_index, only : hor_index_type diff --git a/src/ice_shelf/MOM_ice_shelf_state.F90 b/src/ice_shelf/MOM_ice_shelf_state.F90 index d789c08bd4..bcab79fe95 100644 --- a/src/ice_shelf/MOM_ice_shelf_state.F90 +++ b/src/ice_shelf/MOM_ice_shelf_state.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements the thermodynamic aspects of ocean / ice-shelf interactions, !! along with a crude placeholder for a later implementation of full !! ice shelf dynamics, all using the MOM framework and coding style. module MOM_ice_shelf_state -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_COMPONENT, CLOCK_ROUTINE use MOM_dyn_horgrid, only : dyn_horgrid_type, create_dyn_horgrid, destroy_dyn_horgrid diff --git a/src/ice_shelf/MOM_marine_ice.F90 b/src/ice_shelf/MOM_marine_ice.F90 index 3fec94e499..3f949f8b06 100644 --- a/src/ice_shelf/MOM_marine_ice.F90 +++ b/src/ice_shelf/MOM_marine_ice.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines incorporating the effects of marine ice (sea-ice and icebergs) into !! the ocean model dynamics and thermodynamics. module MOM_marine_ice -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_constants, only : hlf use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl use MOM_domains, only : pass_var, pass_vector, AGRID, BGRID_NE, CGRID_NE diff --git a/src/ice_shelf/user_shelf_init.F90 b/src/ice_shelf/user_shelf_init.F90 index 4d1f263ca8..e3c7e2b49a 100644 --- a/src/ice_shelf/user_shelf_init.F90 +++ b/src/ice_shelf/user_shelf_init.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module specifies the initial values and evolving properties of the !! MOM6 ice shelf, using user-provided code. module user_shelf_init -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_grid, only : ocean_grid_type diff --git a/src/initialization/MOM_coord_initialization.F90 b/src/initialization/MOM_coord_initialization.F90 index 9acf693f5f..571a365937 100644 --- a/src/initialization/MOM_coord_initialization.F90 +++ b/src/initialization/MOM_coord_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initializes fixed aspects of the related to its vertical coordinate. module MOM_coord_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : chksum use MOM_EOS, only : calculate_density, EOS_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/initialization/MOM_fixed_initialization.F90 b/src/initialization/MOM_fixed_initialization.F90 index 78559c72f2..eb405f2e6e 100644 --- a/src/initialization/MOM_fixed_initialization.F90 +++ b/src/initialization/MOM_fixed_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initializes fixed aspects of the model, such as horizontal grid metrics, !! topography and Coriolis. module MOM_fixed_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, qchksum, uvchksum use MOM_domains, only : pass_var use MOM_dyn_horgrid, only : dyn_horgrid_type diff --git a/src/initialization/MOM_grid_initialize.F90 b/src/initialization/MOM_grid_initialize.F90 index 21b8a735d3..78160866d5 100644 --- a/src/initialization/MOM_grid_initialize.F90 +++ b/src/initialization/MOM_grid_initialize.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initializes horizontal grid module MOM_grid_initialize -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_checksums, only : hchksum, Bchksum, uvchksum, hchksum_pair, Bchksum_pair use MOM_domains, only : pass_var, pass_vector, pe_here, root_PE, broadcast use MOM_domains, only : AGRID, BGRID_NE, CGRID_NE, To_All, Scalar_Pair diff --git a/src/initialization/MOM_shared_initialization.F90 b/src/initialization/MOM_shared_initialization.F90 index cbb966c43d..8cdf8156af 100644 --- a/src/initialization/MOM_shared_initialization.F90 +++ b/src/initialization/MOM_shared_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Code that initializes fixed aspects of the model grid, such as horizontal !! grid metrics, topography and Coriolis, and can be shared between components. module MOM_shared_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : max_across_PEs, reproducing_sum use MOM_domains, only : pass_var, pass_vector, sum_across_PEs, broadcast use MOM_domains, only : root_PE, To_All, SCALAR_PAIR, CGRID_NE, AGRID diff --git a/src/initialization/MOM_state_initialization.F90 b/src/initialization/MOM_state_initialization.F90 index 1ea49671a6..a1a512ac92 100644 --- a/src/initialization/MOM_state_initialization.F90 +++ b/src/initialization/MOM_state_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization functions for state variables, u, v, h, T and S. module MOM_state_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, qchksum, uvchksum use MOM_density_integrals, only : int_specific_vol_dp use MOM_density_integrals, only : find_depth_of_pressure_in_cell diff --git a/src/initialization/MOM_tracer_initialization_from_Z.F90 b/src/initialization/MOM_tracer_initialization_from_Z.F90 index b100e0bf1c..d444fafdd9 100644 --- a/src/initialization/MOM_tracer_initialization_from_Z.F90 +++ b/src/initialization/MOM_tracer_initialization_from_Z.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initializes hydrography from z-coordinate climatology files module MOM_tracer_initialization_from_Z -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_ROUTINE, CLOCK_LOOP diff --git a/src/ocean_data_assim/MOM_oda_driver.F90 b/src/ocean_data_assim/MOM_oda_driver.F90 index 3b277578a3..4c665fd9e1 100644 --- a/src/ocean_data_assim/MOM_oda_driver.F90 +++ b/src/ocean_data_assim/MOM_oda_driver.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interfaces for MOM6 ensembles and data assimilation. module MOM_oda_driver_mod diff --git a/src/ocean_data_assim/MOM_oda_incupd.F90 b/src/ocean_data_assim/MOM_oda_incupd.F90 index b22cbb47d8..d55d030d44 100644 --- a/src/ocean_data_assim/MOM_oda_incupd.F90 +++ b/src/ocean_data_assim/MOM_oda_incupd.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the routines used to apply incremental updates !! from data assimilation. ! @@ -13,7 +17,6 @@ module MOM_oda_incupd -! This file is part of MOM6. See LICENSE.md for the license. use MOM_array_transform, only : rotate_array use MOM_coms, only : sum_across_PEs use MOM_diag_mediator, only : post_data, query_averaging_enabled, register_diag_field @@ -599,19 +602,19 @@ subroutine apply_oda_incupd(h, tv, u, v, dt, G, GV, US, CS) tmp_val1(:) = 0.0 tmp_t(:,:,:) = 0.0 ; tmp_s(:,:,:) = 0.0 ! diagnostics do j=js,je ; do i=is,ie - ! account for the different SSH - sum_h1 = 0.0 - do k=1,nz - sum_h1 = sum_h1+h(i,j,k) - enddo - sum_h2 = 0.0 - do k=1,nz_data - sum_h2 = sum_h2+h_obs(i,j,k) - enddo - do k=1,nz_data - tmp_h(k) = ( sum_h1 / sum_h2 ) * h_obs(i,j,k) - enddo if (G%mask2dT(i,j) == 1) then + ! account for the different SSH + sum_h1 = 0.0 + do k=1,nz + sum_h1 = sum_h1+h(i,j,k) + enddo + sum_h2 = 0.0 + do k=1,nz_data + sum_h2 = sum_h2+h_obs(i,j,k) + enddo + do k=1,nz_data + tmp_h(k) = ( sum_h1 / sum_h2 ) * h_obs(i,j,k) + enddo ! get temperature increment do k=1,nz_data tmp_val2(k) = CS%Inc(1)%p(i,j,k) diff --git a/src/parameterizations/lateral/MOM_MEKE.F90 b/src/parameterizations/lateral/MOM_MEKE.F90 index 41c98884ba..3f96e689c7 100644 --- a/src/parameterizations/lateral/MOM_MEKE.F90 +++ b/src/parameterizations/lateral/MOM_MEKE.F90 @@ -1,9 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements the Mesoscale Eddy Kinetic Energy framework !! with topographic beta effect included in computing beta in Rhines scale module MOM_MEKE -! This file is part of MOM6. See LICENSE.md for the license. use iso_fortran_env, only : real32 use MOM_coms, only : PE_here diff --git a/src/parameterizations/lateral/MOM_MEKE_types.F90 b/src/parameterizations/lateral/MOM_MEKE_types.F90 index e277036716..26bc168730 100644 --- a/src/parameterizations/lateral/MOM_MEKE_types.F90 +++ b/src/parameterizations/lateral/MOM_MEKE_types.F90 @@ -1,6 +1,8 @@ -module MOM_MEKE_types +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 -! This file is part of MOM6. See LICENSE.md for the license. +module MOM_MEKE_types implicit none ; private diff --git a/src/parameterizations/lateral/MOM_Zanna_Bolton.F90 b/src/parameterizations/lateral/MOM_Zanna_Bolton.F90 index 075ec9049c..8b4a8856b7 100644 --- a/src/parameterizations/lateral/MOM_Zanna_Bolton.F90 +++ b/src/parameterizations/lateral/MOM_Zanna_Bolton.F90 @@ -1,8 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates Zanna and Bolton 2020 parameterization !! Implemented by Perezhogin P.A. Contact: pperezhogin@gmail.com module MOM_Zanna_Bolton -! This file is part of MOM6. See LICENSE.md for the license. use MOM_grid, only : ocean_grid_type use MOM_verticalGrid, only : verticalGrid_type use MOM_diag_mediator, only : diag_ctrl, time_type diff --git a/src/parameterizations/lateral/MOM_hor_visc.F90 b/src/parameterizations/lateral/MOM_hor_visc.F90 index ff54cd8092..d09592f975 100644 --- a/src/parameterizations/lateral/MOM_hor_visc.F90 +++ b/src/parameterizations/lateral/MOM_hor_visc.F90 @@ -1,7 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates horizontal viscosity and viscous stresses module MOM_hor_visc -! This file is part of MOM6. See LICENSE.md for the license. use MOM_checksums, only : hchksum, Bchksum, uvchksum use MOM_coms, only : min_across_PEs use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr @@ -3904,4 +3907,4 @@ end subroutine hor_visc_end !! Smith, R.D., and McWilliams, J.C., 2003: Anisotropic horizontal viscosity for !! ocean models. Ocean Modelling, 5(2), 129-156. !! https://doi.org/10.1016/S1463-5003(02)00016-1 -end module MOM_hor_visc \ No newline at end of file +end module MOM_hor_visc diff --git a/src/parameterizations/lateral/MOM_interface_filter.F90 b/src/parameterizations/lateral/MOM_interface_filter.F90 index 12bda8c020..652da865ee 100644 --- a/src/parameterizations/lateral/MOM_interface_filter.F90 +++ b/src/parameterizations/lateral/MOM_interface_filter.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface height filtering module module MOM_interface_filter -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, uvchksum use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl use MOM_diag_mediator, only : register_diag_field, safe_alloc_ptr, time_type diff --git a/src/parameterizations/lateral/MOM_internal_tides.F90 b/src/parameterizations/lateral/MOM_internal_tides.F90 index 1f51cc99a9..73740e5412 100644 --- a/src/parameterizations/lateral/MOM_internal_tides.F90 +++ b/src/parameterizations/lateral/MOM_internal_tides.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Subroutines that use the ray-tracing equations to propagate the internal tide energy density. !! !! \author Benjamin Mater & Robert Hallberg, 2015 module MOM_internal_tides -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_checksums, only : hchksum use MOM_debugging, only : is_NaN use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_axis_init diff --git a/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 b/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 index c742dda898..f220d696c8 100644 --- a/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 +++ b/src/parameterizations/lateral/MOM_lateral_mixing_coeffs.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Variable mixing coefficients module MOM_lateral_mixing_coeffs -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, uvchksum use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg use MOM_diag_mediator, only : register_diag_field, safe_alloc_ptr, post_data diff --git a/src/parameterizations/lateral/MOM_load_love_numbers.F90 b/src/parameterizations/lateral/MOM_load_love_numbers.F90 index 8faf3aafab..8ca2951cc4 100644 --- a/src/parameterizations/lateral/MOM_load_love_numbers.F90 +++ b/src/parameterizations/lateral/MOM_load_love_numbers.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Load Love Numbers for degree range [0, 1440] module MOM_load_love_numbers diff --git a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 index 5581ae2ed2..4176359f30 100644 --- a/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 +++ b/src/parameterizations/lateral/MOM_mixed_layer_restrat.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> \brief Parameterization of mixed layer restratification by unresolved mixed-layer eddies. module MOM_mixed_layer_restrat -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl use MOM_diag_mediator, only : register_diag_field, safe_alloc_ptr, time_type diff --git a/src/parameterizations/lateral/MOM_self_attr_load.F90 b/src/parameterizations/lateral/MOM_self_attr_load.F90 index 045027f05c..ae1e0fec7c 100644 --- a/src/parameterizations/lateral/MOM_self_attr_load.F90 +++ b/src/parameterizations/lateral/MOM_self_attr_load.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + module MOM_self_attr_load use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_MODULE diff --git a/src/parameterizations/lateral/MOM_spherical_harmonics.F90 b/src/parameterizations/lateral/MOM_spherical_harmonics.F90 index 7606ac3ce1..44bdce9b71 100644 --- a/src/parameterizations/lateral/MOM_spherical_harmonics.F90 +++ b/src/parameterizations/lateral/MOM_spherical_harmonics.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Laplace's spherical harmonic transforms (SHT) module MOM_spherical_harmonics use MOM_coms_infra, only : sum_across_PEs diff --git a/src/parameterizations/lateral/MOM_streaming_filter.F90 b/src/parameterizations/lateral/MOM_streaming_filter.F90 index 7a8bc1b774..618ae12786 100644 --- a/src/parameterizations/lateral/MOM_streaming_filter.F90 +++ b/src/parameterizations/lateral/MOM_streaming_filter.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Streaming band-pass filter for detecting the instantaneous tidal signals in the simulation module MOM_streaming_filter diff --git a/src/parameterizations/lateral/MOM_thickness_diffuse.F90 b/src/parameterizations/lateral/MOM_thickness_diffuse.F90 index 4c194b413a..1c7fe38155 100644 --- a/src/parameterizations/lateral/MOM_thickness_diffuse.F90 +++ b/src/parameterizations/lateral/MOM_thickness_diffuse.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Isopycnal height diffusion (or Gent McWilliams diffusion) module MOM_thickness_diffuse -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum, uvchksum use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl use MOM_diag_mediator, only : register_diag_field, safe_alloc_ptr, time_type diff --git a/src/parameterizations/lateral/MOM_tidal_forcing.F90 b/src/parameterizations/lateral/MOM_tidal_forcing.F90 index 55daa49a3b..47e01fd50d 100644 --- a/src/parameterizations/lateral/MOM_tidal_forcing.F90 +++ b/src/parameterizations/lateral/MOM_tidal_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Tidal contributions to geopotential module MOM_tidal_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, & CLOCK_MODULE, CLOCK_ROUTINE use MOM_domains, only : pass_var diff --git a/src/parameterizations/lateral/MOM_wave_drag.F90 b/src/parameterizations/lateral/MOM_wave_drag.F90 index a507c762c1..aef40d86b1 100644 --- a/src/parameterizations/lateral/MOM_wave_drag.F90 +++ b/src/parameterizations/lateral/MOM_wave_drag.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Frequency-dependent linear wave drag module MOM_wave_drag diff --git a/src/parameterizations/stochastic/MOM_stochastics.F90 b/src/parameterizations/stochastic/MOM_stochastics.F90 index 32f9da0e40..42301f60c7 100644 --- a/src/parameterizations/stochastic/MOM_stochastics.F90 +++ b/src/parameterizations/stochastic/MOM_stochastics.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Top-level module for the MOM6 ocean model in coupled mode. module MOM_stochastics -! This file is part of MOM6. See LICENSE.md for the license. - ! This is the top level module for the MOM6 ocean model. It contains routines ! for initialization, update, and writing restart of stochastic physics. This ! particular version wraps all of the calls for MOM6 in the calls that had diff --git a/src/parameterizations/vertical/MOM_ALE_sponge.F90 b/src/parameterizations/vertical/MOM_ALE_sponge.F90 index ebbba53b37..c0cfb3b45c 100644 --- a/src/parameterizations/vertical/MOM_ALE_sponge.F90 +++ b/src/parameterizations/vertical/MOM_ALE_sponge.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the routines used to apply sponge layers when using !! the ALE mode. !! @@ -11,7 +15,6 @@ module MOM_ALE_sponge -! This file is part of MOM6. See LICENSE.md for the license. use MOM_array_transform, only: rotate_array use MOM_coms, only : sum_across_PEs use MOM_diag_mediator, only : post_data, query_averaging_enabled, register_diag_field diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index 1ad7435cb8..e0cf922c68 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix. module MOM_CVMix_KPP -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : max_across_PEs use MOM_debugging, only : hchksum, is_NaN use MOM_diag_mediator, only : time_type, diag_ctrl, safe_alloc_ptr, post_data diff --git a/src/parameterizations/vertical/MOM_CVMix_conv.F90 b/src/parameterizations/vertical/MOM_CVMix_conv.F90 index 69d835ae95..759c470d39 100644 --- a/src/parameterizations/vertical/MOM_CVMix_conv.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_conv.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to CVMix convection scheme. module MOM_CVMix_conv -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum use MOM_diag_mediator, only : diag_ctrl, time_type, register_diag_field use MOM_diag_mediator, only : post_data diff --git a/src/parameterizations/vertical/MOM_CVMix_ddiff.F90 b/src/parameterizations/vertical/MOM_CVMix_ddiff.F90 index 173ab7a36d..c46efb8a45 100644 --- a/src/parameterizations/vertical/MOM_CVMix_ddiff.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_ddiff.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to CVMix double diffusion scheme. module MOM_CVMix_ddiff -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, time_type, register_diag_field use MOM_diag_mediator, only : post_data use MOM_EOS, only : calculate_density_derivs diff --git a/src/parameterizations/vertical/MOM_CVMix_shear.F90 b/src/parameterizations/vertical/MOM_CVMix_shear.F90 index 36d92616b3..d4d9f031d9 100644 --- a/src/parameterizations/vertical/MOM_CVMix_shear.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_shear.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to CVMix interior shear schemes module MOM_CVMix_shear -! This file is part of MOM6. See LICENSE.md for the license. - !> \author Brandon Reichl use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr diff --git a/src/parameterizations/vertical/MOM_bkgnd_mixing.F90 b/src/parameterizations/vertical/MOM_bkgnd_mixing.F90 index d6c51201a6..d9fcbe081a 100644 --- a/src/parameterizations/vertical/MOM_bkgnd_mixing.F90 +++ b/src/parameterizations/vertical/MOM_bkgnd_mixing.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to background mixing schemes, including the Bryan and Lewis (1979) !! which is applied via CVMix. module MOM_bkgnd_mixing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : hchksum use MOM_diag_mediator, only : diag_ctrl, time_type, register_diag_field use MOM_diag_mediator, only : post_data diff --git a/src/parameterizations/vertical/MOM_bulk_mixed_layer.F90 b/src/parameterizations/vertical/MOM_bulk_mixed_layer.F90 index 690688dc1e..b9fc8eb70a 100644 --- a/src/parameterizations/vertical/MOM_bulk_mixed_layer.F90 +++ b/src/parameterizations/vertical/MOM_bulk_mixed_layer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Build mixed layer parameterization module MOM_bulk_mixed_layer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_alloc use MOM_diag_mediator, only : time_type, diag_ctrl, diag_update_remap_grids diff --git a/src/parameterizations/vertical/MOM_diabatic_aux.F90 b/src/parameterizations/vertical/MOM_diabatic_aux.F90 index 9fffc1a6c4..bcde4feb34 100644 --- a/src/parameterizations/vertical/MOM_diabatic_aux.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_aux.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides functions for some diabatic processes such as frazil, brine rejection, !! tendency due to surface flux divergence. module MOM_diabatic_aux -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE_DRIVER, CLOCK_MODULE, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr diff --git a/src/parameterizations/vertical/MOM_diabatic_driver.F90 b/src/parameterizations/vertical/MOM_diabatic_driver.F90 index e60a292a37..33cb72e83b 100644 --- a/src/parameterizations/vertical/MOM_diabatic_driver.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_driver.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This routine drives the diabatic/dianeutral physics for MOM module MOM_diabatic_driver -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_bulk_mixed_layer, only : bulkmixedlayer, bulkmixedlayer_init, bulkmixedlayer_CS use MOM_debugging, only : hchksum use MOM_checksum_packages, only : MOM_state_chksum, MOM_state_stats diff --git a/src/parameterizations/vertical/MOM_diapyc_energy_req.F90 b/src/parameterizations/vertical/MOM_diapyc_energy_req.F90 index d197a7a8f1..a7d4bd71d8 100644 --- a/src/parameterizations/vertical/MOM_diapyc_energy_req.F90 +++ b/src/parameterizations/vertical/MOM_diapyc_energy_req.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates the energy requirements of mixing. module MOM_diapyc_energy_req -! This file is part of MOM6. See LICENSE.md for the license. - !! \author By Robert Hallberg, May 2015 use MOM_diag_mediator, only : diag_ctrl, Time_type, post_data, register_diag_field diff --git a/src/parameterizations/vertical/MOM_energetic_PBL.F90 b/src/parameterizations/vertical/MOM_energetic_PBL.F90 index 7a67cbb5a5..b7f3a3462b 100644 --- a/src/parameterizations/vertical/MOM_energetic_PBL.F90 +++ b/src/parameterizations/vertical/MOM_energetic_PBL.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Energetically consistent planetary boundary layer parameterization module MOM_energetic_PBL -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_coms, only : EFP_type, real_to_EFP, EFP_to_real, operator(+), assignment(=), EFP_sum_across_PEs use MOM_debugging, only : hchksum diff --git a/src/parameterizations/vertical/MOM_entrain_diffusive.F90 b/src/parameterizations/vertical/MOM_entrain_diffusive.F90 index 5141176d08..4f5ae31f0c 100644 --- a/src/parameterizations/vertical/MOM_entrain_diffusive.F90 +++ b/src/parameterizations/vertical/MOM_entrain_diffusive.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Diapycnal mixing and advection in isopycnal mode module MOM_entrain_diffusive -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr use MOM_diag_mediator, only : diag_ctrl, time_type use MOM_EOS, only : calculate_density, calculate_density_derivs diff --git a/src/parameterizations/vertical/MOM_full_convection.F90 b/src/parameterizations/vertical/MOM_full_convection.F90 index a5fba3adc6..bcf715a204 100644 --- a/src/parameterizations/vertical/MOM_full_convection.F90 +++ b/src/parameterizations/vertical/MOM_full_convection.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Does full convective adjustment of unstable regions via a strong diffusivity. module MOM_full_convection -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_grid, only : ocean_grid_type use MOM_interface_heights, only : thickness_to_dz use MOM_unit_scaling, only : unit_scale_type diff --git a/src/parameterizations/vertical/MOM_geothermal.F90 b/src/parameterizations/vertical/MOM_geothermal.F90 index ac12bcdb1b..7746ed84dc 100644 --- a/src/parameterizations/vertical/MOM_geothermal.F90 +++ b/src/parameterizations/vertical/MOM_geothermal.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implemented geothermal heating at the ocean bottom. module MOM_geothermal -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_alloc use MOM_diag_mediator, only : register_static_field, time_type, diag_ctrl use MOM_domains, only : pass_var diff --git a/src/parameterizations/vertical/MOM_internal_tide_input.F90 b/src/parameterizations/vertical/MOM_internal_tide_input.F90 index 2384844f6e..a03dca73a8 100644 --- a/src/parameterizations/vertical/MOM_internal_tide_input.F90 +++ b/src/parameterizations/vertical/MOM_internal_tide_input.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates energy input to the internal tides module MOM_int_tide_input -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE_DRIVER, CLOCK_MODULE, CLOCK_ROUTINE use MOM_diag_mediator, only : diag_ctrl, query_averaging_enabled diff --git a/src/parameterizations/vertical/MOM_kappa_shear.F90 b/src/parameterizations/vertical/MOM_kappa_shear.F90 index da2c261ad9..b2e112cb36 100644 --- a/src/parameterizations/vertical/MOM_kappa_shear.F90 +++ b/src/parameterizations/vertical/MOM_kappa_shear.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Shear-dependent mixing following Jackson et al. 2008. module MOM_kappa_shear -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE_DRIVER, CLOCK_MODULE, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr diff --git a/src/parameterizations/vertical/MOM_opacity.F90 b/src/parameterizations/vertical/MOM_opacity.F90 index 8289144ec3..6728bf820c 100644 --- a/src/parameterizations/vertical/MOM_opacity.F90 +++ b/src/parameterizations/vertical/MOM_opacity.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines used to calculate the opacity of the ocean. module MOM_opacity -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : time_type, diag_ctrl, safe_alloc_ptr, post_data use MOM_diag_mediator, only : query_averaging_enabled, register_diag_field use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING diff --git a/src/parameterizations/vertical/MOM_regularize_layers.F90 b/src/parameterizations/vertical/MOM_regularize_layers.F90 index b00238f60c..da1667a77b 100644 --- a/src/parameterizations/vertical/MOM_regularize_layers.F90 +++ b/src/parameterizations/vertical/MOM_regularize_layers.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides regularization of layers in isopycnal mode module MOM_regularize_layers -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr use MOM_diag_mediator, only : time_type, diag_ctrl diff --git a/src/parameterizations/vertical/MOM_set_diffusivity.F90 b/src/parameterizations/vertical/MOM_set_diffusivity.F90 index caf0555d28..c6124e0c9a 100644 --- a/src/parameterizations/vertical/MOM_set_diffusivity.F90 +++ b/src/parameterizations/vertical/MOM_set_diffusivity.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculate vertical diffusivity from all mixing processes module MOM_set_diffusivity -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_bkgnd_mixing, only : calculate_bkgnd_mixing, bkgnd_mixing_init, bkgnd_mixing_cs use MOM_bkgnd_mixing, only : bkgnd_mixing_end use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end diff --git a/src/parameterizations/vertical/MOM_set_viscosity.F90 b/src/parameterizations/vertical/MOM_set_viscosity.F90 index 499e388d06..2bfada3bf1 100644 --- a/src/parameterizations/vertical/MOM_set_viscosity.F90 +++ b/src/parameterizations/vertical/MOM_set_viscosity.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates various values related to the bottom boundary layer, such as the viscosity and !! thickness of the BBL (set_viscous_BBL). module MOM_set_visc -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ALE, only : ALE_CS, ALE_remap_velocities, ALE_remap_interface_vals, ALE_remap_vertex_vals use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, CLOCK_ROUTINE use MOM_cvmix_conv, only : cvmix_conv_is_used diff --git a/src/parameterizations/vertical/MOM_sponge.F90 b/src/parameterizations/vertical/MOM_sponge.F90 index c919e57d94..aa8361e2c7 100644 --- a/src/parameterizations/vertical/MOM_sponge.F90 +++ b/src/parameterizations/vertical/MOM_sponge.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements sponge regions in isopycnal mode module MOM_sponge -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : sum_across_PEs use MOM_diag_mediator, only : post_data, query_averaging_enabled, register_diag_field use MOM_diag_mediator, only : diag_ctrl diff --git a/src/parameterizations/vertical/MOM_tidal_mixing.F90 b/src/parameterizations/vertical/MOM_tidal_mixing.F90 index 9a972e6e06..e596a9af2f 100644 --- a/src/parameterizations/vertical/MOM_tidal_mixing.F90 +++ b/src/parameterizations/vertical/MOM_tidal_mixing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface to vertical tidal mixing schemes including CVMix tidal mixing. module MOM_tidal_mixing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, time_type, register_diag_field use MOM_diag_mediator, only : safe_alloc_ptr, post_data use MOM_diagnose_Kdwork, only : vbf_CS diff --git a/src/parameterizations/vertical/MOM_vert_friction.F90 b/src/parameterizations/vertical/MOM_vert_friction.F90 index dac10b6fdb..30c3d12e63 100644 --- a/src/parameterizations/vertical/MOM_vert_friction.F90 +++ b/src/parameterizations/vertical/MOM_vert_friction.F90 @@ -1,7 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements vertical viscosity (vertvisc) module MOM_vert_friction -! This file is part of MOM6. See LICENSE.md for the license. use MOM_domains, only : pass_var, To_All, Omit_corners use MOM_domains, only : pass_vector, Scalar_Pair use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr diff --git a/src/tracer/DOME_tracer.F90 b/src/tracer/DOME_tracer.F90 index 839e923844..7ef2dee58c 100644 --- a/src/tracer/DOME_tracer.F90 +++ b/src/tracer/DOME_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package that is used as a diagnostic in the DOME experiments module DOME_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING diff --git a/src/tracer/ISOMIP_tracer.F90 b/src/tracer/ISOMIP_tracer.F90 index 7361b893ec..f1a158fb90 100644 --- a/src/tracer/ISOMIP_tracer.F90 +++ b/src/tracer/ISOMIP_tracer.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Routines used to set up and use a set of (one for now) !! dynamically passive tracers in the ISOMIP configuration. !! @@ -5,8 +9,6 @@ !! the sponge layer. module ISOMIP_tracer -! This file is part of MOM6. See LICENSE.md for the license. - ! Original sample tracer package by Robert Hallberg, 2002 ! Adapted to the ISOMIP test case by Gustavo Marques, May 2016 diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index 7769175e83..d7e753e127 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module provides a common datatype to provide forcing for MARBL tracers !! regardless of driver module MARBL_forcing_mod diff --git a/src/tracer/MARBL_tracers.F90 b/src/tracer/MARBL_tracers.F90 index c5e0936fe8..a7bd64999e 100644 --- a/src/tracer/MARBL_tracers.F90 +++ b/src/tracer/MARBL_tracers.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package for tracers computed in the MARBL library !! !! Currently configured for use with marbl0.36.0 @@ -5,8 +9,6 @@ !! (clone entire repo into pkg/MARBL) module MARBL_tracers -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type, root_PE, broadcast use MOM_debugging, only : hchksum use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/MOM_CFC_cap.F90 b/src/tracer/MOM_CFC_cap.F90 index f9aa421f86..f8420b47a0 100644 --- a/src/tracer/MOM_CFC_cap.F90 +++ b/src/tracer/MOM_CFC_cap.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Simulates CFCs using atmospheric pressure, wind speed and sea ice cover !! provided via cap (only NUOPC cap is implemented so far). module MOM_CFC_cap -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_debugging, only : hchksum use MOM_diag_mediator, only : diag_ctrl, register_diag_field, post_data diff --git a/src/tracer/MOM_OCMIP2_CFC.F90 b/src/tracer/MOM_OCMIP2_CFC.F90 index 0a80cfaf2f..ee6609903f 100644 --- a/src/tracer/MOM_OCMIP2_CFC.F90 +++ b/src/tracer/MOM_OCMIP2_CFC.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Simulates CFCs using the OCMIP2 protocols module MOM_OCMIP2_CFC -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : extract_coupler_type_data, set_coupler_type_data use MOM_coupler_types, only : atmos_ocn_coupler_flux diff --git a/src/tracer/MOM_hor_bnd_diffusion.F90 b/src/tracer/MOM_hor_bnd_diffusion.F90 index afb4732cb5..96cddfa4d1 100644 --- a/src/tracer/MOM_hor_bnd_diffusion.F90 +++ b/src/tracer/MOM_hor_bnd_diffusion.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Calculates and applies diffusive fluxes as a parameterization of horizontal mixing (non-neutral) by !! mesoscale eddies near the top and bottom (to be implemented) boundary layers of the ocean. module MOM_hor_bnd_diffusion -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE use MOM_checksums, only : hchksum diff --git a/src/tracer/MOM_neutral_diffusion.F90 b/src/tracer/MOM_neutral_diffusion.F90 index 0d039dd090..bf28f2dbfc 100644 --- a/src/tracer/MOM_neutral_diffusion.F90 +++ b/src/tracer/MOM_neutral_diffusion.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A column-wise toolbox for implementing neutral diffusion module MOM_neutral_diffusion -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE, CLOCK_ROUTINE use MOM_domains, only : pass_var diff --git a/src/tracer/MOM_offline_aux.F90 b/src/tracer/MOM_offline_aux.F90 index 4adf8de293..4ea3ee70cc 100644 --- a/src/tracer/MOM_offline_aux.F90 +++ b/src/tracer/MOM_offline_aux.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Contains routines related to offline transport of tracers. These routines are likely to be called from !> the MOM_offline_main module module MOM_offline_aux -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_debugging, only : check_column_integrals use MOM_domains, only : pass_var, pass_vector, To_All use MOM_diag_mediator, only : post_data diff --git a/src/tracer/MOM_offline_main.F90 b/src/tracer/MOM_offline_main.F90 index b0537955ef..e97eb61373 100644 --- a/src/tracer/MOM_offline_main.F90 +++ b/src/tracer/MOM_offline_main.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The routines here implement the offline tracer algorithm used in MOM6. These are called from step_offline !! Some routines called here can be found in the MOM_offline_aux module. module MOM_offline_main -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ALE, only : ALE_CS, ALE_regrid, ALE_offline_inputs use MOM_ALE, only : pre_ALE_adjustments, ALE_update_regrid_weights use MOM_ALE, only : ALE_remap_tracers diff --git a/src/tracer/MOM_tracer_Z_init.F90 b/src/tracer/MOM_tracer_Z_init.F90 index 8b2c12fd9b..63b5107d19 100644 --- a/src/tracer/MOM_tracer_Z_init.F90 +++ b/src/tracer/MOM_tracer_Z_init.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Used to initialize tracers from a depth- (or z*-) space file. module MOM_tracer_Z_init -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_grid, only : ocean_grid_type diff --git a/src/tracer/MOM_tracer_advect.F90 b/src/tracer/MOM_tracer_advect.F90 index 1c9f4e4da7..5241043309 100644 --- a/src/tracer/MOM_tracer_advect.F90 +++ b/src/tracer/MOM_tracer_advect.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the subroutines that advect tracers along coordinate surfaces. module MOM_tracer_advect -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, query_averaging_enabled, diag_ctrl diff --git a/src/tracer/MOM_tracer_advect_schemes.F90 b/src/tracer/MOM_tracer_advect_schemes.F90 index 630f451cfa..2afe72ec46 100644 --- a/src/tracer/MOM_tracer_advect_schemes.F90 +++ b/src/tracer/MOM_tracer_advect_schemes.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains constants for the tracer advection schemes. module MOM_tracer_advect_schemes -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_error, FATAL implicit none ; public diff --git a/src/tracer/MOM_tracer_diabatic.F90 b/src/tracer/MOM_tracer_diabatic.F90 index 417cf7c151..ae6d98e3a7 100644 --- a/src/tracer/MOM_tracer_diabatic.F90 +++ b/src/tracer/MOM_tracer_diabatic.F90 @@ -1,10 +1,12 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains routines that implement physical fluxes of tracers (e.g. due !! to surface fluxes or mixing). These are intended to be called from call_tracer_column_fns !! in the MOM_tracer_flow_control module. module MOM_tracer_diabatic -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_grid, only : ocean_grid_type use MOM_verticalGrid, only : verticalGrid_type use MOM_forcing_type, only : forcing diff --git a/src/tracer/MOM_tracer_flow_control.F90 b/src/tracer/MOM_tracer_flow_control.F90 index 7898eacf82..33db88fe3f 100644 --- a/src/tracer/MOM_tracer_flow_control.F90 +++ b/src/tracer/MOM_tracer_flow_control.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Orchestrates the registration and calling of tracer packages module MOM_tracer_flow_control -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type, assignment(=), EFP_to_real, real_to_EFP, EFP_sum_across_PEs use MOM_diag_mediator, only : time_type, diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING diff --git a/src/tracer/MOM_tracer_hor_diff.F90 b/src/tracer/MOM_tracer_hor_diff.F90 index 02aa597a7e..c550f73ef5 100644 --- a/src/tracer/MOM_tracer_hor_diff.F90 +++ b/src/tracer/MOM_tracer_hor_diff.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Main routine for lateral (along surface or neutral) diffusion of tracers module MOM_tracer_hor_diff -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_MODULE, CLOCK_ROUTINE use MOM_diag_mediator, only : post_data, diag_ctrl diff --git a/src/tracer/MOM_tracer_registry.F90 b/src/tracer/MOM_tracer_registry.F90 index 9cebbb8f3c..08860c3ccb 100644 --- a/src/tracer/MOM_tracer_registry.F90 +++ b/src/tracer/MOM_tracer_registry.F90 @@ -1,11 +1,13 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains subroutines that handle registration of tracers !! and related subroutines. The primary subroutine, register_tracer, is !! called to indicate the tracers advected and diffused. !! It also makes public the types defined in MOM_tracer_types. module MOM_tracer_registry -! This file is part of MOM6. See LICENSE.md for the license. - ! use MOM_diag_mediator, only : diag_ctrl use MOM_coms, only : reproducing_sum use MOM_debugging, only : hchksum diff --git a/src/tracer/MOM_tracer_types.F90 b/src/tracer/MOM_tracer_types.F90 index a42f3ea72a..68a6f7da4f 100644 --- a/src/tracer/MOM_tracer_types.F90 +++ b/src/tracer/MOM_tracer_types.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the tracer_type and tracer_registry_type module MOM_tracer_types diff --git a/src/tracer/RGC_tracer.F90 b/src/tracer/RGC_tracer.F90 index b276b94fec..7f15d0ba1b 100644 --- a/src/tracer/RGC_tracer.F90 +++ b/src/tracer/RGC_tracer.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This module contains the routines used to set up a !! dynamically passive tracer. !! Set up and use passive tracers requires the following: @@ -11,8 +15,6 @@ module RGC_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING use MOM_file_parser, only : get_param, log_param, log_version, param_file_type diff --git a/src/tracer/advection_test_tracer.F90 b/src/tracer/advection_test_tracer.F90 index 90a377de79..7a20967777 100644 --- a/src/tracer/advection_test_tracer.F90 +++ b/src/tracer/advection_test_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This tracer package is used to test advection schemes module advection_test_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/boundary_impulse_tracer.F90 b/src/tracer/boundary_impulse_tracer.F90 index 0698d7f9cc..6dd5127d94 100644 --- a/src/tracer/boundary_impulse_tracer.F90 +++ b/src/tracer/boundary_impulse_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Implements a boundary impulse response tracer to calculate Green's functions module boundary_impulse_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/dye_example.F90 b/src/tracer/dye_example.F90 index c1146e19f9..dbff568937 100644 --- a/src/tracer/dye_example.F90 +++ b/src/tracer/dye_example.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package for using dyes to diagnose regional flows. module regional_dyes -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/dyed_obc_tracer.F90 b/src/tracer/dyed_obc_tracer.F90 index 1e113f0fc5..1e1b391964 100644 --- a/src/tracer/dyed_obc_tracer.F90 +++ b/src/tracer/dyed_obc_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> This tracer package dyes flow through open boundaries module dyed_obc_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coupler_types, only : atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING diff --git a/src/tracer/ideal_age_example.F90 b/src/tracer/ideal_age_example.F90 index 147c48eebd..dca68c724d 100644 --- a/src/tracer/ideal_age_example.F90 +++ b/src/tracer/ideal_age_example.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package of ideal age tracers module ideal_age_example -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/nw2_tracers.F90 b/src/tracer/nw2_tracers.F90 index f93c6d4c69..b8dcb61326 100644 --- a/src/tracer/nw2_tracers.F90 +++ b/src/tracer/nw2_tracers.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Ideal tracers designed to help diagnose a tracer diffusivity tensor in NeverWorld2 module nw2_tracers -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl use MOM_error_handler, only : MOM_error, FATAL, WARNING use MOM_file_parser, only : get_param, log_param, log_version, param_file_type diff --git a/src/tracer/oil_tracer.F90 b/src/tracer/oil_tracer.F90 index 7a119d308c..9f6e263974 100644 --- a/src/tracer/oil_tracer.F90 +++ b/src/tracer/oil_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package to mimic dissolved oil. module oil_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/tracer/pseudo_salt_tracer.F90 b/src/tracer/pseudo_salt_tracer.F90 index b737dba5b7..4be887940a 100644 --- a/src/tracer/pseudo_salt_tracer.F90 +++ b/src/tracer/pseudo_salt_tracer.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A tracer package that mimics salinity module pseudo_salt_tracer -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_debugging, only : hchksum use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr diff --git a/src/tracer/tracer_example.F90 b/src/tracer/tracer_example.F90 index 7026670245..14011d16b9 100644 --- a/src/tracer/tracer_example.F90 +++ b/src/tracer/tracer_example.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A sample tracer package that has striped initial conditions module USER_tracer_example -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : EFP_type use MOM_coupler_types, only : set_coupler_type_data, atmos_ocn_coupler_flux use MOM_diag_mediator, only : diag_ctrl diff --git a/src/user/BFB_initialization.F90 b/src/user/BFB_initialization.F90 index 67381bfdc5..34b128522e 100644 --- a/src/user/BFB_initialization.F90 +++ b/src/user/BFB_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization of the boundary-forced-basing configuration module BFB_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/BFB_surface_forcing.F90 b/src/user/BFB_surface_forcing.F90 index fcbd66e1d8..fb4e87f51d 100644 --- a/src/user/BFB_surface_forcing.F90 +++ b/src/user/BFB_surface_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Surface forcing for the boundary-forced-basin (BFB) configuration module BFB_surface_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled use MOM_diag_mediator, only : register_diag_field, diag_ctrl use MOM_domains, only : pass_var, pass_vector, AGRID diff --git a/src/user/DOME2d_initialization.F90 b/src/user/DOME2d_initialization.F90 index 3903290212..96cb779eb5 100644 --- a/src/user/DOME2d_initialization.F90 +++ b/src/user/DOME2d_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization of the 2D DOME experiment with density water initialized on a coastal shelf. module DOME2d_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ALE_sponge, only : ALE_sponge_CS, set_up_ALE_sponge_field, initialize_ALE_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL diff --git a/src/user/DOME_initialization.F90 b/src/user/DOME_initialization.F90 index 229ab2785d..d7e6c1cd6a 100644 --- a/src/user/DOME_initialization.F90 +++ b/src/user/DOME_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the "DOME" experiment. !! DOME = Dynamics of Overflows and Mixing Experiment module DOME_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/user/ISOMIP_initialization.F90 b/src/user/ISOMIP_initialization.F90 index 4bf7931856..e93d0604f0 100644 --- a/src/user/ISOMIP_initialization.F90 +++ b/src/user/ISOMIP_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the ISOMIP test case. module ISOMIP_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ALE_sponge, only : ALE_sponge_CS, set_up_ALE_sponge_field, initialize_ALE_sponge use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type diff --git a/src/user/Idealized_Hurricane.F90 b/src/user/Idealized_Hurricane.F90 index 635f94d940..fe37fd4e67 100644 --- a/src/user/Idealized_Hurricane.F90 +++ b/src/user/Idealized_Hurricane.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Forcing for the idealized hurricane and SCM_idealized_hurricane examples. module Idealized_hurricane -! This file is part of MOM6. See LICENSE.md for the license. - ! History !-------- ! November 2014: Origination. diff --git a/src/user/Kelvin_initialization.F90 b/src/user/Kelvin_initialization.F90 index d8dbab62af..bbd6ffa4a5 100644 --- a/src/user/Kelvin_initialization.F90 +++ b/src/user/Kelvin_initialization.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the Kelvin wave experiment. !! !! Kelvin = coastally-trapped Kelvin waves from the ROMS examples. @@ -5,8 +9,6 @@ !! radiate out at the east. module Kelvin_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/MOM_controlled_forcing.F90 b/src/user/MOM_controlled_forcing.F90 index cd7389b961..68e2eb4265 100644 --- a/src/user/MOM_controlled_forcing.F90 +++ b/src/user/MOM_controlled_forcing.F90 @@ -1,3 +1,7 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Use control-theory to adjust the surface heat flux and precipitation. !! !! Adjustments are based on the time-mean or periodically (seasonally) varying @@ -6,8 +10,6 @@ !! The techniques behind this are described in Hallberg and Adcroft (2018, in prep.). module MOM_controlled_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled, enable_averages, disable_averaging use MOM_diag_mediator, only : register_diag_field, diag_ctrl, safe_alloc_ptr use MOM_domains, only : pass_var, pass_vector, AGRID, To_South, To_West, To_All diff --git a/src/user/MOM_wave_interface.F90 b/src/user/MOM_wave_interface.F90 index bbb3b6ce83..d7ce6cb95e 100644 --- a/src/user/MOM_wave_interface.F90 +++ b/src/user/MOM_wave_interface.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Interface for surface waves module MOM_wave_interface -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_data_override, only : data_override_init, data_override use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_alloc use MOM_diag_mediator, only : diag_ctrl diff --git a/src/user/Neverworld_initialization.F90 b/src/user/Neverworld_initialization.F90 index ba8263ca1c..c67237a048 100644 --- a/src/user/Neverworld_initialization.F90 +++ b/src/user/Neverworld_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the "Neverworld" configuration module Neverworld_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe diff --git a/src/user/Phillips_initialization.F90 b/src/user/Phillips_initialization.F90 index 4a115031e1..3b20be4f34 100644 --- a/src/user/Phillips_initialization.F90 +++ b/src/user/Phillips_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the "Phillips" channel configuration module Phillips_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/RGC_initialization.F90 b/src/user/RGC_initialization.F90 index 95fe3bf35f..418f739242 100644 --- a/src/user/RGC_initialization.F90 +++ b/src/user/RGC_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the models sponges for the Rotating Gravity Current (RGC) experiment. module RGC_initialization -! This file is part of MOM6. See LICENSE.md for the license. - !*********************************************************************** !* By Elizabeth Yankovsky, May 2018 * !*********************************************************************** diff --git a/src/user/Rossby_front_2d_initialization.F90 b/src/user/Rossby_front_2d_initialization.F90 index 05a223cfb9..ffc7610391 100644 --- a/src/user/Rossby_front_2d_initialization.F90 +++ b/src/user/Rossby_front_2d_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initial conditions for the 2D Rossby front test module Rossby_front_2d_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/SCM_CVMix_tests.F90 b/src/user/SCM_CVMix_tests.F90 index def4c59568..dc026b5a38 100644 --- a/src/user/SCM_CVMix_tests.F90 +++ b/src/user/SCM_CVMix_tests.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initial conditions and forcing for the single column model (SCM) CVMix test set. module SCM_CVMix_tests -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : pass_var, pass_vector, TO_ALL use MOM_error_handler, only : MOM_error, FATAL use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/adjustment_initialization.F90 b/src/user/adjustment_initialization.F90 index 4a1d6c3d9f..5e60f33057 100644 --- a/src/user/adjustment_initialization.F90 +++ b/src/user/adjustment_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the geostrophic adjustment test case. module adjustment_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/baroclinic_zone_initialization.F90 b/src/user/baroclinic_zone_initialization.F90 index e2c6182231..f50c103583 100644 --- a/src/user/baroclinic_zone_initialization.F90 +++ b/src/user/baroclinic_zone_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initial conditions for an idealized baroclinic zone module baroclinic_zone_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_file_parser, only : openParameterBlock, closeParameterBlock use MOM_grid, only : ocean_grid_type diff --git a/src/user/basin_builder.F90 b/src/user/basin_builder.F90 index 721b0b33cc..67afd0e6ba 100644 --- a/src/user/basin_builder.F90 +++ b/src/user/basin_builder.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> An idealized topography building system module basin_builder -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/benchmark_initialization.F90 b/src/user/benchmark_initialization.F90 index 333f53895e..6685c75305 100644 --- a/src/user/benchmark_initialization.F90 +++ b/src/user/benchmark_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the "bench mark" configuration module benchmark_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe diff --git a/src/user/circle_obcs_initialization.F90 b/src/user/circle_obcs_initialization.F90 index 98b5bd4705..26e26d0a44 100644 --- a/src/user/circle_obcs_initialization.F90 +++ b/src/user/circle_obcs_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the "circle_obcs" experiment which tests !! Open Boundary Conditions radiating an SSH anomaly. module circle_obcs_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/dense_water_initialization.F90 b/src/user/dense_water_initialization.F90 index fbff153e23..c8ee29f8f4 100644 --- a/src/user/dense_water_initialization.F90 +++ b/src/user/dense_water_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization routines for the dense water formation !! and overflow experiment. module dense_water_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_ALE_sponge, only : ALE_sponge_CS, set_up_ALE_sponge_field, initialize_ALE_sponge use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_EOS, only : EOS_type diff --git a/src/user/dumbbell_initialization.F90 b/src/user/dumbbell_initialization.F90 index 04af1d2d5b..df286716f0 100644 --- a/src/user/dumbbell_initialization.F90 +++ b/src/user/dumbbell_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the idealized dumbbell test case. module dumbbell_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : sum_across_PEs use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe diff --git a/src/user/dumbbell_surface_forcing.F90 b/src/user/dumbbell_surface_forcing.F90 index 288ccd89fa..2b09631151 100644 --- a/src/user/dumbbell_surface_forcing.F90 +++ b/src/user/dumbbell_surface_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Surface forcing for the dumbbell test case module dumbbell_surface_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : post_data, query_averaging_enabled use MOM_diag_mediator, only : register_diag_field, diag_ctrl use MOM_domains, only : pass_var, pass_vector, AGRID diff --git a/src/user/dyed_channel_initialization.F90 b/src/user/dyed_channel_initialization.F90 index c4cf25281f..b61b9242b6 100644 --- a/src/user/dyed_channel_initialization.F90 +++ b/src/user/dyed_channel_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the dyed_channel configuration module dyed_channel_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/dyed_obcs_initialization.F90 b/src/user/dyed_obcs_initialization.F90 index ffa217e0b5..f298c6eefb 100644 --- a/src/user/dyed_obcs_initialization.F90 +++ b/src/user/dyed_obcs_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Dyed open boundary conditions; OBC_USER_CONFIG="dyed_obcs" module dyed_obcs_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/external_gwave_initialization.F90 b/src/user/external_gwave_initialization.F90 index 437edc49b2..552abe2f66 100644 --- a/src/user/external_gwave_initialization.F90 +++ b/src/user/external_gwave_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the "external gravity wave wave" configuration module external_gwave_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/lock_exchange_initialization.F90 b/src/user/lock_exchange_initialization.F90 index ab08d4068d..8f2297c730 100644 --- a/src/user/lock_exchange_initialization.F90 +++ b/src/user/lock_exchange_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization of the "lock exchange" experiment. !! lock_exchange = A 2-d density driven hydraulic exchange flow. module lock_exchange_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/seamount_initialization.F90 b/src/user/seamount_initialization.F90 index 59709ecde7..77556f123a 100644 --- a/src/user/seamount_initialization.F90 +++ b/src/user/seamount_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the idealized seamount test case. module seamount_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : sum_across_PEs use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe diff --git a/src/user/shelfwave_initialization.F90 b/src/user/shelfwave_initialization.F90 index 93ed4b2c87..3360b29a1d 100644 --- a/src/user/shelfwave_initialization.F90 +++ b/src/user/shelfwave_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the idealized shelfwave test case. module shelfwave_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : sum_across_PEs use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/user/sloshing_initialization.F90 b/src/user/sloshing_initialization.F90 index 4381d42038..3fef6fd4e4 100644 --- a/src/user/sloshing_initialization.F90 +++ b/src/user/sloshing_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initialization for the "sloshing" internal waves configuration. module sloshing_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : sum_across_PEs use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe diff --git a/src/user/soliton_initialization.F90 b/src/user/soliton_initialization.F90 index a734574995..569d6904aa 100644 --- a/src/user/soliton_initialization.F90 +++ b/src/user/soliton_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Initial conditions for the Equatorial Rossby soliton test (Boyd). module soliton_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type use MOM_get_input, only : directories diff --git a/src/user/supercritical_initialization.F90 b/src/user/supercritical_initialization.F90 index 4d4bd68f84..526e3a8a10 100644 --- a/src/user/supercritical_initialization.F90 +++ b/src/user/supercritical_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> The "super critical" configuration module supercritical_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/tidal_bay_initialization.F90 b/src/user/tidal_bay_initialization.F90 index 24aefe2bb1..abd60c53ff 100644 --- a/src/user/tidal_bay_initialization.F90 +++ b/src/user/tidal_bay_initialization.F90 @@ -1,9 +1,11 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Configures the model for the "tidal_bay" experiment. !! tidal_bay = Tidally resonant bay from Zygmunt Kowalik's class on tides. module tidal_bay_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_coms, only : reproducing_sum use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, WARNING, is_root_pe diff --git a/src/user/user_change_diffusivity.F90 b/src/user/user_change_diffusivity.F90 index 1a1881a42b..fcd94442a3 100644 --- a/src/user/user_change_diffusivity.F90 +++ b/src/user/user_change_diffusivity.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Increments the diapycnal diffusivity in a specified band of latitudes and densities. module user_change_diffusivity -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_diag_mediator, only : diag_ctrl, time_type use MOM_error_handler, only : MOM_error, is_root_pe, FATAL, WARNING, NOTE use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/user_initialization.F90 b/src/user/user_initialization.F90 index 207f009c9c..390b42bd84 100644 --- a/src/user/user_initialization.F90 +++ b/src/user/user_initialization.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> A template of a user to code up customized initial conditions. module user_initialization -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe use MOM_dyn_horgrid, only : dyn_horgrid_type use MOM_file_parser, only : get_param, log_version, param_file_type diff --git a/src/user/user_revise_forcing.F90 b/src/user/user_revise_forcing.F90 index ce767d7479..db0df72f19 100644 --- a/src/user/user_revise_forcing.F90 +++ b/src/user/user_revise_forcing.F90 @@ -1,8 +1,10 @@ +! This file is part of MOM6, the Modular Ocean Model version 6. +! See the LICENSE file for licensing information. +! SPDX-License-Identifier: Apache-2.0 + !> Provides a template for users to code updating the forcing fluxes. module user_revise_forcing -! This file is part of MOM6. See LICENSE.md for the license. - use MOM_domains, only : pass_var, pass_vector, AGRID use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe use MOM_file_parser, only : get_param, log_version, param_file_type From 9f622bfd70490e4004eb3c7adb9b74892cfb8e82 Mon Sep 17 00:00:00 2001 From: Alper Altuntas Date: Thu, 9 Apr 2026 14:29:06 -0600 Subject: [PATCH 38/41] fix get_param STOKES_MOST and WAVE_ENHANCED_USTAR in MOM.F90 (#418) * fix get_param STOKES_MOST and WAVE_ENHANCED_USTAR in MOM.F90 by opening/closing appropriate parameter blocks * remove unnecessary comment * remove more unnecessary comment * do not log MLE block from MOM.F90 --- src/core/MOM.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index 60834838fc..0f48fc9d7c 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -36,6 +36,7 @@ module MOM use MOM_error_handler, only : MOM_set_verbosity, callTree_showQuery use MOM_error_handler, only : callTree_enter, callTree_leave, callTree_waypoint use MOM_file_parser, only : read_param, get_param, log_version, param_file_type +use MOM_file_parser, only : openParameterBlock, closeParameterBlock use MOM_forcing_type, only : forcing, mech_forcing, find_ustar use MOM_forcing_type, only : MOM_forcing_chksum, MOM_mech_forcing_chksum use MOM_get_input, only : Get_MOM_Input, directories @@ -2471,12 +2472,15 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, & call MOM_error(FATAL, "initialize_MOM: "//& "FPMIX=True only works when SPLIT=True.") endif - ! STOKES_MOST and needed to + call openParameterBlock(param_file, 'KPP', do_not_log=.true.) call get_param(param_file, '', 'STOKES_MOST', CS%StokesMOST, & 'If True, use Stokes Similarity package.', & default=.False., do_not_log=.true.) + call closeParameterBlock(param_file) + call openParameterBlock(param_file,'MLE', do_not_log=.true.) call get_param(param_file, '', "WAVE_ENHANCED_USTAR", CS%wave_enhanced_ustar, & "If true, enhance ustar in Bodner23.", default=.false., do_not_log=.true.) + call closeParameterBlock(param_file) call get_param(param_file, "MOM", "BOUSSINESQ", Boussinesq, & "If true, make the Boussinesq approximation.", default=.true., do_not_log=.true.) call get_param(param_file, "MOM", "SEMI_BOUSSINESQ", semi_Boussinesq, & From 5544903f9e29d241e9371580a9bfc8c14596b200 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Fri, 10 Apr 2026 07:58:28 -0600 Subject: [PATCH 39/41] Make sure MARBL fluxes get averaged correctly When DT_THERMO is larger than the coupling interval, MOM6 stores a weighted average of fluxes used by the thermodynamics over the multiple intervals. Several forcings used for MARBL were not included in this process. Also, dust_flux and iron_flux are computed from five constituent classes (atmospheric fine / coarse dust, sea ice dust, atmospheric black carbon, and sea ice black carbon); these five fields were not being accumulated correctly in cases where DT_THERMO is larger than the coupling interval. This commit contains a first attempt at fixing that -- moving the enable_averages() call into convert_driver_fields_to_forcings() and only calling it / post_data() when flux_used = true. These diagnostics are still wrong in this commit, though. --- .../nuopc_cap/mom_ocean_model_nuopc.F90 | 8 +- .../nuopc_cap/mom_surface_forcing_nuopc.F90 | 14 ++-- src/core/MOM_forcing_type.F90 | 80 ++++++++++++++++--- src/tracer/MARBL_forcing_mod.F90 | 44 +++++----- 4 files changed, 109 insertions(+), 37 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index 87a16300ee..f4207f1d96 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -564,13 +564,13 @@ subroutine update_ocean_model(Ice_ocean_boundary, OS, Ocean_sfc, & if (OS%fluxes%fluxes_used) then - ! enable_averages() is necessary to post forcing fields to diagnostics - call enable_averages(dt_coupling, OS%Time + Ocean_coupling_time_step, OS%diag) - if (do_thermo) & call convert_IOB_to_fluxes(Ice_ocean_boundary, OS%fluxes, index_bnds, OS%Time, dt_coupling, & OS%grid, OS%US, OS%forcing_CSp, OS%sfc_state, & - OS%restore_salinity, OS%restore_temp) + OS%restore_salinity, OS%restore_temp, Ocean_coupling_time_step) + + ! enable_averages() is necessary to post forcing fields to diagnostics + call enable_averages(dt_coupling, OS%Time + Ocean_coupling_time_step, OS%diag) ! Add ice shelf fluxes if (OS%use_ice_shelf) then diff --git a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 index a32987e6a2..9af2c7255e 100644 --- a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 @@ -247,7 +247,7 @@ module MOM_surface_forcing_nuopc !! thermodynamic forcing type, including changes of units, sign conventions, !! and putting the fields into arrays with MOM-standard halos. subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, US, CS, & - sfc_state, restore_salt, restore_temp) + sfc_state, restore_salt, restore_temp, Ocean_coupling_time_step) type(ice_ocean_boundary_type), & target, intent(in) :: IOB !< An ice-ocean boundary type with fluxes to drive !! the ocean in a coupled model @@ -265,8 +265,10 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, !! previous call to surface_forcing_init. type(surface), intent(in) :: sfc_state !< A structure containing fields that describe the !! surface state of the ocean. - logical, optional, intent(in) :: restore_salt !< If true, salinity is restored to a target value. - logical, optional, intent(in) :: restore_temp !< If true, temperature is restored to a target value. + logical, optional, intent(in) :: restore_salt !< If true, salinity is restored to a target value. + logical, optional, intent(in) :: restore_temp !< If true, temperature is restored to a target value. + type(time_type), optional, intent(in) :: Ocean_coupling_time_step !< The amount of time over + !! which to advance the ocean. ! local variables real, dimension(SZI_(G),SZJ_(G)) :: & @@ -620,7 +622,8 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, IOB%seaice_dust_flux, IOB%atm_bc_flux, IOB%seaice_bc_flux, & IOB%nhx_dep, IOB%noy_dep, IOB%atm_co2_prog, IOB%atm_co2_diag, & IOB%afracr, IOB%swnet_afracr, IOB%ifrac_n, IOB%swpen_ifrac_n, & - Time, G, US, i0, j0, fluxes, CS%marbl_forcing_CSp) + Time, G, US, i0, j0, fluxes, CS%marbl_forcing_CSp, & + Ocean_coupling_time_step) ! wave to ocean coupling if ( associated(IOB%lamult)) then @@ -1468,7 +1471,8 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, restore_salt, call register_forcing_type_diags(Time, diag, US, CS%use_temperature, CS%handles, & use_berg_fluxes=iceberg_flux_diags, use_waves=use_waves, & - use_cfcs=CS%use_CFC, use_glc_runoff=glc_runoff_diags) + use_cfcs=CS%use_CFC, use_MARBL_tracers=CS%use_MARBL_tracers, & + use_glc_runoff=glc_runoff_diags) call get_param(param_file, mdl, "ALLOW_FLUX_ADJUSTMENTS", CS%allow_flux_adjustments, & "If true, allows flux adjustments to specified via the "//& diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index 1ceaa3988f..60160db3c6 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -1540,7 +1540,7 @@ end subroutine forcing_SinglePointPrint !> Register members of the forcing type for diagnostics subroutine register_forcing_type_diags(Time, diag, US, use_temperature, handles, use_berg_fluxes, use_waves, & - use_cfcs, use_glc_runoff) + use_cfcs, use_MARBL_tracers, use_glc_runoff) type(time_type), intent(in) :: Time !< time type type(diag_ctrl), intent(inout) :: diag !< diagnostic control type type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -1549,8 +1549,18 @@ subroutine register_forcing_type_diags(Time, diag, US, use_temperature, handles, logical, optional, intent(in) :: use_berg_fluxes !< If true, allow iceberg flux diagnostics logical, optional, intent(in) :: use_waves !< If true, allow wave forcing diagnostics logical, optional, intent(in) :: use_cfcs !< If true, allow cfc related diagnostics + logical, optional, intent(in) :: use_MARBL_tracers !< If true, allow MARBL related diagnostics logical, optional, intent(in) :: use_glc_runoff !< If true, allow separate glacial runoff diagnostics + logical :: use_cfcs_or_MARBL_tracers + + ! some diagnostics should be registered if either cfc or MARBL tracers are enabled + use_cfcs_or_MARBL_tracers = .false. + if (present(use_cfcs)) & + use_cfcs_or_MARBL_tracers = use_cfcs_or_MARBL_tracers .or. use_cfcs + if (present(use_MARBL_tracers)) & + use_cfcs_or_MARBL_tracers = use_cfcs_or_MARBL_tracers .or. use_MARBL_tracers + ! Clock for forcing diagnostics handles%id_clock_forcing=cpu_clock_id('(Ocean forcing diagnostics)', grain=CLOCK_ROUTINE) @@ -1599,15 +1609,12 @@ subroutine register_forcing_type_diags(Time, diag, US, use_temperature, handles, endif endif - ! See: - if (present(use_cfcs)) then - if (use_cfcs) then - handles%id_ice_fraction = register_diag_field('ocean_model', 'ice_fraction', diag%axesT1, Time, & - 'Fraction of cell area covered by sea ice', 'm2 m-2', conversion=1.0) + if (use_cfcs_or_MARBL_tracers) then + handles%id_ice_fraction = register_diag_field('ocean_model', 'ice_fraction', diag%axesT1, Time, & + 'Fraction of cell area covered by sea ice', 'm2 m-2', conversion=1.0) - handles%id_u10_sqr = register_diag_field('ocean_model', 'u10_sqr', diag%axesT1, Time, & - 'Wind magnitude at 10m, squared', 'm2 s-2', conversion=US%L_to_m**2*US%s_to_T**2) - endif + handles%id_u10_sqr = register_diag_field('ocean_model', 'u10_sqr', diag%axesT1, Time, & + 'Wind magnitude at 10m, squared', 'm2 s-2', conversion=US%L_to_m**2*US%s_to_T**2) endif handles%id_psurf = register_diag_field('ocean_model', 'p_surf', diag%axesT1, Time, & @@ -2338,7 +2345,7 @@ subroutine fluxes_accumulate(flux_tmp, fluxes, G, wt2, forces) ! applied based on the time interval stored in flux_tmp. real :: wt1 ! The relative weight of the previous fluxes [nondim] - integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq + integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq, n integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB @@ -2499,6 +2506,59 @@ subroutine fluxes_accumulate(flux_tmp, fluxes, G, wt2, forces) enddo ; enddo endif + ! Forcings introduced for MARBL + ! NOTE: fluxes%salt_flux, %sw, and %p_surf_full are handled above + if (associated(fluxes%nhx_dep) .and. associated(flux_tmp%nhx_dep)) then + do j=jsd,jed ; do i=isd,ied + fluxes%nhx_dep(i,j) = wt1*fluxes%nhx_dep(i,j) + wt2*flux_tmp%nhx_dep(i,j) + enddo ; enddo + endif + if (associated(fluxes%noy_dep) .and. associated(flux_tmp%noy_dep)) then + do j=jsd,jed ; do i=isd,ied + fluxes%noy_dep(i,j) = wt1*fluxes%noy_dep(i,j) + wt2*flux_tmp%noy_dep(i,j) + enddo ; enddo + endif + if (associated(fluxes%atm_co2) .and. associated(flux_tmp%atm_co2)) then + do j=jsd,jed ; do i=isd,ied + fluxes%atm_co2(i,j) = wt1*fluxes%atm_co2(i,j) + wt2*flux_tmp%atm_co2(i,j) + enddo ; enddo + endif + if (associated(fluxes%atm_alt_co2) .and. associated(flux_tmp%atm_alt_co2)) then + do j=jsd,jed ; do i=isd,ied + fluxes%atm_alt_co2(i,j) = wt1*fluxes%atm_alt_co2(i,j) + wt2*flux_tmp%atm_alt_co2(i,j) + enddo ; enddo + endif + if (associated(fluxes%dust_flux) .and. associated(flux_tmp%dust_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%dust_flux(i,j) = wt1*fluxes%dust_flux(i,j) + wt2*flux_tmp%dust_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%iron_flux) .and. associated(flux_tmp%iron_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%iron_flux(i,j) = wt1*fluxes%iron_flux(i,j) + wt2*flux_tmp%iron_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%fracr_cat) .and. associated(flux_tmp%fracr_cat)) then + do n=1,size(fluxes%fracr_cat,dim=3) ; do j=jsd,jed ; do i=isd,ied + fluxes%fracr_cat(i,j,n) = wt1*fluxes%fracr_cat(i,j,n) + wt2*flux_tmp%fracr_cat(i,j,n) + enddo ; enddo ; enddo + endif + if (associated(fluxes%qsw_cat) .and. associated(flux_tmp%qsw_cat)) then + do n=1,size(fluxes%qsw_cat,dim=3) ; do j=jsd,jed ; do i=isd,ied + fluxes%qsw_cat(i,j,n) = wt1*fluxes%qsw_cat(i,j,n) + wt2*flux_tmp%qsw_cat(i,j,n) + enddo ; enddo ; enddo + endif + if (associated(fluxes%ice_fraction) .and. associated(flux_tmp%ice_fraction)) then + do j=jsd,jed ; do i=isd,ied + fluxes%ice_fraction(i,j) = wt1*fluxes%ice_fraction(i,j) + wt2*flux_tmp%ice_fraction(i,j) + enddo ; enddo + endif + if (associated(fluxes%u10_sqr) .and. associated(flux_tmp%u10_sqr)) then + do j=jsd,jed ; do i=isd,ied + fluxes%u10_sqr(i,j) = wt1*fluxes%u10_sqr(i,j) + wt2*flux_tmp%u10_sqr(i,j) + enddo ; enddo + endif + if (coupler_type_initialized(fluxes%tr_fluxes) .and. & coupler_type_initialized(flux_tmp%tr_fluxes)) & call coupler_type_increment_data(flux_tmp%tr_fluxes, fluxes%tr_fluxes, & diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index 7769175e83..a6f5d08577 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -7,7 +7,8 @@ module MARBL_forcing_mod !! (This comment can go in the wiki on the NCAR fork?) use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl, register_diag_field, post_data -use MOM_time_manager, only : time_type +use MOM_diag_mediator, only : enable_averages, disable_averaging +use MOM_time_manager, only : time_type, operator(+) use MOM_error_handler, only : MOM_error, WARNING, FATAL use MOM_file_parser, only : get_param, log_param, param_file_type use MOM_grid, only : ocean_grid_type @@ -173,7 +174,8 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust seaice_dust_flux, atm_bc_flux, seaice_bc_flux, & nhx_dep, noy_dep, atm_co2_prog, atm_co2_diag, & afracr, swnet_afracr, ifrac_n, & - swpen_ifrac_n, Time, G, US, i0, j0, fluxes, CS) + swpen_ifrac_n, Time, G, US, i0, j0, fluxes, CS, & + Ocean_coupling_time_step) real, dimension(:,:), pointer, intent(in) :: atm_fine_dust_flux !< atmosphere fine dust flux from IOB !! [kg m-2 s-1] @@ -184,13 +186,13 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust !! [kg m-2 s-1] real, dimension(:,:), pointer, intent(in) :: seaice_bc_flux !< sea ice black carbon flux from IOB !! [kg m-2 s-1] - real, dimension(:,:), pointer, intent(in) :: afracr !< open ocean fraction [1] real, dimension(:,:), pointer, intent(in) :: nhx_dep !< NHx flux from atmosphere [kg m-2 s-1] real, dimension(:,:), pointer, intent(in) :: noy_dep !< NOy flux from atmosphere [kg m-2 s-1] real, dimension(:,:), pointer, intent(in) :: atm_co2_prog !< Prognostic atmospheric CO2 concentration !! [ppm] real, dimension(:,:), pointer, intent(in) :: atm_co2_diag !< Diagnostic atmospheric CO2 concentration !! [ppm] + real, dimension(:,:), pointer, intent(in) :: afracr !< open ocean fraction [1] real, dimension(:,:), pointer, intent(in) :: swnet_afracr !< shortwave flux * open ocean fraction !! [W m-2] real, dimension(:,:,:), pointer, intent(in) :: ifrac_n !< per-category ice fraction [1] @@ -207,6 +209,8 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust type(forcing), intent(inout) :: fluxes !< MARBL-specific forcing fields type(marbl_forcing_CS), pointer, intent(inout) :: CS !< A pointer that is set to point to !! control structure for MARBL forcing + type(time_type), optional, intent(in) :: Ocean_coupling_time_step !< The amount of time over + !! which to advance the ocean. integer :: i, j, is, ie, js, je, m real :: atm_fe_bioavail_frac !< Fraction of iron from the atmosphere available for biological uptake [1] @@ -227,21 +231,25 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust ! Post fields from coupler to diagnostics ! TODO: units from diag register are incorrect; we should be converting these in the cap, I think - if (CS%diag_ids%atm_fine_dust > 0) & - call post_data(CS%diag_ids%atm_fine_dust, atm_fine_dust_flux(is-i0:ie-i0,js-j0:je-j0), & - CS%diag, mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%atm_coarse_dust > 0) & - call post_data(CS%diag_ids%atm_coarse_dust, atm_coarse_dust_flux(is-i0:ie-i0,js-j0:je-j0), & - CS%diag, mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%atm_bc > 0) & - call post_data(CS%diag_ids%atm_bc, atm_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%ice_dust > 0) & - call post_data(CS%diag_ids%ice_dust, seaice_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%ice_bc > 0) & - call post_data(CS%diag_ids%ice_bc, seaice_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) + if (present(Ocean_coupling_time_step)) then + call enable_averages(fluxes%dt_buoy_accum, Time + Ocean_coupling_time_step, CS%diag) + if (CS%diag_ids%atm_fine_dust > 0) & + call post_data(CS%diag_ids%atm_fine_dust, atm_fine_dust_flux(is-i0:ie-i0,js-j0:je-j0), & + CS%diag, mask=G%mask2dT(is:ie,js:je)) + if (CS%diag_ids%atm_coarse_dust > 0) & + call post_data(CS%diag_ids%atm_coarse_dust, atm_coarse_dust_flux(is-i0:ie-i0,js-j0:je-j0), & + CS%diag, mask=G%mask2dT(is:ie,js:je)) + if (CS%diag_ids%atm_bc > 0) & + call post_data(CS%diag_ids%atm_bc, atm_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + mask=G%mask2dT(is:ie,js:je)) + if (CS%diag_ids%ice_dust > 0) & + call post_data(CS%diag_ids%ice_dust, seaice_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + mask=G%mask2dT(is:ie,js:je)) + if (CS%diag_ids%ice_bc > 0) & + call post_data(CS%diag_ids%ice_bc, seaice_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + mask=G%mask2dT(is:ie,js:je)) + call disable_averaging(CS%diag) + endif do j=js,je ; do i=is,ie ! Nitrogen Deposition From 3c15cad5ab1fef97f116b2570e2e0d82b46b6d13 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Fri, 10 Apr 2026 08:04:27 -0600 Subject: [PATCH 40/41] Move dust / iron flux constituents to forcing_type Added five new fields to forcing_type so they can be added to history files from forcing_diagnostics() with the rest of the flux fields. This fixes the issue where these fields were not being accumulated correctly when DT_THERMO was greater than the coupling interval. --- .../nuopc_cap/mom_ocean_model_nuopc.F90 | 2 +- .../nuopc_cap/mom_surface_forcing_nuopc.F90 | 11 +-- src/core/MOM_forcing_type.F90 | 82 ++++++++++++++++++- src/tracer/MARBL_forcing_mod.F90 | 73 +++-------------- 4 files changed, 98 insertions(+), 70 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index f4207f1d96..cfdfee4f96 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -567,7 +567,7 @@ subroutine update_ocean_model(Ice_ocean_boundary, OS, Ocean_sfc, & if (do_thermo) & call convert_IOB_to_fluxes(Ice_ocean_boundary, OS%fluxes, index_bnds, OS%Time, dt_coupling, & OS%grid, OS%US, OS%forcing_CSp, OS%sfc_state, & - OS%restore_salinity, OS%restore_temp, Ocean_coupling_time_step) + OS%restore_salinity, OS%restore_temp) ! enable_averages() is necessary to post forcing fields to diagnostics call enable_averages(dt_coupling, OS%Time + Ocean_coupling_time_step, OS%diag) diff --git a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 index 9af2c7255e..aac1ecbaad 100644 --- a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 @@ -247,7 +247,7 @@ module MOM_surface_forcing_nuopc !! thermodynamic forcing type, including changes of units, sign conventions, !! and putting the fields into arrays with MOM-standard halos. subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, US, CS, & - sfc_state, restore_salt, restore_temp, Ocean_coupling_time_step) + sfc_state, restore_salt, restore_temp) type(ice_ocean_boundary_type), & target, intent(in) :: IOB !< An ice-ocean boundary type with fluxes to drive !! the ocean in a coupled model @@ -265,10 +265,8 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, !! previous call to surface_forcing_init. type(surface), intent(in) :: sfc_state !< A structure containing fields that describe the !! surface state of the ocean. - logical, optional, intent(in) :: restore_salt !< If true, salinity is restored to a target value. - logical, optional, intent(in) :: restore_temp !< If true, temperature is restored to a target value. - type(time_type), optional, intent(in) :: Ocean_coupling_time_step !< The amount of time over - !! which to advance the ocean. + logical, optional, intent(in) :: restore_salt !< If true, salinity is restored to a target value. + logical, optional, intent(in) :: restore_temp !< If true, temperature is restored to a target value. ! local variables real, dimension(SZI_(G),SZJ_(G)) :: & @@ -622,8 +620,7 @@ subroutine convert_IOB_to_fluxes(IOB, fluxes, index_bounds, Time, valid_time, G, IOB%seaice_dust_flux, IOB%atm_bc_flux, IOB%seaice_bc_flux, & IOB%nhx_dep, IOB%noy_dep, IOB%atm_co2_prog, IOB%atm_co2_diag, & IOB%afracr, IOB%swnet_afracr, IOB%ifrac_n, IOB%swpen_ifrac_n, & - Time, G, US, i0, j0, fluxes, CS%marbl_forcing_CSp, & - Ocean_coupling_time_step) + Time, G, US, i0, j0, fluxes, CS%marbl_forcing_CSp) ! wave to ocean coupling if ( associated(IOB%lamult)) then diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index 60160db3c6..9da9f1b049 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -234,7 +234,12 @@ module MOM_forcing_type atm_co2 => NULL(), & !< Atmospheric CO2 Concentration [ppm] atm_alt_co2 => NULL(), & !< Alternate atmospheric CO2 Concentration [ppm] dust_flux => NULL(), & !< Flux of dust into the ocean [R Z T-1 ~> kgN m-2 s-1] - iron_flux => NULL() !< Flux of dust into the ocean [conc Z T-1 ~> conc m s-1] + iron_flux => NULL(), & !< Flux of dust into the ocean [conc Z T-1 ~> conc m s-1] + atm_fine_dust_flux => NULL(), & !< Fine dust flux from atmosphere [R Z T-1 ~> kg m-2 s-1] + atm_coarse_dust_flux => NULL(), & !< Coarse dust flux from atmosphere [R Z T-1 ~> kg m-2 s-1] + seaice_dust_flux => NULL(), & !< Dust flux from seaice [R Z T-1 ~> kg m-2 s-1] + atm_bc_flux => NULL(), & !< Black carbon flux from atmosphere [R Z T-1 ~> kg m-2 s-1] + seaice_bc_flux => NULL() !< Black carbon flux from seaice [R Z T-1 ~> kg m-2 s-1] real, pointer, dimension(:,:,:) :: & fracr_cat => NULL(), & !< per-category ice fraction [nondim] @@ -421,6 +426,11 @@ module MOM_forcing_type ! tracer surface flux related diagnostics handles integer :: id_ice_fraction = -1 integer :: id_u10_sqr = -1 + integer :: id_atm_fine_dust_flux = -1 + integer :: id_atm_coarse_dust_flux = -1 + integer :: id_atm_bc_flux = -1 + integer :: id_seaice_dust_flux = -1 + integer :: id_seaice_bc_flux = -1 ! iceberg diagnostic handles integer :: id_ustar_berg = -1 @@ -1617,6 +1627,26 @@ subroutine register_forcing_type_diags(Time, diag, US, use_temperature, handles, 'Wind magnitude at 10m, squared', 'm2 s-2', conversion=US%L_to_m**2*US%s_to_T**2) endif + if (present(use_MARBL_tracers)) then + if (use_MARBL_tracers) then + handles%id_atm_fine_dust_flux = register_diag_field('ocean_model', 'ATM_FINE_DUST_FLUX_CPL', & + diag%axesT1, Time, 'ATM_FINE_DUST_FLUX from cpl', 'kg m-2 s', & + conversion=US%RZ_T_to_kg_m2s) + handles%id_atm_coarse_dust_flux = register_diag_field('ocean_model', 'ATM_COARSE_DUST_FLUX_CPL', & + diag%axesT1, Time, 'ATM_COARSE_DUST_FLUX from cpl', 'kg m-2 s', & + conversion=US%RZ_T_to_kg_m2s) + handles%id_atm_bc_flux = register_diag_field('ocean_model', 'ATM_BLACK_CARBON_FLUX_CPL', & + diag%axesT1, Time, 'ATM_BLACK_CARBON_FLUX from cpl', 'kg m-2 s', & + conversion=US%RZ_T_to_kg_m2s) + + handles%id_seaice_dust_flux = register_diag_field('ocean_model', 'SEAICE_DUST_FLUX_CPL', & + diag%axesT1, Time, 'SEAICE_DUST_FLUX from cpl', 'kg m-2 s', & + conversion=US%RZ_T_to_kg_m2s) + handles%id_seaice_bc_flux = register_diag_field('ocean_model', 'SEAICE_BLACK_CARBON_FLUX_CPL', & + diag%axesT1, Time, 'SEAICE_BLACK_CARBON_FLUX from cpl', 'kg m-2 s', & + conversion=US%RZ_T_to_kg_m2s) + end if + end if handles%id_psurf = register_diag_field('ocean_model', 'p_surf', diag%axesT1, Time, & 'Pressure at ice-ocean or atmosphere-ocean interface', & 'Pa', conversion=US%RL2_T2_to_Pa, cmor_field_name='pso', & @@ -2538,6 +2568,31 @@ subroutine fluxes_accumulate(flux_tmp, fluxes, G, wt2, forces) fluxes%iron_flux(i,j) = wt1*fluxes%iron_flux(i,j) + wt2*flux_tmp%iron_flux(i,j) enddo ; enddo endif + if (associated(fluxes%atm_fine_dust_flux) .and. associated(flux_tmp%atm_fine_dust_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%atm_fine_dust_flux(i,j) = wt1*fluxes%atm_fine_dust_flux(i,j) + wt2*flux_tmp%atm_fine_dust_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%atm_coarse_dust_flux) .and. associated(flux_tmp%atm_coarse_dust_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%atm_coarse_dust_flux(i,j) = wt1*fluxes%atm_coarse_dust_flux(i,j) + wt2*flux_tmp%atm_coarse_dust_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%atm_bc_flux) .and. associated(flux_tmp%atm_bc_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%atm_bc_flux(i,j) = wt1*fluxes%atm_bc_flux(i,j) + wt2*flux_tmp%atm_bc_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%seaice_dust_flux) .and. associated(flux_tmp%seaice_dust_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%seaice_dust_flux(i,j) = wt1*fluxes%seaice_dust_flux(i,j) + wt2*flux_tmp%seaice_dust_flux(i,j) + enddo ; enddo + endif + if (associated(fluxes%seaice_bc_flux) .and. associated(flux_tmp%seaice_bc_flux)) then + do j=jsd,jed ; do i=isd,ied + fluxes%seaice_bc_flux(i,j) = wt1*fluxes%seaice_bc_flux(i,j) + wt2*flux_tmp%seaice_bc_flux(i,j) + enddo ; enddo + endif if (associated(fluxes%fracr_cat) .and. associated(flux_tmp%fracr_cat)) then do n=1,size(fluxes%fracr_cat,dim=3) ; do j=jsd,jed ; do i=isd,ied fluxes%fracr_cat(i,j,n) = wt1*fluxes%fracr_cat(i,j,n) + wt2*flux_tmp%fracr_cat(i,j,n) @@ -3426,6 +3481,21 @@ subroutine forcing_diagnostics(fluxes_in, sfc_state, G_in, US, time_end, diag, h if ((handles%id_u10_sqr > 0) .and. associated(fluxes%u10_sqr)) & call post_data(handles%id_u10_sqr, fluxes%u10_sqr, diag) + if ((handles%id_atm_fine_dust_flux > 0) .and. associated(fluxes%atm_fine_dust_flux)) & + call post_data(handles%id_atm_fine_dust_flux, fluxes%atm_fine_dust_flux, diag) + + if ((handles%id_atm_coarse_dust_flux > 0) .and. associated(fluxes%atm_coarse_dust_flux)) & + call post_data(handles%id_atm_coarse_dust_flux, fluxes%atm_coarse_dust_flux, diag) + + if ((handles%id_atm_bc_flux > 0) .and. associated(fluxes%atm_bc_flux)) & + call post_data(handles%id_atm_bc_flux, fluxes%atm_bc_flux, diag) + + if ((handles%id_seaice_dust_flux > 0) .and. associated(fluxes%seaice_dust_flux)) & + call post_data(handles%id_seaice_dust_flux, fluxes%seaice_dust_flux, diag) + + if ((handles%id_seaice_bc_flux > 0) .and. associated(fluxes%seaice_bc_flux)) & + call post_data(handles%id_seaice_bc_flux, fluxes%seaice_bc_flux, diag) + ! remaining boundary terms ================================================== if ((handles%id_psurf > 0) .and. associated(fluxes%p_surf)) & @@ -3595,6 +3665,11 @@ subroutine allocate_forcing_by_group(G, fluxes, water, heat, ustar, press, & call myAlloc(fluxes%atm_alt_co2,isd,ied,jsd,jed, marbl) call myAlloc(fluxes%dust_flux,isd,ied,jsd,jed, marbl) call myAlloc(fluxes%iron_flux,isd,ied,jsd,jed, marbl) + call myAlloc(fluxes%atm_fine_dust_flux,isd,ied,jsd,jed, marbl) + call myAlloc(fluxes%atm_coarse_dust_flux,isd,ied,jsd,jed, marbl) + call myAlloc(fluxes%atm_bc_flux,isd,ied,jsd,jed, marbl) + call myAlloc(fluxes%seaice_dust_flux,isd,ied,jsd,jed, marbl) + call myAlloc(fluxes%seaice_bc_flux,isd,ied,jsd,jed, marbl) ! These fields should only be allocated when receiving multiple ice categories if (present(ice_ncat)) then @@ -3901,6 +3976,11 @@ subroutine deallocate_forcing_type(fluxes) if (associated(fluxes%atm_alt_co2)) deallocate(fluxes%atm_alt_co2) if (associated(fluxes%dust_flux)) deallocate(fluxes%dust_flux) if (associated(fluxes%iron_flux)) deallocate(fluxes%iron_flux) + if (associated(fluxes%atm_fine_dust_flux)) deallocate(fluxes%atm_fine_dust_flux) + if (associated(fluxes%atm_coarse_dust_flux)) deallocate(fluxes%atm_coarse_dust_flux) + if (associated(fluxes%atm_bc_flux)) deallocate(fluxes%atm_bc_flux) + if (associated(fluxes%seaice_dust_flux)) deallocate(fluxes%seaice_dust_flux) + if (associated(fluxes%seaice_bc_flux)) deallocate(fluxes%seaice_bc_flux) if (associated(fluxes%fracr_cat)) deallocate(fluxes%fracr_cat) if (associated(fluxes%qsw_cat)) deallocate(fluxes%qsw_cat) diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index a6f5d08577..0ed00b8774 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -6,9 +6,8 @@ module MARBL_forcing_mod !! for passing forcing fields to MARBL !! (This comment can go in the wiki on the NCAR fork?) -use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl, register_diag_field, post_data -use MOM_diag_mediator, only : enable_averages, disable_averaging -use MOM_time_manager, only : time_type, operator(+) +use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl +use MOM_time_manager, only : time_type use MOM_error_handler, only : MOM_error, WARNING, FATAL use MOM_file_parser, only : get_param, log_param, param_file_type use MOM_grid, only : ocean_grid_type @@ -25,16 +24,6 @@ module MARBL_forcing_mod public :: MARBL_forcing_init public :: convert_driver_fields_to_forcings -!> Data type used to store diagnostic index returned from register_diag_field() -!! For the forcing fields that can be written via post_data() -type, private :: marbl_forcing_diag_ids - integer :: atm_fine_dust !< Atmospheric fine dust component of dust_flux - integer :: atm_coarse_dust !< Atmospheric coarse dust component of dust_flux - integer :: atm_bc !< Atmospheric black carbon component of iron_flux - integer :: ice_dust !< Sea-ice dust component of dust_flux - integer :: ice_bc !< Sea-ice black carbon component of iron_flux -end type marbl_forcing_diag_ids - !> Control structure for this module type, public :: marbl_forcing_CS ; private type(diag_ctrl), pointer :: diag => NULL() !< A structure that is used to @@ -51,8 +40,6 @@ module MARBL_forcing_mod real :: atm_alt_co2_const !< alternate atmospheric CO2 for _ALT_CO2 tracers !! (if specifying a constant value) [ppm] - type(marbl_forcing_diag_ids) :: diag_ids !< used for registering and posting some MARBL forcing fields as diagnostics - logical :: use_MARBL_tracers !< most functions can return immediately !! MARBL tracers are turned off integer :: atm_co2_iopt !< Integer version of atm_co2_opt, which determines source of atm_co2 @@ -147,26 +134,6 @@ subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_MARBL_ default=284.317, units="ppm") endif - ! Register diagnostic fields for outputing forcing values - ! These fields are posted from convert_driver_fields_to_forcings(), and they are received - ! in physical units so no conversion is necessary here. - CS%diag_ids%atm_fine_dust = register_diag_field("ocean_model", "ATM_FINE_DUST_FLUX_CPL", & - CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_FINE_DUST_FLUX from cpl", "kg/m^2/s") - CS%diag_ids%atm_coarse_dust = register_diag_field("ocean_model", "ATM_COARSE_DUST_FLUX_CPL", & - CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_COARSE_DUST_FLUX from cpl", "kg/m^2/s") - CS%diag_ids%atm_bc = register_diag_field("ocean_model", "ATM_BLACK_CARBON_FLUX_CPL", & - CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_BLACK_CARBON_FLUX from cpl", "kg/m^2/s") - - CS%diag_ids%ice_dust = register_diag_field("ocean_model", "SEAICE_DUST_FLUX_CPL", & - CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "SEAICE_DUST_FLUX from cpl", "kg/m^2/s") - CS%diag_ids%ice_bc = register_diag_field("ocean_model", "SEAICE_BLACK_CARBON_FLUX_CPL", & - CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "SEAICE_BLACK_CARBON_FLUX from cpl", "kg/m^2/s") - end subroutine MARBL_forcing_init ! Note: ice fraction and u10_sqr are handled in mom_surface_forcing because of CFCs @@ -174,8 +141,7 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust seaice_dust_flux, atm_bc_flux, seaice_bc_flux, & nhx_dep, noy_dep, atm_co2_prog, atm_co2_diag, & afracr, swnet_afracr, ifrac_n, & - swpen_ifrac_n, Time, G, US, i0, j0, fluxes, CS, & - Ocean_coupling_time_step) + swpen_ifrac_n, Time, G, US, i0, j0, fluxes, CS) real, dimension(:,:), pointer, intent(in) :: atm_fine_dust_flux !< atmosphere fine dust flux from IOB !! [kg m-2 s-1] @@ -209,8 +175,6 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust type(forcing), intent(inout) :: fluxes !< MARBL-specific forcing fields type(marbl_forcing_CS), pointer, intent(inout) :: CS !< A pointer that is set to point to !! control structure for MARBL forcing - type(time_type), optional, intent(in) :: Ocean_coupling_time_step !< The amount of time over - !! which to advance the ocean. integer :: i, j, is, ie, js, je, m real :: atm_fe_bioavail_frac !< Fraction of iron from the atmosphere available for biological uptake [1] @@ -229,29 +193,16 @@ subroutine convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust ndep_conversion = (1.e6/14.) * (US%m_to_Z * US%T_to_s) iron_flux_conversion = (1.e6 / molw_Fe) * (US%m_to_Z * US%T_to_s) - ! Post fields from coupler to diagnostics - ! TODO: units from diag register are incorrect; we should be converting these in the cap, I think - if (present(Ocean_coupling_time_step)) then - call enable_averages(fluxes%dt_buoy_accum, Time + Ocean_coupling_time_step, CS%diag) - if (CS%diag_ids%atm_fine_dust > 0) & - call post_data(CS%diag_ids%atm_fine_dust, atm_fine_dust_flux(is-i0:ie-i0,js-j0:je-j0), & - CS%diag, mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%atm_coarse_dust > 0) & - call post_data(CS%diag_ids%atm_coarse_dust, atm_coarse_dust_flux(is-i0:ie-i0,js-j0:je-j0), & - CS%diag, mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%atm_bc > 0) & - call post_data(CS%diag_ids%atm_bc, atm_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%ice_dust > 0) & - call post_data(CS%diag_ids%ice_dust, seaice_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%ice_bc > 0) & - call post_data(CS%diag_ids%ice_bc, seaice_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - call disable_averaging(CS%diag) - endif - do j=js,je ; do i=is,ie + ! Components of dust flux + fluxes%atm_fine_dust_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * atm_fine_dust_flux(i-i0,j-j0) + fluxes%atm_coarse_dust_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * atm_coarse_dust_flux(i-i0,j-j0) + fluxes%seaice_dust_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * seaice_dust_flux(i-i0,j-j0) + + ! Components of black carbon flux + fluxes%atm_bc_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * atm_bc_flux(i-i0,j-j0) + fluxes%seaice_bc_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * seaice_bc_flux(i-i0,j-j0) + ! Nitrogen Deposition fluxes%nhx_dep(i,j) = (G%mask2dT(i,j) * ndep_conversion) * nhx_dep(i-i0,j-j0) fluxes%noy_dep(i,j) = (G%mask2dT(i,j) * ndep_conversion) * noy_dep(i-i0,j-j0) From da74cad0b1363068154631ba20c9ad3c29b3795f Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Mon, 13 Apr 2026 09:40:37 -0600 Subject: [PATCH 41/41] Remove enable_averages() in update_ocean_model() I had added enable_averages() when I put some post_data() calls in a routine called from convert_IOB_to_fluxes(), but I moved those calls to forcing_diagnostics() so we are back to not calling post_data() from this part of the code. --- config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 index cfdfee4f96..342abae563 100644 --- a/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_ocean_model_nuopc.F90 @@ -569,9 +569,6 @@ subroutine update_ocean_model(Ice_ocean_boundary, OS, Ocean_sfc, & OS%grid, OS%US, OS%forcing_CSp, OS%sfc_state, & OS%restore_salinity, OS%restore_temp) - ! enable_averages() is necessary to post forcing fields to diagnostics - call enable_averages(dt_coupling, OS%Time + Ocean_coupling_time_step, OS%diag) - ! Add ice shelf fluxes if (OS%use_ice_shelf) then if (do_thermo) &