80 implicit none ;
private 82 #include <MOM_memory.h> 92 real,
dimension(:,:,:),
pointer :: p => null()
97 logical :: coupled_tracers = .false.
99 character(len=200) :: ic_file
102 real :: oil_source_longitude, oil_source_latitude
103 integer :: oil_source_i=-999, oil_source_j=-999
104 real :: oil_source_rate
105 real :: oil_start_year
109 type(time_type),
pointer :: time
111 real,
pointer :: tr(:,:,:,:) => null()
113 type(
p3d),
dimension(NTR_MAX) :: &
118 real,
dimension(NTR_MAX) :: &
124 real,
dimension(NTR_MAX) :: oil_decay_days, &
126 integer,
dimension(NTR_MAX) :: oil_source_k
127 logical :: mask_tracers
128 logical :: oil_may_reinit
131 integer,
dimension(NTR_MAX) :: &
134 id_tracer = -1, id_tr_adx = -1, id_tr_ady = -1, &
135 id_tr_dfx = -1, id_tr_dfy = -1
166 #include "version_variable.h" 167 character(len=40) :: mdl =
"oil_tracer" 168 character(len=200) :: inputdir
169 character(len=48) :: var_name
170 character(len=3) :: name_tag
171 real,
pointer :: tr_ptr(:,:,:) => null()
172 logical :: register_oil_tracer
173 integer :: isd, ied, jsd, jed, nz, m, i, j
174 isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
176 if (
associated(cs))
then 177 call mom_error(warning,
"register_oil_tracer called with an "// &
178 "associated control structure.")
185 call get_param(param_file, mdl,
"OIL_IC_FILE", cs%IC_file, &
186 "The file in which the oil tracer initial values can be \n"//&
187 "found, or an empty string for internal initialization.", &
189 if ((len_trim(cs%IC_file) > 0) .and. (scan(cs%IC_file,
'/') == 0))
then 191 call get_param(param_file, mdl,
"INPUTDIR", inputdir, default=
".")
192 cs%IC_file = trim(slasher(inputdir))//trim(cs%IC_file)
193 call log_param(param_file, mdl,
"INPUTDIR/CFC_IC_FILE", cs%IC_file)
195 call get_param(param_file, mdl,
"OIL_IC_FILE_IS_Z", cs%Z_IC_file, &
196 "If true, OIL_IC_FILE is in depth space, not layer space", &
199 call get_param(param_file, mdl,
"MASK_MASSLESS_TRACERS", cs%mask_tracers, &
200 "If true, the tracers are masked out in massless layer. \n"//&
201 "This can be a problem with time-averages.", default=.false.)
202 call get_param(param_file, mdl,
"OIL_MAY_REINIT", cs%oil_may_reinit, &
203 "If true, oil tracers may go through the initialization \n"//&
204 "code if they are not found in the restart files. \n"//&
205 "Otherwise it is a fatal error if the oil tracers are not \n"//&
206 "found in the restart files of a restarted run.", &
208 call get_param(param_file, mdl,
"OIL_SOURCE_LONGITUDE", cs%oil_source_longitude, &
209 "The geographic longitude of the oil source.", units=
"degrees E", &
210 fail_if_missing=.true.)
211 call get_param(param_file, mdl,
"OIL_SOURCE_LATITUDE", cs%oil_source_latitude, &
212 "The geographic latitude of the oil source.", units=
"degrees N", &
213 fail_if_missing=.true.)
214 call get_param(param_file, mdl,
"OIL_SOURCE_LAYER", cs%oil_source_k, &
215 "The layer into which the oil is introduced, or a \n"//&
216 "negative number for a vertically uniform source, \n"//&
217 "or 0 not to use this tracer.", units=
"Layer", default=0)
218 call get_param(param_file, mdl,
"OIL_SOURCE_RATE", cs%oil_source_rate, &
219 "The rate of oil injection.", units=
"kg s-1", default=1.0)
220 call get_param(param_file, mdl,
"OIL_DECAY_DAYS", cs%oil_decay_days, &
221 "The decay timescale in days (if positive), or no decay \n"//&
222 "if 0, or use the temperature dependent decay rate of \n"//&
223 "Adcroft et al. (GRL, 2010) if negative.", units=
"days", &
225 call get_param(param_file, mdl,
"OIL_DATED_START_YEAR", cs%oil_start_year, &
226 "The time at which the oil source starts", units=
"years", &
228 call get_param(param_file, mdl,
"OIL_DATED_END_YEAR", cs%oil_end_year, &
229 "The time at which the oil source ends", units=
"years", &
233 cs%oil_decay_rate(:) = 0.
235 if (cs%oil_source_k(m)/=0)
then 236 write(name_tag(1:3),
'("_",I2.2)') m
238 cs%tr_desc(m) =
var_desc(
"oil"//trim(name_tag),
"kg/m3",
"Oil Tracer", caller=mdl)
240 if (cs%oil_decay_days(m)>0.)
then 241 cs%oil_decay_rate(m)=1./(86400.0*cs%oil_decay_days(m))
242 elseif (cs%oil_decay_days(m)<0.)
then 243 cs%oil_decay_rate(m)=-1.
247 call log_param(param_file, mdl,
"OIL_DECAY_RATE", cs%oil_decay_rate(1:cs%ntr))
249 allocate(cs%tr(isd:ied,jsd:jed,nz,cs%ntr)) ; cs%tr(:,:,:,:) = 0.0
254 tr_ptr => cs%tr(:,:,:,m)
255 call query_vardesc(cs%tr_desc(m), name=var_name, caller=
"register_oil_tracer")
258 .not.cs%oil_may_reinit, restart_cs)
260 call register_tracer(tr_ptr, cs%tr_desc(m), param_file, hi, gv, tr_reg, &
261 tr_desc_ptr=cs%tr_desc(m))
266 if (cs%coupled_tracers) &
268 flux_type=
' ', implementation=
' ', caller=
"register_oil_tracer")
272 cs%restart_CSp => restart_cs
273 register_oil_tracer = .true.
278 sponge_CSp, diag_to_Z_CSp)
279 logical,
intent(in) :: restart
280 type(time_type),
target,
intent(in) :: day
283 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
284 type(
diag_ctrl),
target,
intent(in) :: diag
307 character(len=16) :: name
308 character(len=72) :: longname
309 character(len=48) :: units
310 character(len=48) :: flux_units
313 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz, m
314 integer :: IsdB, IedB, JsdB, JedB
316 if (.not.
associated(cs))
return 317 if (cs%ntr < 1)
return 318 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
319 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
320 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
323 do j=g%jsdB+1,g%jed ;
do i=g%isdB+1,g%ied
326 if (cs%oil_source_longitude<g%geoLonBu(i,j) .and. &
327 cs%oil_source_longitude>=g%geoLonBu(i-1,j) .and. &
328 cs%oil_source_latitude<g%geoLatBu(i,j) .and. &
329 cs%oil_source_latitude>=g%geoLatBu(i,j-1) )
then 339 call query_vardesc(cs%tr_desc(m), name=name, caller=
"initialize_oil_tracer")
340 if ((.not.restart) .or. (cs%oil_may_reinit .and. .not. &
343 if (len_trim(cs%IC_file) > 0)
then 346 call mom_error(fatal,
"initialize_oil_tracer: "// &
347 "Unable to open "//cs%IC_file)
349 if (cs%Z_IC_file)
then 354 trim(name), g, -1e34, 0.0)
355 if (.not.ok)
call mom_error(fatal,
"initialize_oil_tracer: "//&
356 "Unable to read "//trim(name)//
" from "//&
357 trim(cs%IC_file)//
".")
360 call read_data(cs%IC_file, trim(name), cs%tr(:,:,:,m), &
361 domain=g%Domain%mpp_domain)
364 do k=1,nz ;
do j=js,je ;
do i=is,ie
365 if (g%mask2dT(i,j) < 0.5)
then 366 cs%tr(i,j,k,m) = cs%land_val(m)
368 cs%tr(i,j,k,m) = cs%IC_val(m)
370 enddo ;
enddo ;
enddo 376 if (
associated(obc))
then 385 if (gv%Boussinesq)
then ; flux_units =
"years m3 s-1" 386 else ; flux_units =
"years kg s-1" ;
endif 390 call query_vardesc(cs%tr_desc(m), name, units=units, longname=longname, &
391 caller=
"initialize_oil_tracer")
392 cs%id_tracer(m) = register_diag_field(
"ocean_model", trim(name), cs%diag%axesTL, &
393 day, trim(longname) , trim(units))
394 cs%id_tr_adx(m) = register_diag_field(
"ocean_model", trim(name)//
"_adx", &
395 cs%diag%axesCuL, day, trim(longname)//
" advective zonal flux" , &
397 cs%id_tr_ady(m) = register_diag_field(
"ocean_model", trim(name)//
"_ady", &
398 cs%diag%axesCvL, day, trim(longname)//
" advective meridional flux" , &
400 cs%id_tr_dfx(m) = register_diag_field(
"ocean_model", trim(name)//
"_dfx", &
401 cs%diag%axesCuL, day, trim(longname)//
" diffusive zonal flux" , &
403 cs%id_tr_dfy(m) = register_diag_field(
"ocean_model", trim(name)//
"_dfy", &
404 cs%diag%axesCvL, day, trim(longname)//
" diffusive zonal flux" , &
406 if (cs%id_tr_adx(m) > 0)
call safe_alloc_ptr(cs%tr_adx(m)%p,isdb,iedb,jsd,jed,nz)
407 if (cs%id_tr_ady(m) > 0)
call safe_alloc_ptr(cs%tr_ady(m)%p,isd,ied,jsdb,jedb,nz)
408 if (cs%id_tr_dfx(m) > 0)
call safe_alloc_ptr(cs%tr_dfx(m)%p,isdb,iedb,jsd,jed,nz)
409 if (cs%id_tr_dfy(m) > 0)
call safe_alloc_ptr(cs%tr_dfy(m)%p,isd,ied,jsdb,jedb,nz)
412 if ((cs%id_tr_adx(m) > 0) .or. (cs%id_tr_ady(m) > 0) .or. &
413 (cs%id_tr_dfx(m) > 0) .or. (cs%id_tr_dfy(m) > 0)) &
415 cs%tr_ady(m)%p,cs%tr_dfx(m)%p,cs%tr_dfy(m)%p)
418 day, g, diag_to_z_csp)
423 subroutine oil_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS, tv, &
424 evap_CFL_limit, minimum_forcing_depth)
425 type(ocean_grid_type),
intent(in) :: G
426 type(verticalgrid_type),
intent(in) :: GV
427 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_old, h_new, ea, eb
428 type(forcing),
intent(in) :: fluxes
429 real,
intent(in) :: dt
431 type(thermo_var_ptrs),
intent(in) :: tv
432 real,
optional,
intent(in) :: evap_CFL_limit
433 real,
optional,
intent(in) :: minimum_forcing_depth
457 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_work
458 real :: Isecs_per_year = 1.0 / (365.0*86400.0)
459 real :: year, h_total, ldecay
460 integer :: secs, days
461 integer :: i, j, k, is, ie, js, je, nz, m, k_max
462 real,
allocatable :: local_tr(:,:,:)
463 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
465 if (.not.
associated(cs))
return 466 if (cs%ntr < 1)
return 468 if (
present(evap_cfl_limit) .and.
present(minimum_forcing_depth))
then 470 do k=1,nz ;
do j=js,je ;
do i=is,ie
471 h_work(i,j,k) = h_old(i,j,k)
472 enddo ;
enddo ; enddo;
473 call applytracerboundaryfluxesinout(g, gv, cs%tr(:,:,:,m) , dt, fluxes, h_work, &
474 evap_cfl_limit, minimum_forcing_depth)
475 call tracer_vertdiff(h_work, ea, eb, dt, cs%tr(:,:,:,m), g, gv)
479 call tracer_vertdiff(h_old, ea, eb, dt, cs%tr(:,:,:,m), g, gv)
485 call get_time(cs%Time, secs, days)
486 year = (86400.0*days +
real(secs)) * isecs_per_year
490 do k=1,nz ;
do j=js,je ;
do i=is,ie
493 if (cs%oil_decay_rate(m)>0.)
then 494 cs%tr(i,j,k,m) = g%mask2dT(i,j)*max(1.-dt*cs%oil_decay_rate(m),0.)*cs%tr(i,j,k,m)
495 elseif (cs%oil_decay_rate(m)<0.)
then 496 ldecay = 12.*(3.0**(-(tv%T(i,j,k)-20.)/10.))
497 ldecay = 1./(86400.*ldecay)
498 cs%tr(i,j,k,m) = g%mask2dT(i,j)*max(1.-dt*ldecay,0.)*cs%tr(i,j,k,m)
500 enddo ;
enddo ;
enddo 504 if (year>=cs%oil_start_year .and. year<=cs%oil_end_year .and. &
505 cs%oil_source_i>-999 .and. cs%oil_source_j>-999)
then 506 i=cs%oil_source_i ; j=cs%oil_source_j
507 k_max=nz ; h_total=0.
509 h_total = h_total + h_new(i,j,k)
510 if (h_total<10.) k_max=k-1
516 cs%tr(i,j,k,m) = cs%tr(i,j,k,m) + cs%oil_source_rate*dt / &
517 ((h_new(i,j,k)+gv%H_subroundoff) * g%areaT(i,j) )
519 h_total=gv%H_subroundoff
521 h_total = h_total + h_new(i,j,k)
524 cs%tr(i,j,k,m) = cs%tr(i,j,k,m) + cs%oil_source_rate*dt/(h_total &
531 allocate(local_tr(g%isd:g%ied,g%jsd:g%jed,nz))
533 if (cs%id_tracer(m)>0)
then 534 if (cs%mask_tracers)
then 535 do k=1,nz ;
do j=js,je ;
do i=is,ie
536 if (h_new(i,j,k) < 1.1*gv%Angstrom)
then 537 local_tr(i,j,k) = cs%land_val(m)
539 local_tr(i,j,k) = cs%tr(i,j,k,m)
541 enddo ;
enddo ;
enddo 543 do k=1,nz ;
do j=js,je ;
do i=is,ie
544 local_tr(i,j,k) = cs%tr(i,j,k,m)
545 enddo ;
enddo ;
enddo 547 call post_data(cs%id_tracer(m),local_tr,cs%diag)
549 if (cs%id_tr_adx(m)>0) &
550 call post_data(cs%id_tr_adx(m),cs%tr_adx(m)%p(:,:,:),cs%diag)
551 if (cs%id_tr_ady(m)>0) &
552 call post_data(cs%id_tr_ady(m),cs%tr_ady(m)%p(:,:,:),cs%diag)
553 if (cs%id_tr_dfx(m)>0) &
554 call post_data(cs%id_tr_dfx(m),cs%tr_dfx(m)%p(:,:,:),cs%diag)
555 if (cs%id_tr_dfy(m)>0) &
556 call post_data(cs%id_tr_dfy(m),cs%tr_dfy(m)%p(:,:,:),cs%diag)
562 function oil_stock(h, stocks, G, GV, CS, names, units, stock_index)
563 type(ocean_grid_type),
intent(in) :: G
564 type(verticalgrid_type),
intent(in) :: GV
565 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
566 real,
dimension(:),
intent(out) :: stocks
568 character(len=*),
dimension(:),
intent(out) :: names
569 character(len=*),
dimension(:),
intent(out) :: units
570 integer,
optional,
intent(in) :: stock_index
588 integer :: i, j, k, is, ie, js, je, nz, m
589 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
592 if (.not.
associated(cs))
return 593 if (cs%ntr < 1)
return 595 if (
present(stock_index))
then ;
if (stock_index > 0)
then 603 call query_vardesc(cs%tr_desc(m), name=names(m), units=units(m), caller=
"oil_stock")
604 units(m) = trim(units(m))//
" kg" 606 do k=1,nz ;
do j=js,je ;
do i=is,ie
607 stocks(m) = stocks(m) + cs%tr(i,j,k,m) * &
608 (g%mask2dT(i,j) * g%areaT(i,j) * h(i,j,k))
609 enddo ;
enddo ;
enddo 610 stocks(m) = gv%H_to_kg_m2 * stocks(m)
617 type(ocean_grid_type),
intent(in) :: G
618 type(surface),
intent(inout) :: state
619 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
629 integer :: m, is, ie, js, je
630 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
632 if (.not.
associated(cs))
return 634 if (cs%coupled_tracers)
then 638 call set_coupler_values(cs%tr(:,:,1,m), state%tr_fields, cs%ind_tr(m), &
639 ind_csurf, is, ie, js, je)
649 if (
associated(cs))
then 650 if (
associated(cs%tr))
deallocate(cs%tr)
652 if (
associated(cs%tr_adx(m)%p))
deallocate(cs%tr_adx(m)%p)
653 if (
associated(cs%tr_ady(m)%p))
deallocate(cs%tr_ady(m)%p)
654 if (
associated(cs%tr_dfx(m)%p))
deallocate(cs%tr_dfx(m)%p)
655 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...
subroutine, public oil_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS, tv, evap_CFL_limit, minimum_forcing_depth)
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)
logical function, public tracer_z_init(tr, h, filename, tr_name, G, missing_val, land_val)
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.
subroutine, public initialize_oil_tracer(restart, day, G, GV, h, diag, OBC, CS, sponge_CSp, diag_to_Z_CSp)
Container for horizontal index ranges for data, computational and global domains. ...
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 oil_tracer_surface_state(state, h, G, CS)
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
subroutine, public oil_tracer_end(CS)
subroutine, public applytracerboundaryfluxesinout(G, GV, Tr, dt, fluxes, h, evap_CFL_limit, minimum_forcing_depth, in_flux_optional, out_flux_optional, update_h_opt)
This routine is modeled after applyBoundaryFluxesInOut in MOM_diabatic_aux.F90 NOTE: Please note that...
subroutine, public set_up_sponge_field(sp_val, f_ptr, G, nlay, CS, sp_val_i_mean)
Type to carry basic tracer information.
This module contains routines that implement physical fluxes of tracers (e.g. due to surface fluxes o...
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.
integer function, public oil_stock(h, stocks, G, GV, CS, names, units, stock_index)
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)
Type for describing a variable, typically a tracer.
subroutine, public tracer_vertdiff(h_old, ea, eb, dt, tr, G, GV, sfc_flux, btm_flux, btm_reservoir, sink_rate, convert_flux_in)
This subroutine solves a tridiagonal equation for the final tracer concentrations after the dual-entr...
integer, parameter ntr_max
logical function, public register_oil_tracer(HI, GV, param_file, CS, tr_Reg, restart_CS)
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
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)