MOM_tracer_flow_control.F90

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Orchestrates the registration and calling of tracer packages
7
8use mom_coms, only : efp_type, assignment(=), efp_to_real, real_to_efp, efp_sum_across_pes
9use mom_diag_mediator, only : time_type, diag_ctrl
10use mom_error_handler, only : mom_error, fatal, warning
11use mom_file_parser, only : get_param, log_version, param_file_type, close_param_file
12use mom_forcing_type, only : forcing, optics_type
14use mom_grid, only : ocean_grid_type
17use mom_cvmix_kpp, only : kpp_cs
20use mom_sponge, only : sponge_cs
22use mom_tracer_registry, only : tracer_registry_type
26#include <MOM_memory.h>
27
28! Add references to other user-provide tracer modules here.
80
81implicit none ; private
82
87
88!> The control structure for orchestrating the calling of tracer packages
89type, public :: tracer_flow_control_cs ; private
90 logical :: use_user_tracer_example = .false. !< If true, use the USER_tracer_example package
91 logical :: use_dome_tracer = .false. !< If true, use the DOME_tracer package
92 logical :: use_isomip_tracer = .false. !< If true, use the ISOMPE_tracer package
93 logical :: use_rgc_tracer =.false. !< If true, use the RGC_tracer package
94 logical :: use_ideal_age = .false. !< If true, use the ideal age tracer package
95 logical :: use_marbl_tracers = .false. !< If true, use the MARBL tracer package
96 logical :: use_regional_dyes = .false. !< If true, use the regional dyes tracer package
97 logical :: use_oil = .false. !< If true, use the oil tracer package
98 logical :: use_advection_test_tracer = .false. !< If true, use the advection_test_tracer package
99 logical :: use_ocmip2_cfc = .false. !< If true, use the OCMIP2_CFC tracer package
100 logical :: use_cfc_cap = .false. !< If true, use the CFC_cap tracer package
101 logical :: use_mom_generic_tracer = .false. !< If true, use the MOM_generic_tracer packages
102 logical :: use_pseudo_salt_tracer = .false. !< If true, use the psuedo_salt tracer package
103 logical :: use_boundary_impulse_tracer = .false. !< If true, use the boundary impulse tracer package
104 logical :: use_dyed_obc_tracer = .false. !< If true, use the dyed OBC tracer package
105 logical :: use_nw2_tracers = .false. !< If true, use the NW2 tracer package
106 logical :: get_chl_from_marbl = .false. !< If true, use the MARBL-provided Chl for shortwave penetration
107 !>@{ Pointers to the control strucures for the tracer packages
108 type(user_tracer_example_cs), pointer :: user_tracer_example_csp => null()
109 type(dome_tracer_cs), pointer :: dome_tracer_csp => null()
110 type(isomip_tracer_cs), pointer :: isomip_tracer_csp => null()
111 type(rgc_tracer_cs), pointer :: rgc_tracer_csp => null()
112 type(ideal_age_tracer_cs), pointer :: ideal_age_tracer_csp => null()
113 type(marbl_tracers_cs), pointer :: marbl_tracers_csp => null()
114 type(dye_tracer_cs), pointer :: dye_tracer_csp => null()
115 type(oil_tracer_cs), pointer :: oil_tracer_csp => null()
116 type(advection_test_tracer_cs), pointer :: advection_test_tracer_csp => null()
117 type(ocmip2_cfc_cs), pointer :: ocmip2_cfc_csp => null()
118 type(cfc_cap_cs), pointer :: cfc_cap_csp => null()
119 type(mom_generic_tracer_cs), pointer :: mom_generic_tracer_csp => null()
120 type(pseudo_salt_tracer_cs), pointer :: pseudo_salt_tracer_csp => null()
121 type(boundary_impulse_tracer_cs), pointer :: boundary_impulse_tracer_csp => null()
122 type(dyed_obc_tracer_cs), pointer :: dyed_obc_tracer_csp => null()
123 type(nw2_tracers_cs), pointer :: nw2_tracers_csp => null()
124 !>@}
126
127contains
128
129
130!> This subroutine carries out a series of calls to initialize the air-sea
131!! tracer fluxes, but it does not record the generated indicies, and it may
132!! be called _before_ the ocean model has been initialized and may be called
133!! on non-ocean PEs. It is not necessary to call this routine for ocean-only
134!! runs, because the same calls are made again inside of the routines called by
135!! call_tracer_register
136subroutine call_tracer_flux_init(verbosity)
137 integer, optional, intent(in) :: verbosity !< A 0-9 integer indicating a level of verbosity.
138
139 type(param_file_type) :: param_file ! A structure to parse for run-time parameters
140 character(len=40) :: mdl = "call_tracer_flux_init" ! This module's name.
141 logical :: use_ocmip_cfcs, use_mom_generic_tracer
142
143 ! Determine which tracer routines with tracer fluxes are to be called. Note
144 ! that not every tracer package is required to have a flux_init call.
145 call get_mom_input(param_file, check_params=.false.)
146
147 call get_param(param_file, mdl, "USE_OCMIP2_CFC", use_ocmip_cfcs, &
148 default=.false., do_not_log=.true.)
149 call get_param(param_file, mdl, "USE_generic_tracer", use_mom_generic_tracer,&
150 default=.false., do_not_log=.true.)
151 call close_param_file(param_file, quiet_close=.true.)
152
153 if (use_ocmip_cfcs) call flux_init_ocmip2_cfc(verbosity=verbosity)
154 if (use_mom_generic_tracer) then
155 call mom_generic_flux_init(verbosity=verbosity)
156 endif
157
158end subroutine call_tracer_flux_init
159
160! The following 5 subroutines and associated definitions provide the machinery to register and call
161! the subroutines that initialize tracers and apply vertical column processes to tracers.
162
163!> This subroutine determines which tracer packages are to be used and does the calls to
164!! register their tracers to be advected, diffused, and read from restarts.
165subroutine call_tracer_register(G, GV, US, param_file, CS, tr_Reg, restart_CS)
166 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
167 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
168 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
169 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
170 !! parameters.
171 type(tracer_flow_control_cs), pointer :: cs !< A pointer that is set to point to the
172 !! control structure for this module.
173 type(tracer_registry_type), pointer :: tr_reg !< A pointer that is set to point to the
174 !! control structure for the tracer
175 !! advection and diffusion module.
176 type(mom_restart_cs), intent(inout) :: restart_cs !< A pointer to the restart control
177 !! structure.
178
179 ! This include declares and sets the variable "version".
180# include "version_variable.h"
181 character(len=40) :: mdl = "MOM_tracer_flow_control" ! This module's name.
182
183 if (associated(cs)) then
184 call mom_error(warning, "call_tracer_register called with an associated "// &
185 "control structure.")
186 return
187 else ; allocate(cs) ; endif
188
189 ! Read all relevant parameters and write them to the model log.
190 call log_version(param_file, mdl, version, "")
191 call get_param(param_file, mdl, "USE_USER_TRACER_EXAMPLE", cs%use_USER_tracer_example, &
192 "If true, use the USER_tracer_example tracer package.", &
193 default=.false.)
194 call get_param(param_file, mdl, "USE_DOME_TRACER", cs%use_DOME_tracer, &
195 "If true, use the DOME_tracer tracer package.", &
196 default=.false.)
197 call get_param(param_file, mdl, "USE_ISOMIP_TRACER", cs%use_ISOMIP_tracer, &
198 "If true, use the ISOMIP_tracer tracer package.", &
199 default=.false.)
200 call get_param(param_file, mdl, "USE_RGC_TRACER", cs%use_RGC_tracer, &
201 "If true, use the RGC_tracer tracer package.", &
202 default=.false.)
203 call get_param(param_file, mdl, "USE_IDEAL_AGE_TRACER", cs%use_ideal_age, &
204 "If true, use the ideal_age_example tracer package.", &
205 default=.false.)
206 call get_param(param_file, mdl, "USE_MARBL_TRACERS", cs%use_marbl_tracers, &
207 "If true, use the MARBL tracer package.", &
208 default=.false.)
209 call get_param(param_file, mdl, "USE_REGIONAL_DYES", cs%use_regional_dyes, &
210 "If true, use the regional_dyes tracer package.", &
211 default=.false.)
212 call get_param(param_file, mdl, "USE_OIL_TRACER", cs%use_oil, &
213 "If true, use the oil_tracer tracer package.", &
214 default=.false.)
215 call get_param(param_file, mdl, "USE_ADVECTION_TEST_TRACER", cs%use_advection_test_tracer, &
216 "If true, use the advection_test_tracer tracer package.", &
217 default=.false.)
218 call get_param(param_file, mdl, "USE_OCMIP2_CFC", cs%use_OCMIP2_CFC, &
219 "If true, use the MOM_OCMIP2_CFC tracer package.", &
220 default=.false.)
221 call get_param(param_file, mdl, "USE_CFC_CAP", cs%use_CFC_cap, &
222 "If true, use the MOM_CFC_cap tracer package.", &
223 default=.false.)
224 call get_param(param_file, mdl, "USE_generic_tracer", cs%use_MOM_generic_tracer, &
225 "If true and _USE_GENERIC_TRACER is defined as a "//&
226 "preprocessor macro, use the MOM_generic_tracer packages.", &
227 default=.false.)
228 call get_param(param_file, mdl, "USE_PSEUDO_SALT_TRACER", cs%use_pseudo_salt_tracer, &
229 "If true, use the pseudo salt tracer, typically run as a diagnostic.", &
230 default=.false.)
231 call get_param(param_file, mdl, "USE_BOUNDARY_IMPULSE_TRACER", cs%use_boundary_impulse_tracer, &
232 "If true, use the boundary impulse tracer.", &
233 default=.false.)
234 call get_param(param_file, mdl, "USE_DYED_OBC_TRACER", cs%use_dyed_obc_tracer, &
235 "If true, use the dyed_obc_tracer tracer package.", &
236 default=.false.)
237 call get_param(param_file, mdl, "USE_NW2_TRACERS", cs%use_nw2_tracers, &
238 "If true, use the NeverWorld2 tracers.", &
239 default=.false.)
240
241! Add other user-provided calls to register tracers for restarting here. Each
242! tracer package registration call returns a logical false if it cannot be run
243! for some reason. This then overrides the run-time selection from above.
244 if (cs%use_USER_tracer_example) cs%use_USER_tracer_example = &
245 user_register_tracer_example(g, gv, us, param_file, cs%USER_tracer_example_CSp, &
246 tr_reg, restart_cs)
247 if (cs%use_DOME_tracer) cs%use_DOME_tracer = &
248 register_dome_tracer(g, gv, us, param_file, cs%DOME_tracer_CSp, &
249 tr_reg, restart_cs)
250 if (cs%use_ISOMIP_tracer) cs%use_ISOMIP_tracer = &
251 register_isomip_tracer(g%HI, gv, param_file, cs%ISOMIP_tracer_CSp, &
252 tr_reg, restart_cs)
253 if (cs%use_RGC_tracer) cs%use_RGC_tracer = &
254 register_rgc_tracer(g, gv, param_file, cs%RGC_tracer_CSp, &
255 tr_reg, restart_cs)
256 if (cs%use_ideal_age) cs%use_ideal_age = &
257 register_ideal_age_tracer(g%HI, gv, param_file, cs%ideal_age_tracer_CSp, &
258 tr_reg, restart_cs)
259 if (cs%use_MARBL_tracers) cs%use_MARBL_tracers = &
260 register_marbl_tracers(g%HI, gv, us, param_file, cs%MARBL_tracers_CSp, &
261 tr_reg, restart_cs, cs%get_chl_from_MARBL)
262 if (cs%use_regional_dyes) cs%use_regional_dyes = &
263 register_dye_tracer(g%HI, gv, us, param_file, cs%dye_tracer_CSp, &
264 tr_reg, restart_cs)
265 if (cs%use_oil) cs%use_oil = &
266 register_oil_tracer(g%HI, gv, us, param_file, cs%oil_tracer_CSp, &
267 tr_reg, restart_cs)
268 if (cs%use_advection_test_tracer) cs%use_advection_test_tracer = &
269 register_advection_test_tracer(g, gv, param_file, cs%advection_test_tracer_CSp, &
270 tr_reg, restart_cs)
271 if (cs%use_OCMIP2_CFC) cs%use_OCMIP2_CFC = &
272 register_ocmip2_cfc(g%HI, gv, param_file, cs%OCMIP2_CFC_CSp, &
273 tr_reg, restart_cs)
274 if (cs%use_CFC_cap) cs%use_CFC_cap = &
275 register_cfc_cap(g%HI, gv, param_file, cs%CFC_cap_CSp, &
276 tr_reg, restart_cs)
277 if (cs%use_MOM_generic_tracer) cs%use_MOM_generic_tracer = &
278 register_mom_generic_tracer(g%HI, gv, param_file, cs%MOM_generic_tracer_CSp, &
279 tr_reg, restart_cs)
280 if (cs%use_pseudo_salt_tracer) cs%use_pseudo_salt_tracer = &
281 register_pseudo_salt_tracer(g%HI, gv, param_file, cs%pseudo_salt_tracer_CSp, &
282 tr_reg, restart_cs)
283 if (cs%use_boundary_impulse_tracer) cs%use_boundary_impulse_tracer = &
284 register_boundary_impulse_tracer(g%HI, gv, us, param_file, cs%boundary_impulse_tracer_CSp, &
285 tr_reg, restart_cs)
286 if (cs%use_dyed_obc_tracer) cs%use_dyed_obc_tracer = &
287 register_dyed_obc_tracer(g%HI, gv, param_file, cs%dyed_obc_tracer_CSp, &
288 tr_reg, restart_cs)
289 if (cs%use_nw2_tracers) cs%use_nw2_tracers = &
290 register_nw2_tracers(g%HI, gv, us, param_file, cs%nw2_tracers_CSp, tr_reg, restart_cs)
291
292end subroutine call_tracer_register
293
294!> This subroutine calls all registered tracer initialization
295!! subroutines.
296subroutine tracer_flow_control_init(restart, day, G, GV, US, h, param_file, diag, OBC, &
297 CS, sponge_CSp, ALE_sponge_CSp, tv)
298 logical, intent(in) :: restart !< 1 if the fields have already
299 !! been read from a restart file.
300 type(time_type), target, intent(in) :: day !< Time of the start of the run.
301 type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
302 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid
303 !! structure.
304 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
305 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
306 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
307 type(param_file_type), intent(in) :: param_file !< A structure to parse for
308 !! run-time parameters
309 type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to
310 !! regulate diagnostic output.
311 type(ocean_obc_type), pointer :: obc !< This open boundary condition
312 !! type specifies whether, where,
313 !! and what open boundary
314 !! conditions are used.
315 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned
316 !! by a previous call to
317 !! call_tracer_register.
318 type(sponge_cs), pointer :: sponge_csp !< A pointer to the control
319 !! structure for the sponges, if they are in use.
320 !! Otherwise this may be unassociated.
321 type(ale_sponge_cs), pointer :: ale_sponge_csp !< A pointer to the control
322 !! structure for the ALE sponges, if they are in use.
323 !! Otherwise this may be unassociated.
324 type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
325 !! thermodynamic variables
326
327 if (.not. associated(cs)) call mom_error(fatal, "tracer_flow_control_init: "// &
328 "Module must be initialized via call_tracer_register before it is used.")
329
330! Add other user-provided calls here.
331 if (cs%use_USER_tracer_example) &
332 call user_initialize_tracer(restart, day, g, gv, us, h, diag, obc, cs%USER_tracer_example_CSp, &
333 sponge_csp)
334 if (cs%use_DOME_tracer) &
335 call initialize_dome_tracer(restart, day, g, gv, us, h, diag, obc, cs%DOME_tracer_CSp, &
336 sponge_csp, tv)
337 if (cs%use_ISOMIP_tracer) &
338 call initialize_isomip_tracer(restart, day, g, gv, h, diag, obc, cs%ISOMIP_tracer_CSp, &
339 ale_sponge_csp)
340 if (cs%use_RGC_tracer) &
341 call initialize_rgc_tracer(restart, day, g, gv, h, diag, obc, cs%RGC_tracer_CSp, &
342 sponge_csp, ale_sponge_csp)
343 if (cs%use_ideal_age) &
344 call initialize_ideal_age_tracer(restart, day, g, gv, us, h, diag, obc, cs%ideal_age_tracer_CSp, &
345 sponge_csp)
346 if (cs%use_MARBL_tracers) &
347 call initialize_marbl_tracers(restart, day, g, gv, us, h, param_file, diag, obc, cs%MARBL_tracers_CSp, &
348 sponge_csp)
349 if (cs%use_regional_dyes) &
350 call initialize_dye_tracer(restart, day, g, gv, us, h, diag, obc, cs%dye_tracer_CSp, sponge_csp, tv)
351 if (cs%use_oil) &
352 call initialize_oil_tracer(restart, day, g, gv, us, h, diag, obc, cs%oil_tracer_CSp, sponge_csp)
353 if (cs%use_advection_test_tracer) &
354 call initialize_advection_test_tracer(restart, day, g, gv, h, diag, obc, cs%advection_test_tracer_CSp, &
355 sponge_csp)
356 if (cs%use_OCMIP2_CFC) &
357 call initialize_ocmip2_cfc(restart, day, g, gv, us, h, diag, obc, cs%OCMIP2_CFC_CSp, sponge_csp)
358 if (cs%use_CFC_cap) &
359 call initialize_cfc_cap(restart, day, g, gv, us, h, diag, obc, cs%CFC_cap_CSp)
360
361 if (cs%use_MOM_generic_tracer) &
362 call initialize_mom_generic_tracer(restart, day, g, gv, us, h, tv, param_file, diag, obc, &
363 cs%MOM_generic_tracer_CSp, sponge_csp, ale_sponge_csp)
364 if (cs%use_pseudo_salt_tracer) &
365 call initialize_pseudo_salt_tracer(restart, day, g, gv, us, h, diag, obc, cs%pseudo_salt_tracer_CSp, &
366 sponge_csp, tv)
367 if (cs%use_boundary_impulse_tracer) &
368 call initialize_boundary_impulse_tracer(restart, day, g, gv, us, h, diag, obc, cs%boundary_impulse_tracer_CSp, &
369 sponge_csp, tv)
370 if (cs%use_dyed_obc_tracer) &
371 call initialize_dyed_obc_tracer(restart, day, g, gv, h, diag, obc, cs%dyed_obc_tracer_CSp)
372 if (cs%use_nw2_tracers) &
373 call initialize_nw2_tracers(restart, day, g, gv, us, h, tv, diag, cs%nw2_tracers_CSp)
374
375end subroutine tracer_flow_control_init
376
377!> This subroutine calls all registered tracers to register their OBC segments
378!! similar to register_temp_salt_segments for T&S
379subroutine call_tracer_register_obc_segments(GV, param_file, CS, tr_Reg, OBC)
380 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
381 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
382 !! parameters.
383 type(tracer_flow_control_cs), pointer :: cs !< A pointer that is set to point to the
384 !! control structure for this module.
385 type(tracer_registry_type), pointer :: tr_reg !< A pointer that is set to point to the
386 !! control structure for the tracer
387 !! advection and diffusion module.
388 type(ocean_obc_type), pointer :: obc !< This open boundary condition
389 !! type specifies whether, where,
390 !! and what open boundary
391 !! conditions are used.
392
393 if (cs%use_MOM_generic_tracer) &
394 call register_mom_generic_tracer_segments(cs%MOM_generic_tracer_CSp, gv, obc, tr_reg, param_file)
395
397
398!> This subroutine extracts the chlorophyll concentrations from the model state, if possible
399subroutine get_chl_from_model(Chl_array, G, GV, CS)
400 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
401 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
402 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
403 intent(out) :: chl_array !< The array in which to store the model's
404 !! Chlorophyll-A concentrations [mg m-3].
405 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by a
406 !! previous call to call_tracer_register.
407
408 if (cs%get_chl_from_MARBL) then
409 call marbl_tracers_get('Chl', g, gv, chl_array, cs%MARBL_tracers_CSp)
410 elseif (cs%use_MOM_generic_tracer) then
411 call mom_generic_tracer_get('chl', 'field', chl_array, cs%MOM_generic_tracer_CSp)
412 else
413 call mom_error(fatal, "get_chl_from_model was called in a configuration "// &
414 "that is unable to provide a sensible model-based value.\n"// &
415 "CS%use_MOM_generic_tracer is false and no other viable options are on.")
416 endif
417
418end subroutine get_chl_from_model
419
420!> This subroutine calls the individual tracer modules' subroutines to
421!! specify or read quantities related to their surface forcing.
422subroutine call_tracer_set_forcing(sfc_state, fluxes, day_start, day_interval, G, US, Rho0, CS)
423
424 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
425 !! describe the surface state of the
426 !! ocean.
427 type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
428 !! possible forcing fields. Unused fields
429 !! have NULL ptrs.
430 type(time_type), intent(in) :: day_start !< Start time of the fluxes.
431 type(time_type), intent(in) :: day_interval !< Length of time over which these
432 !! fluxes will be applied.
433 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
434 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
435 real, intent(in) :: rho0 !< The mean ocean density [R ~> kg m-3]
436 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by a
437 !! previous call to call_tracer_register.
438
439 if (.not. associated(cs)) call mom_error(fatal, "call_tracer_set_forcing: "// &
440 "Module must be initialized via call_tracer_register before it is used.")
441! if (CS%use_ideal_age) &
442! call ideal_age_tracer_set_forcing(sfc_state, fluxes, day_start, day_interval, &
443! G, CS%ideal_age_tracer_CSp)
444 if (cs%use_CFC_cap) &
445 call cfc_cap_set_forcing(sfc_state, fluxes, day_start, day_interval, g, us, rho0, &
446 cs%CFC_cap_CSp)
447
448 if (cs%use_MARBL_tracers) &
449 call marbl_tracers_set_forcing(day_start, g, cs%MARBL_tracers_CSp)
450
451end subroutine call_tracer_set_forcing
452
453!> This subroutine calls all registered tracer column physics subroutines.
454subroutine call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, mld, dt, G, GV, US, tv, optics, CS, &
455 debug, KPP_CSp, nonLocalTrans, evap_CFL_limit, minimum_forcing_depth, h_BL)
456 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
457 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
458 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h_old !< Layer thickness before entrainment
459 !! [H ~> m or kg m-2].
460 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h_new !< Layer thickness after entrainment
461 !! [H ~> m or kg m-2].
462 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: ea !< an array to which the amount of
463 !! fluid entrained from the layer above during this call
464 !! will be added [H ~> m or kg m-2].
465 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: eb !< an array to which the amount of
466 !! fluid entrained from the layer below during this call
467 !! will be added [H ~> m or kg m-2].
468 type(forcing), intent(in) :: fluxes !< A structure containing pointers to
469 !! any possible forcing fields.
470 !! Unused fields have NULL ptrs.
471 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: mld !< Mixed layer depth [Z ~> m]
472 real, intent(in) :: dt !< The amount of time covered by this
473 !! call [T ~> s]
474 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
475 type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
476 !! thermodynamic variables.
477 type(optics_type), pointer :: optics !< The structure containing optical
478 !! properties.
479 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by
480 !! a previous call to
481 !! call_tracer_register.
482 logical, intent(in) :: debug !< If true calculate checksums
483 type(kpp_cs), optional, pointer :: kpp_csp !< KPP control structure
484 real, optional, intent(in) :: nonlocaltrans(:,:,:) !< Non-local transport [nondim]
485 real, optional, intent(in) :: evap_cfl_limit !< Limit on the fraction of
486 !! the water that can be fluxed out
487 !! of the top layer in a timestep [nondim]
488 real, optional, intent(in) :: minimum_forcing_depth !< The smallest depth over
489 !! which fluxes can be applied [H ~> m or kg m-2]
490 real, dimension(:,:), optional, pointer :: h_bl !< Thickness of active mixing layer [H ~> m or kg m-2]
491
492 ! Local variables
493 real :: hbl(szi_(g),szj_(g)) !< Boundary layer thickness [H ~> m or kg m-2]
494 logical :: use_h_bl
495
496 if (.not. associated(cs)) call mom_error(fatal, "call_tracer_column_fns: "// &
497 "Module must be initialized via call_tracer_register before it is used.")
498
499 ! Use the applyTracerBoundaryFluxesInOut to handle surface fluxes
500 if (present(evap_cfl_limit) .and. present(minimum_forcing_depth)) then
501 ! Add calls to tracer column functions here.
502 if (cs%use_USER_tracer_example) &
503 call tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
504 g, gv, us, cs%USER_tracer_example_CSp)
505 if (cs%use_DOME_tracer) &
506 call dome_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
507 g, gv, us, cs%DOME_tracer_CSp, &
508 evap_cfl_limit=evap_cfl_limit, &
509 minimum_forcing_depth=minimum_forcing_depth)
510 if (cs%use_ISOMIP_tracer) &
511 call isomip_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
512 g, gv, us, cs%ISOMIP_tracer_CSp, &
513 evap_cfl_limit=evap_cfl_limit, &
514 minimum_forcing_depth=minimum_forcing_depth)
515 if (cs%use_RGC_tracer) &
516 call rgc_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
517 g, gv, us, cs%RGC_tracer_CSp, &
518 evap_cfl_limit=evap_cfl_limit, &
519 minimum_forcing_depth=minimum_forcing_depth)
520 if (cs%use_ideal_age) then
521 use_h_bl = .false. ; if (present(h_bl)) use_h_bl = associated(h_bl)
522 if (present(h_bl)) then
523 hbl(:,:) = h_bl(:,:)
524 else ! This option is here mostly to support the offline tracers.
525 call convert_mld_to_ml_thickness(mld, h_new, hbl, tv, g, gv)
526 endif
527 call ideal_age_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
528 g, gv, us, cs%ideal_age_tracer_CSp, &
529 evap_cfl_limit=evap_cfl_limit, &
530 minimum_forcing_depth=minimum_forcing_depth, hbl=hbl)
531 endif
532 if (cs%use_MARBL_tracers) &
533 call marbl_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
534 g, gv, us, cs%MARBL_tracers_CSp, tv, &
535 kpp_csp=kpp_csp, &
536 nonlocaltrans=nonlocaltrans, &
537 evap_cfl_limit=evap_cfl_limit, &
538 minimum_forcing_depth=minimum_forcing_depth)
539 if (cs%use_regional_dyes) &
540 call dye_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
541 g, gv, us, tv, cs%dye_tracer_CSp, &
542 evap_cfl_limit=evap_cfl_limit, &
543 minimum_forcing_depth=minimum_forcing_depth)
544 if (cs%use_oil) &
545 call oil_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
546 g, gv, us, cs%oil_tracer_CSp, tv, &
547 evap_cfl_limit=evap_cfl_limit, &
548 minimum_forcing_depth=minimum_forcing_depth)
549
550 if (cs%use_advection_test_tracer) &
551 call advection_test_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
552 g, gv, us, cs%advection_test_tracer_CSp, &
553 evap_cfl_limit=evap_cfl_limit, &
554 minimum_forcing_depth=minimum_forcing_depth)
555 if (cs%use_OCMIP2_CFC) &
556 call ocmip2_cfc_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
557 g, gv, us, cs%OCMIP2_CFC_CSp, &
558 evap_cfl_limit=evap_cfl_limit, &
559 minimum_forcing_depth=minimum_forcing_depth)
560 if (cs%use_CFC_cap) &
561 call cfc_cap_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
562 g, gv, us, cs%CFC_cap_CSp, &
563 kpp_csp=kpp_csp, &
564 nonlocaltrans=nonlocaltrans, &
565 evap_cfl_limit=evap_cfl_limit, &
566 minimum_forcing_depth=minimum_forcing_depth)
567 if (cs%use_MOM_generic_tracer) then
568 if (us%QRZ_T_to_W_m2 /= 1.0) call mom_error(fatal, "MOM_generic_tracer_column_physics "//&
569 "has not been written to permit dimensionsal rescaling. Set all 4 of the "//&
570 "[QRZT]_RESCALE_POWER parameters to 0.")
571 call mom_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, mld, dt, &
572 g, gv, us, cs%MOM_generic_tracer_CSp, tv, optics, &
573 evap_cfl_limit=evap_cfl_limit, &
574 minimum_forcing_depth=minimum_forcing_depth)
575 endif
576 if (cs%use_pseudo_salt_tracer) &
577 call pseudo_salt_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
578 g, gv, us, cs%pseudo_salt_tracer_CSp, tv, &
579 debug, &
580 kpp_csp=kpp_csp, &
581 nonlocaltrans=nonlocaltrans, &
582 evap_cfl_limit=evap_cfl_limit, &
583 minimum_forcing_depth=minimum_forcing_depth)
584 if (cs%use_boundary_impulse_tracer) &
585 call boundary_impulse_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
586 g, gv, us, cs%boundary_impulse_tracer_CSp, tv, debug, &
587 evap_cfl_limit=evap_cfl_limit, &
588 minimum_forcing_depth=minimum_forcing_depth)
589 if (cs%use_dyed_obc_tracer) &
590 call dyed_obc_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
591 g, gv, us, cs%dyed_obc_tracer_CSp, &
592 evap_cfl_limit=evap_cfl_limit, &
593 minimum_forcing_depth=minimum_forcing_depth)
594 if (cs%use_nw2_tracers) &
595 call nw2_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
596 g, gv, us, tv, cs%nw2_tracers_CSp, &
597 evap_cfl_limit=evap_cfl_limit, &
598 minimum_forcing_depth=minimum_forcing_depth)
599 else ! Apply tracer surface fluxes using ea on the first layer
600 if (cs%use_USER_tracer_example) &
601 call tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
602 g, gv, us, cs%USER_tracer_example_CSp)
603 if (cs%use_DOME_tracer) &
604 call dome_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
605 g, gv, us, cs%DOME_tracer_CSp)
606 if (cs%use_ISOMIP_tracer) &
607 call isomip_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
608 g, gv, us, cs%ISOMIP_tracer_CSp)
609 if (cs%use_RGC_tracer) &
610 call rgc_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
611 g, gv, us, cs%RGC_tracer_CSp)
612 if (cs%use_ideal_age) then
613 use_h_bl = .false. ; if (present(h_bl)) use_h_bl = associated(h_bl)
614 if (present(h_bl)) then
615 hbl(:,:) = h_bl(:,:)
616 else ! This option is here mostly to support the offline tracers.
617 call convert_mld_to_ml_thickness(mld, h_new, hbl, tv, g, gv)
618 endif
619 call ideal_age_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
620 g, gv, us, cs%ideal_age_tracer_CSp, hbl=hbl)
621 endif
622 if (cs%use_MARBL_tracers) &
623 call marbl_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
624 g, gv, us, cs%MARBL_tracers_CSp, tv, &
625 kpp_csp=kpp_csp, &
626 nonlocaltrans=nonlocaltrans)
627 if (cs%use_regional_dyes) &
628 call dye_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
629 g, gv, us, tv, cs%dye_tracer_CSp)
630 if (cs%use_oil) &
631 call oil_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
632 g, gv, us, cs%oil_tracer_CSp, tv)
633 if (cs%use_advection_test_tracer) &
634 call advection_test_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
635 g, gv, us, cs%advection_test_tracer_CSp)
636 if (cs%use_OCMIP2_CFC) &
637 call ocmip2_cfc_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
638 g, gv, us, cs%OCMIP2_CFC_CSp)
639 if (cs%use_CFC_cap) &
640 call cfc_cap_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
641 g, gv, us, cs%CFC_cap_CSp, &
642 kpp_csp=kpp_csp, &
643 nonlocaltrans=nonlocaltrans)
644 if (cs%use_MOM_generic_tracer) then
645 if (us%QRZ_T_to_W_m2 /= 1.0) call mom_error(fatal, "MOM_generic_tracer_column_physics "//&
646 "has not been written to permit dimensionsal rescaling. Set all 4 of the "//&
647 "[QRZT]_RESCALE_POWER parameters to 0.")
648 call mom_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, mld, dt, &
649 g, gv, us, cs%MOM_generic_tracer_CSp, tv, optics)
650 endif
651 if (cs%use_pseudo_salt_tracer) &
652 call pseudo_salt_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
653 g, gv, us, cs%pseudo_salt_tracer_CSp, &
654 tv, debug, &
655 kpp_csp=kpp_csp, &
656 nonlocaltrans=nonlocaltrans)
657 if (cs%use_boundary_impulse_tracer) &
658 call boundary_impulse_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
659 g, gv, us, cs%boundary_impulse_tracer_CSp, tv, debug)
660 if (cs%use_dyed_obc_tracer) &
661 call dyed_obc_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
662 g, gv, us, cs%dyed_obc_tracer_CSp)
663 if (cs%use_nw2_tracers) call nw2_tracer_column_physics(h_old, h_new, ea, eb, fluxes, dt, &
664 g, gv, us, tv, cs%nw2_tracers_CSp)
665 endif
666
667end subroutine call_tracer_column_fns
668
669!> This subroutine calls all registered tracer packages to enable them to
670!! add to the surface state returned to the coupler. These routines are optional.
671subroutine call_tracer_stocks(h, stock_values, G, GV, US, CS, stock_names, stock_units, &
672 num_stocks, stock_index, got_min_max, global_min, global_max, &
673 xgmin, ygmin, zgmin, xgmax, ygmax, zgmax)
674 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
675 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
676 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
677 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
678 real, dimension(:), intent(out) :: stock_values !< The globally mass-integrated
679 !! amount of a tracer [kg conc].
680 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
681 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by a
682 !! previous call to
683 !! call_tracer_register.
684 character(len=*), dimension(:), &
685 optional, intent(out) :: stock_names !< Diagnostic names to use for each stock.
686 character(len=*), dimension(:), &
687 optional, intent(out) :: stock_units !< Units to use in the metadata for each stock.
688 integer, optional, intent(out) :: num_stocks !< The number of tracer stocks being returned.
689 integer, optional, intent(in) :: stock_index !< The integer stock index from
690 !! stocks_constants_mod of the stock to be returned. If this is
691 !! present and greater than 0, only a single stock can be returned.
692 logical, dimension(:), &
693 optional, intent(inout) :: got_min_max !< Indicates whether the global min and
694 !! max are found for each tracer
695 real, dimension(:), optional, intent(out) :: global_min !< The global minimum of each tracer [conc]
696 real, dimension(:), optional, intent(out) :: global_max !< The global maximum of each tracer [conc]
697 real, dimension(:), optional, intent(out) :: xgmin !< The x-position of the global minimum in the
698 !! units of G%geoLonT, often [degrees_E] or [km]
699 real, dimension(:), optional, intent(out) :: ygmin !< The y-position of the global minimum in the
700 !! units of G%geoLatT, often [degrees_N] or [km]
701 real, dimension(:), optional, intent(out) :: zgmin !< The z-position of the global minimum [layer]
702 real, dimension(:), optional, intent(out) :: xgmax !< The x-position of the global maximum in the
703 !! units of G%geoLonT, often [degrees_E] or [km]
704 real, dimension(:), optional, intent(out) :: ygmax !< The y-position of the global maximum in the
705 !! units of G%geoLatT, often [degrees_N] or [km]
706 real, dimension(:), optional, intent(out) :: zgmax !< The z-position of the global maximum [layer]
707
708 ! Local variables
709 character(len=200), dimension(MAX_FIELDS_) :: names, units
710 character(len=200) :: set_pkg_name
711 ! real, dimension(MAX_FIELDS_) :: values ! Globally integrated tracer amounts in a
712 ! new list for each tracer package [kg conc]
713 type(efp_type), dimension(MAX_FIELDS_) :: values_efp ! Globally integrated tracer amounts in a
714 ! new list for each tracer package [kg conc]
715 type(efp_type), dimension(MAX_FIELDS_) :: stock_val_efp ! Globally integrated tracer amounts in a
716 ! single master list for all tracers [kg conc]
717 integer :: max_ns, ns_tot, ns, index, nn, n
718
719 if (.not. associated(cs)) call mom_error(fatal, "call_tracer_stocks: "// &
720 "Module must be initialized via call_tracer_register before it is used.")
721
722 index = -1 ; if (present(stock_index)) index = stock_index
723 ns_tot = 0
724 max_ns = size(stock_values)
725 if (present(stock_names)) max_ns = min(max_ns,size(stock_names))
726 if (present(stock_units)) max_ns = min(max_ns,size(stock_units))
727
728! Add other user-provided calls here.
729 if (cs%use_USER_tracer_example) then
730 ns = user_tracer_stock(h, values_efp, g, gv, cs%USER_tracer_example_CSp, &
731 names, units, stock_index)
732 call store_stocks("tracer_example", ns, names, units, values_efp, index, stock_val_efp, &
733 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
734 endif
735! if (CS%use_DOME_tracer) then
736! ns = DOME_tracer_stock(h, values, G, GV, CS%DOME_tracer_CSp, &
737! names, units, stock_index)
738! do n=1,ns ; values_EFP(n) = real_to_EFP(values(n)) ; enddo
739! call store_stocks("DOME_tracer", ns, names, units, values_EFP, index, stock_val_EFP, &
740! set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
741! endif
742 if (cs%use_ideal_age) then
743 ns = ideal_age_stock(h, values_efp, g, gv, cs%ideal_age_tracer_CSp, &
744 names, units, stock_index)
745 call store_stocks("ideal_age_example", ns, names, units, values_efp, index, stock_val_efp, &
746 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
747 endif
748 if (cs%use_MARBL_tracers) then
749 ns = marbl_tracers_stock(h, values_efp, g, gv, cs%MARBL_tracers_CSp, &
750 names, units, stock_index)
751 call store_stocks("MARBL_tracers", ns, names, units, values_efp, index, stock_val_efp, &
752 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
753 endif
754 if (cs%use_regional_dyes) then
755 ns = dye_stock(h, values_efp, g, gv, cs%dye_tracer_CSp, names, units, stock_index)
756 call store_stocks("regional_dyes", ns, names, units, values_efp, index, stock_val_efp, &
757 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
758 endif
759 if (cs%use_oil) then
760 ns = oil_stock(h, values_efp, g, gv, cs%oil_tracer_CSp, names, units, stock_index)
761 call store_stocks("oil_tracer", ns, names, units, values_efp, index, stock_val_efp, &
762 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
763 endif
764 if (cs%use_OCMIP2_CFC) then
765 ns = ocmip2_cfc_stock(h, values_efp, g, gv, cs%OCMIP2_CFC_CSp, names, units, stock_index)
766 call store_stocks("MOM_OCMIP2_CFC", ns, names, units, values_efp, index, stock_val_efp, &
767 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
768 endif
769
770 if (cs%use_CFC_cap) then
771 ns = cfc_cap_stock(h, values_efp, g, gv, cs%CFC_cap_CSp, names, units, stock_index)
772 call store_stocks("MOM_CFC_cap", ns, names, units, values_efp, index, stock_val_efp, &
773 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
774 endif
775
776 if (cs%use_advection_test_tracer) then
777 ns = advection_test_stock( h, values_efp, g, gv, cs%advection_test_tracer_CSp, &
778 names, units, stock_index )
779 ! do n=1,ns ; values_EFP(n) = real_to_EFP(values(n)) ; enddo
780 call store_stocks("advection_test_tracer", ns, names, units, values_efp, index, stock_val_efp, &
781 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
782 endif
783
784 if (cs%use_MOM_generic_tracer) then
785 ns = mom_generic_tracer_stock(h, values_efp, g, gv, cs%MOM_generic_tracer_CSp, &
786 names, units, stock_index)
787 call store_stocks("MOM_generic_tracer", ns, names, units, values_efp, index, stock_val_efp, &
788 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
789 nn=ns_tot-ns+1
790 if (present(got_min_max) .and. present(global_min) .and. present(global_max)) &
791 nn = mom_generic_tracer_min_max(nn, got_min_max, global_min, global_max, &
792 g, cs%MOM_generic_tracer_CSp, names, units, &
793 xgmin, ygmin, zgmin, xgmax, ygmax, zgmax)
794
795 endif
796 if (cs%use_pseudo_salt_tracer) then
797 ns = pseudo_salt_stock(h, values_efp, g, gv, cs%pseudo_salt_tracer_CSp, &
798 names, units, stock_index)
799 call store_stocks("pseudo_salt_tracer", ns, names, units, values_efp, index, stock_val_efp, &
800 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
801 endif
802
803 if (cs%use_boundary_impulse_tracer) then
804 ns = boundary_impulse_stock(h, values_efp, g, gv, cs%boundary_impulse_tracer_CSp, &
805 names, units, stock_index)
806 call store_stocks("boundary_impulse_tracer", ns, names, units, values_efp, index, stock_val_efp, &
807 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
808 endif
809
810 ! Sum the various quantities across all the processors.
811 if (ns_tot > 0) then
812 call efp_sum_across_pes(stock_val_efp, ns_tot)
813 do n=1,ns_tot ; stock_values(n) = efp_to_real(stock_val_efp(n)) ; enddo
814 else
815 stock_values(1) = 0.0
816 endif
817
818 if (present(num_stocks)) num_stocks = ns_tot
819
820end subroutine call_tracer_stocks
821
822!> This routine stores the stocks and does error handling for call_tracer_stocks.
823subroutine store_stocks(pkg_name, ns, names, units, values, index, stock_values, &
824 set_pkg_name, max_ns, ns_tot, stock_names, stock_units)
825 character(len=*), intent(in) :: pkg_name !< The tracer package name
826 integer, intent(in) :: ns !< The number of stocks associated with this tracer package
827 character(len=*), dimension(:), &
828 intent(in) :: names !< Diagnostic names to use for each stock.
829 character(len=*), dimension(:), &
830 intent(in) :: units !< Units to use in the metadata for each stock.
831 type(efp_type), dimension(:), &
832 intent(in) :: values !< The values of the tracer stocks [conc kg]
833 integer, intent(in) :: index !< The integer stock index from
834 !! stocks_constants_mod of the stock to be returned. If this is
835 !! present and greater than 0, only a single stock can be returned.
836 type(efp_type), dimension(:), &
837 intent(inout) :: stock_values !< The master list of stock values [conc kg]
838 character(len=*), intent(inout) :: set_pkg_name !< The name of the last tracer package whose
839 !! stocks were stored for a specific index. This is
840 !! used to trigger an error if there are redundant stocks.
841 integer, intent(in) :: max_ns !< The maximum size of the master stock list
842 integer, intent(inout) :: ns_tot !< The total number of stocks in the master list
843 character(len=*), dimension(:), &
844 optional, intent(inout) :: stock_names !< Diagnostic names to use for each stock in the master list
845 character(len=*), dimension(:), &
846 optional, intent(inout) :: stock_units !< Units to use in the metadata for each stock in the master list
847
848! This routine stores the stocks and does error handling for call_tracer_stocks.
849 character(len=16) :: ind_text, ns_text, max_text
850 integer :: n
851
852 if ((index > 0) .and. (ns > 0)) then
853 write(ind_text,'(I0)') index
854 if (ns > 1) then
855 call mom_error(fatal,"Tracer package "//trim(pkg_name)//&
856 " is not permitted to return more than one value when queried "//&
857 "for specific stock index "//trim(ind_text)//".")
858 elseif (ns+ns_tot > 1) then
859 call mom_error(fatal,"Tracer packages "//trim(pkg_name)//" and "//&
860 trim(set_pkg_name)//" both attempted to set values for "//&
861 "specific stock index "//trim(ind_text)//".")
862 else
863 set_pkg_name = pkg_name
864 endif
865 endif
866
867 if (ns_tot+ns > max_ns) then
868 write(ns_text,'(I0)') ns_tot+ns ; write(max_text,'(I0)') max_ns
869 call mom_error(fatal,"Attempted to return more tracer stock values (at least "//&
870 trim(ns_text)//") than the size "//trim(max_text)//&
871 "of the smallest value, name, or units array.")
872 endif
873
874 do n=1,ns
875 stock_values(ns_tot+n) = values(n)
876 if (present(stock_names)) stock_names(ns_tot+n) = names(n)
877 if (present(stock_units)) stock_units(ns_tot+n) = units(n)
878 enddo
879 ns_tot = ns_tot + ns
880
881end subroutine store_stocks
882
883!> This subroutine calls all registered tracer packages to enable them to
884!! add to the surface state returned to the coupler. These routines are optional.
885subroutine call_tracer_surface_state(sfc_state, h, G, GV, US, CS)
886 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
887 !! describe the surface state of the ocean.
888 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
889 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
890 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
891 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
892 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
893 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by a
894 !! previous call to call_tracer_register.
895
896 if (.not. associated(cs)) call mom_error(fatal, "call_tracer_surface_state: "// &
897 "Module must be initialized via call_tracer_register before it is used.")
898
899! Add other user-provided calls here.
900 if (cs%use_USER_tracer_example) &
901 call user_tracer_surface_state(sfc_state, h, g, gv, cs%USER_tracer_example_CSp)
902 if (cs%use_DOME_tracer) &
903 call dome_tracer_surface_state(sfc_state, h, g, gv, cs%DOME_tracer_CSp)
904 if (cs%use_ISOMIP_tracer) &
905 call isomip_tracer_surface_state(sfc_state, h, g, gv, cs%ISOMIP_tracer_CSp)
906 if (cs%use_ideal_age) &
907 call ideal_age_tracer_surface_state(sfc_state, h, g, gv, cs%ideal_age_tracer_CSp)
908 if (cs%use_MARBL_tracers) &
909 call marbl_tracers_surface_state(sfc_state, g, us, cs%MARBL_tracers_CSp)
910 if (cs%use_regional_dyes) &
911 call dye_tracer_surface_state(sfc_state, h, g, gv, cs%dye_tracer_CSp)
912 if (cs%use_oil) &
913 call oil_tracer_surface_state(sfc_state, h, g, gv, cs%oil_tracer_CSp)
914 if (cs%use_advection_test_tracer) &
915 call advection_test_tracer_surface_state(sfc_state, h, g, gv, cs%advection_test_tracer_CSp)
916 if (cs%use_OCMIP2_CFC) &
917 call ocmip2_cfc_surface_state(sfc_state, h, g, gv, us, cs%OCMIP2_CFC_CSp)
918 if (cs%use_MOM_generic_tracer) &
919 call mom_generic_tracer_surface_state(sfc_state, h, g, gv, cs%MOM_generic_tracer_CSp)
920
921end subroutine call_tracer_surface_state
922
923subroutine tracer_flow_control_end(CS)
924 type(tracer_flow_control_cs), pointer :: cs !< The control structure returned by a
925 !! previous call to call_tracer_register.
926
927 if (cs%use_USER_tracer_example) &
928 call user_tracer_example_end(cs%USER_tracer_example_CSp)
929 if (cs%use_DOME_tracer) call dome_tracer_end(cs%DOME_tracer_CSp)
930 if (cs%use_ISOMIP_tracer) call isomip_tracer_end(cs%ISOMIP_tracer_CSp)
931 if (cs%use_RGC_tracer) call rgc_tracer_end(cs%RGC_tracer_CSp)
932 if (cs%use_ideal_age) call ideal_age_example_end(cs%ideal_age_tracer_CSp)
933 if (cs%use_MARBL_tracers) call marbl_tracers_end(cs%MARBL_tracers_CSp)
934 if (cs%use_regional_dyes) call regional_dyes_end(cs%dye_tracer_CSp)
935 if (cs%use_oil) call oil_tracer_end(cs%oil_tracer_CSp)
936 if (cs%use_advection_test_tracer) call advection_test_tracer_end(cs%advection_test_tracer_CSp)
937 if (cs%use_OCMIP2_CFC) call ocmip2_cfc_end(cs%OCMIP2_CFC_CSp)
938 if (cs%use_CFC_cap) call cfc_cap_end(cs%CFC_cap_CSp)
939 if (cs%use_MOM_generic_tracer) call end_mom_generic_tracer(cs%MOM_generic_tracer_CSp)
940 if (cs%use_pseudo_salt_tracer) call pseudo_salt_tracer_end(cs%pseudo_salt_tracer_CSp)
941 if (cs%use_boundary_impulse_tracer) call boundary_impulse_tracer_end(cs%boundary_impulse_tracer_CSp)
942 if (cs%use_dyed_obc_tracer) call dyed_obc_tracer_end(cs%dyed_obc_tracer_CSp)
943 if (cs%use_nw2_tracers) call nw2_tracers_end(cs%nw2_tracers_CSp)
944
945 if (associated(cs)) deallocate(cs)
946end subroutine tracer_flow_control_end
947
948!> \namespace MOM_tracer_flow_control
949!!
950!! By Will Cooke, April 2003
951!! Edited by Elizabeth Yankovsky, May 2019
952!!
953!! This module contains two subroutines into which calls to other
954!! tracer initialization (call_tracer_init_fns) and column physics
955!! routines (call_tracer_column_fns) can be inserted.
956!!