← back to index

src/user/benchmark_initialization.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Initialization for the "bench mark" configuration
6module benchmark_initialization
7
8use MOM_sponge, only : sponge_CS, set_up_sponge_field, initialize_sponge
9use MOM_dyn_horgrid, only : dyn_horgrid_type
10use MOM_error_handler, only : MOM_mesg, MOM_error, FATAL, is_root_pe
11use MOM_file_parser, only : get_param, log_version, param_file_type
12use MOM_get_input, only : directories
13use MOM_grid, only : ocean_grid_type
14use MOM_tracer_registry, only : tracer_registry_type
15use MOM_unit_scaling, only : unit_scale_type
16use MOM_variables, only : thermo_var_ptrs
17use MOM_verticalGrid, only : verticalGrid_type
18use MOM_EOS, only : calculate_density, calculate_density_derivs, EOS_type
19
20implicit none ; private
21
22#include <MOM_memory.h>
23
24public benchmark_initialize_topography
25public benchmark_initialize_thickness
26public benchmark_init_temperature_salinity
27
28! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
29! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
30! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
31! vary with the Boussinesq approximation, the Boussinesq variant is given first.
32
33contains
34
35!> This subroutine sets up the benchmark test case topography.
361subroutine benchmark_initialize_topography(D, G, param_file, max_depth, US)
37 type(dyn_horgrid_type), intent(in) :: G !< The dynamic horizontal grid type
38 real, dimension(G%isd:G%ied,G%jsd:G%jed), &
39 intent(out) :: D !< Ocean bottom depth [Z ~> m]
40 type(param_file_type), intent(in) :: param_file !< Parameter file structure
41 real, intent(in) :: max_depth !< Maximum model depth [Z ~> m]
42 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
43
44 ! Local variables
45 real :: min_depth ! The minimum basin depth [Z ~> m]
46 real :: PI ! 3.1415926... calculated as 4*atan(1) [nondim]
47 real :: D0 ! A constant to make the maximum basin depth MAXIMUM_DEPTH [Z ~> m]
48 real :: x ! Longitude relative to the domain edge, normalized by its extent [nondim]
49 real :: y ! Latitude relative to the domain edge, normalized by its extent [nondim]
50 ! This include declares and sets the variable "version".
51# include "version_variable.h"
52 character(len=40) :: mdl = "benchmark_initialize_topography" ! This subroutine's name.
53 integer :: i, j, is, ie, js, je
541 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
55
561 call MOM_mesg(" benchmark_initialization.F90, benchmark_initialize_topography: setting topography", 5)
57
581 call log_version(param_file, mdl, version, "")
59 call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, &
601 "The minimum depth of the ocean.", units="m", default=0.0, scale=US%m_to_Z)
61
621 PI = 4.0*atan(1.0)
631 D0 = max_depth / 0.5
64
65! Calculate the depth of the bottom.
667261 do j=js,je ; do i=is,ie
677200 x = (G%geoLonT(i,j)-G%west_lon) / G%len_lon
687200 y = (G%geoLatT(i,j)-G%south_lat) / G%len_lat
69! This sets topography that has a reentrant channel to the south.
70 D(i,j) = -D0 * ( y*(1.0 + 0.6*cos(4.0*PI*x)) &
71 + 0.75*exp(-6.0*y) &
727200 + 0.05*cos(10.0*PI*x) - 0.7 )
737200 if (D(i,j) > max_depth) D(i,j) = max_depth
747260 if (D(i,j) < min_depth) D(i,j) = 0.
75 enddo ; enddo
76
771end subroutine benchmark_initialize_topography
78
79!> Initializes layer thicknesses for the benchmark test case,
80!! by finding the depths of interfaces in a specified latitude-dependent
81!! temperature profile with an exponentially decaying thermocline on top of a
82!! linear stratification.
830subroutine benchmark_initialize_thickness(h, depth_tot, G, GV, US, param_file, eqn_of_state, &
84 P_Ref, just_read)
85 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
86 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
87 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
88 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
89 intent(out) :: h !< The thickness that is being initialized [Z ~> m]
90 real, dimension(SZI_(G),SZJ_(G)), &
91 intent(in) :: depth_tot !< The nominal total depth of the ocean [Z ~> m]
92 type(param_file_type), intent(in) :: param_file !< A structure indicating the open file
93 !! to parse for model parameter values.
94 type(EOS_type), intent(in) :: eqn_of_state !< Equation of state structure
95 real, intent(in) :: P_Ref !< The coordinate-density
96 !! reference pressure [R L2 T-2 ~> Pa].
97 logical, intent(in) :: just_read !< If true, this call will
98 !! only read parameters without changing h.
99 ! Local variables
1000 real :: e0(SZK_(GV)+1) ! The resting interface heights, in depth units [Z ~> m],
101 ! usually negative because it is positive upward.
1020 real :: e_pert(SZK_(GV)+1) ! Interface height perturbations, positive upward,
103 ! in depth units [Z ~> m].
1040 real :: eta1D(SZK_(GV)+1) ! Interface height relative to the sea surface
105 ! positive upward, in depth units [Z ~> m].
106 real :: SST ! The initial sea surface temperature [C ~> degC].
107 real :: S_ref ! A default value for salinities [S ~> ppt]
108 real :: T_light ! A first guess at the temperature of the lightest layer [C ~> degC]
109 real :: T_int ! The initial temperature of an interface [C ~> degC].
110 real :: ML_depth ! The specified initial mixed layer depth, in depth units [Z ~> m].
111 real :: thermocline_scale ! The e-folding scale of the thermocline, in depth units [Z ~> m].
112 real, dimension(SZK_(GV)) :: &
1130 T0, S0, & ! Profiles of temperature [C ~> degC] and salinity [S ~> ppt]
1140 rho_guess, & ! Potential density at T0 & S0 [R ~> kg m-3].
1150 drho_dT, & ! Derivative of density with temperature [R C-1 ~> kg m-3 degC-1].
1160 drho_dS ! Derivative of density with salinity [R S-1 ~> kg m-3 ppt-1].
1170 real :: pres(SZK_(GV)) ! Reference pressure [R L2 T-2 ~> Pa].
118 real :: a_exp ! The fraction of the overall stratification that is exponential [nondim]
119 real :: I_ts, I_md ! Inverse lengthscales [Z-1 ~> m-1].
120 real :: T_frac ! A ratio of the interface temperature to the range
121 ! between SST and the bottom temperature [nondim].
122 real :: err ! The normalized error between the profile's temperature and the
123 ! interface temperature for a given z [nondim]
124 real :: derr_dz ! The derivative of the normalized error between the profile's
125 ! temperature and the interface temperature with z [Z-1 ~> m-1]
126 real :: pi ! 3.1415926... calculated as 4*atan(1) [nondim]
127 real :: z ! A work variable for the interface position [Z ~> m]
128 ! This include declares and sets the variable "version".
129# include "version_variable.h"
130 character(len=40) :: mdl = "benchmark_initialize_thickness" ! This subroutine's name.
131 integer :: i, j, k, k1, is, ie, js, je, nz, itt
132
1330 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
134
1350 if (.not.just_read) call log_version(param_file, mdl, version, "")
136 call get_param(param_file, mdl, "BENCHMARK_ML_DEPTH_IC", ML_depth, &
137 "Initial mixed layer depth in the benchmark test case.", &
1380 units='m', default=50.0, scale=US%m_to_Z, do_not_log=just_read)
139 call get_param(param_file, mdl, "BENCHMARK_THERMOCLINE_SCALE", thermocline_scale, &
140 "Initial thermocline depth scale in the benchmark test case.", &
1410 default=500.0, units="m", scale=US%m_to_Z, do_not_log=just_read)
142 call get_param(param_file, mdl, "BENCHMARK_T_LIGHT", T_light, &
143 "A first guess at the temperature of the lightest layer in the benchmark test case.", &
1440 units="degC", default=29.0, scale=US%degC_to_C, do_not_log=just_read)
145 call get_param(param_file, mdl, "S_REF", S_ref, &
146 "The uniform salinities used to initialize the benchmark test case.", &
1470 units="ppt", default=35.0, scale=US%ppt_to_S, do_not_log=just_read)
148
1490 if (just_read) return ! This subroutine has no run-time parameters.
150
1510 call MOM_mesg(" benchmark_initialization.F90, benchmark_initialize_thickness: setting thickness", 5)
152
1530 k1 = GV%nk_rho_varies + 1
154
1550 a_exp = 0.9
156
157! This block calculates T0(k) for the purpose of diagnosing where the
158! interfaces will be found.
1590 do k=1,nz
1600 pres(k) = P_Ref ; S0(k) = S_ref
161 enddo
1620 T0(k1) = T_light
1630 call calculate_density(T0(k1), S0(k1), pres(k1), rho_guess(k1), eqn_of_state)
1640 call calculate_density_derivs(T0(k1), S0(k1), pres(k1), drho_dT(k1), drho_dS(k1), eqn_of_state)
165
166! A first guess of the layers' temperatures.
1670 do k=1,nz
1680 T0(k) = T0(k1) + (GV%Rlay(k) - rho_guess(k1)) / drho_dT(k1)
169 enddo
170
171! Refine the guesses for each layer.
1720 do itt=1,6
1730 call calculate_density(T0, S0, pres, rho_guess, eqn_of_state)
1740 call calculate_density_derivs(T0, S0, pres, drho_dT, drho_dS, eqn_of_state)
1750 do k=1,nz
1760 T0(k) = T0(k) + (GV%Rlay(k) - rho_guess(k)) / drho_dT(k)
177 enddo
178 enddo
179
1800 pi = 4.0*atan(1.0)
1810 I_ts = 1.0 / thermocline_scale
1820 I_md = 1.0 / G%max_depth
1830 do j=js,je ; do i=is,ie
184 SST = 0.5*(T0(k1)+T0(nz)) - 0.9*0.5*(T0(k1)-T0(nz)) * &
1850 cos(pi*(G%geoLatT(i,j)-G%south_lat)/(G%len_lat))
186
1870 do k=1,nz ; e_pert(K) = 0.0 ; enddo
188
189 ! This sets the initial thickness (in [Z ~> m]) of the layers. The thicknesses
190 ! are set to insure that:
191 ! 1. each layer is at least GV%Angstrom_Z thick, and
192 ! 2. the interfaces are where they should be based on the resting depths and
193 ! interface height perturbations, as long at this doesn't interfere with 1.
1940 eta1D(nz+1) = -depth_tot(i,j)
195
1960 do k=nz,2,-1
1970 T_int = 0.5*(T0(k) + T0(k-1))
1980 T_frac = (T_int - T0(nz)) / (SST - T0(nz))
199 ! Find the z such that T_frac = a exp(z/thermocline_scale) + (1-a) (z+D)/D
2000 z = 0.0
2010 do itt=1,6
2020 err = a_exp * exp(z*I_ts) + (1.0 - a_exp) * (z*I_md + 1.0) - T_frac
2030 derr_dz = a_exp * I_ts * exp(z*I_ts) + (1.0 - a_exp) * I_md
2040 z = z - err / derr_dz
205 enddo
2060 e0(K) = z
207! e0(K) = -ML_depth + thermocline_scale * log((T_int - T0(nz)) / (SST - T0(nz)))
208
2090 eta1D(K) = e0(K) + e_pert(K)
210
2110 if (eta1D(K) > -ML_depth) eta1D(K) = -ML_depth
212
2130 if (eta1D(K) < eta1D(K+1) + GV%Angstrom_Z) &
2140 eta1D(K) = eta1D(K+1) + GV%Angstrom_Z
215
2160 h(i,j,k) = max(eta1D(K) - eta1D(K+1), GV%Angstrom_Z)
217 enddo
2180 h(i,j,1) = max(0.0 - eta1D(2), GV%Angstrom_Z)
219
220 enddo ; enddo
221
222end subroutine benchmark_initialize_thickness
223
224!> Initializes layer temperatures and salinities for benchmark
2250subroutine benchmark_init_temperature_salinity(T, S, G, GV, US, param_file, &
226 eqn_of_state, P_Ref, just_read)
227 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
228 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
229 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(out) :: T !< The potential temperature
230 !! that is being initialized [C ~> degC]
231 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(out) :: S !< The salinity that is being
232 !! initialized [S ~> ppt]
233 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
234 type(param_file_type), intent(in) :: param_file !< A structure indicating the
235 !! open file to parse for
236 !! model parameter values.
237 type(EOS_type), intent(in) :: eqn_of_state !< Equation of state structure
238 real, intent(in) :: P_Ref !< The coordinate-density
239 !! reference pressure [R L2 T-2 ~> Pa]
240 logical, intent(in) :: just_read !< If true, this call will only read
241 !! parameters without changing T & S.
242 ! Local variables
2430 real :: T0(SZK_(GV)) ! A profile of temperatures [C ~> degC]
2440 real :: S0(SZK_(GV)) ! A profile of salinities [S ~> ppt]
245 real :: S_ref ! A default value for salinities [S ~> ppt]
246 real :: T_light ! A first guess at the temperature of the lightest layer [C ~> degC]
2470 real :: pres(SZK_(GV)) ! Reference pressure [R L2 T-2 ~> Pa]
2480 real :: drho_dT(SZK_(GV)) ! Derivative of density with temperature [R C-1 ~> kg m-3 degC-1]
2490 real :: drho_dS(SZK_(GV)) ! Derivative of density with salinity [R S-1 ~> kg m-3 ppt-1]
2500 real :: rho_guess(SZK_(GV)) ! Potential density at T0 & S0 [R ~> kg m-3]
251 real :: PI ! 3.1415926... calculated as 4*atan(1) [nondim]
252 real :: SST ! The initial sea surface temperature [C ~> degC]
253 character(len=40) :: mdl = "benchmark_init_temperature_salinity" ! This subroutine's name.
254 integer :: i, j, k, k1, is, ie, js, je, nz, itt
255
2560 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
257
258 call get_param(param_file, mdl, "S_REF", S_ref, &
2590 units="ppt", default=35.0, scale=US%ppt_to_S, do_not_log=.true.)
260 call get_param(param_file, mdl, "BENCHMARK_T_LIGHT", T_light, &
2610 units="degC", default=29.0, scale=US%degC_to_C, do_not_log=.true.)
262
2630 if (just_read) return ! All run-time parameters have been read, so return.
264
2650 k1 = GV%nk_rho_varies + 1
266
2670 do k=1,nz
2680 pres(k) = P_Ref ; S0(k) = S_ref
269 enddo
270
2710 T0(k1) = T_light
2720 call calculate_density(T0(k1), S0(k1), pres(k1), rho_guess(k1), eqn_of_state)
2730 call calculate_density_derivs(T0, S0, pres, drho_dT, drho_dS, eqn_of_state, (/k1,k1/) )
274
275! A first guess of the layers' temperatures. !
2760 do k=1,nz
2770 T0(k) = T0(k1) + (GV%Rlay(k) - rho_guess(k1)) / drho_dT(k1)
278 enddo
279
280! Refine the guesses for each layer. !
2810 do itt = 1,6
2820 call calculate_density(T0, S0, pres, rho_guess, eqn_of_state)
2830 call calculate_density_derivs(T0, S0, pres, drho_dT, drho_dS, eqn_of_state)
2840 do k=1,nz
2850 T0(k) = T0(k) + (GV%Rlay(k) - rho_guess(k)) / drho_dT(k)
286 enddo
287 enddo
288
2890 do k=1,nz ; do j=js,je ; do i=is,ie
2900 T(i,j,k) = T0(k)
2910 S(i,j,k) = S0(k)
292 enddo ; enddo ; enddo
2930 PI = 4.0*atan(1.0)
2940 do j=js,je ; do i=is,ie
295 SST = 0.5*(T0(k1)+T0(nz)) - 0.9*0.5*(T0(k1)-T0(nz)) * &
2960 cos(PI*(G%geoLatT(i,j)-G%south_lat)/(G%len_lat))
2970 do k=1,k1-1
2980 T(i,j,k) = SST
299 enddo
300 enddo ; enddo
301
302end subroutine benchmark_init_temperature_salinity
303
304end module benchmark_initialization