18 implicit none ;
private 20 #include <MOM_memory.h> 22 public geothermal_entraining, geothermal_in_place, geothermal_init, geothermal_end
26 real :: drcv_dt_inplace
29 real,
pointer :: geo_heat(:,:) => null()
30 real :: geothermal_thick
32 logical :: apply_geothermal
36 type(time_type),
pointer :: time => null()
39 integer :: id_internal_heat_heat_tendency = -1
40 integer :: id_internal_heat_temp_tendency = -1
41 integer :: id_internal_heat_h_tendency = -1
53 subroutine geothermal_entraining(h, tv, dt, ea, eb, G, GV, US, CS, halo)
56 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
61 real,
intent(in) :: dt
62 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: ea
66 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: eb
74 integer,
optional,
intent(in) :: halo
76 real,
dimension(SZI_(G)) :: &
82 real,
dimension(2) :: &
87 real :: angstrom, h_neglect
109 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: t_old
112 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_old
115 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: work_3d
120 logical :: do_i(szi_(g))
121 logical :: compute_h_old, compute_t_old
122 integer :: i, j, k, is, ie, js, je, nz, k2, i2
123 integer :: isj, iej, num_left, nkmb, k_tgt
125 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
126 if (
present(halo))
then 127 is = g%isc-halo ; ie = g%iec+halo ; js = g%jsc-halo ; je = g%jec+halo
130 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_geothermal: "//&
131 "Module must be initialized before it is used.")
132 if (.not.cs%apply_geothermal)
return 134 nkmb = gv%nk_rho_varies
135 irho_cp = 1.0 / (gv%H_to_RZ * tv%C_p)
136 angstrom = gv%Angstrom_H
137 h_neglect = gv%H_subroundoff
141 if (.not.
associated(tv%T))
call mom_error(fatal,
"MOM geothermal_entraining: "//&
142 "Geothermal heating can only be applied if T & S are state variables.")
149 compute_h_old = cs%id_internal_heat_h_tendency > 0 &
150 .or. cs%id_internal_heat_heat_tendency > 0 &
151 .or. cs%id_internal_heat_temp_tendency > 0
153 compute_t_old = cs%id_internal_heat_heat_tendency > 0 &
154 .or. cs%id_internal_heat_temp_tendency > 0
156 if (cs%id_internal_heat_heat_tendency > 0) work_3d(:,:,:) = 0.0
158 if (compute_h_old .or. compute_t_old)
then ;
do k=1,nz ;
do j=js,je ;
do i=is,ie
160 h_old(i,j,k) = h(i,j,k)
161 t_old(i,j,k) = tv%T(i,j,k)
162 enddo ;
enddo ;
enddo ;
endif 191 heat_rem(i) = g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp))
192 do_i(i) = .true. ;
if (heat_rem(i) <= 0.0) do_i(i) = .false.
193 if (do_i(i)) num_left = num_left + 1
194 h_geo_rem(i) = cs%Geothermal_thick
196 if (num_left == 0) cycle
199 isj = ie+1 ;
do i=is,ie ;
if (do_i(i))
then ; isj = i ;
exit ;
endif ;
enddo 200 iej = is-1 ;
do i=ie,is,-1 ;
if (do_i(i))
then ; iej = i ;
exit ;
endif ;
enddo 204 tv%eqn_of_state, (/isj-(g%isd-1),iej-(g%isd-1)/) )
210 do i=isj,iej ;
if (do_i(i))
then 212 if (h(i,j,k) > angstrom)
then 213 if ((h(i,j,k)-angstrom) >= h_geo_rem(i))
then 214 h_heated = h_geo_rem(i)
215 heat_avail = heat_rem(i)
218 h_heated = (h(i,j,k)-angstrom)
219 heat_avail = heat_rem(i) * (h_heated / &
220 (h_geo_rem(i) + h_neglect))
221 h_geo_rem(i) = h_geo_rem(i) - h_heated
224 if (k<=nkmb .or. nkmb<=0)
then 228 elseif ((k==nkmb+1) .or. (gv%Rlay(k-1) < rcv_bl(i)))
then 235 rcv_tgt = gv%Rlay(k-1)
238 if (k<=nkmb .or. nkmb<=0)
then 239 rcv = 0.0 ; drcv_dt = 0.0
242 rcv, tv%eqn_of_state)
243 t2(1) = tv%T(i,j,k) ; s2(1) = tv%S(i,j,k)
244 t2(2) = tv%T(i,j,k_tgt) ; s2(2) = tv%S(i,j,k_tgt)
246 tv%eqn_of_state, (/1,2/) )
247 drcv_dt = 0.5*(drcv_dt_(1) + drcv_dt_(2))
250 if ((drcv_dt >= 0.0) .or. (k<=nkmb .or. nkmb<=0))
then 252 heat_in_place = heat_avail
254 elseif (drcv_dt <= cs%dRcv_dT_inplace)
then 256 heat_in_place = min(heat_avail, max(0.0, h(i,j,k) * &
257 ((gv%Rlay(k)-rcv) / drcv_dt)))
258 heat_trans = heat_avail - heat_in_place
261 wt_in_place = (cs%dRcv_dT_inplace - drcv_dt) / cs%dRcv_dT_inplace
262 heat_in_place = max(wt_in_place*heat_avail, &
263 h(i,j,k) * ((gv%Rlay(k)-rcv) / drcv_dt) )
264 heat_trans = heat_avail - heat_in_place
267 if (heat_in_place > 0.0)
then 273 dtemp = heat_in_place / (h(i,j,k) + h_neglect)
274 tv%T(i,j,k) = tv%T(i,j,k) + dtemp
275 heat_rem(i) = heat_rem(i) - heat_in_place
276 rcv = rcv + drcv_dt * dtemp
279 if (heat_trans > 0.0)
then 282 drcv = max(rcv - rcv_tgt, 0.0)
286 if ((-drcv_dt * heat_trans) >= drcv * (h(i,j,k)-angstrom))
then 287 h_transfer = h(i,j,k) - angstrom
288 heating = (h_transfer * drcv) / (-drcv_dt)
292 h_geo_rem(i) = h_geo_rem(i) + h_heated * &
293 ((heat_avail - (heating + heat_in_place)) / heat_avail)
295 h_transfer = (-drcv_dt * heat_trans) / drcv
298 heat_rem(i) = heat_rem(i) - heating
300 i_h = 1.0 / ((h(i,j,k_tgt) + h_neglect) + h_transfer)
301 tv%T(i,j,k_tgt) = ((h(i,j,k_tgt) + h_neglect) * tv%T(i,j,k_tgt) + &
302 (h_transfer * tv%T(i,j,k) + heating)) * i_h
303 tv%S(i,j,k_tgt) = ((h(i,j,k_tgt) + h_neglect) * tv%S(i,j,k_tgt) + &
304 h_transfer * tv%S(i,j,k)) * i_h
306 h(i,j,k) = h(i,j,k) - h_transfer
307 h(i,j,k_tgt) = h(i,j,k_tgt) + h_transfer
308 eb(i,j,k_tgt) = eb(i,j,k_tgt) + h_transfer
309 if (k_tgt < k-1)
then 311 eb(i,j,k2) = eb(i,j,k2) + h_transfer
316 if (heat_rem(i) <= 0.0)
then 317 do_i(i) = .false. ; num_left = num_left-1
329 if (cs%id_internal_heat_heat_tendency > 0)
then 330 work_3d(i,j,k) = ((gv%H_to_RZ*tv%C_p) * idt) * (h(i,j,k) * tv%T(i,j,k) - h_old(i,j,k) * t_old(i,j,k))
334 if (num_left <= 0)
exit 337 if (
associated(tv%internal_heat))
then ;
do i=is,ie
338 tv%internal_heat(i,j) = tv%internal_heat(i,j) + gv%H_to_RZ * &
339 (g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp)) - heat_rem(i))
344 if (cs%id_internal_heat_heat_tendency > 0)
then 345 call post_data(cs%id_internal_heat_heat_tendency, work_3d, cs%diag, alt_h=h_old)
347 if (cs%id_internal_heat_temp_tendency > 0)
then 348 do k=1,nz ;
do j=js,je ;
do i=is,ie
349 work_3d(i,j,k) = idt * (tv%T(i,j,k) - t_old(i,j,k))
351 call post_data(cs%id_internal_heat_temp_tendency, work_3d, cs%diag, alt_h=h_old)
353 if (cs%id_internal_heat_h_tendency > 0)
then 354 do k=1,nz ;
do j=js,je ;
do i=is,ie
355 work_3d(i,j,k) = idt * (h(i,j,k) - h_old(i,j,k))
356 enddo ;
enddo ;
enddo 357 call post_data(cs%id_internal_heat_h_tendency, work_3d, cs%diag, alt_h=h_old)
365 end subroutine geothermal_entraining
370 subroutine geothermal_in_place(h, tv, dt, G, GV, US, CS, halo)
371 type(ocean_grid_type),
intent(inout) :: g
372 type(verticalgrid_type),
intent(in) :: gv
373 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
374 type(thermo_var_ptrs),
intent(inout) :: tv
378 real,
intent(in) :: dt
379 type(unit_scale_type),
intent(in) :: us
382 integer,
optional,
intent(in) :: halo
385 real,
dimension(SZI_(G)) :: &
389 real :: angstrom, h_neglect
395 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
400 logical :: calc_diags
401 integer :: i, j, k, is, ie, js, je, nz, i2, isj, iej
403 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
404 if (
present(halo))
then 405 is = g%isc-halo ; ie = g%iec+halo ; js = g%jsc-halo ; je = g%jec+halo
408 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_geothermal: "//&
409 "Module must be initialized before it is used.")
410 if (.not.cs%apply_geothermal)
return 412 irho_cp = 1.0 / (gv%H_to_RZ * tv%C_p)
413 angstrom = gv%Angstrom_H
414 h_neglect = gv%H_subroundoff
417 if (.not.
associated(tv%T))
call mom_error(fatal,
"MOM geothermal_in_place: "//&
418 "Geothermal heating can only be applied if T & S are state variables.")
425 calc_diags = (cs%id_internal_heat_heat_tendency > 0) .or. (cs%id_internal_heat_temp_tendency > 0)
427 if (calc_diags) dtdt_diag(:,:,:) = 0.0
438 heat_rem(i) = g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp))
439 if (heat_rem(i) > 0.0) do_any = .true.
440 h_geo_rem(i) = cs%Geothermal_thick
442 if (.not.do_any) cycle
445 isj = ie+1 ;
do i=is,ie ;
if (heat_rem(i) > 0.0)
then ; isj = i ;
exit ;
endif ;
enddo 446 iej = is-1 ;
do i=ie,is,-1 ;
if (heat_rem(i) > 0.0)
then ; iej = i ;
exit ;
endif ;
enddo 451 if ((heat_rem(i) > 0.0) .and. (h(i,j,k) > angstrom))
then 454 if ((h(i,j,k)-angstrom) >= h_geo_rem(i))
then 455 heat_here = heat_rem(i)
459 heat_here = heat_rem(i) * ((h(i,j,k)-angstrom) / (h_geo_rem(i) + h_neglect))
460 h_geo_rem(i) = h_geo_rem(i) - (h(i,j,k)-angstrom)
461 heat_rem(i) = heat_rem(i) - heat_here
464 dtemp = heat_here / (h(i,j,k) + h_neglect)
465 tv%T(i,j,k) = tv%T(i,j,k) + dtemp
466 if (calc_diags) dtdt_diag(i,j,k) = dtemp * idt
469 if (heat_rem(i) > 0.0) do_any= .true.
472 if (.not.do_any)
exit 475 if (
associated(tv%internal_heat))
then ;
do i=is,ie
476 tv%internal_heat(i,j) = tv%internal_heat(i,j) + gv%H_to_RZ * &
477 (g%mask2dT(i,j) * (cs%geo_heat(i,j) * (dt*irho_cp)) - heat_rem(i))
482 if (cs%id_internal_heat_temp_tendency > 0)
then 483 call post_data(cs%id_internal_heat_temp_tendency, dtdt_diag, cs%diag, alt_h=h)
485 if (cs%id_internal_heat_heat_tendency > 0)
then 486 do k=1,nz ;
do j=js,je ;
do i=is,ie
489 dtdt_diag(i,j,k) = (gv%H_to_RZ*tv%C_p) * (h(i,j,k) * dtdt_diag(i,j,k))
490 enddo ;
enddo ;
enddo 491 call post_data(cs%id_internal_heat_heat_tendency, dtdt_diag, cs%diag, alt_h=h)
499 end subroutine geothermal_in_place
502 subroutine geothermal_init(Time, G, GV, US, param_file, diag, CS, useALEalgorithm)
503 type(time_type),
target,
intent(in) :: time
504 type(ocean_grid_type),
intent(inout) :: g
505 type(verticalgrid_type),
intent(in) :: gv
506 type(unit_scale_type),
intent(in) :: us
507 type(param_file_type),
intent(in) :: param_file
509 type(diag_ctrl),
target,
intent(inout) :: diag
512 logical,
optional,
intent(in) :: usealealgorithm
515 #include "version_variable.h" 516 character(len=40) :: mdl =
"MOM_geothermal" 517 character(len=48) :: thickness_units
519 character(len=200) :: inputdir, geo_file, filename, geotherm_var
522 integer :: i, j, isd, ied, jsd, jed, id
523 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
525 if (
associated(cs))
then 526 call mom_error(warning,
"geothermal_init called with an associated"// &
527 "associated control structure.")
529 else ;
allocate(cs) ;
endif 535 call log_version(param_file, mdl, version,
"")
536 call get_param(param_file, mdl,
"GEOTHERMAL_SCALE", geo_scale, &
537 "The constant geothermal heat flux, a rescaling "//&
538 "factor for the heat flux read from GEOTHERMAL_FILE, or "//&
539 "0 to disable the geothermal heating.", &
540 units=
"W m-2 or various", default=0.0, scale=us%W_m2_to_QRZ_T)
541 cs%apply_geothermal = .not.(geo_scale == 0.0)
542 if (.not.cs%apply_geothermal)
return 544 call safe_alloc_ptr(cs%geo_heat, isd, ied, jsd, jed) ; cs%geo_heat(:,:) = 0.0
546 call get_param(param_file, mdl,
"GEOTHERMAL_FILE", geo_file, &
547 "The file from which the geothermal heating is to be "//&
548 "read, or blank to use a constant heating rate.", default=
" ")
549 call get_param(param_file, mdl,
"GEOTHERMAL_THICKNESS", cs%geothermal_thick, &
550 "The thickness over which to apply geothermal heating.", &
551 units=
"m", default=0.1, scale=gv%m_to_H)
552 call get_param(param_file, mdl,
"GEOTHERMAL_DRHO_DT_INPLACE", cs%dRcv_dT_inplace, &
553 "The value of drho_dT above which geothermal heating "//&
554 "simply heats water in place instead of moving it between "//&
555 "isopycnal layers. This must be negative.", &
556 units=
"kg m-3 K-1", scale=us%kg_m3_to_R, default=-0.01)
557 if (cs%dRcv_dT_inplace >= 0.0)
call mom_error(fatal,
"geothermal_init: "//&
558 "GEOTHERMAL_DRHO_DT_INPLACE must be negative.")
560 if (len_trim(geo_file) >= 1)
then 561 call get_param(param_file, mdl,
"INPUTDIR", inputdir, default=
".")
562 inputdir = slasher(inputdir)
563 filename = trim(inputdir)//trim(geo_file)
564 call log_param(param_file, mdl,
"INPUTDIR/GEOTHERMAL_FILE", filename)
565 call get_param(param_file, mdl,
"GEOTHERMAL_VARNAME", geotherm_var, &
566 "The name of the geothermal heating variable in "//&
567 "GEOTHERMAL_FILE.", default=
"geo_heat")
568 call mom_read_data(filename, trim(geotherm_var), cs%geo_heat, g%Domain)
569 do j=jsd,jed ;
do i=isd,ied
570 cs%geo_heat(i,j) = (g%mask2dT(i,j) * geo_scale) * cs%geo_heat(i,j)
573 do j=jsd,jed ;
do i=isd,ied
574 cs%geo_heat(i,j) = g%mask2dT(i,j) * geo_scale
577 call pass_var(cs%geo_heat, g%domain)
579 thickness_units = get_thickness_units(gv)
582 id = register_static_field(
'ocean_model',
'geo_heat', diag%axesT1, &
583 'Geothermal heat flux into ocean',
'W m-2', conversion=us%QRZ_T_to_W_m2, &
584 cmor_field_name=
'hfgeou', cmor_units=
'W m-2', &
585 cmor_standard_name=
'upward_geothermal_heat_flux_at_sea_floor', &
586 cmor_long_name=
'Upward geothermal heat flux at sea floor', &
587 x_cell_method=
'mean', y_cell_method=
'mean', area_cell_method=
'mean')
588 if (id > 0)
call post_data(id, cs%geo_heat, diag, .true.)
591 cs%id_internal_heat_heat_tendency=register_diag_field(
'ocean_model', &
592 'internal_heat_heat_tendency', diag%axesTL, time, &
593 'Heat tendency (in 3D) due to internal (geothermal) sources', &
594 'W m-2', conversion=us%QRZ_T_to_W_m2, v_extensive=.true.)
595 cs%id_internal_heat_temp_tendency=register_diag_field(
'ocean_model', &
596 'internal_heat_temp_tendency', diag%axesTL, time, &
597 'Temperature tendency (in 3D) due to internal (geothermal) sources', &
598 'degC s-1', conversion=us%s_to_T, v_extensive=.true.)
599 if (
present(usealealgorithm))
then ;
if (.not.usealealgorithm)
then 601 cs%id_internal_heat_h_tendency=register_diag_field(
'ocean_model', &
602 'internal_heat_h_tendency', diag%axesTL, time, &
603 'Thickness tendency (in 3D) due to internal (geothermal) sources', &
604 trim(thickness_units), conversion=gv%H_to_MKS*us%s_to_T, v_extensive=.true.)
607 end subroutine geothermal_init
610 subroutine geothermal_end(CS)
614 if (
associated(cs%geo_heat))
deallocate(cs%geo_heat)
615 if (
associated(cs))
deallocate(cs)
616 end subroutine geothermal_end
Implemented geothermal heating at the ocean bottom.
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
This module contains I/O framework code.
The MOM6 facility to parse input files for runtime parameters.
An overloaded interface to log the values of various types of parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Routines for error handling and I/O management.
Calculate the derivatives of density with temperature and salinity from T, S, and P...
Provides subroutines for quantities specific to the equation of state.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Provides a transparent vertical ocean grid type and supporting routines.
Provides transparent structures with groups of MOM6 variables and supporting routines.
Control structure for geothermal heating.
Do a halo update on an array.
Read a data field from a file.
An overloaded interface to read and log the values of various types of parameters.