← back to index

src/core/MOM_PressureForce_Montgomery.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!> Provides the Montgomery potential form of pressure gradient
6module MOM_PressureForce_Mont
7
8use MOM_density_integrals, only : int_specific_vol_dp
9use MOM_diag_mediator, only : post_data, register_diag_field
10use MOM_diag_mediator, only : safe_alloc_ptr, diag_ctrl, time_type
11use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, is_root_pe
12use MOM_file_parser, only : get_param, log_param, log_version, param_file_type
13use MOM_grid, only : ocean_grid_type
14use MOM_self_attr_load, only : calc_SAL, SAL_CS
15use MOM_tidal_forcing, only : calc_tidal_forcing, tidal_forcing_CS
16use MOM_unit_scaling, only : unit_scale_type
17use MOM_variables, only : thermo_var_ptrs
18use MOM_verticalGrid, only : verticalGrid_type
19use MOM_EOS, only : calculate_density, calculate_density_derivs
20use MOM_EOS, only : query_compressible
21
22implicit none ; private
23
24#include <MOM_memory.h>
25
26public PressureForce_Mont_Bouss, PressureForce_Mont_nonBouss, Set_pbce_Bouss
27public Set_pbce_nonBouss, PressureForce_Mont_init
28
29! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
30! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
31! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
32! vary with the Boussinesq approximation, the Boussinesq variant is given first.
33
34!> Control structure for the Montgomery potential form of pressure gradient
35type, public :: PressureForce_Mont_CS ; private
36 logical :: initialized = .false. !< True if this control structure has been initialized.
37 logical :: calculate_SAL !< If true, calculate self-attraction and loading.
38 logical :: tides !< If true, apply tidal momentum forcing.
39 real :: Rho0 !< The density used in the Boussinesq
40 !! approximation [R ~> kg m-3].
41 real :: GFS_scale !< Ratio between gravity applied to top interface and the
42 !! gravitational acceleration of the planet [nondim].
43 !! Usually this ratio is 1.
44 type(time_type), pointer :: Time => NULL() !< A pointer to the ocean model's clock.
45 type(diag_ctrl), pointer :: diag => NULL() !< A structure that is used to regulate
46 !! the timing of diagnostic output.
47 real, allocatable :: PFu_bc(:,:,:) !< Zonal accelerations due to pressure gradients
48 !! deriving from density gradients within layers [L T-2 ~> m s-2].
49 real, allocatable :: PFv_bc(:,:,:) !< Meridional accelerations due to pressure gradients
50 !! deriving from density gradients within layers [L T-2 ~> m s-2].
51 !>@{ Diagnostic IDs
52 integer :: id_PFu_bc = -1, id_PFv_bc = -1, id_e_sal = -1
53 integer :: id_e_tide = -1, id_e_tide_eq = -1, id_e_tide_sal = -1
54 !>@}
55 type(SAL_CS), pointer :: SAL_CSp => NULL() !< SAL control structure
56 type(tidal_forcing_CS), pointer :: tides_CSp => NULL() !< The tidal forcing control structure
57end type PressureForce_Mont_CS
58
59contains
60
61!> \brief Non-Boussinesq Montgomery-potential form of pressure gradient
62!!
63!! Determines the acceleration due to pressure forces in a
64!! non-Boussinesq fluid using the compressibility compensated (if appropriate)
65!! Montgomery-potential form described in Hallberg (Ocean Mod., 2005).
66!!
67!! To work, the following fields must be set outside of the usual (is:ie,js:je)
68!! range before this subroutine is called:
69!! h(isB:ie+1,jsB:je+1), T(isB:ie+1,jsB:je+1), and S(isB:ie+1,jsB:je+1).
700subroutine PressureForce_Mont_nonBouss(h, tv, PFu, PFv, G, GV, US, CS, p_atm, pbce, eta)
71 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure.
72 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
73 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
74 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thickness, [H ~> kg m-2].
75 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables.
76 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(out) :: PFu !< Zonal acceleration due to pressure gradients
77 !! (equal to -dM/dx) [L T-2 ~> m s-2].
78 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(out) :: PFv !< Meridional acceleration due to pressure gradients
79 !! (equal to -dM/dy) [L T-2 ~> m s-2].
80 type(PressureForce_Mont_CS), intent(inout) :: CS !< Control structure for Montgomery potential PGF
81 real, dimension(:,:), pointer :: p_atm !< The pressure at the ice-ocean or
82 !! atmosphere-ocean [R L2 T-2 ~> Pa].
83 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
84 optional, intent(out) :: pbce !< The baroclinic pressure anomaly in
85 !! each layer due to free surface height anomalies,
86 !! [L2 T-2 H-1 ~> m s-2 or m4 kg-1 s-2].
87 real, dimension(SZI_(G),SZJ_(G)), optional, intent(out) :: eta !< The total column mass used to calculate
88 !! PFu and PFv [H ~> kg m-2].
89 ! Local variables
90 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
910 M, & ! The Montgomery potential, M = (p/rho + gz) [L2 T-2 ~> m2 s-2].
920 alpha_star, & ! Compression adjusted specific volume [R-1 ~> m3 kg-1].
930 dz_geo ! The change in geopotential across a layer [L2 T-2 ~> m2 s-2].
940 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: p ! Interface pressure [R L2 T-2 ~> Pa].
95 ! p may be adjusted (with a nonlinear equation of state) so that
96 ! its derivative compensates for the adiabatic compressibility
97 ! in seawater, but p will still be close to the pressure.
98 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), target :: &
990 T_tmp, & ! Temporary array of temperatures where layers that are lighter
100 ! than the mixed layer have the mixed layer's properties [C ~> degC].
1010 S_tmp ! Temporary array of salinities where layers that are lighter
102 ! than the mixed layer have the mixed layer's properties [S ~> ppt].
103
1040 real, dimension(SZI_(G)) :: Rho_cv_BL ! The coordinate potential density in the
105 ! deepest variable density near-surface layer [R ~> kg m-3].
106
107 real, dimension(SZI_(G),SZJ_(G)) :: &
1080 dM, & ! A barotropic correction to the Montgomery potentials to enable the use
109 ! of a reduced gravity form of the equations [L2 T-2 ~> m2 s-2].
1100 dp_star, & ! Layer thickness after compensation for compressibility [R L2 T-2 ~> Pa].
1110 SSH, & ! The sea surface height anomaly, in depth units [Z ~> m].
1120 e_sal, & ! Bottom geopotential anomaly due to self-attraction and loading [Z ~> m].
1130 e_tide_eq, & ! Bottom geopotential anomaly due to tidal forces from astronomical sources [Z ~> m].
1140 e_tide_sal, & ! Bottom geopotential anomaly due to harmonic self-attraction and loading
115 ! specific to tides [Z ~> m].
1160 geopot_bot ! Bottom geopotential relative to a temporally fixed reference value,
117 ! including any tidal contributions [L2 T-2 ~> m2 s-2].
1180 real :: p_ref(SZI_(G)) ! The pressure used to calculate the coordinate
119 ! density [R L2 T-2 ~> Pa] (usually 2e7 Pa = 2000 dbar).
1200 real :: rho_in_situ(SZI_(G)) !In-situ density of a layer [R ~> kg m-3].
121 real :: PFu_bc, PFv_bc ! The pressure gradient force due to along-layer
122 ! compensated density gradients [L T-2 ~> m s-2]
123 real :: dp_neglect ! A thickness that is so small it is usually lost
124 ! in roundoff and can be neglected [R L2 T-2 ~> Pa].
125 logical :: use_p_atm ! If true, use the atmospheric pressure.
126 logical :: use_EOS ! If true, density is calculated from T & S using an equation of state.
127 logical :: is_split ! A flag indicating whether the pressure gradient terms are to be
128 ! split into barotropic and baroclinic pieces.
1290 type(thermo_var_ptrs) :: tv_tmp! A structure of temporary T & S.
130
131 real :: I_gEarth ! The inverse of g_Earth [T2 Z L-2 ~> s2 m-1]
132! real :: dalpha
133 real :: Pa_to_H ! A factor to convert from R L2 T-2 to the thickness units (H)
134 ! [H T2 R-1 L-2 ~> m2 s2 kg-1 or s2 m-1].
1350 real :: alpha_Lay(SZK_(GV)) ! The specific volume of each layer [R-1 ~> m3 kg-1].
1360 real :: dalpha_int(SZK_(GV)+1) ! The change in specific volume across each
137 ! interface [R-1 ~> m3 kg-1].
138 integer, dimension(2) :: EOSdom ! The computational domain for the equation of state
139 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb
140 integer :: i, j, k
1410 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
1420 nkmb=GV%nk_rho_varies
1430 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
1440 EOSdom(1) = Isq - (G%isd-1) ; EOSdom(2) = G%iec+1 - (G%isd-1)
145
1460 use_p_atm = associated(p_atm)
1470 is_split = present(pbce)
1480 use_EOS = associated(tv%eqn_of_state)
149
1500 if (.not.CS%initialized) call MOM_error(FATAL, &
1510 "MOM_PressureForce_Mont: Module must be initialized before it is used.")
152
1530 if (use_EOS) then
1540 if (query_compressible(tv%eqn_of_state)) call MOM_error(FATAL, &
155 "PressureForce_Mont_nonBouss: The Montgomery form of the pressure force "//&
1560 "can no longer be used with a compressible EOS. Use #define ANALYTIC_FV_PGF.")
157 endif
158
1590 I_gEarth = 1.0 / GV%g_Earth
1600 dp_neglect = GV%g_Earth * GV%H_to_RZ * GV%H_subroundoff
1610 do k=1,nz ; alpha_Lay(k) = 1.0 / (GV%Rlay(k)) ; enddo
1620 do k=2,nz ; dalpha_int(K) = alpha_Lay(k-1) - alpha_Lay(k) ; enddo
163
1640 if (use_p_atm) then
165 !$OMP parallel do default(shared)
1660 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1 ; p(i,j,1) = p_atm(i,j) ; enddo ; enddo
167 else
168 !$OMP parallel do default(shared)
1690 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1 ; p(i,j,1) = 0.0 ; enddo ; enddo
170 endif
171 !$OMP parallel do default(shared)
1720 do j=Jsq,Jeq+1 ; do k=1,nz ; do i=Isq,Ieq+1
1730 p(i,j,K+1) = p(i,j,K) + GV%g_Earth * GV%H_to_RZ * h(i,j,k)
174 enddo ; enddo ; enddo
175
1760 if (present(eta)) then
1770 Pa_to_H = 1.0 / (GV%g_Earth * GV%H_to_RZ)
1780 if (use_p_atm) then
179 !$OMP parallel do default(shared)
1800 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
1810 eta(i,j) = (p(i,j,nz+1) - p_atm(i,j)) * Pa_to_H ! eta has the same units as h.
182 enddo ; enddo
183 else
184 !$OMP parallel do default(shared)
1850 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
1860 eta(i,j) = p(i,j,nz+1) * Pa_to_H ! eta has the same units as h.
187 enddo ; enddo
188 endif
189 endif
190
191 !$OMP parallel do default(shared)
1920 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
1930 geopot_bot(i,j) = -GV%g_Earth * G%bathyT(i,j)
194 enddo ; enddo
195
196 ! Calculate and add the self-attraction and loading geopotential anomaly.
1970 if (CS%calculate_SAL) then
198 ! Determine the sea surface height anomalies, to enable the calculation
199 ! of self-attraction and loading.
200 !$OMP parallel do default(shared)
2010 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
2020 SSH(i,j) = min(-G%bathyT(i,j) - G%meanSL(i,j), 0.0)
203 enddo ; enddo
2040 if (use_EOS) then
205 !$OMP parallel do default(shared)
2060 do k=1,nz
207 call int_specific_vol_dp(tv%T(:,:,k), tv%S(:,:,k), p(:,:,k), p(:,:,k+1), &
2080 0.0, G%HI, tv%eqn_of_state, US, dz_geo(:,:,k), halo_size=1)
209 enddo
210 !$OMP parallel do default(shared)
2110 do j=Jsq,Jeq+1 ; do k=1,nz ; do i=Isq,Ieq+1
2120 SSH(i,j) = SSH(i,j) + I_gEarth * dz_geo(i,j,k)
213 enddo ; enddo ; enddo
214 else
215 !$OMP parallel do default(shared)
2160 do j=Jsq,Jeq+1 ; do k=1,nz ; do i=Isq,Ieq+1
2170 SSH(i,j) = SSH(i,j) + GV%H_to_RZ * h(i,j,k) * alpha_Lay(k)
218 enddo ; enddo ; enddo
219 endif
220
2210 call calc_SAL(SSH, e_sal, G, CS%SAL_CSp, tmp_scale=US%Z_to_m)
222 !$OMP parallel do default(shared)
2230 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
2240 geopot_bot(i,j) = geopot_bot(i,j) - GV%g_Earth*e_sal(i,j)
225 enddo ; enddo
226 endif
227
228 ! Calculate and add the tidal geopotential anomaly.
2290 if (CS%tides) then
2300 call calc_tidal_forcing(CS%Time, e_tide_eq, e_tide_sal, G, US, CS%tides_CSp)
231 !$OMP parallel do default(shared)
2320 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
2330 geopot_bot(i,j) = geopot_bot(i,j) - GV%g_Earth*(e_tide_eq(i,j) + e_tide_sal(i,j))
234 enddo ; enddo
235 endif
236
2370 if (use_EOS) then
238 ! Calculate in-situ specific volumes (alpha_star).
239
240 ! With a bulk mixed layer, replace the T & S of any layers that are
241 ! lighter than the buffer layer with the properties of the buffer
242 ! layer. These layers will be massless anyway, and it avoids any
243 ! formal calculations with hydrostatically unstable profiles.
2440 if (nkmb>0) then
2450 tv_tmp%T => T_tmp ; tv_tmp%S => S_tmp
2460 tv_tmp%eqn_of_state => tv%eqn_of_state
2470 do i=Isq,Ieq+1 ; p_ref(i) = tv%P_Ref ; enddo
248 !$OMP parallel do default(shared) private(Rho_cv_BL)
2490 do j=Jsq,Jeq+1
2500 do k=1,nkmb ; do i=Isq,Ieq+1
2510 tv_tmp%T(i,j,k) = tv%T(i,j,k) ; tv_tmp%S(i,j,k) = tv%S(i,j,k)
252 enddo ; enddo
253 call calculate_density(tv%T(:,j,nkmb), tv%S(:,j,nkmb), p_ref, Rho_cv_BL(:), &
2540 tv%eqn_of_state, EOSdom)
2550 do k=nkmb+1,nz ; do i=Isq,Ieq+1
2560 if (GV%Rlay(k) < Rho_cv_BL(i)) then
2570 tv_tmp%T(i,j,k) = tv%T(i,j,nkmb) ; tv_tmp%S(i,j,k) = tv%S(i,j,nkmb)
258 else
2590 tv_tmp%T(i,j,k) = tv%T(i,j,k) ; tv_tmp%S(i,j,k) = tv%S(i,j,k)
260 endif
261 enddo ; enddo
262 enddo
263 else
2640 tv_tmp%T => tv%T ; tv_tmp%S => tv%S
2650 tv_tmp%eqn_of_state => tv%eqn_of_state
2660 do i=Isq,Ieq+1 ; p_ref(i) = 0 ; enddo
267 endif
268 !$OMP parallel do default(shared) private(rho_in_situ)
2690 do k=1,nz ; do j=Jsq,Jeq+1
270 call calculate_density(tv_tmp%T(:,j,k), tv_tmp%S(:,j,k), p_ref, rho_in_situ, &
2710 tv%eqn_of_state, EOSdom)
2720 do i=Isq,Ieq+1 ; alpha_star(i,j,k) = 1.0 / rho_in_situ(i) ; enddo
273 enddo ; enddo
274 endif ! use_EOS
275
2760 if (use_EOS) then
277 !$OMP parallel do default(shared)
2780 do j=Jsq,Jeq+1
2790 do i=Isq,Ieq+1
2800 M(i,j,nz) = geopot_bot(i,j) + p(i,j,nz+1) * alpha_star(i,j,nz)
281 enddo
2820 do k=nz-1,1,-1 ; do i=Isq,Ieq+1
2830 M(i,j,k) = M(i,j,k+1) + p(i,j,K+1) * (alpha_star(i,j,k) - alpha_star(i,j,k+1))
284 enddo ; enddo
285 enddo
286 else ! not use_EOS
287 !$OMP parallel do default(shared)
2880 do j=Jsq,Jeq+1
2890 do i=Isq,Ieq+1
2900 M(i,j,nz) = geopot_bot(i,j) + p(i,j,nz+1) * alpha_Lay(nz)
291 enddo
2920 do k=nz-1,1,-1 ; do i=Isq,Ieq+1
2930 M(i,j,k) = M(i,j,k+1) + p(i,j,K+1) * dalpha_int(K+1)
294 enddo ; enddo
295 enddo
296 endif ! use_EOS
297
2980 if (CS%GFS_scale < 1.0) then
299 ! Adjust the Montgomery potential to make this a reduced gravity model.
300 !$OMP parallel do default(shared)
3010 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
3020 dM(i,j) = (CS%GFS_scale - 1.0) * M(i,j,1)
303 enddo ; enddo
304 !$OMP parallel do default(shared)
3050 do k=1,nz ; do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
3060 M(i,j,k) = M(i,j,k) + dM(i,j)
307 enddo ; enddo ; enddo
308
309 ! Could instead do the following, to avoid taking small differences
310 ! of large numbers...
311! do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
312! M(i,j,1) = CS%GFS_scale * M(i,j,1)
313! enddo ; enddo
314! if (use_EOS) then
315! do k=2,nz ; do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
316! M(i,j,k) = M(i,j,k-1) - p(i,j,K) * (alpha_star(i,j,k-1) - alpha_star(i,j,k))
317! enddo ; enddo ; enddo
318! else ! not use_EOS
319! do k=2,nz ; do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
320! M(i,j,k) = M(i,j,k-1) - p(i,j,K) * dalpha_int(K)
321! enddo ; enddo ; enddo
322! endif ! use_EOS
323
324 endif
325
326 ! Note that ddM/dPb = alpha_star(i,j,1)
3270 if (present(pbce)) then
3280 call Set_pbce_nonBouss(p, tv_tmp, G, GV, US, CS%GFS_scale, pbce, alpha_star)
329 endif
330
331! Calculate the pressure force. On a Cartesian grid,
332! PFu = - dM/dx and PFv = - dM/dy.
3330 if (use_EOS) then
334 !$OMP parallel do default(shared) private(dp_star,PFu_bc,PFv_bc)
3350 do k=1,nz
3360 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
3370 dp_star(i,j) = (p(i,j,K+1) - p(i,j,K)) + dp_neglect
338 enddo ; enddo
3390 do j=js,je ; do I=Isq,Ieq
340 ! PFu_bc = p* grad alpha*
341 PFu_bc = (alpha_star(i+1,j,k) - alpha_star(i,j,k)) * (G%IdxCu(I,j) * &
342 ((dp_star(i,j)*dp_star(i+1,j) + ((p(i,j,K)*dp_star(i+1,j)) + (p(i+1,j,K)*dp_star(i,j)))) / &
3430 (dp_star(i,j) + dp_star(i+1,j))))
3440 PFu(I,j,k) = -(M(i+1,j,k) - M(i,j,k)) * G%IdxCu(I,j) + PFu_bc
3450 if (allocated(CS%PFu_bc)) CS%PFu_bc(i,j,k) = PFu_bc
346 enddo ; enddo
3470 do J=Jsq,Jeq ; do i=is,ie
348 PFv_bc = (alpha_star(i,j+1,k) - alpha_star(i,j,k)) * (G%IdyCv(i,J) * &
349 ((dp_star(i,j)*dp_star(i,j+1) + ((p(i,j,K)*dp_star(i,j+1)) + (p(i,j+1,K)*dp_star(i,j)))) / &
3500 (dp_star(i,j) + dp_star(i,j+1))))
3510 PFv(i,J,k) = -(M(i,j+1,k) - M(i,j,k)) * G%IdyCv(i,J) + PFv_bc
3520 if (allocated(CS%PFv_bc)) CS%PFv_bc(i,j,k) = PFv_bc
353 enddo ; enddo
354 enddo ! k-loop
355 else ! .not. use_EOS
356 !$OMP parallel do default(shared)
3570 do k=1,nz
3580 do j=js,je ; do I=Isq,Ieq
3590 PFu(I,j,k) = -(M(i+1,j,k) - M(i,j,k)) * G%IdxCu(I,j)
360 enddo ; enddo
3610 do J=Jsq,Jeq ; do i=is,ie
3620 PFv(i,J,k) = -(M(i,j+1,k) - M(i,j,k)) * G%IdyCv(i,J)
363 enddo ; enddo
364 enddo
365 endif ! use_EOS
366
3670 if (CS%id_PFu_bc>0) call post_data(CS%id_PFu_bc, CS%PFu_bc, CS%diag)
3680 if (CS%id_PFv_bc>0) call post_data(CS%id_PFv_bc, CS%PFv_bc, CS%diag)
369 ! To be consistent with old runs, tidal forcing diagnostic also includes total SAL.
370 ! New diagnostics are given for each individual field.
3710 if (CS%id_e_tide>0) call post_data(CS%id_e_tide, e_sal+e_tide_eq+e_tide_sal, CS%diag)
3720 if (CS%id_e_sal>0) call post_data(CS%id_e_sal, e_sal, CS%diag)
3730 if (CS%id_e_tide_eq>0) call post_data(CS%id_e_tide_eq, e_tide_eq, CS%diag)
3740 if (CS%id_e_tide_sal>0) call post_data(CS%id_e_tide_sal, e_tide_sal, CS%diag)
375
3760end subroutine PressureForce_Mont_nonBouss
377
378!> \brief Boussinesq Montgomery-potential form of pressure gradient
379!!
380!! Determines the acceleration due to pressure forces.
381!!
382!! To work, the following fields must be set outside of the usual (is:ie,js:je)
383!! range before this subroutine is called:
384!! h(isB:ie+1,jsB:je+1), T(isB:ie+1,jsB:je+1), and S(isB:ie+1,jsB:je+1).
3850subroutine PressureForce_Mont_Bouss(h, tv, PFu, PFv, G, GV, US, CS, p_atm, pbce, eta)
386 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure.
387 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
388 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
389 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thickness [H ~> m].
390 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables.
391 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(out) :: PFu !< Zonal acceleration due to pressure gradients
392 !! (equal to -dM/dx) [L T-2 ~> m s-2].
393 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(out) :: PFv !< Meridional acceleration due to pressure gradients
394 !! (equal to -dM/dy) [L T-2 ~> m s-2].
395 type(PressureForce_Mont_CS), intent(inout) :: CS !< Control structure for Montgomery potential PGF
396 real, dimension(:,:), pointer :: p_atm !< The pressure at the ice-ocean or
397 !! atmosphere-ocean [R L2 T-2 ~> Pa].
398 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), optional, intent(out) :: pbce !< The baroclinic pressure anomaly in
399 !! each layer due to free surface height anomalies
400 !! [L2 T-2 H-1 ~> m s-2].
401 real, dimension(SZI_(G),SZJ_(G)), optional, intent(out) :: eta !< Free surface height [H ~> m].
402 ! Local variables
403 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
4040 M, & ! The Montgomery potential, M = (p/rho + gz) [L2 T-2 ~> m2 s-2].
4050 rho_star ! In-situ density divided by the derivative with depth of the
406 ! corrected e times (G_Earth/Rho0) [L2 Z-1 T-2 ~> m s-2].
4070 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: e ! Interface height [Z ~> m].
408 ! e may be adjusted (with a nonlinear equation of state) so that
409 ! its derivative compensates for the adiabatic compressibility
410 ! in seawater, but e will still be close to the interface depth.
411 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), target :: &
4120 T_tmp, & ! Temporary array of temperatures where layers that are lighter
413 ! than the mixed layer have the mixed layer's properties [C ~> degC].
4140 S_tmp ! Temporary array of salinities where layers that are lighter
415 ! than the mixed layer have the mixed layer's properties [S ~> ppt].
416
4170 real :: Rho_cv_BL(SZI_(G)) ! The coordinate potential density in
418 ! the deepest variable density near-surface layer [R ~> kg m-3].
4190 real :: h_star(SZI_(G),SZJ_(G)) ! Layer thickness after compensation
420 ! for compressibility [Z ~> m].
4210 real :: SSH(SZI_(G),SZJ_(G)) ! The sea surface height anomaly, in depth units [Z ~> m].
4220 real :: e_sal(SZI_(G),SZJ_(G)) ! The bottom geopotential anomaly due to self-attraction and loading [Z ~> m].
4230 real :: e_tide_eq(SZI_(G),SZJ_(G)) ! Bottom geopotential anomaly due to tidal forces from astronomical sources
424 ! [Z ~> m].
4250 real :: e_tide_sal(SZI_(G),SZJ_(G)) ! Bottom geopotential anomaly due to harmonic self-attraction and loading
426 ! specific to tides, in depth units [Z ~> m].
4270 real :: p_ref(SZI_(G)) ! The pressure used to calculate the coordinate
428 ! density [R L2 T-2 ~> Pa] (usually 2e7 Pa = 2000 dbar).
429 real :: I_Rho0 ! 1/Rho0 [R-1 ~> m3 kg-1].
430 real :: G_Rho0 ! G_Earth / Rho0 [L2 Z-1 T-2 R-1 ~> m4 s-2 kg-1].
431 real :: PFu_bc, PFv_bc ! The pressure gradient force due to along-layer
432 ! compensated density gradients [L T-2 ~> m s-2]
433 real :: dz_neglect ! A vertical distance that is so small it is usually lost
434 ! in roundoff and can be neglected [Z ~> m].
435 logical :: use_p_atm ! If true, use the atmospheric pressure.
436 logical :: use_EOS ! If true, density is calculated from T & S using
437 ! an equation of state.
438 logical :: is_split ! A flag indicating whether the pressure
439 ! gradient terms are to be split into
440 ! barotropic and baroclinic pieces.
4410 type(thermo_var_ptrs) :: tv_tmp! A structure of temporary T & S.
442 integer, dimension(2) :: EOSdom ! The computational domain for the equation of state
443 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb
444 integer :: i, j, k
445
4460 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
4470 nkmb=GV%nk_rho_varies
4480 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
4490 EOSdom(1) = Isq - (G%isd-1) ; EOSdom(2) = G%iec+1 - (G%isd-1)
450
4510 use_p_atm = associated(p_atm)
4520 is_split = present(pbce)
4530 use_EOS = associated(tv%eqn_of_state)
454
4550 if (.not.CS%initialized) call MOM_error(FATAL, &
4560 "MOM_PressureForce_Mont: Module must be initialized before it is used.")
457
4580 if (use_EOS) then
4590 if (query_compressible(tv%eqn_of_state)) call MOM_error(FATAL, &
460 "PressureForce_Mont_Bouss: The Montgomery form of the pressure force "//&
4610 "can no longer be used with a compressible EOS. Use #define ANALYTIC_FV_PGF.")
462 endif
463
4640 dz_neglect = GV%dZ_subroundoff
4650 I_Rho0 = 1.0/CS%Rho0
4660 G_Rho0 = GV%g_Earth / GV%Rho0
467
468 !$OMP parallel do default(shared)
4690 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
4700 e(i,j,nz+1) = -G%bathyT(i,j)
471 enddo ; enddo
472
473 ! Calculate and add the self-attraction and loading geopotential anomaly.
4740 if (CS%calculate_SAL) then
475 ! Determine the surface height anomaly for calculating self attraction
476 ! and loading. This should really be based on bottom pressure anomalies,
477 ! but that is not yet implemented, and the current form is correct for
478 ! barotropic tides.
479 !$OMP parallel do default(shared)
4800 do j=Jsq,Jeq+1
4810 do i=Isq,Ieq+1 ; SSH(i,j) = min(-G%bathyT(i,j) - G%meanSL(i,j), 0.0) ; enddo
4820 do k=1,nz ; do i=Isq,Ieq+1
4830 SSH(i,j) = SSH(i,j) + h(i,j,k)*GV%H_to_Z
484 enddo ; enddo
485 enddo
4860 call calc_SAL(SSH, e_sal, G, CS%SAL_CSp, tmp_scale=US%Z_to_m)
487 !$OMP parallel do default(shared)
4880 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
4890 e(i,j,nz+1) = e(i,j,nz+1) - e_sal(i,j)
490 enddo ; enddo
491 endif
492
493 ! Calculate and add the tidal geopotential anomaly.
4940 if (CS%tides) then
4950 call calc_tidal_forcing(CS%Time, e_tide_eq, e_tide_sal, G, US, CS%tides_CSp)
496 !$OMP parallel do default(shared)
4970 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
4980 e(i,j,nz+1) = e(i,j,nz+1) - (e_tide_eq(i,j) + e_tide_sal(i,j))
499 enddo ; enddo
500 endif
501
502 !$OMP parallel do default(shared)
5030 do j=Jsq,Jeq+1 ; do k=nz,1,-1 ; do i=Isq,Ieq+1
5040 e(i,j,K) = e(i,j,K+1) + h(i,j,k)*GV%H_to_Z
505 enddo ; enddo ; enddo
506
5070 if (use_EOS) then
508! Calculate in-situ densities (rho_star).
509
510! With a bulk mixed layer, replace the T & S of any layers that are
511! lighter than the buffer layer with the properties of the buffer
512! layer. These layers will be massless anyway, and it avoids any
513! formal calculations with hydrostatically unstable profiles.
514
5150 if (nkmb>0) then
5160 tv_tmp%T => T_tmp ; tv_tmp%S => S_tmp
5170 tv_tmp%eqn_of_state => tv%eqn_of_state
518
5190 do i=Isq,Ieq+1 ; p_ref(i) = tv%P_Ref ; enddo
520 !$OMP parallel do default(shared) private(Rho_cv_BL)
5210 do j=Jsq,Jeq+1
5220 do k=1,nkmb ; do i=Isq,Ieq+1
5230 tv_tmp%T(i,j,k) = tv%T(i,j,k) ; tv_tmp%S(i,j,k) = tv%S(i,j,k)
524 enddo ; enddo
525 call calculate_density(tv%T(:,j,nkmb), tv%S(:,j,nkmb), p_ref, Rho_cv_BL(:), &
5260 tv%eqn_of_state, EOSdom)
527
5280 do k=nkmb+1,nz ; do i=Isq,Ieq+1
5290 if (GV%Rlay(k) < Rho_cv_BL(i)) then
5300 tv_tmp%T(i,j,k) = tv%T(i,j,nkmb) ; tv_tmp%S(i,j,k) = tv%S(i,j,nkmb)
531 else
5320 tv_tmp%T(i,j,k) = tv%T(i,j,k) ; tv_tmp%S(i,j,k) = tv%S(i,j,k)
533 endif
534 enddo ; enddo
535 enddo
536 else
5370 tv_tmp%T => tv%T ; tv_tmp%S => tv%S
5380 tv_tmp%eqn_of_state => tv%eqn_of_state
5390 do i=Isq,Ieq+1 ; p_ref(i) = 0.0 ; enddo
540 endif
541
542 ! This no longer includes any pressure dependency, since this routine
543 ! will come down with a fatal error if there is any compressibility.
544 !$OMP parallel do default(shared)
5450 do k=1,nz ; do j=Jsq,Jeq+1
546 call calculate_density(tv_tmp%T(:,j,k), tv_tmp%S(:,j,k), p_ref, rho_star(:,j,k), &
5470 tv%eqn_of_state, EOSdom)
5480 do i=Isq,Ieq+1 ; rho_star(i,j,k) = G_Rho0*rho_star(i,j,k) ; enddo
549 enddo ; enddo
550 endif ! use_EOS
551
552! Here the layer Montgomery potentials, M, are calculated.
5530 if (use_EOS) then
554 !$OMP parallel do default(shared)
5550 do j=Jsq,Jeq+1
5560 do i=Isq,Ieq+1
5570 M(i,j,1) = CS%GFS_scale * (rho_star(i,j,1) * e(i,j,1))
5580 if (use_p_atm) M(i,j,1) = M(i,j,1) + p_atm(i,j) * I_Rho0
559 enddo
5600 do k=2,nz ; do i=Isq,Ieq+1
5610 M(i,j,k) = M(i,j,k-1) + (rho_star(i,j,k) - rho_star(i,j,k-1)) * e(i,j,K)
562 enddo ; enddo
563 enddo
564 else ! not use_EOS
565 !$OMP parallel do default(shared)
5660 do j=Jsq,Jeq+1
5670 do i=Isq,Ieq+1
5680 M(i,j,1) = GV%g_prime(1) * e(i,j,1)
5690 if (use_p_atm) M(i,j,1) = M(i,j,1) + p_atm(i,j) * I_Rho0
570 enddo
5710 do k=2,nz ; do i=Isq,Ieq+1
5720 M(i,j,k) = M(i,j,k-1) + GV%g_prime(K) * e(i,j,K)
573 enddo ; enddo
574 enddo
575 endif ! use_EOS
576
5770 if (present(pbce)) then
5780 call Set_pbce_Bouss(e, tv_tmp, G, GV, US, CS%Rho0, CS%GFS_scale, pbce, rho_star, 1)
579 endif
580
581! Calculate the pressure force. On a Cartesian grid,
582! PFu = - dM/dx and PFv = - dM/dy.
5830 if (use_EOS) then
584 !$OMP parallel do default(shared) private(h_star,PFu_bc,PFv_bc)
5850 do k=1,nz
5860 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
5870 h_star(i,j) = (e(i,j,K) - e(i,j,K+1)) + dz_neglect
588 enddo ; enddo
5890 do j=js,je ; do I=Isq,Ieq
590 PFu_bc = -1.0*(rho_star(i+1,j,k) - rho_star(i,j,k)) * (G%IdxCu(I,j) * &
591 ((h_star(i,j) * h_star(i+1,j) - ((e(i,j,K) * h_star(i+1,j)) + &
5920 (e(i+1,j,K) * h_star(i,j)))) / (h_star(i,j) + h_star(i+1,j))))
5930 PFu(I,j,k) = -(M(i+1,j,k) - M(i,j,k)) * G%IdxCu(I,j) + PFu_bc
5940 if (allocated(CS%PFu_bc)) CS%PFu_bc(i,j,k) = PFu_bc
595 enddo ; enddo
5960 do J=Jsq,Jeq ; do i=is,ie
597 PFv_bc = -1.0*(rho_star(i,j+1,k) - rho_star(i,j,k)) * (G%IdyCv(i,J) * &
598 ((h_star(i,j) * h_star(i,j+1) - ((e(i,j,K) * h_star(i,j+1)) + &
5990 (e(i,j+1,K) * h_star(i,j)))) / (h_star(i,j) + h_star(i,j+1))))
6000 PFv(i,J,k) = -(M(i,j+1,k) - M(i,j,k)) * G%IdyCv(i,J) + PFv_bc
6010 if (allocated(CS%PFv_bc)) CS%PFv_bc(i,j,k) = PFv_bc
602 enddo ; enddo
603 enddo ! k-loop
604 else ! .not. use_EOS
605 !$OMP parallel do default(shared)
6060 do k=1,nz
6070 do j=js,je ; do I=Isq,Ieq
6080 PFu(I,j,k) = -(M(i+1,j,k) - M(i,j,k)) * G%IdxCu(I,j)
609 enddo ; enddo
6100 do J=Jsq,Jeq ; do i=is,ie
6110 PFv(i,J,k) = -(M(i,j+1,k) - M(i,j,k)) * G%IdyCv(i,J)
612 enddo ; enddo
613 enddo
614 endif ! use_EOS
615
6160 if (present(eta)) then
617 ! eta is the sea surface height relative to a time-invariant geoid, for
618 ! comparison with what is used for eta in btstep. See how e was calculated
619 ! about 200 lines above.
620 !$OMP parallel do default(shared)
6210 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
6220 eta(i,j) = e(i,j,1)*GV%Z_to_H
623 enddo ; enddo
6240 if (CS%tides) then
625 !$OMP parallel do default(shared)
6260 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
6270 eta(i,j) = eta(i,j) + (e_tide_eq(i,j)+e_tide_sal(i,j))*GV%Z_to_H
628 enddo ; enddo
629 endif
6300 if (CS%calculate_SAL) then
631 !$OMP parallel do default(shared)
6320 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
6330 eta(i,j) = eta(i,j) + e_sal(i,j)*GV%Z_to_H
634 enddo ; enddo
635 endif
636 endif
637
6380 if (CS%id_PFu_bc>0) call post_data(CS%id_PFu_bc, CS%PFu_bc, CS%diag)
6390 if (CS%id_PFv_bc>0) call post_data(CS%id_PFv_bc, CS%PFv_bc, CS%diag)
640 ! To be consistent with old runs, tidal forcing diagnostic also includes total SAL.
641 ! New diagnostics are given for each individual field.
6420 if (CS%id_e_tide>0) call post_data(CS%id_e_tide, e_sal+e_tide_eq+e_tide_sal, CS%diag)
6430 if (CS%id_e_sal>0) call post_data(CS%id_e_sal, e_sal, CS%diag)
6440 if (CS%id_e_tide_eq>0) call post_data(CS%id_e_tide_eq, e_tide_eq, CS%diag)
6450 if (CS%id_e_tide_sal>0) call post_data(CS%id_e_tide_sal, e_tide_sal, CS%diag)
646
6470end subroutine PressureForce_Mont_Bouss
648
649!> Determines the partial derivative of the acceleration due
650!! to pressure forces with the free surface height.
6510subroutine Set_pbce_Bouss(e, tv, G, GV, US, Rho0, GFS_scale, pbce, rho_star, nkblock)
652 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
653 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
654 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(in) :: e !< Interface height [Z ~> m].
655 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
656 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
657 real, intent(in) :: Rho0 !< The "Boussinesq" ocean density [R ~> kg m-3].
658 real, intent(in) :: GFS_scale !< Ratio between gravity applied to top
659 !! interface and the gravitational acceleration of
660 !! the planet [nondim]. Usually this ratio is 1.
661 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
662 intent(out) :: pbce !< The baroclinic pressure anomaly in each layer due
663 !! to free surface height anomalies
664 !! [L2 T-2 H-1 ~> m s-2].
665 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
666 optional, intent(in) :: rho_star !< The layer densities (maybe compressibility
667 !! compensated), times g/rho_0 [L2 Z-1 T-2 ~> m s-2].
668 integer, intent(in) :: nkblock !< The number of vertical levels in each block for the variable density
669 !! near-surface layer. This is needed to determine whether rho_star is
670 !! compressibility compensated or not.
67148 real :: Ihtot(SZI_(G),SZJ_(G)) ! The inverse of the sum of the layer thicknesses [H-1 ~> m-1 or m2 kg-1].
67248 real :: press(SZI_(G),SZJ_(G),nkblock) ! Interface pressure [R L2 T-2 ~> Pa].
67348 real :: T_int(SZI_(G),SZJ_(G),nkblock) ! Interface temperature [C ~> degC]
67448 real :: S_int(SZI_(G),SZJ_(G),nkblock) ! Interface salinity [S ~> ppt]
67548 real :: dR_dT(SZI_(G),SZJ_(G),nkblock) ! Partial derivative of density with temperature [R C-1 ~> kg m-3 degC-1]
67648 real :: dR_dS(SZI_(G),SZJ_(G),nkblock) ! Partial derivative of density with salinity [R S-1 ~> kg m-3 ppt-1].
67748 real :: rho_in_situ(SZI_(G),SZJ_(G)) ! In-situ density at the top of a layer [R ~> kg m-3].
678 real :: G_Rho0 ! A scaled version of g_Earth / Rho0 [L2 Z-1 T-2 R-1 ~> m4 s-2 kg-1]
679 real :: Rho0xG ! g_Earth * Rho0 [R L2 Z-1 T-2 ~> kg s-2 m-2]
680 logical :: use_EOS ! If true, density is calculated from T & S using
681 ! an equation of state.
682 real :: dz_neglect ! A vertical distance that is so small it is usually lost
683 ! in roundoff and can be neglected [Z ~> m].
684 integer :: EOSdom(3,2) ! The computational domain for the equation of state
685 integer :: Isq, Ieq, Jsq, Jeq, nz, i, j, k, kstart, kend, kk
686
687 !$omp target data map(alloc: Ihtot)
68824 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB ; nz = GV%ke
689
69024 use_EOS = associated(tv%eqn_of_state)
69124 dz_neglect = GV%dZ_subroundoff
692
69324 if (use_EOS) then
69424 if (present(rho_star)) then
6950 do concurrent (j=Jsq:Jeq+1)
6960 do concurrent (i=Isq:Ieq+1)
6970 Ihtot(i,j) = GV%H_to_Z / ((e(i,j,1) - e(i,j,nz+1)) + dz_neglect)
6980 pbce(i,j,1) = GFS_scale * rho_star(i,j,1) * GV%H_to_Z
699 enddo
700
7010 do k=2,nz
7020 do concurrent (i=Isq:Ieq+1)
703 pbce(i,j,k) = pbce(i,j,k-1) + (rho_star(i,j,k) - rho_star(i,j,k-1)) &
7040 * ((e(i,j,K) - e(i,j,nz+1)) * Ihtot(i,j))
705 enddo
706 enddo
707 enddo
708 else
709 !$omp target data &
710 !$omp map(alloc: EOSdom, press, T_int, S_int, rho_in_situ) &
711 !$omp map(alloc: dR_dT, dR_dS)
712
71324 Rho0xG = Rho0 * GV%g_Earth
71424 G_Rho0 = GV%g_Earth / GV%Rho0
715
71672 EOSdom(1,:) = [Isq - (G%isd-1), G%iec+1 - (G%isd-1)]
71772 EOSdom(2,:) = [Jsq - (G%jsd-1), G%jec+1 - (G%jsd-1)]
7182952 do concurrent (j=Jsq:Jeq+1, i=Isq:Ieq+1)
719181536 Ihtot(i,j) = GV%H_to_Z / ((e(i,j,1) - e(i,j,nz+1)) + dz_neglect)
720184488 press(i,j,1) = -Rho0xG * (e(i,j,1) - G%meanSL(i,j))
721 enddo
722
723 call calculate_density(tv%T(:,:,1), tv%S(:,:,1), press(:,:,1), rho_in_situ, &
72424 tv%eqn_of_state, EOSdom(1:2,:))
725
7262952 do concurrent (j=Jsq:Jeq+1, i=Isq:Ieq+1)
727184488 pbce(i,j,1) = G_Rho0 * (GFS_scale * rho_in_situ(i,j)) * GV%H_to_Z
728 enddo
729
73024 EOSdom(3,1) = 1
7311800 do kstart=2,nz,nkblock
7321776 kend = min(kstart+nkblock-1, nz)
733218448 do concurrent (k=kstart:kend, j=Jsq:Jeq+1, i=Isq:Ieq+1)
73413433664 kk=k-kstart+1
73513433664 press(i,j,kk) = -Rho0xG * (e(i,j,K) - G%meanSL(i,j))
73613433664 T_int(i,j,kk) = 0.5 * (tv%T(i,j,k-1) + tv%T(i,j,k))
73727085776 S_int(i,j,kk) = 0.5 * (tv%S(i,j,k-1) + tv%S(i,j,k))
738 enddo
7391776 EOSdom(3,2) = kend-kstart+1
740 call calculate_density_derivs(T_int, S_int, press, dR_dT, dR_dS, &
7411776 tv%eqn_of_state, EOSdom)
742
74324 do concurrent(j=Jsq:Jeq+1)
744222000 do k=kstart,kend ; do concurrent (i=Isq:Ieq+1)
74513433664 kk=k-kstart+1
746 pbce(i,j,k) = pbce(i,j,k-1) + G_Rho0 * &
747 ((e(i,j,K) - e(i,j,nz+1)) * Ihtot(i,j)) * &
748 (dR_dT(i,j,kk) * (tv%T(i,j,k) - tv%T(i,j,k-1)) + &
74913543776 dR_dS(i,j,kk) * (tv%S(i,j,k) - tv%S(i,j,k-1)))
750 enddo ; enddo
751 enddo
752 enddo
753 !$omp end target data
754 endif
755 else
7560 do concurrent (j=Jsq:Jeq+1)
7570 do concurrent (i=Isq:Ieq+1)
7580 Ihtot(i,j) = 1.0 / ((e(i,j,1) - e(i,j,nz+1)) + dz_neglect)
7590 pbce(i,j,1) = GV%g_prime(1) * GV%H_to_Z
760 enddo
7610 do k=2,nz
7620 do concurrent (i=Isq:Ieq+1)
763 pbce(i,j,k) = pbce(i,j,k-1) + (GV%g_prime(K) * GV%H_to_Z) &
7640 * ((e(i,j,K) - e(i,j,nz+1)) * Ihtot(i,j))
765 enddo
766 enddo
767 enddo
768 endif
769 !$omp end target data
77024end subroutine Set_pbce_Bouss
771
772!> Determines the partial derivative of the acceleration due
773!! to pressure forces with the column mass.
7740subroutine Set_pbce_nonBouss(p, tv, G, GV, US, GFS_scale, pbce, alpha_star)
775 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
776 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
777 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(in) :: p !< Interface pressures [R L2 T-2 ~> Pa].
778 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables
779 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
780 real, intent(in) :: GFS_scale !< Ratio between gravity applied to top
781 !! interface and the gravitational acceleration of
782 !! the planet [nondim]. Usually this ratio is 1.
783 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(out) :: pbce !< The baroclinic pressure anomaly in each
784 !! layer due to free surface height anomalies
785 !! [L2 H-1 T-2 ~> m4 kg-1 s-2].
786 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), optional, intent(in) :: alpha_star !< The layer specific volumes
787 !! (maybe compressibility compensated) [R-1 ~> m3 kg-1].
788 ! Local variables
789 real, dimension(SZI_(G),SZJ_(G)) :: &
7900 dpbce, & ! A barotropic correction to the pbce to enable the use of
791 ! a reduced gravity form of the equations [L2 H-1 T-2 ~> m4 kg-1 s-2].
7920 C_htot ! dP_dH divided by the total ocean pressure [H-1 ~> m2 kg-1].
7930 real :: T_int(SZI_(G)) ! Interface temperature [C ~> degC]
7940 real :: S_int(SZI_(G)) ! Interface salinity [S ~> ppt]
7950 real :: dR_dT(SZI_(G)) ! Partial derivative of density with temperature [R C-1 ~> kg m-3 degC-1]
7960 real :: dR_dS(SZI_(G)) ! Partial derivative of density with salinity [R S-1 ~> kg m-3 ppt-1].
7970 real :: rho_in_situ(SZI_(G)) ! In-situ density at an interface [R ~> kg m-3].
7980 real :: alpha_Lay(SZK_(GV)) ! The specific volume of each layer [R-1 ~> m3 kg-1].
7990 real :: dalpha_int(SZK_(GV)+1) ! The change in specific volume across each interface [R-1 ~> m3 kg-1].
800 real :: dP_dH ! A factor that converts from thickness to pressure times other dimensional
801 ! conversion factors [R L2 T-2 H-1 ~> Pa m2 kg-1].
802 real :: dp_neglect ! A thickness that is so small it is usually lost
803 ! in roundoff and can be neglected [R L2 T-2 ~> Pa].
804 logical :: use_EOS ! If true, density is calculated from T & S using an equation of state.
805 integer, dimension(2) :: EOSdom ! The computational domain for the equation of state
806 integer :: Isq, Ieq, Jsq, Jeq, nz, i, j, k
807
8080 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB ; nz = GV%ke
8090 EOSdom(1) = Isq - (G%isd-1) ; EOSdom(2) = G%iec+1 - (G%isd-1)
810
8110 use_EOS = associated(tv%eqn_of_state)
812
8130 dP_dH = GV%g_Earth * GV%H_to_RZ
8140 dp_neglect = GV%g_Earth * GV%H_to_RZ * GV%H_subroundoff
815
8160 if (use_EOS) then
8170 if (present(alpha_star)) then
818 !$OMP parallel do default(shared)
8190 do j=Jsq,Jeq+1
8200 do i=Isq,Ieq+1
8210 C_htot(i,j) = dP_dH / ((p(i,j,nz+1)-p(i,j,1)) + dp_neglect)
8220 pbce(i,j,nz) = dP_dH * alpha_star(i,j,nz)
823 enddo
8240 do k=nz-1,1,-1 ; do i=Isq,Ieq+1
825 pbce(i,j,k) = pbce(i,j,k+1) + ((p(i,j,K+1)-p(i,j,1)) * C_htot(i,j)) * &
8260 (alpha_star(i,j,k) - alpha_star(i,j,k+1))
827 enddo ; enddo
828 enddo
829 else
830 !$OMP parallel do default(shared) private(T_int,S_int,dR_dT,dR_dS,rho_in_situ)
8310 do j=Jsq,Jeq+1
832 call calculate_density(tv%T(:,j,nz), tv%S(:,j,nz), p(:,j,nz+1), rho_in_situ, &
8330 tv%eqn_of_state, EOSdom)
8340 do i=Isq,Ieq+1
8350 C_htot(i,j) = dP_dH / ((p(i,j,nz+1)-p(i,j,1)) + dp_neglect)
8360 pbce(i,j,nz) = dP_dH / (rho_in_situ(i))
837 enddo
8380 do k=nz-1,1,-1
8390 do i=Isq,Ieq+1
8400 T_int(i) = 0.5*(tv%T(i,j,k)+tv%T(i,j,k+1))
8410 S_int(i) = 0.5*(tv%S(i,j,k)+tv%S(i,j,k+1))
842 enddo
8430 call calculate_density(T_int, S_int, p(:,j,k+1), rho_in_situ, tv%eqn_of_state, EOSdom)
844 call calculate_density_derivs(T_int, S_int, p(:,j,k+1), dR_dT, dR_dS, &
8450 tv%eqn_of_state, EOSdom)
8460 do i=Isq,Ieq+1
847 pbce(i,j,k) = pbce(i,j,k+1) + ((p(i,j,K+1)-p(i,j,1))*C_htot(i,j)) * &
848 ((dR_dT(i)*(tv%T(i,j,k+1)-tv%T(i,j,k)) + &
8490 dR_dS(i)*(tv%S(i,j,k+1)-tv%S(i,j,k))) / (rho_in_situ(i)**2))
850 enddo
851 enddo
852 enddo
853 endif
854 else ! not use_EOS
855
8560 do k=1,nz ; alpha_Lay(k) = 1.0 / (GV%Rlay(k)) ; enddo
8570 do k=2,nz ; dalpha_int(K) = alpha_Lay(k-1) - alpha_Lay(k) ; enddo
858
859 !$OMP parallel do default(shared)
8600 do j=Jsq,Jeq+1
8610 do i=Isq,Ieq+1
8620 C_htot(i,j) = dP_dH / ((p(i,j,nz+1)-p(i,j,1)) + dp_neglect)
8630 pbce(i,j,nz) = dP_dH * alpha_Lay(nz)
864 enddo
8650 do k=nz-1,1,-1 ; do i=Isq,Ieq+1
8660 pbce(i,j,k) = pbce(i,j,k+1) + ((p(i,j,K+1)-p(i,j,1))*C_htot(i,j)) * dalpha_int(K+1)
867 enddo ; enddo
868 enddo
869 endif ! use_EOS
870
8710 if (GFS_scale < 1.0) then
872 ! Adjust the Montgomery potential to make this a reduced gravity model.
873 !$OMP parallel do default(shared)
8740 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
8750 dpbce(i,j) = (GFS_scale - 1.0) * pbce(i,j,1)
876 enddo ; enddo
877 !$OMP parallel do default(shared)
8780 do k=1,nz ; do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
8790 pbce(i,j,k) = pbce(i,j,k) + dpbce(i,j)
880 enddo ; enddo ; enddo
881 endif
882
8830end subroutine Set_pbce_nonBouss
884
885!> Initialize the Montgomery-potential form of PGF control structure
8860subroutine PressureForce_Mont_init(Time, G, GV, US, param_file, diag, CS, SAL_CSp, tides_CSp)
887 type(time_type), target, intent(in) :: Time !< Current model time
888 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
889 type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure
890 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
891 type(param_file_type), intent(in) :: param_file !< Parameter file handles
892 type(diag_ctrl), target, intent(inout) :: diag !< Diagnostics control structure
893 type(PressureForce_Mont_CS), intent(inout) :: CS !< Montgomery PGF control structure
894 type(SAL_CS), intent(in), target, optional :: SAL_CSp !< SAL control structure
895 type(tidal_forcing_CS), intent(in), target, optional :: tides_CSp !< Tides control structure
896
897 ! Local variables
898 logical :: use_EOS
899 ! This include declares and sets the variable "version".
900# include "version_variable.h"
901 character(len=40) :: mdl ! This module's name.
902
9030 CS%initialized = .true.
9040 CS%diag => diag ; CS%Time => Time
9050 if (present(tides_CSp)) &
9060 CS%tides_CSp => tides_CSp
9070 if (present(SAL_CSp)) &
9080 CS%SAL_CSp => SAL_CSp
909
9100 mdl = "MOM_PressureForce_Mont"
9110 call log_version(param_file, mdl, version, "")
912 call get_param(param_file, mdl, "RHO_0", CS%Rho0, &
913 "The mean ocean density used with BOUSSINESQ true to "//&
914 "calculate accelerations and the mass for conservation "//&
915 "properties, or with BOUSSINESQ false to convert some "//&
916 "parameters from vertical units of m to kg m-2.", &
9170 units="kg m-3", default=1035.0, scale=US%R_to_kg_m3)
918 call get_param(param_file, mdl, "TIDES", CS%tides, &
9190 "If true, apply tidal momentum forcing.", default=.false.)
920 call get_param(param_file, mdl, "CALCULATE_SAL", CS%calculate_SAL, &
9210 "If true, calculate self-attraction and loading.", default=CS%tides)
922 call get_param(param_file, mdl, "USE_EOS", use_EOS, default=.true., &
9230 do_not_log=.true.) ! Input for diagnostic use only.
924
9250 if (use_EOS) then
926 CS%id_PFu_bc = register_diag_field('ocean_model', 'PFu_bc', diag%axesCuL, Time, &
9270 'Density Gradient Zonal Pressure Force Accel.', "meter second-2", conversion=US%L_T2_to_m_s2)
928 CS%id_PFv_bc = register_diag_field('ocean_model', 'PFv_bc', diag%axesCvL, Time, &
9290 'Density Gradient Meridional Pressure Force Accel.', "meter second-2", conversion=US%L_T2_to_m_s2)
9300 if (CS%id_PFu_bc > 0) &
9310 allocate(CS%PFu_bc(G%IsdB:G%IedB,G%jsd:G%jed,GV%ke), source=0.)
9320 if (CS%id_PFv_bc > 0) &
9330 allocate(CS%PFv_bc(G%isd:G%ied,G%JsdB:G%JedB,GV%ke), source=0.)
934 endif
935
9360 if (CS%calculate_SAL) then
937 CS%id_e_sal = register_diag_field('ocean_model', 'e_sal', diag%axesT1, Time, &
9380 'Self-attraction and loading height anomaly', 'meter', conversion=US%Z_to_m)
939 endif
9400 if (CS%tides) then
941 CS%id_e_tide = register_diag_field('ocean_model', 'e_tidal', diag%axesT1, Time, &
9420 'Tidal Forcing Astronomical and SAL Height Anomaly', 'meter', conversion=US%Z_to_m)
943 CS%id_e_tide_eq = register_diag_field('ocean_model', 'e_tide_eq', diag%axesT1, Time, &
9440 'Equilibrium tides height anomaly', 'meter', conversion=US%Z_to_m)
945 CS%id_e_tide_sal = register_diag_field('ocean_model', 'e_tide_sal', diag%axesT1, Time, &
9460 'Read-in tidal self-attraction and loading height anomaly', 'meter', conversion=US%Z_to_m)
947 endif
948
9490 CS%GFS_scale = 1.0
9500 if (GV%g_prime(1) /= GV%g_Earth) CS%GFS_scale = GV%g_prime(1) / GV%g_Earth
951
9520 call log_param(param_file, mdl, "GFS / G_EARTH", CS%GFS_scale, units="nondim")
953
9540end subroutine PressureForce_Mont_init
955
956!>\namespace mom_pressureforce_mont
957!!
958!! Provides the Boussunesq and non-Boussinesq forms of the horizontal
959!! accelerations due to pressure gradients using the Montgomery potential. A
960!! second-order accurate, centered scheme is used. If a split time stepping
961!! scheme is used, the vertical decomposition into barotropic and baroclinic
962!! contributions described by Hallberg (J Comp Phys 1997) is used. With a
963!! nonlinear equation of state, compressibility is added along the lines proposed
964!! by Sun et al. (JPO 1999), but with compressibility coefficients based on a fit
965!! to a user-provided reference profile.
966
9670end module MOM_PressureForce_Mont