6 #include <MOM_memory.h>
11 #define _ALLOCATED associated
13 #define _ALLOCATED allocated
17 use field_manager_mod,
only: fm_string_len
19 use generic_tracer,
only: generic_tracer_register, generic_tracer_get_diag_list
20 use generic_tracer,
only: generic_tracer_init, generic_tracer_source, generic_tracer_register_diag
21 use generic_tracer,
only: generic_tracer_coupler_get, generic_tracer_coupler_set
22 use generic_tracer,
only: generic_tracer_end, generic_tracer_get_list, do_generic_tracer
23 use generic_tracer,
only: generic_tracer_update_from_bottom,generic_tracer_vertdiff_g
54 implicit none ;
private
58 logical :: g_registered = .false.
60 public register_mom_generic_tracer, initialize_mom_generic_tracer
61 public mom_generic_tracer_column_physics, mom_generic_tracer_surface_state
62 public end_mom_generic_tracer, mom_generic_tracer_get
63 public mom_generic_tracer_stock
64 public mom_generic_flux_init
65 public mom_generic_tracer_min_max
66 public mom_generic_tracer_fluxes_accumulate
70 character(len = 200) :: ic_file
73 real :: tracer_ic_val = 0.0
74 real :: tracer_land_val = -1.0
75 logical :: tracers_may_reinit
90 #include "version_variable.h"
97 function register_mom_generic_tracer(HI, GV, param_file, CS, tr_Reg, restart_CS)
107 logical :: register_mom_generic_tracer
109 character(len=128),
parameter :: sub_name =
'register_MOM_generic_tracer'
110 character(len=200) :: inputdir
113 integer :: ntau, k,i,j,axes(3)
115 character(len=fm_string_len) :: g_tracer_name,longname,units
116 real,
dimension(:,:,:,:),
pointer :: tr_field
117 real,
dimension(:,:,:),
pointer :: tr_ptr
118 real,
dimension(HI%isd:HI%ied, HI%jsd:HI%jed,GV%ke) :: grid_tmask
119 integer,
dimension(HI%isd:HI%ied, HI%jsd:HI%jed) :: grid_kmt
121 register_mom_generic_tracer = .false.
122 if (
associated(cs))
then
123 call mom_error(warning,
"register_MOM_generic_tracer called with an "// &
124 "associated control structure.")
132 if (.not. g_registered)
then
133 call generic_tracer_register()
134 g_registered = .true.
139 call log_version(param_file, sub_name, version,
"")
140 call get_param(param_file, sub_name,
"GENERIC_TRACER_IC_FILE", cs%IC_file, &
141 "The file in which the generic trcer initial values can "//&
142 "be found, or an empty string for internal initialization.", &
144 if ((len_trim(cs%IC_file) > 0) .and. (scan(cs%IC_file,
'/') == 0))
then
146 call get_param(param_file, sub_name,
"INPUTDIR", inputdir, default=
".")
147 cs%IC_file = trim(slasher(inputdir))//trim(cs%IC_file)
148 call log_param(param_file, sub_name,
"INPUTDIR/GENERIC_TRACER_IC_FILE", cs%IC_file)
150 call get_param(param_file, sub_name,
"GENERIC_TRACER_IC_FILE_IS_Z", cs%Z_IC_file, &
151 "If true, GENERIC_TRACER_IC_FILE is in depth space, not "//&
152 "layer space.",default=.false.)
153 call get_param(param_file, sub_name,
"TRACERS_MAY_REINIT", cs%tracers_may_reinit, &
154 "If true, tracers may go through the initialization code "//&
155 "if they are not found in the restart files. Otherwise "//&
156 "it is a fatal error if tracers are not found in the "//&
157 "restart files of a restarted run.", default=.false.)
159 cs%restart_CSp => restart_cs
169 grid_tmask(:,:,:) = 0.0
176 call generic_tracer_init(hi%isc,hi%iec,hi%jsc,hi%jec,hi%isd,hi%ied,hi%jsd,hi%jed,&
177 gv%ke,ntau,axes,grid_tmask,grid_kmt,set_time(0,0))
185 call generic_tracer_get_list(cs%g_tracer_list)
186 if (.NOT.
associated(cs%g_tracer_list))
call mom_error(fatal, trim(sub_name)//&
187 ": No tracer in the list.")
190 g_tracer=>cs%g_tracer_list
192 call g_tracer_get_alias(g_tracer,g_tracer_name)
199 tr_ptr => tr_field(:,:,:,1)
201 if (g_tracer_is_prog(g_tracer))
then
202 call register_tracer(tr_ptr, tr_reg, param_file, hi, gv, &
203 name=g_tracer_name, longname=longname, units=units, &
204 registry_diags=.false., &
205 restart_cs=restart_cs, mandatory=.not.cs%tracers_may_reinit)
208 restart_cs, longname=longname, units=units)
212 call g_tracer_get_next(g_tracer, g_tracer_next)
213 if (.NOT.
associated(g_tracer_next))
exit
214 g_tracer=>g_tracer_next
218 register_mom_generic_tracer = .true.
219 end function register_mom_generic_tracer
230 subroutine initialize_mom_generic_tracer(restart, day, G, GV, US, h, param_file, diag, OBC, CS, &
231 sponge_CSp, ALE_sponge_CSp)
232 logical,
intent(in) :: restart
234 type(time_type),
target,
intent(in) :: day
238 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
240 type(
diag_ctrl),
target,
intent(in) :: diag
248 character(len=128),
parameter :: sub_name =
'initialize_MOM_generic_tracer'
250 integer :: i, j, k, isc, iec, jsc, jec, nk
252 character(len=fm_string_len) :: g_tracer_name
253 real,
dimension(:,:,:,:),
pointer :: tr_field
254 real,
dimension(:,:,:),
pointer :: tr_ptr
255 real,
dimension(G%isd:G%ied, G%jsd:G%jed,1:G%ke) :: grid_tmask
256 integer,
dimension(G%isd:G%ied, G%jsd:G%jed) :: grid_kmt
262 isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec ; nk = g%ke
266 if (.NOT.
associated(cs%g_tracer_list))
call mom_error(fatal, trim(sub_name)//&
267 ": No tracer in the list.")
269 g_tracer=>cs%g_tracer_list
272 if (index(cs%IC_file,
'_NULL_') /= 0)
then
273 call mom_error(warning,
"The name of the IC_file "//trim(cs%IC_file)//&
274 " indicates no MOM initialization was asked for the generic tracers."//&
275 "Bypassing the MOM initialization of ALL generic tracers!")
278 call g_tracer_get_alias(g_tracer,g_tracer_name)
280 tr_ptr => tr_field(:,:,:,1)
282 if (.not.restart .or. (cs%tracers_may_reinit .and. &
285 if (g_tracer%requires_src_info )
then
286 call mom_error(note,
"initialize_MOM_generic_tracer: "//&
287 "initializing generic tracer "//trim(g_tracer_name)//&
288 " using MOM_initialize_tracer_from_Z ")
290 call mom_initialize_tracer_from_z(h, tr_ptr, g, gv, us, param_file, &
291 src_file = g_tracer%src_file, &
292 src_var_nam = g_tracer%src_var_name, &
293 src_var_unit_conversion = g_tracer%src_var_unit_conversion,&
294 src_var_record = g_tracer%src_var_record, &
295 src_var_gridspec = g_tracer%src_var_gridspec )
298 do k=1,nk ;
do j=jsc,jec ;
do i=isc,iec
299 if (tr_ptr(i,j,k) /= cs%tracer_land_val)
then
300 if (tr_ptr(i,j,k) < g_tracer%src_var_valid_min) tr_ptr(i,j,k) = g_tracer%src_var_valid_min
304 enddo ;
enddo ;
enddo
307 if ( (trim(g_tracer_name) ==
'cased') .or. (trim(g_tracer_name) ==
'ca13csed') )
then
308 do k=2,nk ;
do j=jsc,jec ;
do i=isc,iec
309 if (tr_ptr(i,j,k) /= cs%tracer_land_val)
then
312 enddo ;
enddo ;
enddo
314 elseif(.not. g_tracer%requires_restart)
then
316 call mom_error(note,
"initialize_MOM_generic_tracer: "//&
317 "skip initialization of generic tracer "//trim(g_tracer_name))
320 if (len_trim(cs%IC_file) > 0)
then
322 if (.not.
file_exists(cs%IC_file))
call mom_error(fatal, &
323 "initialize_MOM_Generic_tracer: Unable to open "//cs%IC_file)
324 if (cs%Z_IC_file)
then
325 ok = tracer_z_init(tr_ptr, h, cs%IC_file, g_tracer_name, g, us)
327 ok = tracer_z_init(tr_ptr, h, cs%IC_file, trim(g_tracer_name), g, us)
328 if (.not.ok)
call mom_error(fatal,
"initialize_MOM_Generic_tracer: "//&
329 "Unable to read "//trim(g_tracer_name)//
" from "//&
330 trim(cs%IC_file)//
".")
332 call mom_error(note,
"initialize_MOM_generic_tracer: "//&
333 "initialized generic tracer "//trim(g_tracer_name)//&
334 " using Generic Tracer File on Z: "//cs%IC_file)
337 call mom_error(note,
"initialize_MOM_generic_tracer: "//&
338 "Using Generic Tracer IC file on native grid "//trim(cs%IC_file)//&
339 " for tracer "//trim(g_tracer_name))
340 call mom_read_data(cs%IC_file, trim(g_tracer_name), tr_ptr, g%Domain)
343 call mom_error(fatal,
"initialize_MOM_generic_tracer: "//&
344 "check Generic Tracer IC filename "//trim(cs%IC_file)//&
345 " for tracer "//trim(g_tracer_name))
352 call g_tracer_get_next(g_tracer, g_tracer_next)
353 if (.NOT.
associated(g_tracer_next))
exit
354 g_tracer=>g_tracer_next
362 grid_tmask(:,:,:) = 0.0
364 do j = g%jsd, g%jed ;
do i = g%isd, g%ied
365 if (g%mask2dT(i,j) > 0)
then
366 grid_tmask(i,j,:) = 1.0
370 call g_tracer_set_common(g%isc,g%iec,g%jsc,g%jec,g%isd,g%ied,g%jsd,g%jed,&
371 gv%ke,1,cs%diag%axesTL%handles,grid_tmask,grid_kmt,day)
375 #ifdef _USE_MOM6_DIAG
376 call g_tracer_set_csdiag(cs%diag)
378 call generic_tracer_register_diag()
379 #ifdef _USE_MOM6_DIAG
380 call g_tracer_set_csdiag(cs%diag)
383 cs%H_to_m = gv%H_to_m
385 end subroutine initialize_mom_generic_tracer
397 subroutine mom_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml, dt, G, GV, CS, tv, optics, &
398 evap_CFL_limit, minimum_forcing_depth)
401 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
403 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
405 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
408 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
411 type(
forcing),
intent(in) :: fluxes
413 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: hml
414 real,
intent(in) :: dt
417 type(optics_type),
intent(in) :: optics
418 real,
optional,
intent(in) :: evap_cfl_limit
420 real,
optional,
intent(in) :: minimum_forcing_depth
427 character(len=128),
parameter :: sub_name =
'MOM_generic_tracer_column_physics'
430 character(len=fm_string_len) :: g_tracer_name
431 real,
dimension(:,:),
pointer :: stf_array,trunoff_array,runoff_tracer_flux_array
433 real :: surface_field(szi_(g),szj_(g))
434 real :: dz_ml(szi_(g),szj_(g))
437 real,
dimension(G%isd:G%ied,G%jsd:G%jed,G%ke) :: rho_dzt, dzt
438 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_work
439 integer :: i, j, k, isc, iec, jsc, jec, nk
441 isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec ; nk = g%ke
444 if (.NOT.
associated(cs%g_tracer_list))
call mom_error(fatal,&
445 trim(sub_name)//
": No tracer in the list.")
447 #ifdef _USE_MOM6_DIAG
448 call g_tracer_set_csdiag(cs%diag)
462 g_tracer=>cs%g_tracer_list
464 if (_allocated(g_tracer%trunoff))
then
465 call g_tracer_get_alias(g_tracer,g_tracer_name)
470 runoff_tracer_flux_array(:,:) = trunoff_array(:,:) * &
471 g%US%RZ_T_to_kg_m2s*fluxes%lrunoff(:,:)
472 stf_array = stf_array + runoff_tracer_flux_array
476 call g_tracer_get_next(g_tracer, g_tracer_next)
477 if (.NOT.
associated(g_tracer_next))
exit
478 g_tracer=>g_tracer_next
486 rho_dzt(:,:,:) = gv%H_to_kg_m2 * gv%Angstrom_H
487 do k = 1, nk ;
do j = jsc, jec ;
do i = isc, iec
488 rho_dzt(i,j,k) = gv%H_to_kg_m2 * h_old(i,j,k)
489 enddo ;
enddo ;
enddo
492 do k = 1, nk ;
do j = jsc, jec ;
do i = isc, iec
493 dzt(i,j,k) = gv%H_to_m * h_old(i,j,k)
494 enddo ;
enddo ;
enddo
496 do j=jsc,jec ;
do i=isc,iec
497 surface_field(i,j) = tv%S(i,j,1)
498 dz_ml(i,j) = g%US%Z_to_m * hml(i,j)
500 sosga = global_area_mean(surface_field, g)
505 if ((g%US%L_to_m == 1.0) .and. (g%US%RZ_to_kg_m2 == 1.0) .and. (g%US%s_to_T == 1.0))
then
507 call generic_tracer_source(tv%T, tv%S, rho_dzt, dzt, dz_ml, g%isd, g%jsd, 1, dt, &
508 g%areaT, get_diag_time_end(cs%diag), &
509 optics%nbands, optics%max_wavelength_band, optics%sw_pen_band, optics%opacity_band, &
510 internal_heat=tv%internal_heat, frunoff=fluxes%frunoff, sosga=sosga)
512 call generic_tracer_source(tv%T, tv%S, rho_dzt, dzt, dz_ml, g%isd, g%jsd, 1, dt, &
513 g%US%L_to_m**2*g%areaT(:,:), get_diag_time_end(cs%diag), &
514 optics%nbands, optics%max_wavelength_band, optics%sw_pen_band, optics%opacity_band, &
515 internal_heat=g%US%RZ_to_kg_m2*tv%internal_heat(:,:), &
516 frunoff=g%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga)
521 if (
present(evap_cfl_limit) .and.
present(minimum_forcing_depth))
then
522 g_tracer=>cs%g_tracer_list
524 if (g_tracer_is_prog(g_tracer))
then
525 do k=1,nk ;
do j=jsc,jec ;
do i=isc,iec
526 h_work(i,j,k) = h_old(i,j,k)
527 enddo ;
enddo ;
enddo
528 call applytracerboundaryfluxesinout(g, gv, g_tracer%field(:,:,:,1), g%US%s_to_T*dt, &
529 fluxes, h_work, evap_cfl_limit, minimum_forcing_depth)
533 call g_tracer_get_next(g_tracer, g_tracer_next)
534 if (.NOT.
associated(g_tracer_next))
exit
535 g_tracer=>g_tracer_next
544 if (
present(evap_cfl_limit) .and.
present(minimum_forcing_depth))
then
546 call generic_tracer_vertdiff_g(h_work, ea, eb, dt, gv%kg_m2_to_H, gv%m_to_H, 1)
549 call generic_tracer_vertdiff_g(h_old, ea, eb, dt, gv%kg_m2_to_H, gv%m_to_H, 1)
555 call generic_tracer_update_from_bottom(dt, 1, get_diag_time_end(cs%diag))
558 call g_tracer_send_diag(cs%g_tracer_list, get_diag_time_end(cs%diag), tau=1)
559 #ifdef _USE_MOM6_DIAG
560 call g_tracer_set_csdiag(cs%diag)
563 end subroutine mom_generic_tracer_column_physics
570 function mom_generic_tracer_stock(h, stocks, G, GV, CS, names, units, stock_index)
573 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
574 real,
dimension(:),
intent(out) :: stocks
577 character(len=*),
dimension(:),
intent(out) :: names
578 character(len=*),
dimension(:),
intent(out) :: units
579 integer,
optional,
intent(in) :: stock_index
581 integer :: mom_generic_tracer_stock
586 real,
dimension(:,:,:,:),
pointer :: tr_field
587 real,
dimension(:,:,:),
pointer :: tr_ptr
588 character(len=128),
parameter :: sub_name =
'MOM_generic_tracer_stock'
590 integer :: i, j, k, is, ie, js, je, nz, m
591 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
593 mom_generic_tracer_stock = 0
594 if (.not.
associated(cs))
return
596 if (
present(stock_index))
then ;
if (stock_index > 0)
then
603 if (.NOT.
associated(cs%g_tracer_list))
return
605 m=1 ; g_tracer=>cs%g_tracer_list
607 call g_tracer_get_alias(g_tracer,names(m))
609 units(m) = trim(units(m))//
" kg"
613 tr_ptr => tr_field(:,:,:,1)
614 do k=1,nz ;
do j=js,je ;
do i=is,ie
615 stocks(m) = stocks(m) + tr_ptr(i,j,k) * &
616 (g%mask2dT(i,j) * g%US%L_to_m**2*g%areaT(i,j) * h(i,j,k))
617 enddo ;
enddo ;
enddo
618 stocks(m) = gv%H_to_kg_m2 * stocks(m)
621 call g_tracer_get_next(g_tracer, g_tracer_next)
622 if (.NOT.
associated(g_tracer_next))
exit
623 g_tracer=>g_tracer_next
627 mom_generic_tracer_stock = m
629 end function mom_generic_tracer_stock
634 function mom_generic_tracer_min_max(ind_start, got_minmax, gmin, gmax, xgmin, ygmin, zgmin, &
635 xgmax, ygmax, zgmax , G, CS, names, units)
636 use mpp_utilities_mod,
only: mpp_array_global_min_max
637 integer,
intent(in) :: ind_start
638 logical,
dimension(:),
intent(out) :: got_minmax
640 real,
dimension(:),
intent(out) :: gmin
642 real,
dimension(:),
intent(out) :: gmax
644 real,
dimension(:),
intent(out) :: xgmin
645 real,
dimension(:),
intent(out) :: ygmin
646 real,
dimension(:),
intent(out) :: zgmin
647 real,
dimension(:),
intent(out) :: xgmax
648 real,
dimension(:),
intent(out) :: ygmax
649 real,
dimension(:),
intent(out) :: zgmax
652 character(len=*),
dimension(:),
intent(out) :: names
653 character(len=*),
dimension(:),
intent(out) :: units
654 integer :: mom_generic_tracer_min_max
659 real,
dimension(:,:,:,:),
pointer :: tr_field
660 real,
dimension(:,:,:),
pointer :: tr_ptr
661 character(len=128),
parameter :: sub_name =
'MOM_generic_tracer_min_max'
663 real,
dimension(:,:,:),
pointer :: grid_tmask
664 integer :: isc,iec,jsc,jec,isd,ied,jsd,jed,nk,ntau
666 integer :: i, j, k, is, ie, js, je, nz, m
667 real,
allocatable,
dimension(:) :: geo_z
669 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
671 mom_generic_tracer_min_max = 0
672 if (.not.
associated(cs))
return
674 if (.NOT.
associated(cs%g_tracer_list))
return
677 call g_tracer_get_common(isc,iec,jsc,jec,isd,ied,jsd,jed,nk,ntau,grid_tmask=grid_tmask)
682 do k=1,nk ; geo_z(k) = real(k) ;
enddo
684 m=ind_start ; g_tracer=>cs%g_tracer_list
686 call g_tracer_get_alias(g_tracer,names(m))
688 units(m) = trim(units(m))//
" kg"
694 tr_ptr => tr_field(:,:,:,1)
696 call mpp_array_global_min_max(tr_ptr, grid_tmask,isd,jsd,isc,iec,jsc,jec,nk , gmin(m), gmax(m), &
697 g%geoLonT,g%geoLatT,geo_z,xgmin(m), ygmin(m), zgmin(m), &
698 xgmax(m), ygmax(m), zgmax(m))
700 got_minmax(m) = .true.
703 call g_tracer_get_next(g_tracer, g_tracer_next)
704 if (.NOT.
associated(g_tracer_next))
exit
705 g_tracer=>g_tracer_next
709 mom_generic_tracer_min_max = m
711 end function mom_generic_tracer_min_max
719 subroutine mom_generic_tracer_surface_state(sfc_state, h, G, CS)
721 type(
surface),
intent(inout) :: sfc_state
723 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
729 character(len=128),
parameter :: sub_name =
'MOM_generic_tracer_surface_state'
730 real,
dimension(G%isd:G%ied,G%jsd:G%jed,1:G%ke,1) :: rho0
731 real,
dimension(G%isd:G%ied,G%jsd:G%jed,1:G%ke) :: dzt
738 dzt(:,:,:) = cs%H_to_m * h(:,:,:)
740 sosga = global_area_mean(sfc_state%SSS, g)
742 call generic_tracer_coupler_set(sfc_state%tr_fields,&
746 ilb=g%isd, jlb=g%jsd,&
748 tau=1,sosga=sosga,model_time=get_diag_time_end(cs%diag))
759 end subroutine mom_generic_tracer_surface_state
762 subroutine mom_generic_flux_init(verbosity)
763 integer,
optional,
intent(in) :: verbosity
766 character(len=fm_string_len) :: g_tracer_name,longname, package,units,old_package,file_in,file_out
767 real :: const_init_value
768 character(len=128),
parameter :: sub_name =
'MOM_generic_flux_init'
769 type(
g_tracer_type),
pointer :: g_tracer_list,g_tracer,g_tracer_next
771 if (.not. g_registered)
then
772 call generic_tracer_register()
773 g_registered = .true.
776 call generic_tracer_get_list(g_tracer_list)
777 if (.NOT.
associated(g_tracer_list))
then
778 call mom_error(warning, trim(sub_name)//
": No generic tracer in the list.")
782 g_tracer=>g_tracer_list
785 call g_tracer_flux_init(g_tracer)
788 call g_tracer_get_next(g_tracer, g_tracer_next)
789 if (.NOT.
associated(g_tracer_next))
exit
790 g_tracer=>g_tracer_next
794 end subroutine mom_generic_flux_init
796 subroutine mom_generic_tracer_fluxes_accumulate(flux_tmp, weight)
799 real,
intent(in) :: weight
801 call generic_tracer_coupler_accumulate(flux_tmp%tr_fluxes, weight)
803 end subroutine mom_generic_tracer_fluxes_accumulate
806 subroutine mom_generic_tracer_get(name,member,array, CS)
807 character(len=*),
intent(in) :: name
808 character(len=*),
intent(in) :: member
809 real,
dimension(:,:,:),
intent(out) :: array
812 real,
dimension(:,:,:),
pointer :: array_ptr
813 character(len=128),
parameter :: sub_name =
'MOM_generic_tracer_get'
816 array(:,:,:) = array_ptr(:,:,:)
818 end subroutine mom_generic_tracer_get
821 subroutine end_mom_generic_tracer(CS)
824 call generic_tracer_end()
826 if (
associated(cs))
then
829 end subroutine end_mom_generic_tracer