MOM6
boundary_impulse_tracer.F90
Go to the documentation of this file.
1 !> Implements a boundary impulse response tracer to calculate Green's functions
3 ! This file is part of MOM6. See LICENSE.md for the license.
4 
5 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
8 use mom_error_handler, only : mom_error, fatal, warning
10 use mom_forcing_type, only : forcing
11 use mom_grid, only : ocean_grid_type
12 use mom_hor_index, only : hor_index_type
13 use mom_io, only : file_exists, read_data, slasher, vardesc, var_desc, query_vardesc
17 use mom_time_manager, only : time_type, get_time
22 use mom_variables, only : surface
25 use coupler_util, only : set_coupler_values, ind_csurf
27 
28 implicit none ; private
29 
30 #include <MOM_memory.h>
31 
35 
36 ! NTR_MAX is the maximum number of tracers in this module.
37 integer, parameter :: ntr_max = 1
38 
39 type p3d
40  real, dimension(:,:,:), pointer :: p => null()
41 end type p3d
42 
43 type, public :: boundary_impulse_tracer_cs ; private
44  integer :: ntr=ntr_max ! The number of tracers that are actually used.
45  logical :: coupled_tracers = .false. ! These tracers are not offered to the
46  ! coupler.
47  type(time_type), pointer :: time ! A pointer to the ocean model's clock.
48  type(tracer_registry_type), pointer :: tr_reg => null()
49  real, pointer :: tr(:,:,:,:) => null() ! The array of tracers used in this
50  ! subroutine, in g m-3?
51  type(p3d), dimension(NTR_MAX) :: &
52  tr_adx, &! Tracer zonal advective fluxes in g m-3 m3 s-1.An Error Has Occurred
53 
54 
55  tr_ady, &! Tracer meridional advective fluxes in g m-3 m3 s-1.
56  tr_dfx, &! Tracer zonal diffusive fluxes in g m-3 m3 s-1.
57  tr_dfy ! Tracer meridional diffusive fluxes in g m-3 m3 s-1.
58  logical :: mask_tracers ! If true, boundary_impulse is masked out in massless layers.
59  logical :: tracers_may_reinit ! If true, boundary_impulse can be initialized if
60  ! not found in restart file
61  integer, dimension(NTR_MAX) :: &
62  ind_tr, & ! Indices returned by aof_set_coupler_flux if it is used and the
63  ! surface tracer concentrations are to be provided to the coupler.
64  id_tracer = -1, id_tr_adx = -1, id_tr_ady = -1, &
65  id_tr_dfx = -1, id_tr_dfy = -1
66 
67  integer :: nkml ! Number of layers in mixed layer
68  real, dimension(NTR_MAX) :: land_val = -1.0
69  real :: kw_eff ! An effective piston velocity used to flux tracer out at the surface
70  real :: remaining_source_time ! How much longer (same units as the timestep) to
71  ! inject the tracer at the surface
72 
73  type(diag_ctrl), pointer :: diag ! A structure that is used to regulate the
74  ! timing of diagnostic output.
75  type(mom_restart_cs), pointer :: restart_csp => null()
76 
77  type(vardesc) :: tr_desc(ntr_max)
79 
80 contains
81 
82 !> Read in runtime options and add boundary impulse tracer to tracer registry
83 function register_boundary_impulse_tracer(HI, GV, param_file, CS, tr_Reg, restart_CS)
84  type(hor_index_type), intent(in ) :: HI
85  type(verticalgrid_type), intent(in ) :: GV !< The ocean's vertical grid structure
86  type(param_file_type), intent(in ) :: param_file !< A structure to parse for run-time parameters
87  type(boundary_impulse_tracer_cs), pointer, intent(inout) :: CS
88  type(tracer_registry_type), pointer, intent(inout) :: tr_Reg
89  type(mom_restart_cs), pointer, intent(inout) :: restart_CS
90 ! This subroutine is used to register tracer fields and subroutines
91 ! to be used with MOM.
92 ! Arguments: HI - A horizontal index type structure.
93 ! (in) GV - The ocean's vertical grid structure.
94 ! (in) param_file - A structure indicating the open file to parse for
95 ! model parameter values.
96 ! (in/out) CS - A pointer that is set to point to the control structure
97 ! for this module
98 ! (in/out) tr_Reg - A pointer that is set to point to the control structure
99 ! for the tracer advection and diffusion module.
100 ! (in) restart_CS - A pointer to the restart control structure.
101 
102 ! This include declares and sets the variable "version".
103 #include "version_variable.h"
104  character(len=40) :: mdl = "boundary_impulse_tracer" ! This module's name.
105  character(len=200) :: inputdir ! The directory where the input files are.
106  character(len=48) :: var_name ! The variable's name.
107  character(len=3) :: name_tag ! String for creating identifying boundary_impulse
108  real, pointer :: tr_ptr(:,:,:) => null()
109  real, pointer :: rem_time_ptr => null()
110  logical :: register_boundary_impulse_tracer
111  integer :: isd, ied, jsd, jed, nz, m, i, j
112  isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
113 
114  if (associated(cs)) then
115  call mom_error(warning, "register_boundary_impulse_tracer called with an "// &
116  "associated control structure.")
117  return
118  endif
119  allocate(cs)
120 
121  ! Read all relevant parameters and write them to the model log.
122  call log_version(param_file, mdl, version, "")
123  call get_param(param_file, mdl, "IMPULSE_SOURCE_TIME", cs%remaining_source_time, &
124  "Length of time for the boundary tracer to be injected\n"//&
125  "into the mixed layer. After this time has elapsed, the\n"//&
126  "surface becomes a sink for the boundary impulse tracer.", &
127  default=31536000.0)
128  call get_param(param_file, mdl, "TRACERS_MAY_REINIT", cs%tracers_may_reinit, &
129  "If true, tracers may go through the initialization code \n"//&
130  "if they are not found in the restart files. Otherwise \n"//&
131  "it is a fatal error if the tracers are not found in the \n"//&
132  "restart files of a restarted run.", default=.false.)
133  cs%ntr = ntr_max
134  allocate(cs%tr(isd:ied,jsd:jed,nz,cs%ntr)) ; cs%tr(:,:,:,:) = 0.0
135 
136  cs%nkml = max(gv%nkml,1)
137 
138  do m=1,cs%ntr
139  ! This is needed to force the compiler not to do a copy in the registration
140  ! calls. Curses on the designers and implementers of Fortran90.
141  cs%tr_desc(m) = var_desc(trim("boundary_impulse"), "kg", &
142  "Boundary impulse tracer", caller=mdl)
143  tr_ptr => cs%tr(:,:,:,m)
144  call query_vardesc(cs%tr_desc(m), name=var_name, caller="register_boundary_impulse_tracer")
145  ! Register the tracer for the restart file.
146  call register_restart_field(tr_ptr, cs%tr_desc(m), &
147  .not. cs%tracers_may_reinit, restart_cs)
148  ! Register the tracer for horizontal advection & diffusion.
149  call register_tracer(tr_ptr, cs%tr_desc(m), param_file, hi, gv, tr_reg, &
150  tr_desc_ptr=cs%tr_desc(m))
151 
152  ! Set coupled_tracers to be true (hard-coded above) to provide the surface
153  ! values to the coupler (if any). This is meta-code and its arguments will
154  ! currently (deliberately) give fatal errors if it is used.
155  if (cs%coupled_tracers) &
156  cs%ind_tr(m) = aof_set_coupler_flux(trim(var_name)//'_flux', &
157  flux_type=' ', implementation=' ', caller="register_boundary_impulse_tracer")
158  enddo
159  ! Register remaining source time as a restart field
160  rem_time_ptr => cs%remaining_source_time
161  call register_restart_field(rem_time_ptr, &
162  var_desc(trim("bir_remain_time"), "s", "Remaining time to apply BIR source", &
163  hor_grid = "1", z_grid = "1", caller=mdl), &
164  .not. cs%tracers_may_reinit, restart_cs)
165 
166  cs%tr_Reg => tr_reg
167  cs%restart_CSp => restart_cs
168  register_boundary_impulse_tracer = .true.
169 
171 
172 !> Initialize tracer from restart or set to 1 at surface to initialize
173 subroutine initialize_boundary_impulse_tracer(restart, day, G, GV, h, diag, OBC, CS, &
174  sponge_CSp, diag_to_Z_CSp, tv)
175  logical, intent(in ) :: restart
176  type(time_type), target, intent(in ) :: day
177  type(ocean_grid_type), intent(in ) :: G !< The ocean's grid structure
178  type(verticalgrid_type), intent(in ) :: GV !< The ocean's vertical grid structure
179  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in ) :: h !< Layer thicknesses, in H (usually m or kg m-2)
180  type(diag_ctrl), target, intent(in ) :: diag
181  type(ocean_obc_type), pointer, intent(inout) :: OBC
182  type(boundary_impulse_tracer_cs), pointer,intent(inout) :: CS
183  type(sponge_cs), pointer, intent(inout) :: sponge_CSp
184  type(diag_to_z_cs), pointer, intent(inout) :: diag_to_Z_CSp
185  type(thermo_var_ptrs), intent(in ) :: tv !< A structure pointing to various thermodynamic variables
186 ! This subroutine initializes the CS%ntr tracer fields in tr(:,:,:,:)
187 ! and it sets up the tracer output.
188 
189 ! Arguments: restart - .true. if the fields have already been read from
190 ! a restart file.
191 ! (in) day - Time of the start of the run.
192 ! (in) G - The ocean's grid structure.
193 ! (in) GV - The ocean's vertical grid structure.
194 ! (in) h - Layer thickness, in m or kg m-2.
195 ! (in) diag - A structure that is used to regulate diagnostic output.
196 ! (in) OBC - This open boundary condition type specifies whether, where,
197 ! and what open boundary conditions are used.
198 ! (in/out) CS - The control structure returned by a previous call to
199 ! register_boundary_impulse_tracer.
200 ! (in/out) sponge_CSp - A pointer to the control structure for the sponges, if
201 ! they are in use. Otherwise this may be unassociated.
202 ! (in/out) diag_to_Z_Csp - A pointer to the control structure for diagnostics
203 ! in depth space.
204  character(len=16) :: name ! A variable's name in a NetCDF file.
205  character(len=72) :: longname ! The long name of that variable.
206  character(len=48) :: units ! The dimensions of the variable.
207  character(len=48) :: flux_units ! The units for age tracer fluxes, either
208  ! years m3 s-1 or years kg s-1.
209  logical :: OK
210  integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz, m
211  integer :: IsdB, IedB, JsdB, JedB
212 
213  if (.not.associated(cs)) return
214  if (cs%ntr < 1) return
215  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
216  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
217  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
218 
219  cs%Time => day
220  cs%diag => diag
221  name = "boundary_impulse"
222 
223  do m=1,cs%ntr
224  call query_vardesc(cs%tr_desc(m), name=name, caller="initialize_boundary_impulse_tracer")
225  if ((.not.restart) .or. (.not. &
226  query_initialized(cs%tr(:,:,:,m), name, cs%restart_CSp))) then
227  do k=1,cs%nkml ; do j=jsd,jed ; do i=isd,ied
228  cs%tr(i,j,k,m) = 1.0
229  enddo ; enddo ; enddo
230  endif
231  enddo ! Tracer loop
232 
233  if (associated(obc)) then
234  ! All tracers but the first have 0 concentration in their inflows. As this
235  ! is the default value, the following calls are unnecessary.
236  ! do m=1,CS%ntr
237  ! call add_tracer_OBC_values(trim(CS%tr_desc(m)%name), CS%tr_Reg, 0.0)
238  ! enddo
239  endif
240 
241  ! This needs to be changed if the units of tracer are changed above.
242  if (gv%Boussinesq) then ; flux_units = "g salt/(m^2 s)"
243  else ; flux_units = "g salt/(m^2 s)" ; endif
244 
245  do m=1,cs%ntr
246  ! Register the tracer for the restart file.
247  call query_vardesc(cs%tr_desc(m), name, units=units, longname=longname, &
248  caller="initialize_boundary_impulse_tracer")
249  cs%id_tracer(m) = register_diag_field("ocean_model", trim(name), cs%diag%axesTL, &
250  day, trim(longname) , trim(units))
251  cs%id_tr_adx(m) = register_diag_field("ocean_model", trim(name)//"_adx", &
252  cs%diag%axesCuL, day, trim(longname)//" advective zonal flux" , &
253  trim(flux_units))
254  cs%id_tr_ady(m) = register_diag_field("ocean_model", trim(name)//"_ady", &
255  cs%diag%axesCvL, day, trim(longname)//" advective meridional flux" , &
256  trim(flux_units))
257  cs%id_tr_dfx(m) = register_diag_field("ocean_model", trim(name)//"_dfx", &
258  cs%diag%axesCuL, day, trim(longname)//" diffusive zonal flux" , &
259  trim(flux_units))
260  cs%id_tr_dfy(m) = register_diag_field("ocean_model", trim(name)//"_dfy", &
261  cs%diag%axesCvL, day, trim(longname)//" diffusive zonal flux" , &
262  trim(flux_units))
263  if (cs%id_tr_adx(m) > 0) call safe_alloc_ptr(cs%tr_adx(m)%p,isdb,iedb,jsd,jed,nz)
264  if (cs%id_tr_ady(m) > 0) call safe_alloc_ptr(cs%tr_ady(m)%p,isd,ied,jsdb,jedb,nz)
265  if (cs%id_tr_dfx(m) > 0) call safe_alloc_ptr(cs%tr_dfx(m)%p,isdb,iedb,jsd,jed,nz)
266  if (cs%id_tr_dfy(m) > 0) call safe_alloc_ptr(cs%tr_dfy(m)%p,isd,ied,jsdb,jedb,nz)
267 
268 ! Register the tracer for horizontal advection & diffusion.
269  if ((cs%id_tr_adx(m) > 0) .or. (cs%id_tr_ady(m) > 0) .or. &
270  (cs%id_tr_dfx(m) > 0) .or. (cs%id_tr_dfy(m) > 0)) &
271  call add_tracer_diagnostics(name, cs%tr_Reg, cs%tr_adx(m)%p, &
272  cs%tr_ady(m)%p,cs%tr_dfx(m)%p,cs%tr_dfy(m)%p)
273 
274  call register_z_tracer(cs%tr(:,:,:,m), trim(name), longname, units, &
275  day, g, diag_to_z_csp)
276  enddo
277 
279 
280 ! Apply source or sink at boundary and do vertical diffusion
281 subroutine boundary_impulse_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS, tv, debug, &
282  evap_CFL_limit, minimum_forcing_depth)
283  type(ocean_grid_type), intent(in ) :: G !< The ocean's grid structure
284  type(verticalgrid_type), intent(in ) :: GV !< The ocean's vertical grid structure
285  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in ) :: h_old, h_new, ea, eb
286  type(forcing), intent(in ) :: fluxes
287  real, intent(in ) :: dt !< The amount of time covered by this call, in s
288  type(boundary_impulse_tracer_cs), pointer, intent(inout) :: CS
289  type(thermo_var_ptrs), intent(in ) :: tv !< A structure pointing to various thermodynamic variables
290  logical, intent(in ) :: debug
291  real, optional, intent(in ) :: evap_CFL_limit
292  real, optional, intent(in ) :: minimum_forcing_depth
293 
294 ! This subroutine applies diapycnal diffusion and any other column
295 ! tracer physics or chemistry to the tracers from this file.
296 ! This is a simple example of a set of advected passive tracers.
297 
298 ! Arguments: h_old - Layer thickness before entrainment, in m or kg m-2.
299 ! (in) h_new - Layer thickness after entrainment, in m or kg m-2.
300 ! (in) ea - an array to which the amount of fluid entrained
301 ! from the layer above during this call will be
302 ! added, in m or kg m-2.
303 ! (in) eb - an array to which the amount of fluid entrained
304 ! from the layer below during this call will be
305 ! added, in m or kg m-2.
306 ! (in) fluxes - A structure containing pointers to any possible
307 ! forcing fields. Unused fields have NULL ptrs.
308 ! (in) dt - The amount of time covered by this call, in s.
309 ! (in) G - The ocean's grid structure.
310 ! (in) GV - The ocean's vertical grid structure.
311 ! (in) CS - The control structure returned by a previous call to
312 ! register_boundary_impulse_tracer.
313 ! (in) tv - Thermodynamic structure with T and S
314 ! (in) evap_CFL_limit - Limits how much water can be fluxed out of the top layer
315 ! Stored previously in diabatic CS.
316 ! (in) minimum_forcing_depth - The smallest depth over which fluxes can be applied
317 ! Stored previously in diabatic CS.
318 ! (in) debug - Calculates checksums
319 !
320 ! The arguments to this subroutine are redundant in that
321 ! h_new[k] = h_old[k] + ea[k] - eb[k-1] + eb[k] - ea[k+1]
322 
323  real :: Isecs_per_year = 1.0 / (365.0*86400.0)
324  real :: year, h_total, scale, htot, Ih_limit
325  integer :: secs, days
326  integer :: i, j, k, is, ie, js, je, nz, m, k_max
327  real, allocatable :: local_tr(:,:,:)
328  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_work ! Used so that h can be modified
329 
330  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
331 
332  if (.not.associated(cs)) return
333  if (cs%ntr < 1) return
334 
335  ! This uses applyTracerBoundaryFluxesInOut, usually in ALE mode
336  if (present(evap_cfl_limit) .and. present(minimum_forcing_depth)) then
337  do k=1,nz ;do j=js,je ; do i=is,ie
338  h_work(i,j,k) = h_old(i,j,k)
339  enddo ; enddo ; enddo;
340  call applytracerboundaryfluxesinout(g, gv, cs%tr(:,:,:,1), dt, fluxes, h_work, &
341  evap_cfl_limit, minimum_forcing_depth)
342  call tracer_vertdiff(h_work, ea, eb, dt, cs%tr(:,:,:,1), g, gv)
343  else
344  call tracer_vertdiff(h_old, ea, eb, dt, cs%tr(:,:,:,1), g, gv)
345  endif
346 
347  ! Set surface conditions
348  do m=1,1
349  if(cs%remaining_source_time>0.0) then
350  do k=1,cs%nkml ; do j=js,je ; do i=is,ie
351  cs%tr(i,j,k,m) = 1.0
352  enddo ; enddo ; enddo
353  cs%remaining_source_time = cs%remaining_source_time-dt
354  else
355  do k=1,cs%nkml ; do j=js,je ; do i=is,ie
356  cs%tr(i,j,k,m) = 0.0
357  enddo ; enddo ; enddo
358  endif
359 
360  enddo
361 
362  allocate(local_tr(g%isd:g%ied,g%jsd:g%jed,nz))
363  do m=1,1
364  if (cs%id_tracer(m)>0) then
365  if (cs%mask_tracers) then
366  do k=1,nz ; do j=js,je ; do i=is,ie
367  if (h_new(i,j,k) < 1.1*gv%Angstrom) then
368  local_tr(i,j,k) = cs%land_val(m)
369  else
370  local_tr(i,j,k) = cs%tr(i,j,k,m)
371  endif
372  enddo ; enddo ; enddo
373  else
374  do k=1,nz ; do j=js,je ; do i=is,ie
375  local_tr(i,j,k) = cs%tr(i,j,k,m)
376  enddo ; enddo ; enddo
377  endif ! CS%mask_tracers
378  call post_data(cs%id_tracer(m),local_tr,cs%diag)
379  endif ! CS%id_tracer(m)>0
380  if (cs%id_tr_adx(m)>0) &
381  call post_data(cs%id_tr_adx(m),cs%tr_adx(m)%p(:,:,:),cs%diag)
382  if (cs%id_tr_ady(m)>0) &
383  call post_data(cs%id_tr_ady(m),cs%tr_ady(m)%p(:,:,:),cs%diag)
384  if (cs%id_tr_dfx(m)>0) &
385  call post_data(cs%id_tr_dfx(m),cs%tr_dfx(m)%p(:,:,:),cs%diag)
386  if (cs%id_tr_dfy(m)>0) &
387  call post_data(cs%id_tr_dfy(m),cs%tr_dfy(m)%p(:,:,:),cs%diag)
388  enddo
389  deallocate(local_tr)
390 
392 
393 !> Calculate total inventory of tracer
394 function boundary_impulse_stock(h, stocks, G, GV, CS, names, units, stock_index)
395  type(ocean_grid_type), intent(in ) :: G !< The ocean's grid structure
396  type(verticalgrid_type), intent(in ) :: GV !< The ocean's vertical grid structure
397  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in ) :: h !< Layer thicknesses, in H (usually m or kg m-2)
398  real, dimension(:), intent( out) :: stocks
399  type(boundary_impulse_tracer_cs), pointer, intent(in ) :: CS
400  character(len=*), dimension(:), intent( out) :: names
401  character(len=*), dimension(:), intent( out) :: units
402  integer, optional, intent(in ) :: stock_index
403 ! This function calculates the mass-weighted integral of all tracer stocks,
404 ! returning the number of stocks it has calculated. If the stock_index
405 ! is present, only the stock corresponding to that coded index is returned.
406 
407 ! Arguments: h - Layer thickness, in m or kg m-2.
408 ! (out) stocks - the mass-weighted integrated amount of each tracer,
409 ! in kg times concentration units.
410 ! (in) G - The ocean's grid structure.
411 ! (in) GV - The ocean's vertical grid structure.
412 ! (in) CS - The control structure returned by a previous call to
413 ! register_boundary_impulse_tracer.
414 ! (out) names - the names of the stocks calculated.
415 ! (out) units - the units of the stocks calculated.
416 ! (in,opt) stock_index - the coded index of a specific stock being sought.
417 ! Return value: the number of stocks calculated here.
418  integer :: boundary_impulse_stock
419  integer :: i, j, k, is, ie, js, je, nz, m
420  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
421 
422  boundary_impulse_stock = 0
423  if (.not.associated(cs)) return
424  if (cs%ntr < 1) return
425 
426  if (present(stock_index)) then ; if (stock_index > 0) then
427  ! Check whether this stock is available from this routine.
428 
429  ! No stocks from this routine are being checked yet. Return 0.
430  return
431  endif ; endif
432 
433  do m=1,1
434  call query_vardesc(cs%tr_desc(m), name=names(m), units=units(m), caller="boundary_impulse_stock")
435  units(m) = trim(units(m))//" kg"
436  stocks(m) = 0.0
437  do k=1,nz ; do j=js,je ; do i=is,ie
438  stocks(m) = stocks(m) + cs%tr(i,j,k,m) * &
439  (g%mask2dT(i,j) * g%areaT(i,j) * h(i,j,k))
440  enddo ; enddo ; enddo
441  stocks(m) = gv%H_to_kg_m2 * stocks(m)
442  enddo
443 
444  boundary_impulse_stock = cs%ntr
445 
446 end function boundary_impulse_stock
447 
448 !> Called if returned if coupler needs to know about tracer, currently unused
449 subroutine boundary_impulse_tracer_surface_state(state, h, G, CS)
450  type(ocean_grid_type), intent(in ) :: G !< The ocean's grid structure
451  type(surface), intent(inout) :: state
452  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in ) :: h !< Layer thicknesses, in H (usually m or kg m-2)
453  type(boundary_impulse_tracer_cs), pointer,intent(in ) :: CS
454 ! This particular tracer package does not report anything back to the coupler.
455 ! The code that is here is just a rough guide for packages that would.
456 ! Arguments: state - A structure containing fields that describe the
457 ! surface state of the ocean.
458 ! (in) h - Layer thickness, in m or kg m-2.
459 ! (in) G - The ocean's grid structure.
460 ! (in) CS - The control structure returned by a previous call to
461 ! register_boundary_impulse_tracer.
462  integer :: m, is, ie, js, je
463  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
464 
465  if (.not.associated(cs)) return
466 
467  if (cs%coupled_tracers) then
468  do m=1,cs%ntr
469  ! This call loads the surface vlues into the appropriate array in the
470  ! coupler-type structure.
471  call set_coupler_values(cs%tr(:,:,1,m), state%tr_fields, cs%ind_tr(m), &
472  ind_csurf, is, ie, js, je)
473  enddo
474  endif
475 
477 
478 ! Performs finalization of boundary impulse tracer
479 subroutine boundary_impulse_tracer_end(CS)
480  type(boundary_impulse_tracer_cs), pointer :: CS
481  integer :: m
482 
483  if (associated(cs)) then
484  if (associated(cs%tr)) deallocate(cs%tr)
485  do m=1,cs%ntr
486  if (associated(cs%tr_adx(m)%p)) deallocate(cs%tr_adx(m)%p)
487  if (associated(cs%tr_ady(m)%p)) deallocate(cs%tr_ady(m)%p)
488  if (associated(cs%tr_dfx(m)%p)) deallocate(cs%tr_dfx(m)%p)
489  if (associated(cs%tr_dfy(m)%p)) deallocate(cs%tr_dfy(m)%p)
490  enddo
491 
492  deallocate(cs)
493  endif
494 end subroutine boundary_impulse_tracer_end
495 
496 !> \namespace boundary_impulse_tracer
497 !! \section Boundary Impulse Response Tracer and Transit Time Distributions
498 !! Transit time distributions (TTD) are the Green's function solution of the passive tracer equation between
499 !! the oceanic surface and interior. The name derives from the idea that the 'age' (e.g. time since last
500 !! contact with the atmosphere) of a water parcel is best characterized as a distribution of ages
501 !! because water parcels leaving the surface arrive at a particular interior point at different times.
502 !! The more commonly used ideal age tracer is the first moment of the TTD, equivalently referred to as the
503 !! mean age.
504 !!
505 !! A boundary impulse response (BIR) is a passive tracer whose surface boundary condition is a rectangle
506 !! function with width \f$\Delta t\f$. In the case of unsteady flow, multiple BIRs, initiated at different
507 !! times in the model can be used to infer the transit time distribution or Green's function between
508 !! the oceanic surface and interior. In the case of steady or cyclostationary flow, a single BIR is
509 !! sufficient.
510 !!
511 !! In the References section, both the theoretical discussion of TTDs and BIRs are listed along with
512 !! modeling studies which have this used framework in scientific investigations
513 !!
514 !! \section Run-time parameters
515 !! -DO_BOUNDARY_IMPULSE_TRACER: Enables the boundary impulse tracer model
516 !! -IMPULSE_SOURCE_TIME: Length of time that the surface layer acts as a source of the BIR tracer
517 !!
518 !! \section References
519 !! \subsection TTD and BIR Theory
520 !! -Holzer, M., and T.M. Hall, 2000: Transit-time and tracer-age distributions in geophysical flows.
521 !! J. Atmos. Sci., 57, 3539-3558, doi:10.1175/1520-0469(2000)057<3539:TTATAD>2.0.CO;2.
522 !! -T.W.N. Haine, H. Zhang, D.W. Waugh, M. Holzer, On transit-time distributions in unsteady circulation
523 !! models, Ocean Modelling, Volume 21, Issues 1–2, 2008, Pages 35-45, ISSN 1463-5003
524 !! http://dx.doi.org/10.1016/j.ocemod.2007.11.004.
525 !! \subsection BIR Modelling applications
526 !! -Peacock, S., and M. Maltrud (2006), Transit-time distributions in a global ocean model,
527 !! J. Phys. Oceanogr., 36(3), 474–495, doi:10.1175/JPO2860.1.
528 !! -Maltrud, M., Bryan, F. & Peacock, Boundary impulse response functions in a century-long eddying global
529 !! ocean simulation, S. Environ Fluid Mech (2010) 10: 275. doi:10.1007/s10652-009-9154-3
530 !!
531 end module boundary_impulse_tracer
logical function, public register_boundary_impulse_tracer(HI, GV, param_file, CS, tr_Reg, restart_CS)
Read in runtime options and add boundary impulse tracer to tracer registry.
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...
Definition: MOM_io.F90:585
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.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
subroutine, public boundary_impulse_tracer_end(CS)
Provides the ocean grid type.
Definition: MOM_grid.F90:2
This module contains I/O framework code.
Definition: MOM_io.F90:2
Defines the horizontal index type (hor_index_type) used for providing index ranges.
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.
integer function, public boundary_impulse_stock(h, stocks, G, GV, CS, names, units, stock_index)
Calculate total inventory of tracer.
Implements a boundary impulse response tracer to calculate Green&#39;s functions.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
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)
Definition: MOM_sponge.F90:271
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 boundary_impulse_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, CS, tv, debug, evap_CFL_limit, minimum_forcing_depth)
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)
subroutine, public initialize_boundary_impulse_tracer(restart, day, G, GV, h, diag, OBC, CS, sponge_CSp, diag_to_Z_CSp, tv)
Initialize tracer from restart or set to 1 at surface to initialize.
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
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...
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.
Definition: MOM_io.F90:664
Controls where open boundary conditions are applied.
subroutine, public boundary_impulse_tracer_surface_state(state, h, G, CS)
Called if returned if coupler needs to know about tracer, currently unused.
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)