17 implicit none ;
private
19 #include <MOM_memory.h>
21 public geothermal, geothermal_init, geothermal_end
25 real :: drcv_dt_inplace
28 real,
pointer :: geo_heat(:,:) => null()
29 real :: geothermal_thick
31 logical :: apply_geothermal
35 type(time_type),
pointer :: time => null()
48 subroutine geothermal(h, tv, dt, ea, eb, G, GV, CS, halo)
51 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
56 real,
intent(in) :: dt
57 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: ea
61 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: eb
68 integer,
optional,
intent(in) :: halo
70 real,
dimension(SZI_(G)) :: &
76 real,
dimension(2) :: &
81 real :: angstrom, h_neglect
103 logical :: do_i(szi_(g))
104 integer :: i, j, k, is, ie, js, je, nz, k2, i2
105 integer :: isj, iej, num_start, num_left, nkmb, k_tgt
108 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
109 if (
present(halo))
then
110 is = g%isc-halo ; ie = g%iec+halo ; js = g%jsc-halo ; je = g%jec+halo
113 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_geothermal: "//&
114 "Module must be initialized before it is used.")
115 if (.not.cs%apply_geothermal)
return
117 nkmb = gv%nk_rho_varies
118 irho_cp = 1.0 / (gv%H_to_kg_m2 * tv%C_p)
119 angstrom = gv%Angstrom_H
120 h_neglect = gv%H_subroundoff
123 if (.not.
associated(tv%T))
call mom_error(fatal,
"MOM geothermal: "//&
124 "Geothermal heating can only be applied if T & S are state variables.")
156 heat_rem(i) = g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp))
157 do_i(i) = .true. ;
if (heat_rem(i) <= 0.0) do_i(i) = .false.
158 if (do_i(i)) num_start = num_start + 1
159 h_geo_rem(i) = cs%Geothermal_thick * gv%m_to_H
161 if (num_start == 0) cycle
165 isj = ie+1 ;
do i=is,ie ;
if (do_i(i))
then ; isj = i ;
exit ;
endif ;
enddo
166 iej = is-1 ;
do i=ie,is,-1 ;
if (do_i(i))
then ; iej = i ;
exit ;
endif ;
enddo
170 rcv_bl(:), isj, iej-isj+1, tv%eqn_of_state)
176 do i=isj,iej ;
if (do_i(i))
then
178 if (h(i,j,k) > angstrom)
then
179 if ((h(i,j,k)-angstrom) >= h_geo_rem(i))
then
180 h_heated = h_geo_rem(i)
181 heat_avail = heat_rem(i)
184 h_heated = (h(i,j,k)-angstrom)
185 heat_avail = heat_rem(i) * (h_heated / &
186 (h_geo_rem(i) + h_neglect))
187 h_geo_rem(i) = h_geo_rem(i) - h_heated
190 if (k<=nkmb .or. nkmb<=0)
then
194 elseif ((k==nkmb+1) .or. (gv%Rlay(k-1) < rcv_bl(i)))
then
201 rcv_tgt = gv%Rlay(k-1)
204 if (k<=nkmb .or. nkmb<=0)
then
205 rcv = 0.0 ; drcv_dt = 0.0
208 rcv, tv%eqn_of_state)
209 t2(1) = tv%T(i,j,k) ; s2(1) = tv%S(i,j,k)
210 t2(2) = tv%T(i,j,k_tgt) ; s2(2) = tv%S(i,j,k_tgt)
212 drcv_dt_, drcv_ds_, 1, 2, tv%eqn_of_state)
213 drcv_dt = 0.5*(drcv_dt_(1) + drcv_dt_(2))
216 if ((drcv_dt >= 0.0) .or. (k<=nkmb .or. nkmb<=0))
then
218 heat_in_place = heat_avail
220 elseif (drcv_dt <= cs%dRcv_dT_inplace)
then
222 heat_in_place = min(heat_avail, max(0.0, h(i,j,k) * &
223 ((gv%Rlay(k)-rcv) / drcv_dt)))
224 heat_trans = heat_avail - heat_in_place
227 wt_in_place = (cs%dRcv_dT_inplace - drcv_dt) / cs%dRcv_dT_inplace
228 heat_in_place = max(wt_in_place*heat_avail, &
229 h(i,j,k) * ((gv%Rlay(k)-rcv) / drcv_dt) )
230 heat_trans = heat_avail - heat_in_place
233 if (heat_in_place > 0.0)
then
239 dtemp = heat_in_place / (h(i,j,k) + h_neglect)
240 tv%T(i,j,k) = tv%T(i,j,k) + dtemp
241 heat_rem(i) = heat_rem(i) - heat_in_place
242 rcv = rcv + drcv_dt * dtemp
245 if (heat_trans > 0.0)
then
248 drcv = max(rcv - rcv_tgt, 0.0)
252 if ((-drcv_dt * heat_trans) >= drcv * (h(i,j,k)-angstrom))
then
253 h_transfer = h(i,j,k) - angstrom
254 heating = (h_transfer * drcv) / (-drcv_dt)
258 h_geo_rem(i) = h_geo_rem(i) + h_heated * &
259 ((heat_avail - (heating + heat_in_place)) / heat_avail)
261 h_transfer = (-drcv_dt * heat_trans) / drcv
264 heat_rem(i) = heat_rem(i) - heating
266 i_h = 1.0 / (h(i,j,k_tgt) + h_transfer + h_neglect)
267 tv%T(i,j,k_tgt) = (h(i,j,k_tgt) * tv%T(i,j,k_tgt) + &
268 (h_transfer * tv%T(i,j,k) + heating)) * i_h
269 tv%S(i,j,k_tgt) = (h(i,j,k_tgt) * tv%S(i,j,k_tgt) + &
270 h_transfer * tv%S(i,j,k)) * i_h
272 h(i,j,k) = h(i,j,k) - h_transfer
273 h(i,j,k_tgt) = h(i,j,k_tgt) + h_transfer
274 eb(i,j,k_tgt) = eb(i,j,k_tgt) + h_transfer
275 if (k_tgt < k-1)
then
277 eb(i,j,k2) = eb(i,j,k2) + h_transfer
282 if (heat_rem(i) <= 0.0)
then
283 do_i(i) = .false. ; num_left = num_left-1
298 if (num_left <= 0)
exit
301 if (
associated(tv%internal_heat))
then ;
do i=is,ie
302 tv%internal_heat(i,j) = tv%internal_heat(i,j) + gv%H_to_kg_m2 * &
303 (g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp)) - heat_rem(i))
312 end subroutine geothermal
315 subroutine geothermal_init(Time, G, param_file, diag, CS)
316 type(time_type),
target,
intent(in) :: time
320 type(
diag_ctrl),
target,
intent(inout) :: diag
324 #include "version_variable.h"
325 character(len=40) :: mdl =
"MOM_geothermal"
327 character(len=200) :: inputdir, geo_file, filename, geotherm_var
329 integer :: i, j, isd, ied, jsd, jed, id
330 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
332 if (
associated(cs))
then
333 call mom_error(warning,
"geothermal_init called with an associated"// &
334 "associated control structure.")
336 else ;
allocate(cs) ;
endif
343 call get_param(param_file, mdl,
"GEOTHERMAL_SCALE", scale, &
344 "The constant geothermal heat flux, a rescaling "//&
345 "factor for the heat flux read from GEOTHERMAL_FILE, or "//&
346 "0 to disable the geothermal heating.", &
347 units=
"W m-2 or various", default=0.0)
348 cs%apply_geothermal = .not.(scale == 0.0)
349 if (.not.cs%apply_geothermal)
return
351 call safe_alloc_ptr(cs%geo_heat, isd, ied, jsd, jed) ; cs%geo_heat(:,:) = 0.0
353 call get_param(param_file, mdl,
"GEOTHERMAL_FILE", geo_file, &
354 "The file from which the geothermal heating is to be "//&
355 "read, or blank to use a constant heating rate.", default=
" ")
356 call get_param(param_file, mdl,
"GEOTHERMAL_THICKNESS", cs%geothermal_thick, &
357 "The thickness over which to apply geothermal heating.", &
358 units=
"m", default=0.1)
359 call get_param(param_file, mdl,
"GEOTHERMAL_DRHO_DT_INPLACE", cs%dRcv_dT_inplace, &
360 "The value of drho_dT above which geothermal heating "//&
361 "simply heats water in place instead of moving it between "//&
362 "isopycnal layers. This must be negative.", &
363 units=
"kg m-3 K-1", default=-0.01)
364 if (cs%dRcv_dT_inplace >= 0.0)
call mom_error(fatal,
"geothermal_init: "//&
365 "GEOTHERMAL_DRHO_DT_INPLACE must be negative.")
367 if (len_trim(geo_file) >= 1)
then
368 call get_param(param_file, mdl,
"INPUTDIR", inputdir, default=
".")
369 inputdir = slasher(inputdir)
370 filename = trim(inputdir)//trim(geo_file)
371 call log_param(param_file, mdl,
"INPUTDIR/GEOTHERMAL_FILE", filename)
372 call get_param(param_file, mdl,
"GEOTHERMAL_VARNAME", geotherm_var, &
373 "The name of the geothermal heating variable in "//&
374 "GEOTHERMAL_FILE.", default=
"geo_heat")
375 call mom_read_data(filename, trim(geotherm_var), cs%geo_heat, g%Domain)
376 do j=jsd,jed ;
do i=isd,ied
377 cs%geo_heat(i,j) = (g%mask2dT(i,j) * scale) * cs%geo_heat(i,j)
380 do j=jsd,jed ;
do i=isd,ied
381 cs%geo_heat(i,j) = g%mask2dT(i,j) * scale
384 call pass_var(cs%geo_heat, g%domain)
387 id = register_static_field(
'ocean_model',
'geo_heat', diag%axesT1, &
388 'Geothermal heat flux into ocean',
'W m-2', &
389 cmor_field_name=
'hfgeou', cmor_units=
'W m-2', &
390 cmor_standard_name=
'upward_geothermal_heat_flux_at_sea_floor', &
391 cmor_long_name=
'Upward geothermal heat flux at sea floor', &
392 x_cell_method=
'mean', y_cell_method=
'mean', area_cell_method=
'mean')
393 if (id > 0)
call post_data(id, cs%geo_heat, diag, .true.)
395 end subroutine geothermal_init
398 subroutine geothermal_end(CS)
402 if (
associated(cs%geo_heat))
deallocate(cs%geo_heat)
403 if (
associated(cs))
deallocate(cs)
404 end subroutine geothermal_end