57 use mom_io, only : read_data, slasher
63 implicit none ;
private 65 #include <MOM_memory.h> 70 real :: drcv_dt_inplace
73 real,
pointer :: geo_heat(:,:) => null()
75 real :: geothermal_thick
77 logical :: apply_geothermal
81 type(time_type),
pointer :: time
94 subroutine geothermal(h, tv, dt, ea, eb, G, GV, CS)
98 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
104 real,
intent(in) :: dt
105 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: ea
111 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: eb
145 real,
dimension(SZI_(G)) :: &
151 real,
dimension(2) :: &
156 real :: Angstrom, H_neglect
164 real :: heat_in_place
174 logical :: do_i(szi_(g))
175 integer :: i, j, k, is, ie, js, je, nz, k2, i2
176 integer :: isj, iej, num_start, num_left, nkmb, k_tgt
179 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
181 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_geothermal: "//&
182 "Module must be initialized before it is used.")
183 if (.not.cs%apply_geothermal)
return 185 nkmb = gv%nk_rho_varies
186 irho_cp = 1.0 / (gv%H_to_kg_m2 * tv%C_p)
187 angstrom = gv%Angstrom
188 h_neglect = gv%H_subroundoff
191 if (.not.
ASSOCIATED(tv%T))
call mom_error(fatal,
"MOM geothermal: "//&
192 "Geothermal heating can only be applied if T & S are state variables.")
224 heat_rem(i) = g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp))
225 do_i(i) = .true. ;
if (heat_rem(i) <= 0.0) do_i(i) = .false.
226 if (do_i(i)) num_start = num_start + 1
227 h_geo_rem(i) = cs%Geothermal_thick * gv%m_to_H
229 if (num_start == 0) cycle
233 isj = ie+1 ;
do i=is,ie ;
if (do_i(i))
then ; isj = i ;
exit ;
endif ;
enddo 234 iej = is-1 ;
do i=ie,is,-1 ;
if (do_i(i))
then ; iej = i ;
exit ;
endif ;
enddo 238 rcv_bl(:), isj, iej-isj+1, tv%eqn_of_state)
244 do i=isj,iej ;
if (do_i(i))
then 246 if (h(i,j,k) > angstrom)
then 247 if ((h(i,j,k)-angstrom) >= h_geo_rem(i))
then 248 h_heated = h_geo_rem(i)
249 heat_avail = heat_rem(i)
252 h_heated = (h(i,j,k)-angstrom)
253 heat_avail = heat_rem(i) * (h_heated / &
254 (h_geo_rem(i) + h_neglect))
255 h_geo_rem(i) = h_geo_rem(i) - h_heated
258 if (k<=nkmb .or. nkmb<=0)
then 262 elseif ((k==nkmb+1) .or. (gv%Rlay(k-1) < rcv_bl(i)))
then 269 rcv_tgt = gv%Rlay(k-1)
272 if (k<=nkmb .or. nkmb<=0)
then 273 rcv = 0.0 ; drcv_dt = 0.0
276 rcv, tv%eqn_of_state)
277 t2(1) = tv%T(i,j,k) ; s2(1) = tv%S(i,j,k)
278 t2(2) = tv%T(i,j,k_tgt) ; s2(2) = tv%S(i,j,k_tgt)
280 drcv_dt_, drcv_ds_, 1, 2, tv%eqn_of_state)
281 drcv_dt = 0.5*(drcv_dt_(1) + drcv_dt_(2))
284 if ((drcv_dt >= 0.0) .or. (k<=nkmb .or. nkmb<=0))
then 286 heat_in_place = heat_avail
288 elseif (drcv_dt <= cs%dRcv_dT_inplace)
then 290 heat_in_place = min(heat_avail, max(0.0, h(i,j,k) * &
291 ((gv%Rlay(k)-rcv) / drcv_dt)))
292 heat_trans = heat_avail - heat_in_place
295 wt_in_place = (cs%dRcv_dT_inplace - drcv_dt) / cs%dRcv_dT_inplace
296 heat_in_place = max(wt_in_place*heat_avail, &
297 h(i,j,k) * ((gv%Rlay(k)-rcv) / drcv_dt) )
298 heat_trans = heat_avail - heat_in_place
301 if (heat_in_place > 0.0)
then 307 dtemp = heat_in_place / (h(i,j,k) + h_neglect)
308 tv%T(i,j,k) = tv%T(i,j,k) + dtemp
309 heat_rem(i) = heat_rem(i) - heat_in_place
310 rcv = rcv + drcv_dt * dtemp
313 if (heat_trans > 0.0)
then 316 drcv = max(rcv - rcv_tgt, 0.0)
320 if ((-drcv_dt * heat_trans) >= drcv * (h(i,j,k)-angstrom))
then 321 h_transfer = h(i,j,k) - angstrom
322 heating = (h_transfer * drcv) / (-drcv_dt)
326 h_geo_rem(i) = h_geo_rem(i) + h_heated * &
327 ((heat_avail - (heating + heat_in_place)) / heat_avail)
329 h_transfer = (-drcv_dt * heat_trans) / drcv
332 heat_rem(i) = heat_rem(i) - heating
334 i_h = 1.0 / (h(i,j,k_tgt) + h_transfer + h_neglect)
335 tv%T(i,j,k_tgt) = (h(i,j,k_tgt) * tv%T(i,j,k_tgt) + &
336 (h_transfer * tv%T(i,j,k) + heating)) * i_h
337 tv%S(i,j,k_tgt) = (h(i,j,k_tgt) * tv%S(i,j,k_tgt) + &
338 h_transfer * tv%S(i,j,k)) * i_h
340 h(i,j,k) = h(i,j,k) - h_transfer
341 h(i,j,k_tgt) = h(i,j,k_tgt) + h_transfer
342 eb(i,j,k_tgt) = eb(i,j,k_tgt) + h_transfer
343 if (k_tgt < k-1)
then 345 eb(i,j,k2) = eb(i,j,k2) + h_transfer
350 if (heat_rem(i) <= 0.0)
then 351 do_i(i) = .false. ; num_left = num_left-1
366 if (num_left <= 0)
exit 369 if (
associated(tv%internal_heat))
then ;
do i=is,ie
370 tv%internal_heat(i,j) = tv%internal_heat(i,j) + gv%H_to_kg_m2 * &
371 (g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp)) - heat_rem(i))
383 type(time_type),
target,
intent(in) :: Time
387 type(
diag_ctrl),
target,
intent(inout) :: diag
400 #include "version_variable.h" 402 character(len=40) :: mdl =
"MOM_geothermal" 403 character(len=200) :: inputdir, geo_file, filename, geotherm_var
405 integer :: i, j, isd, ied, jsd, jed, id
406 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
408 if (
associated(cs))
then 409 call mom_error(warning,
"geothermal_init called with an associated"// &
410 "associated control structure.")
412 else ;
allocate(cs) ;
endif 419 call get_param(param_file, mdl,
"GEOTHERMAL_SCALE", scale, &
420 "The constant geothermal heat flux, a rescaling \n"//&
421 "factor for the heat flux read from GEOTHERMAL_FILE, or \n"//&
422 "0 to disable the geothermal heating.", &
423 units=
"W m-2 or various", default=0.0)
424 cs%apply_geothermal = .not.(scale == 0.0)
425 if (.not.cs%apply_geothermal)
return 427 call safe_alloc_ptr(cs%geo_heat, isd, ied, jsd, jed) ; cs%geo_heat(:,:) = 0.0
429 call get_param(param_file, mdl,
"GEOTHERMAL_FILE", geo_file, &
430 "The file from which the geothermal heating is to be \n"//&
431 "read, or blank to use a constant heating rate.", default=
" ")
432 call get_param(param_file, mdl,
"GEOTHERMAL_THICKNESS", cs%geothermal_thick, &
433 "The thickness over which to apply geothermal heating.", &
434 units=
"m", default=0.1)
435 call get_param(param_file, mdl,
"GEOTHERMAL_DRHO_DT_INPLACE", cs%dRcv_dT_inplace, &
436 "The value of drho_dT above which geothermal heating \n"//&
437 "simply heats water in place instead of moving it between \n"//&
438 "isopycnal layers. This must be negative.", &
439 units=
"kg m-3 K-1", default=-0.01)
440 if (cs%dRcv_dT_inplace >= 0.0)
call mom_error(fatal,
"geothermal_init: "//&
441 "GEOTHERMAL_DRHO_DT_INPLACE must be negative.")
443 if (len_trim(geo_file) >= 1)
then 444 call get_param(param_file, mdl,
"INPUTDIR", inputdir, default=
".")
445 inputdir = slasher(inputdir)
446 filename = trim(inputdir)//trim(geo_file)
447 call log_param(param_file, mdl,
"INPUTDIR/GEOTHERMAL_FILE", filename)
448 call get_param(param_file, mdl,
"GEOTHERMAL_VARNAME", geotherm_var, &
449 "The name of the geothermal heating variable in \n"//&
450 "GEOTHERMAL_FILE.", default=
"geo_heat")
451 call read_data(filename, trim(geotherm_var), cs%geo_heat, &
452 domain=g%Domain%mpp_domain)
453 do j=jsd,jed ;
do i=isd,ied
454 cs%geo_heat(i,j) = (g%mask2dT(i,j) * scale) * cs%geo_heat(i,j)
457 do j=jsd,jed ;
do i=isd,ied
458 cs%geo_heat(i,j) = g%mask2dT(i,j) * scale
464 'Geothermal heat flux into ocean',
'W m-2', &
465 cmor_field_name=
'hfgeou', cmor_units=
'W m-2', &
466 cmor_standard_name=
'upward_geothermal_heat_flux_at_sea_floor', &
467 cmor_long_name=
'Upward geothermal heat flux at sea floor')
468 if (id > 0)
call post_data(id, cs%geo_heat, diag, .true.)
475 if (
associated(cs%geo_heat))
deallocate(cs%geo_heat)
476 if (
associated(cs))
deallocate(cs)
subroutine, public geothermal(h, tv, dt, ea, eb, G, GV, CS)
This subroutine applies geothermal heating, including the movement of water between isopycnal layers ...
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Provides the ocean grid type.
This module contains I/O framework code.
subroutine, public geothermal_end(CS)
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
subroutine, public geothermal_init(Time, G, param_file, diag, CS)
Provides subroutines for quantities specific to the equation of state.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public mom_error(level, message, all_print)