74 implicit none ;
private 76 #include <MOM_memory.h> 82 integer,
parameter ::
ntr = 1
85 real,
dimension(:,:,:),
pointer :: p => null()
89 logical :: coupled_tracers = .false.
91 character(len=200) :: tracer_ic_file
93 type(time_type),
pointer :: time
95 real,
pointer :: tr(:,:,:,:) => null()
97 real,
pointer :: tr_aux(:,:,:,:) => null()
99 type(
p3d),
dimension(NTR) :: &
104 real :: land_val(
ntr) = -1.0
105 logical :: mask_tracers
106 logical :: use_sponge
108 integer,
dimension(NTR) :: ind_tr
114 integer,
dimension(NTR) :: id_tracer = -1, id_tr_adx = -1, id_tr_ady = -1
115 integer,
dimension(NTR) :: id_tr_dfx = -1, id_tr_dfy = -1
140 character(len=80) :: name, longname
142 #include "version_variable.h" 143 character(len=40) :: mdl =
"tracer_example" 144 character(len=200) :: inputdir
145 real,
pointer :: tr_ptr(:,:,:) => null()
146 logical :: USER_register_tracer_example
147 integer :: isd, ied, jsd, jed, nz, m
148 isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
150 if (
associated(cs))
then 151 call mom_error(warning,
"USER_register_tracer_example called with an "// &
152 "associated control structure.")
159 call get_param(param_file, mdl,
"TRACER_EXAMPLE_IC_FILE", cs%tracer_IC_file, &
160 "The name of a file from which to read the initial \n"//&
161 "conditions for the DOME tracers, or blank to initialize \n"//&
162 "them internally.", default=
" ")
163 if (len_trim(cs%tracer_IC_file) >= 1)
then 164 call get_param(param_file, mdl,
"INPUTDIR", inputdir, default=
".")
165 cs%tracer_IC_file = trim(slasher(inputdir))//trim(cs%tracer_IC_file)
166 call log_param(param_file, mdl,
"INPUTDIR/TRACER_EXAMPLE_IC_FILE", &
169 call get_param(param_file, mdl,
"SPONGE", cs%use_sponge, &
170 "If true, sponges may be applied anywhere in the domain. \n"//&
171 "The exact location and properties of those sponges are \n"//&
172 "specified from MOM_initialization.F90.", default=.false.)
174 allocate(cs%tr(isd:ied,jsd:jed,nz,
ntr)) ; cs%tr(:,:,:,:) = 0.0
175 if (cs%mask_tracers)
then 176 allocate(cs%tr_aux(isd:ied,jsd:jed,nz,
ntr)) ; cs%tr_aux(:,:,:,:) = 0.0
180 if (m < 10)
then ;
write(name,
'("tr",I1.1)') m
181 else ;
write(name,
'("tr",I2.2)') m ;
endif 182 write(longname,
'("Concentration of Tracer ",I2.2)') m
183 cs%tr_desc(m) =
var_desc(name, units=
"kg kg-1", longname=longname, caller=mdl)
187 tr_ptr => cs%tr(:,:,:,m)
191 call register_tracer(tr_ptr, cs%tr_desc(m), param_file, hi, gv, tr_reg, &
192 tr_desc_ptr=cs%tr_desc(m))
197 if (cs%coupled_tracers) &
199 flux_type=
' ', implementation=
' ', caller=
"USER_register_tracer_example")
203 user_register_tracer_example = .true.
207 sponge_CSp, diag_to_Z_CSp)
208 logical,
intent(in) :: restart
209 type(time_type),
target,
intent(in) :: day
212 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
214 type(
diag_ctrl),
target,
intent(in) :: diag
237 real,
allocatable :: temp(:,:,:)
238 real,
pointer,
dimension(:,:,:) :: &
239 OBC_tr1_u => null(), &
243 character(len=32) :: name
244 character(len=72) :: longname
245 character(len=48) :: units
246 character(len=48) :: flux_units
248 real,
pointer :: tr_ptr(:,:,:) => null()
252 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz, m
253 integer :: IsdB, IedB, JsdB, JedB, lntr
255 if (.not.
associated(cs))
return 256 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
257 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
258 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
264 if (.not.restart)
then 265 if (len_trim(cs%tracer_IC_file) >= 1)
then 267 if (.not.
file_exists(cs%tracer_IC_file, g%Domain)) &
268 call mom_error(fatal,
"USER_initialize_tracer: Unable to open "// &
271 call query_vardesc(cs%tr_desc(m), name, caller=
"USER_initialize_tracer")
272 call read_data(cs%tracer_IC_file, trim(name), &
273 cs%tr(:,:,:,m), domain=g%Domain%mpp_domain)
277 do k=1,nz ;
do j=js,je ;
do i=is,ie
278 cs%tr(i,j,k,m) = 1.0e-20
279 enddo ;
enddo ;
enddo 285 dist2 = (g%Rad_Earth * pi / 180.0)**2 * &
286 (g%geoLatT(i,j) - 40.0) * (g%geoLatT(i,j) - 40.0)
287 tr_y = 0.5*exp(-dist2/(1.0e5*1.0e5))
289 do k=1,nz ;
do i=is,ie
291 cs%tr(i,j,k,1) = cs%tr(i,j,k,1) + tr_y
297 if ( cs%use_sponge )
then 302 if (.not.
associated(sponge_csp)) &
303 call mom_error(fatal,
"USER_initialize_tracer: "// &
304 "The pointer to sponge_CSp must be associated if SPONGE is defined.")
306 allocate(temp(g%isd:g%ied,g%jsd:g%jed,nz))
307 do k=1,nz ;
do j=js,je ;
do i=is,ie
308 if (g%geoLatT(i,j) > 700.0 .and. (k > nz/2))
then 313 enddo ;
enddo ;
enddo 319 tr_ptr => cs%tr(:,:,:,m)
325 if (
associated(obc))
then 326 call query_vardesc(cs%tr_desc(1), name, caller=
"USER_initialize_tracer")
327 if (obc%specified_v_BCs_exist_globally)
then 328 allocate(obc_tr1_v(g%isd:g%ied,g%jsd:g%jed,nz))
329 do k=1,nz ;
do j=g%jsd,g%jed ;
do i=g%isd,g%ied
330 if (k < nz/2)
then ; obc_tr1_v(i,j,k) = 0.0
331 else ; obc_tr1_v(i,j,k) = 1.0 ;
endif 332 enddo ;
enddo ;
enddo 334 0.0, obc_in_v=obc_tr1_v)
342 call query_vardesc(cs%tr_desc(m), name, caller=
"USER_initialize_tracer")
348 if (gv%Boussinesq)
then ; flux_units =
"kg kg-1 m3 s-1" 349 else ; flux_units =
"kg s-1" ;
endif 353 call query_vardesc(cs%tr_desc(m), name, units=units, longname=longname, &
354 caller=
"USER_initialize_tracer")
355 cs%id_tracer(m) = register_diag_field(
"ocean_model", trim(name), cs%diag%axesTL, &
356 day, trim(longname) , trim(units))
357 cs%id_tr_adx(m) = register_diag_field(
"ocean_model", trim(name)//
"_adx", &
358 cs%diag%axesCuL, day, trim(longname)//
" advective zonal flux" , &
360 cs%id_tr_ady(m) = register_diag_field(
"ocean_model", trim(name)//
"_ady", &
361 cs%diag%axesCvL, day, trim(longname)//
" advective meridional flux" , &
363 cs%id_tr_dfx(m) = register_diag_field(
"ocean_model", trim(name)//
"_dfx", &
364 cs%diag%axesCuL, day, trim(longname)//
" diffusive zonal flux" , &
366 cs%id_tr_dfy(m) = register_diag_field(
"ocean_model", trim(name)//
"_dfy", &
367 cs%diag%axesCvL, day, trim(longname)//
" diffusive zonal flux" , &
369 if (cs%id_tr_adx(m) > 0)
call safe_alloc_ptr(cs%tr_adx(m)%p,isdb,iedb,jsd,jed,nz)
370 if (cs%id_tr_ady(m) > 0)
call safe_alloc_ptr(cs%tr_ady(m)%p,isd,ied,jsdb,jedb,nz)
371 if (cs%id_tr_dfx(m) > 0)
call safe_alloc_ptr(cs%tr_dfx(m)%p,isdb,iedb,jsd,jed,nz)
372 if (cs%id_tr_dfy(m) > 0)
call safe_alloc_ptr(cs%tr_dfy(m)%p,isd,ied,jsdb,jedb,nz)
375 if ((cs%id_tr_adx(m) > 0) .or. (cs%id_tr_ady(m) > 0) .or. &
376 (cs%id_tr_dfx(m) > 0) .or. (cs%id_tr_dfy(m) > 0)) &
378 cs%tr_ady(m)%p,cs%tr_dfx(m)%p,cs%tr_dfy(m)%p)
381 day, g, diag_to_z_csp)
389 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_old, h_new, ea, eb
390 type(
forcing),
intent(in) :: fluxes
391 real,
intent(in) :: dt
416 real :: hold0(szi_(g))
419 real :: c1(szi_(g),szk_(g))
424 integer :: i, j, k, is, ie, js, je, nz, m
444 data trdc / 1.0,0.0,0.0 /
445 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
447 if (.not.
associated(cs))
return 448 h_neglect = gv%H_subroundoff
455 hold0(i) = h_old(i,j,1)
462 b_denom_1 = h_old(i,j,1) + ea(i,j,1) + h_neglect
463 b1(i) = 1.0 / (b_denom_1 + eb(i,j,1))
465 d1(i) = trdc(1) * (b_denom_1 * b1(i)) + (1.0 - trdc(1))
467 cs%tr(i,j,1,m) = b1(i)*(hold0(i)*cs%tr(i,j,1,m) + trdc(3)*eb(i,j,1))
471 do k=2,nz ;
do i=is,ie
472 c1(i,k) = trdc(1) * eb(i,j,k-1) * b1(i)
473 b_denom_1 = h_old(i,j,k) + d1(i)*ea(i,j,k) + h_neglect
474 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
475 d1(i) = trdc(1) * (b_denom_1 * b1(i)) + (1.0 - trdc(1))
477 cs%tr(i,j,k,m) = b1(i) * (h_old(i,j,k)*cs%tr(i,j,k,m) + &
478 ea(i,j,k)*(trdc(1)*cs%tr(i,j,k-1,m)+trdc(2)) + &
482 do m=1,
ntr ;
do k=nz-1,1,-1 ;
do i=is,ie
483 cs%tr(i,j,k,m) = cs%tr(i,j,k,m) + c1(i,k+1)*cs%tr(i,j,k+1,m)
484 enddo ;
enddo ;
enddo 487 if (cs%mask_tracers)
then 488 do m = 1,
ntr ;
if (cs%id_tracer(m) > 0)
then 489 do k=1,nz ;
do j=js,je ;
do i=is,ie
490 if (h_new(i,j,k) < 1.1*gv%Angstrom)
then 491 cs%tr_aux(i,j,k,m) = cs%land_val(m)
493 cs%tr_aux(i,j,k,m) = cs%tr(i,j,k,m)
495 enddo ;
enddo ;
enddo 500 if (cs%mask_tracers)
then 501 if (cs%id_tracer(m)>0) &
502 call post_data(cs%id_tracer(m),cs%tr_aux(:,:,:,m),cs%diag)
504 if (cs%id_tracer(m)>0) &
505 call post_data(cs%id_tracer(m),cs%tr(:,:,:,m),cs%diag)
507 if (cs%id_tr_adx(m)>0) &
508 call post_data(cs%id_tr_adx(m),cs%tr_adx(m)%p(:,:,:),cs%diag)
509 if (cs%id_tr_ady(m)>0) &
510 call post_data(cs%id_tr_ady(m),cs%tr_ady(m)%p(:,:,:),cs%diag)
511 if (cs%id_tr_dfx(m)>0) &
512 call post_data(cs%id_tr_dfx(m),cs%tr_dfx(m)%p(:,:,:),cs%diag)
513 if (cs%id_tr_dfy(m)>0) &
514 call post_data(cs%id_tr_dfy(m),cs%tr_dfy(m)%p(:,:,:),cs%diag)
522 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
524 real,
dimension(:),
intent(out) :: stocks
526 character(len=*),
dimension(:),
intent(out) :: names
527 character(len=*),
dimension(:),
intent(out) :: units
528 integer,
optional,
intent(in) :: stock_index
529 integer :: USER_tracer_stock
546 integer :: i, j, k, is, ie, js, je, nz, m
547 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
549 user_tracer_stock = 0
550 if (.not.
associated(cs))
return 552 if (
present(stock_index))
then ;
if (stock_index > 0)
then 560 call query_vardesc(cs%tr_desc(m), name=names(m), units=units(m), caller=
"USER_tracer_stock")
561 units(m) = trim(units(m))//
" kg" 563 do k=1,nz ;
do j=js,je ;
do i=is,ie
564 stocks(m) = stocks(m) + cs%tr(i,j,k,m) * &
565 (g%mask2dT(i,j) * g%areaT(i,j) * h(i,j,k))
566 enddo ;
enddo ;
enddo 567 stocks(m) = gv%H_to_kg_m2 * stocks(m)
569 user_tracer_stock =
ntr 575 type(
surface),
intent(inout) :: state
576 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
586 integer :: i, j, m, is, ie, js, je
587 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
589 if (.not.
associated(cs))
return 591 if (cs%coupled_tracers)
then 596 ind_csurf, is, ie, js, je)
606 if (
associated(cs))
then 607 if (
associated(cs%tr))
deallocate(cs%tr)
608 if (
associated(cs%tr_aux))
deallocate(cs%tr_aux)
610 if (
associated(cs%tr_adx(m)%p))
deallocate(cs%tr_adx(m)%p)
611 if (
associated(cs%tr_ady(m)%p))
deallocate(cs%tr_ady(m)%p)
612 if (
associated(cs%tr_dfx(m)%p))
deallocate(cs%tr_dfx(m)%p)
613 if (
associated(cs%tr_dfy(m)%p))
deallocate(cs%tr_dfy(m)%p)
The following structure contains pointers to various fields which may be used describe the surface st...
type(vardesc) function, public var_desc(name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
Returns a vardesc type whose elements have been filled with the provided fields. The argument name is...
This module implements boundary forcing for MOM6.
integer function, public aof_set_coupler_flux(name, flux_type, implementation, atm_tr_index, param, flag, ice_restart_file, ocean_restart_file, units, caller)
subroutine, public user_initialize_tracer(restart, day, G, GV, h, diag, OBC, CS, sponge_CSp, diag_to_Z_CSp)
Ocean grid type. See mom_grid for details.
Provides the ocean grid type.
This module contains I/O framework code.
Defines the horizontal index type (hor_index_type) used for providing index ranges.
integer function, public user_tracer_stock(h, stocks, G, GV, CS, names, units, stock_index)
Container for horizontal index ranges for data, computational and global domains. ...
subroutine, public user_tracer_surface_state(state, h, G, CS)
subroutine, public register_tracer(tr1, tr_desc, param_file, HI, GV, Reg, tr_desc_ptr, ad_x, ad_y, df_x, df_y, OBC_inflow, OBC_in_u, OBC_in_v, ad_2d_x, ad_2d_y, df_2d_x, df_2d_y, advection_xy)
This subroutine registers a tracer to be advected and laterally diffused.
subroutine, public tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS)
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
subroutine, public user_tracer_example_end(CS)
subroutine, public set_up_sponge_field(sp_val, f_ptr, G, nlay, CS, sp_val_i_mean)
Type to carry basic tracer information.
subroutine, public register_z_tracer(tr_ptr, name, long_name, units, Time, G, CS, standard_name, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name)
This subroutine registers a tracer to be output in depth space.
subroutine, public add_tracer_obc_values(name, Reg, OBC_inflow, OBC_in_u, OBC_in_v)
This subroutine adds open boundary condition concentrations for a tracer that has previously been reg...
subroutine, public add_tracer_diagnostics(name, Reg, ad_x, ad_y, df_x, df_y, ad_2d_x, ad_2d_y, df_2d_x, df_2d_y, advection_xy)
This subroutine adds diagnostic arrays for a tracer that has previously been registered by a call to ...
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
subroutine, public set_coupler_values(array_in, BC_struc, BC_index, BC_element, is, ie, js, je, conversion)
logical function, public user_register_tracer_example(HI, GV, param_file, CS, tr_Reg, restart_CS)
Type for describing a variable, typically a tracer.
subroutine, public query_vardesc(vd, name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
This routine queries vardesc.
Controls where open boundary conditions are applied.
subroutine, public mom_error(level, message, all_print)