13 implicit none ;
private
15 #include <MOM_memory.h>
16 public tracer_vertdiff
17 public applytracerboundaryfluxesinout
25 subroutine tracer_vertdiff(h_old, ea, eb, dt, tr, G, GV, &
26 sfc_flux, btm_flux, btm_reservoir, sink_rate, convert_flux_in)
29 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h_old
31 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: ea
33 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: eb
35 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: tr
36 real,
intent(in) :: dt
37 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(in) :: sfc_flux
38 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(in) :: btm_flux
40 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(inout) :: btm_reservoir
42 real,
optional,
intent(in) :: sink_rate
43 logical,
optional,
intent(in) :: convert_flux_in
48 real,
dimension(SZI_(G),SZJ_(G)) :: &
49 sfc_src, & !< The time-integrated surface source of the tracer [CU H ~> CU m or CU kg m-2].
51 real,
dimension(SZI_(G)) :: &
52 b1, & !< b1 is used by the tridiagonal solver [H-1 ~> m-1 or m2 kg-1].
54 real :: c1(szi_(g),szk_(gv))
55 real :: h_minus_dsink(szi_(g),szk_(gv))
58 real :: sink(szi_(g),szk_(gv)+1)
66 logical :: convert_flux = .true.
69 integer :: i, j, k, is, ie, js, je, nz
70 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
73 call mom_error(warning,
"MOM_tracer_diabatic.F90, tracer_vertdiff called "//&
74 "with only one vertical level")
78 if (
present(convert_flux_in)) convert_flux = convert_flux_in
79 h_neglect = gv%H_subroundoff
81 if (
present(sink_rate)) sink_dist = (dt*sink_rate) * gv%m_to_H
87 do j=js,je;
do i=is,ie ; sfc_src(i,j) = 0.0 ; btm_src(i,j) = 0.0 ;
enddo ;
enddo
88 if (
present(sfc_flux))
then
89 if (convert_flux)
then
91 do j = js, je;
do i = is,ie
92 sfc_src(i,j) = (sfc_flux(i,j)*dt) * gv%kg_m2_to_H
96 do j = js, je;
do i = is,ie
97 sfc_src(i,j) = sfc_flux(i,j)
101 if (
present(btm_flux))
then
102 if (convert_flux)
then
104 do j = js, je;
do i = is,ie
105 btm_src(i,j) = (btm_flux(i,j)*dt) * gv%kg_m2_to_H
109 do j = js, je;
do i = is,ie
110 btm_src(i,j) = btm_flux(i,j)
115 if (
present(sink_rate))
then
122 if (
present(btm_reservoir))
then
123 do i=is,ie ; sink(i,nz+1) = sink_dist ;
enddo
124 do k=2,nz ;
do i=is,ie
125 sink(i,k) = sink_dist ; h_minus_dsink(i,k) = h_old(i,j,k)
128 do i=is,ie ; sink(i,nz+1) = 0.0 ;
enddo
130 do k=nz,2,-1 ;
do i=is,ie
131 if (sink(i,k+1) >= sink_dist)
then
132 sink(i,k) = sink_dist
133 h_minus_dsink(i,k) = h_old(i,j,k) + (sink(i,k+1) - sink(i,k))
134 elseif (sink(i,k+1) + h_old(i,j,k) < sink_dist)
then
135 sink(i,k) = sink(i,k+1) + h_old(i,j,k)
136 h_minus_dsink(i,k) = 0.0
138 sink(i,k) = sink_dist
139 h_minus_dsink(i,k) = (h_old(i,j,k) + sink(i,k+1)) - sink(i,k)
144 sink(i,1) = 0.0 ; h_minus_dsink(i,1) = (h_old(i,j,1) + sink(i,2))
148 do i=is,ie ;
if (g%mask2dT(i,j) > 0.5)
then
149 b_denom_1 = h_minus_dsink(i,1) + ea(i,j,1) + h_neglect
150 b1(i) = 1.0 / (b_denom_1 + eb(i,j,1))
151 d1(i) = b_denom_1 * b1(i)
152 h_tr = h_old(i,j,1) + h_neglect
153 tr(i,j,1) = (b1(i)*h_tr)*tr(i,j,1) + sfc_src(i,j)
155 do k=2,nz-1 ;
do i=is,ie ;
if (g%mask2dT(i,j) > 0.5)
then
156 c1(i,k) = eb(i,j,k-1) * b1(i)
157 b_denom_1 = h_minus_dsink(i,k) + d1(i) * (ea(i,j,k) + sink(i,k)) + &
159 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
160 d1(i) = b_denom_1 * b1(i)
161 h_tr = h_old(i,j,k) + h_neglect
162 tr(i,j,k) = b1(i) * (h_tr * tr(i,j,k) + &
163 (ea(i,j,k) + sink(i,k)) * tr(i,j,k-1))
164 endif ;
enddo ;
enddo
165 do i=is,ie ;
if (g%mask2dT(i,j) > 0.5)
then
166 c1(i,nz) = eb(i,j,nz-1) * b1(i)
167 b_denom_1 = h_minus_dsink(i,nz) + d1(i) * (ea(i,j,nz) + sink(i,nz)) + &
169 b1(i) = 1.0 / (b_denom_1 + eb(i,j,nz))
170 h_tr = h_old(i,j,nz) + h_neglect
171 tr(i,j,nz) = b1(i) * ((h_tr * tr(i,j,nz) + btm_src(i,j)) + &
172 (ea(i,j,nz) + sink(i,nz)) * tr(i,j,nz-1))
174 if (
present(btm_reservoir))
then ;
do i=is,ie ;
if (g%mask2dT(i,j)>0.5)
then
175 btm_reservoir(i,j) = btm_reservoir(i,j) + &
176 (sink(i,nz+1)*tr(i,j,nz)) * gv%H_to_kg_m2
177 endif ;
enddo ;
endif
179 do k=nz-1,1,-1 ;
do i=is,ie ;
if (g%mask2dT(i,j) > 0.5)
then
180 tr(i,j,k) = tr(i,j,k) + c1(i,k+1)*tr(i,j,k+1)
181 endif ;
enddo ;
enddo
186 do i=is,ie ;
if (g%mask2dT(i,j) > -0.5)
then
187 h_tr = h_old(i,j,1) + h_neglect
188 b_denom_1 = h_tr + ea(i,j,1)
189 b1(i) = 1.0 / (b_denom_1 + eb(i,j,1))
191 tr(i,j,1) = (b1(i)*h_tr)*tr(i,j,1) + sfc_src(i,j)
194 do k=2,nz-1 ;
do i=is,ie ;
if (g%mask2dT(i,j) > -0.5)
then
195 c1(i,k) = eb(i,j,k-1) * b1(i)
196 h_tr = h_old(i,j,k) + h_neglect
197 b_denom_1 = h_tr + d1(i) * ea(i,j,k)
198 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
199 d1(i) = b_denom_1 * b1(i)
200 tr(i,j,k) = b1(i) * (h_tr * tr(i,j,k) + ea(i,j,k) * tr(i,j,k-1))
201 endif ;
enddo ;
enddo
202 do i=is,ie ;
if (g%mask2dT(i,j) > -0.5)
then
203 c1(i,nz) = eb(i,j,nz-1) * b1(i)
204 h_tr = h_old(i,j,nz) + h_neglect
205 b_denom_1 = h_tr + d1(i)*ea(i,j,nz)
206 b1(i) = 1.0 / ( b_denom_1 + eb(i,j,nz))
207 tr(i,j,nz) = b1(i) * (( h_tr * tr(i,j,nz) + btm_src(i,j)) + &
208 ea(i,j,nz) * tr(i,j,nz-1))
210 do k=nz-1,1,-1 ;
do i=is,ie ;
if (g%mask2dT(i,j) > -0.5)
then
211 tr(i,j,k) = tr(i,j,k) + c1(i,k+1)*tr(i,j,k+1)
212 endif ;
enddo ;
enddo
218 end subroutine tracer_vertdiff
223 subroutine applytracerboundaryfluxesinout(G, GV, Tr, dt, fluxes, h, evap_CFL_limit, minimum_forcing_depth, &
224 in_flux_optional, out_flux_optional, update_h_opt)
228 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: tr
229 real,
intent(in ) :: dt
230 type(
forcing),
intent(in ) :: fluxes
231 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
232 real,
intent(in ) :: evap_cfl_limit
235 real,
intent(in ) :: minimum_forcing_depth
237 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(in ) :: in_flux_optional
239 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(in) :: out_flux_optional
241 logical,
optional,
intent(in) :: update_h_opt
244 integer,
parameter :: maxgroundings = 5
245 integer :: numberofgroundings, iground(maxgroundings), jground(maxgroundings)
246 real :: h_limit_fluxes, iforcingdepthscale, idt
247 real :: dthickness, dtracer
248 real :: fractionofforcing, hold, ithickness
249 real :: rivermixconst
250 real,
dimension(SZI_(G)) :: &
255 real,
dimension(SZI_(G), SZK_(G)) :: h2d, tr2d
256 real,
dimension(SZI_(G),SZJ_(G)) :: in_flux
258 real,
dimension(SZI_(G),SZJ_(G)) :: out_flux
260 real,
dimension(SZI_(G)) :: in_flux_1d, out_flux_1d
261 real :: hgrounding(maxgroundings)
264 integer :: i, j, is, ie, js, je, k, nz, n, nsw
265 character(len=45) :: mesg
267 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
270 if ( (.not.
associated(fluxes%netMassIn)) .or. (.not.
associated(fluxes%netMassOut)) )
return
272 in_flux(:,:) = 0.0 ; out_flux(:,:) = 0.0
273 if (
present(in_flux_optional))
then
274 do j=js,je ;
do i=is,ie
275 in_flux(i,j) = in_flux_optional(i,j)
278 if (
present(out_flux_optional))
then
279 do j=js,je ;
do i=is,ie
280 out_flux(i,j) = out_flux_optional(i,j)
284 if (
present(update_h_opt))
then
285 update_h = update_h_opt
291 numberofgroundings = 0
306 do k=1,nz ;
do i=is,ie
308 tr2d(i,k) = tr(i,j,k)
312 in_flux_1d(i) = in_flux(i,j)
313 out_flux_1d(i) = out_flux(i,j)
325 netmassout(i) = fluxes%netMassOut(i,j)
326 netmassin(i) = fluxes%netMassIn(i,j)
333 if (g%mask2dT(i,j)>0.)
then
339 dthickness = netmassin(i)
344 netmassin(i) = netmassin(i) - dthickness
345 dtracer = dtracer + in_flux_1d(i)
350 h2d(i,k) = h2d(i,k) + dthickness
351 if (h2d(i,k) > 0.0)
then
352 ithickness = 1.0/h2d(i,k)
354 if (dthickness /= 0. .or. dtracer /= 0.) tr2d(i,k) = (hold*tr2d(i,k)+ dtracer)*ithickness
365 iforcingdepthscale = 1. / max(gv%H_subroundoff, minimum_forcing_depth*gv%m_to_H - netmassout(i) )
367 fractionofforcing = min(1.0, h2d(i,k)*iforcingdepthscale)
372 if (-fractionofforcing*netmassout(i) > evap_cfl_limit*h2d(i,k))
then
373 fractionofforcing = -evap_cfl_limit*h2d(i,k)/netmassout(i)
377 dthickness = max( fractionofforcing*netmassout(i), -h2d(i,k) )
379 dtracer = fractionofforcing*out_flux_1d(i)
383 netmassout(i) = netmassout(i) - dthickness
384 out_flux_1d(i) = out_flux_1d(i) - dtracer
388 h2d(i,k) = h2d(i,k) + dthickness
389 if (h2d(i,k) > 0.)
then
390 ithickness = 1.0/h2d(i,k)
391 tr2d(i,k) = (hold*tr2d(i,k) + dtracer)*ithickness
399 if (abs(in_flux_1d(i))+abs(out_flux_1d(i)) /= 0.0)
then
401 numberofgroundings = numberofgroundings +1
402 if (numberofgroundings<=maxgroundings)
then
403 iground(numberofgroundings) = i
404 jground(numberofgroundings) = j
405 hgrounding(numberofgroundings) = abs(in_flux_1d(i))+abs(out_flux_1d(i))
413 do k=1,nz ;
do i=is,ie
414 tr(i,j,k) = tr2d(i,k)
418 do k=1,nz ;
do i=is,ie
425 if (numberofgroundings>0)
then
426 do i = 1, min(numberofgroundings, maxgroundings)
427 write(mesg(1:45),
'(3es15.3)') g%geoLonT( iground(i), jground(i) ), &
428 g%geoLatT( iground(i), jground(i)) , hgrounding(i)
429 call mom_error(warning,
"MOM_tracer_diabatic.F90, applyTracerBoundaryFluxesInOut(): "//&
430 "Tracer created. x,y,dh= "//trim(mesg), all_print=.true.)
433 if (numberofgroundings - maxgroundings > 0)
then
434 write(mesg,
'(i4)') numberofgroundings - maxgroundings
435 call mom_error(warning,
"MOM_tracer_vertical.F90, applyTracerBoundaryFluxesInOut(): "//&
436 trim(mesg) //
" groundings remaining")
440 end subroutine applytracerboundaryfluxesinout