MOM6
MOM_generic_tracer.F90
1 !> Drives the generic version of tracers TOPAZ and CFC and other GFDL BGC components
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 #include <MOM_memory.h>
7 
8 ! The following macro is usually defined in <fms_platform.h> but since MOM6 should not directly
9 ! include files from FMS we replicate the macro lines here:
10 #ifdef NO_F2000
11 #define _ALLOCATED associated
12 #else
13 #define _ALLOCATED allocated
14 #endif
15 
16  ! ### These imports should not reach into FMS directly ###
17  use field_manager_mod, only: fm_string_len
18 
19  use generic_tracer, only: generic_tracer_register, generic_tracer_get_diag_list
20  use generic_tracer, only: generic_tracer_init, generic_tracer_source, generic_tracer_register_diag
21  use generic_tracer, only: generic_tracer_coupler_get, generic_tracer_coupler_set
22  use generic_tracer, only: generic_tracer_end, generic_tracer_get_list, do_generic_tracer
23  use generic_tracer, only: generic_tracer_update_from_bottom,generic_tracer_vertdiff_g
24  use generic_tracer, only: generic_tracer_coupler_accumulate
25 
26  use g_tracer_utils, only: g_tracer_get_name,g_tracer_set_values,g_tracer_set_common,g_tracer_get_common
27  use g_tracer_utils, only: g_tracer_get_next,g_tracer_type,g_tracer_is_prog,g_tracer_flux_init
28  use g_tracer_utils, only: g_tracer_send_diag,g_tracer_get_values
29  use g_tracer_utils, only: g_tracer_get_pointer,g_tracer_get_alias,g_tracer_set_csdiag
30 
31  use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
32  use mom_diag_mediator, only : diag_ctrl, get_diag_time_end
33  use mom_error_handler, only : mom_error, fatal, warning, note, is_root_pe
35  use mom_forcing_type, only : forcing, optics_type
36  use mom_grid, only : ocean_grid_type
37  use mom_hor_index, only : hor_index_type
38  use mom_io, only : file_exists, mom_read_data, slasher
40  use mom_spatial_means, only : global_area_mean
41  use mom_sponge, only : set_up_sponge_field, sponge_cs
43  use mom_time_manager, only : time_type, set_time
44  use mom_tracer_diabatic, only : tracer_vertdiff, applytracerboundaryfluxesinout
45  use mom_tracer_registry, only : register_tracer, tracer_registry_type
46  use mom_tracer_z_init, only : tracer_z_init
47  use mom_tracer_initialization_from_z, only : mom_initialize_tracer_from_z
52 
53 
54  implicit none ; private
55 
56  !> An state hidden in module data that is very much not allowed in MOM6
57  ! ### This needs to be fixed
58  logical :: g_registered = .false.
59 
60  public register_mom_generic_tracer, initialize_mom_generic_tracer
61  public mom_generic_tracer_column_physics, mom_generic_tracer_surface_state
62  public end_mom_generic_tracer, mom_generic_tracer_get
63  public mom_generic_tracer_stock
64  public mom_generic_flux_init
65  public mom_generic_tracer_min_max
66  public mom_generic_tracer_fluxes_accumulate
67 
68  !> Control structure for generic tracers
69  type, public :: mom_generic_tracer_cs ; private
70  character(len = 200) :: ic_file !< The file in which the generic tracer initial values can
71  !! be found, or an empty string for internal initialization.
72  logical :: z_ic_file !< If true, the generic_tracer IC_file is in Z-space. The default is false.
73  real :: tracer_ic_val = 0.0 !< The initial value assigned to tracers.
74  real :: tracer_land_val = -1.0 !< The values of tracers used where land is masked out.
75  logical :: tracers_may_reinit !< If true, tracers may go through the
76  !! initialization code if they are not found in the restart files.
77 
78  type(diag_ctrl), pointer :: diag => null() !< A structure that is used to
79  !! regulate the timing of diagnostic output.
80  type(mom_restart_cs), pointer :: restart_csp => null() !< Restart control structure
81 
82  !> Pointer to the first element of the linked list of generic tracers.
83  type(g_tracer_type), pointer :: g_tracer_list => null()
84 
85  integer :: h_to_m !< Auxiliary to access GV%H_to_m in routines that do not have access to GV
86 
87  end type mom_generic_tracer_cs
88 
89 ! This include declares and sets the variable "version".
90 #include "version_variable.h"
91 
92 contains
93 
94  !> Initializes the generic tracer packages and adds their tracers to the list
95  !! Adds the tracers in the list of generic tracers to the set of MOM tracers (i.e., MOM-register them)
96  !! Register these tracers for restart
97  function register_mom_generic_tracer(HI, GV, param_file, CS, tr_Reg, restart_CS)
98  type(hor_index_type), intent(in) :: hi !< Horizontal index ranges
99  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
100  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
101  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module
102  type(tracer_registry_type), pointer :: tr_reg !< Pointer to the control structure for the tracer
103  !! advection and diffusion module.
104  type(mom_restart_cs), pointer :: restart_cs !< Pointer to the restart control structure.
105 
106 ! Local variables
107  logical :: register_mom_generic_tracer
108 
109  character(len=128), parameter :: sub_name = 'register_MOM_generic_tracer'
110  character(len=200) :: inputdir ! The directory where NetCDF input files are.
111  ! These can be overridden later in via the field manager?
112 
113  integer :: ntau, k,i,j,axes(3)
114  type(g_tracer_type), pointer :: g_tracer,g_tracer_next
115  character(len=fm_string_len) :: g_tracer_name,longname,units
116  real, dimension(:,:,:,:), pointer :: tr_field
117  real, dimension(:,:,:), pointer :: tr_ptr
118  real, dimension(HI%isd:HI%ied, HI%jsd:HI%jed,GV%ke) :: grid_tmask
119  integer, dimension(HI%isd:HI%ied, HI%jsd:HI%jed) :: grid_kmt
120 
121  register_mom_generic_tracer = .false.
122  if (associated(cs)) then
123  call mom_error(warning, "register_MOM_generic_tracer called with an "// &
124  "associated control structure.")
125  return
126  endif
127  allocate(cs)
128 
129 
130  !Register all the generic tracers used and create the list of them.
131  !This can be called by ALL PE's. No array fields allocated.
132  if (.not. g_registered) then
133  call generic_tracer_register()
134  g_registered = .true.
135  endif
136 
137 
138  ! Read all relevant parameters and write them to the model log.
139  call log_version(param_file, sub_name, version, "")
140  call get_param(param_file, sub_name, "GENERIC_TRACER_IC_FILE", cs%IC_file, &
141  "The file in which the generic trcer initial values can "//&
142  "be found, or an empty string for internal initialization.", &
143  default=" ")
144  if ((len_trim(cs%IC_file) > 0) .and. (scan(cs%IC_file,'/') == 0)) then
145  ! Add the directory if CS%IC_file is not already a complete path.
146  call get_param(param_file, sub_name, "INPUTDIR", inputdir, default=".")
147  cs%IC_file = trim(slasher(inputdir))//trim(cs%IC_file)
148  call log_param(param_file, sub_name, "INPUTDIR/GENERIC_TRACER_IC_FILE", cs%IC_file)
149  endif
150  call get_param(param_file, sub_name, "GENERIC_TRACER_IC_FILE_IS_Z", cs%Z_IC_file, &
151  "If true, GENERIC_TRACER_IC_FILE is in depth space, not "//&
152  "layer space.",default=.false.)
153  call get_param(param_file, sub_name, "TRACERS_MAY_REINIT", cs%tracers_may_reinit, &
154  "If true, tracers may go through the initialization code "//&
155  "if they are not found in the restart files. Otherwise "//&
156  "it is a fatal error if tracers are not found in the "//&
157  "restart files of a restarted run.", default=.false.)
158 
159  cs%restart_CSp => restart_cs
160 
161 
162  ntau=1 ! MOM needs the fields at only one time step
163 
164 
165  ! At this point G%mask2dT and CS%diag%axesTL are not allocated.
166  ! postpone diag_registeration to initialize_MOM_generic_tracer
167 
168  !Fields cannot be diag registered as they are allocated and have to registered later.
169  grid_tmask(:,:,:) = 0.0
170  grid_kmt(:,:) = 0.0
171  axes(:) = -1
172 
173  !
174  ! Initialize all generic tracers
175  !
176  call generic_tracer_init(hi%isc,hi%iec,hi%jsc,hi%jec,hi%isd,hi%ied,hi%jsd,hi%jed,&
177  gv%ke,ntau,axes,grid_tmask,grid_kmt,set_time(0,0))
178 
179 
180  !
181  ! MOM-register the generic tracers
182  !
183 
184  !Get the tracer list
185  call generic_tracer_get_list(cs%g_tracer_list)
186  if (.NOT. associated(cs%g_tracer_list)) call mom_error(fatal, trim(sub_name)//&
187  ": No tracer in the list.")
188  ! For each tracer name get its T_prog index and get its fields
189 
190  g_tracer=>cs%g_tracer_list
191  do
192  call g_tracer_get_alias(g_tracer,g_tracer_name)
193 
194  call g_tracer_get_pointer(g_tracer,g_tracer_name,'field',tr_field)
195  call g_tracer_get_values(g_tracer,g_tracer_name,'longname', longname)
196  call g_tracer_get_values(g_tracer,g_tracer_name,'units',units )
197 
198  !!nnz: MOM field is 3D. Does this affect performance? Need it be override field?
199  tr_ptr => tr_field(:,:,:,1)
200  ! Register prognastic tracer for horizontal advection, diffusion, and restarts.
201  if (g_tracer_is_prog(g_tracer)) then
202  call register_tracer(tr_ptr, tr_reg, param_file, hi, gv, &
203  name=g_tracer_name, longname=longname, units=units, &
204  registry_diags=.false., & !### CHANGE TO TRUE?
205  restart_cs=restart_cs, mandatory=.not.cs%tracers_may_reinit)
206  else
207  call register_restart_field(tr_ptr, g_tracer_name, .not.cs%tracers_may_reinit, &
208  restart_cs, longname=longname, units=units)
209  endif
210 
211  !traverse the linked list till hit NULL
212  call g_tracer_get_next(g_tracer, g_tracer_next)
213  if (.NOT. associated(g_tracer_next)) exit
214  g_tracer=>g_tracer_next
215 
216  enddo
217 
218  register_mom_generic_tracer = .true.
219  end function register_mom_generic_tracer
220 
221  !> Initialize phase II: Initialize required variables for generic tracers
222  !! There are some steps of initialization that cannot be done in register_MOM_generic_tracer
223  !! This is the place and time to do them:
224  !! Set the grid mask and initial time for all generic tracers.
225  !! Diag_register them.
226  !! Z_diag_register them.
227  !!
228  !! This subroutine initializes the NTR tracer fields in tr(:,:,:,:)
229  !! and it sets up the tracer output.
230  subroutine initialize_mom_generic_tracer(restart, day, G, GV, US, h, param_file, diag, OBC, CS, &
231  sponge_CSp, ALE_sponge_CSp)
232  logical, intent(in) :: restart !< .true. if the fields have already been
233  !! read from a restart file.
234  type(time_type), target, intent(in) :: day !< Time of the start of the run.
235  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure
236  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
237  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
238  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
239  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
240  type(diag_ctrl), target, intent(in) :: diag !< Regulates diagnostic output.
241  type(ocean_obc_type), pointer :: obc !< This open boundary condition type specifies whether,
242  !! where, and what open boundary conditions are used.
243  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
244  type(sponge_cs), pointer :: sponge_csp !< Pointer to the control structure for the sponges.
245  type(ale_sponge_cs), pointer :: ale_sponge_csp !< Pointer to the control structure for the
246  !! ALE sponges.
247 
248  character(len=128), parameter :: sub_name = 'initialize_MOM_generic_tracer'
249  logical :: ok
250  integer :: i, j, k, isc, iec, jsc, jec, nk
251  type(g_tracer_type), pointer :: g_tracer,g_tracer_next
252  character(len=fm_string_len) :: g_tracer_name
253  real, dimension(:,:,:,:), pointer :: tr_field
254  real, dimension(:,:,:), pointer :: tr_ptr
255  real, dimension(G%isd:G%ied, G%jsd:G%jed,1:G%ke) :: grid_tmask
256  integer, dimension(G%isd:G%ied, G%jsd:G%jed) :: grid_kmt
257 
258  !! 2010/02/04 Add code to re-initialize Generic Tracers if needed during a model simulation
259  !! By default, restart cpio should not contain a Generic Tracer IC file and step below will be skipped.
260  !! Ideally, the generic tracer IC file should have the tracers on Z levels.
261 
262  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec ; nk = g%ke
263 
264  cs%diag=>diag
265  !Get the tracer list
266  if (.NOT. associated(cs%g_tracer_list)) call mom_error(fatal, trim(sub_name)//&
267  ": No tracer in the list.")
268  !For each tracer name get its fields
269  g_tracer=>cs%g_tracer_list
270 
271  do
272  if (index(cs%IC_file, '_NULL_') /= 0) then
273  call mom_error(warning, "The name of the IC_file "//trim(cs%IC_file)//&
274  " indicates no MOM initialization was asked for the generic tracers."//&
275  "Bypassing the MOM initialization of ALL generic tracers!")
276  exit
277  endif
278  call g_tracer_get_alias(g_tracer,g_tracer_name)
279  call g_tracer_get_pointer(g_tracer,g_tracer_name,'field',tr_field)
280  tr_ptr => tr_field(:,:,:,1)
281 
282  if (.not.restart .or. (cs%tracers_may_reinit .and. &
283  .not.query_initialized(tr_ptr, g_tracer_name, cs%restart_CSp))) then
284 
285  if (g_tracer%requires_src_info ) then
286  call mom_error(note,"initialize_MOM_generic_tracer: "//&
287  "initializing generic tracer "//trim(g_tracer_name)//&
288  " using MOM_initialize_tracer_from_Z ")
289 
290  call mom_initialize_tracer_from_z(h, tr_ptr, g, gv, us, param_file, &
291  src_file = g_tracer%src_file, &
292  src_var_nam = g_tracer%src_var_name, &
293  src_var_unit_conversion = g_tracer%src_var_unit_conversion,&
294  src_var_record = g_tracer%src_var_record, &
295  src_var_gridspec = g_tracer%src_var_gridspec )
296 
297  !Check/apply the bounds for each g_tracer
298  do k=1,nk ; do j=jsc,jec ; do i=isc,iec
299  if (tr_ptr(i,j,k) /= cs%tracer_land_val) then
300  if (tr_ptr(i,j,k) < g_tracer%src_var_valid_min) tr_ptr(i,j,k) = g_tracer%src_var_valid_min
301  !Jasmin does not want to apply the maximum for now
302  !if (tr_ptr(i,j,k) > g_tracer%src_var_valid_max) tr_ptr(i,j,k) = g_tracer%src_var_valid_max
303  endif
304  enddo ; enddo ; enddo
305 
306  !jgj: Reset CASED to 0 below K=1
307  if ( (trim(g_tracer_name) == 'cased') .or. (trim(g_tracer_name) == 'ca13csed') ) then
308  do k=2,nk ; do j=jsc,jec ; do i=isc,iec
309  if (tr_ptr(i,j,k) /= cs%tracer_land_val) then
310  tr_ptr(i,j,k) = 0.0
311  endif
312  enddo ; enddo ; enddo
313  endif
314  elseif(.not. g_tracer%requires_restart) then
315  !Do nothing for this tracer, it is initialized by the tracer package
316  call mom_error(note,"initialize_MOM_generic_tracer: "//&
317  "skip initialization of generic tracer "//trim(g_tracer_name))
318  else !Do it old way if the tracer is not registered to start from a specific source file.
319  !This path should be deprecated if all generic tracers are required to start from specified sources.
320  if (len_trim(cs%IC_file) > 0) then
321  ! Read the tracer concentrations from a netcdf file.
322  if (.not.file_exists(cs%IC_file)) call mom_error(fatal, &
323  "initialize_MOM_Generic_tracer: Unable to open "//cs%IC_file)
324  if (cs%Z_IC_file) then
325  ok = tracer_z_init(tr_ptr, h, cs%IC_file, g_tracer_name, g, us)
326  if (.not.ok) then
327  ok = tracer_z_init(tr_ptr, h, cs%IC_file, trim(g_tracer_name), g, us)
328  if (.not.ok) call mom_error(fatal,"initialize_MOM_Generic_tracer: "//&
329  "Unable to read "//trim(g_tracer_name)//" from "//&
330  trim(cs%IC_file)//".")
331  endif
332  call mom_error(note,"initialize_MOM_generic_tracer: "//&
333  "initialized generic tracer "//trim(g_tracer_name)//&
334  " using Generic Tracer File on Z: "//cs%IC_file)
335  else
336  ! native grid
337  call mom_error(note,"initialize_MOM_generic_tracer: "//&
338  "Using Generic Tracer IC file on native grid "//trim(cs%IC_file)//&
339  " for tracer "//trim(g_tracer_name))
340  call mom_read_data(cs%IC_file, trim(g_tracer_name), tr_ptr, g%Domain)
341  endif
342  else
343  call mom_error(fatal,"initialize_MOM_generic_tracer: "//&
344  "check Generic Tracer IC filename "//trim(cs%IC_file)//&
345  " for tracer "//trim(g_tracer_name))
346  endif
347 
348  endif
349  endif
350 
351  !traverse the linked list till hit NULL
352  call g_tracer_get_next(g_tracer, g_tracer_next)
353  if (.NOT. associated(g_tracer_next)) exit
354  g_tracer=>g_tracer_next
355  enddo
356  !! end section to re-initialize generic tracers
357 
358 
359  !Now we can reset the grid mask, axes and time to their true values
360  !Note that grid_tmask must be set correctly on the data domain boundary
361  !so that coast mask can be deduced from it.
362  grid_tmask(:,:,:) = 0.0
363  grid_kmt(:,:) = 0
364  do j = g%jsd, g%jed ; do i = g%isd, g%ied
365  if (g%mask2dT(i,j) > 0) then
366  grid_tmask(i,j,:) = 1.0
367  grid_kmt(i,j) = g%ke ! Tell the code that a layer thicker than 1m is the bottom layer.
368  endif
369  enddo ; enddo
370  call g_tracer_set_common(g%isc,g%iec,g%jsc,g%jec,g%isd,g%ied,g%jsd,g%jed,&
371  gv%ke,1,cs%diag%axesTL%handles,grid_tmask,grid_kmt,day)
372 
373  ! Register generic tracer modules diagnostics
374 
375 #ifdef _USE_MOM6_DIAG
376  call g_tracer_set_csdiag(cs%diag)
377 #endif
378  call generic_tracer_register_diag()
379 #ifdef _USE_MOM6_DIAG
380  call g_tracer_set_csdiag(cs%diag)
381 #endif
382 
383  cs%H_to_m = gv%H_to_m
384 
385  end subroutine initialize_mom_generic_tracer
386 
387  !> Column physics for generic tracers.
388  !! Get the coupler values for generic tracers that exchange with atmosphere
389  !! Update generic tracer concentration fields from sources and sinks.
390  !! Vertically diffuse generic tracer concentration fields.
391  !! Update generic tracers from bottom and their bottom reservoir.
392  !!
393  !! This subroutine applies diapycnal diffusion and any other column
394  !! tracer physics or chemistry to the tracers from this file.
395  !! CFCs are relatively simple, as they are passive tracers. with only a surface
396  !! flux as a source.
397  subroutine mom_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml, dt, G, GV, CS, tv, optics, &
398  evap_CFL_limit, minimum_forcing_depth)
399  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
400  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
401  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
402  intent(in) :: h_old !< Layer thickness before entrainment [H ~> m or kg m-2].
403  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
404  intent(in) :: h_new !< Layer thickness after entrainment [H ~> m or kg m-2].
405  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
406  intent(in) :: ea !< The amount of fluid entrained from the layer
407  !! above during this call [H ~> m or kg m-2].
408  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
409  intent(in) :: eb !< The amount of fluid entrained from the layer
410  !! below during this call [H ~> m or kg m-2].
411  type(forcing), intent(in) :: fluxes !< A structure containing pointers to thermodynamic
412  !! and tracer forcing fields.
413  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: hml !< Mixed layer depth [Z ~> m]
414  real, intent(in) :: dt !< The amount of time covered by this call [s]
415  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
416  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various thermodynamic variables
417  type(optics_type), intent(in) :: optics !< The structure containing optical properties.
418  real, optional, intent(in) :: evap_cfl_limit !< Limits how much water can be fluxed out of
419  !! the top layer Stored previously in diabatic CS.
420  real, optional, intent(in) :: minimum_forcing_depth !< The smallest depth over which fluxes
421  !! can be applied [H ~> m or kg m-2]
422  ! Stored previously in diabatic CS.
423  ! The arguments to this subroutine are redundant in that
424  ! h_new(k) = h_old(k) + ea(k) - eb(k-1) + eb(k) - ea(k+1)
425 
426  ! Local variables
427  character(len=128), parameter :: sub_name = 'MOM_generic_tracer_column_physics'
428 
429  type(g_tracer_type), pointer :: g_tracer, g_tracer_next
430  character(len=fm_string_len) :: g_tracer_name
431  real, dimension(:,:), pointer :: stf_array,trunoff_array,runoff_tracer_flux_array
432 
433  real :: surface_field(szi_(g),szj_(g))
434  real :: dz_ml(szi_(g),szj_(g)) ! The mixed layer depth in the MKS units used for generic tracers [m]
435  real :: sosga
436 
437  real, dimension(G%isd:G%ied,G%jsd:G%jed,G%ke) :: rho_dzt, dzt
438  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_work
439  integer :: i, j, k, isc, iec, jsc, jec, nk
440 
441  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec ; nk = g%ke
442 
443  !Get the tracer list
444  if (.NOT. associated(cs%g_tracer_list)) call mom_error(fatal,&
445  trim(sub_name)//": No tracer in the list.")
446 
447 #ifdef _USE_MOM6_DIAG
448  call g_tracer_set_csdiag(cs%diag)
449 #endif
450 
451  !
452  !Extract the tracer surface fields from coupler and update tracer fields from sources
453  !
454  !call generic_tracer_coupler_get(fluxes%tr_fluxes)
455  !Niki: This is moved out to ocean_model_MOM.F90 because if dt_therm>dt_cpld we need to average
456  ! the fluxes without coming into this subroutine.
457  ! MOM5 has to modified to conform.
458 
459  !
460  !Add contribution of river to surface flux
461  !
462  g_tracer=>cs%g_tracer_list
463  do
464  if (_allocated(g_tracer%trunoff)) then
465  call g_tracer_get_alias(g_tracer,g_tracer_name)
466  call g_tracer_get_pointer(g_tracer,g_tracer_name,'stf', stf_array)
467  call g_tracer_get_pointer(g_tracer,g_tracer_name,'trunoff',trunoff_array)
468  call g_tracer_get_pointer(g_tracer,g_tracer_name,'runoff_tracer_flux',runoff_tracer_flux_array)
469  !nnz: Why is fluxes%river = 0?
470  runoff_tracer_flux_array(:,:) = trunoff_array(:,:) * &
471  g%US%RZ_T_to_kg_m2s*fluxes%lrunoff(:,:)
472  stf_array = stf_array + runoff_tracer_flux_array
473  endif
474 
475  !traverse the linked list till hit NULL
476  call g_tracer_get_next(g_tracer, g_tracer_next)
477  if (.NOT. associated(g_tracer_next)) exit
478  g_tracer=>g_tracer_next
479 
480  enddo
481 
482  !
483  !Prepare input arrays for source update
484  !
485 
486  rho_dzt(:,:,:) = gv%H_to_kg_m2 * gv%Angstrom_H
487  do k = 1, nk ; do j = jsc, jec ; do i = isc, iec !{
488  rho_dzt(i,j,k) = gv%H_to_kg_m2 * h_old(i,j,k)
489  enddo ; enddo ; enddo !}
490 
491  dzt(:,:,:) = 1.0
492  do k = 1, nk ; do j = jsc, jec ; do i = isc, iec !{
493  dzt(i,j,k) = gv%H_to_m * h_old(i,j,k)
494  enddo ; enddo ; enddo !}
495  dz_ml(:,:) = 0.0
496  do j=jsc,jec ; do i=isc,iec
497  surface_field(i,j) = tv%S(i,j,1)
498  dz_ml(i,j) = g%US%Z_to_m * hml(i,j)
499  enddo ; enddo
500  sosga = global_area_mean(surface_field, g)
501 
502  !
503  !Calculate tendencies (i.e., field changes at dt) from the sources / sinks
504  !
505  if ((g%US%L_to_m == 1.0) .and. (g%US%RZ_to_kg_m2 == 1.0) .and. (g%US%s_to_T == 1.0)) then
506  ! Avoid unnecessary copies when no unit conversion is needed.
507  call generic_tracer_source(tv%T, tv%S, rho_dzt, dzt, dz_ml, g%isd, g%jsd, 1, dt, &
508  g%areaT, get_diag_time_end(cs%diag), &
509  optics%nbands, optics%max_wavelength_band, optics%sw_pen_band, optics%opacity_band, &
510  internal_heat=tv%internal_heat, frunoff=fluxes%frunoff, sosga=sosga)
511  else
512  call generic_tracer_source(tv%T, tv%S, rho_dzt, dzt, dz_ml, g%isd, g%jsd, 1, dt, &
513  g%US%L_to_m**2*g%areaT(:,:), get_diag_time_end(cs%diag), &
514  optics%nbands, optics%max_wavelength_band, optics%sw_pen_band, optics%opacity_band, &
515  internal_heat=g%US%RZ_to_kg_m2*tv%internal_heat(:,:), &
516  frunoff=g%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga)
517  endif
518 
519  ! This uses applyTracerBoundaryFluxesInOut to handle the change in tracer due to freshwater fluxes
520  ! usually in ALE mode
521  if (present(evap_cfl_limit) .and. present(minimum_forcing_depth)) then
522  g_tracer=>cs%g_tracer_list
523  do
524  if (g_tracer_is_prog(g_tracer)) then
525  do k=1,nk ;do j=jsc,jec ; do i=isc,iec
526  h_work(i,j,k) = h_old(i,j,k)
527  enddo ; enddo ; enddo
528  call applytracerboundaryfluxesinout(g, gv, g_tracer%field(:,:,:,1), g%US%s_to_T*dt, &
529  fluxes, h_work, evap_cfl_limit, minimum_forcing_depth)
530  endif
531 
532  !traverse the linked list till hit NULL
533  call g_tracer_get_next(g_tracer, g_tracer_next)
534  if (.NOT. associated(g_tracer_next)) exit
535  g_tracer=>g_tracer_next
536  enddo
537  endif
538 
539  !
540  !Update Tr(n)%field from explicit vertical diffusion
541  !
542  ! Use a tridiagonal solver to determine the concentrations after the
543  ! surface source is applied and diapycnal advection and diffusion occurs.
544  if (present(evap_cfl_limit) .and. present(minimum_forcing_depth)) then
545  ! Last arg is tau which is always 1 for MOM6
546  call generic_tracer_vertdiff_g(h_work, ea, eb, dt, gv%kg_m2_to_H, gv%m_to_H, 1)
547  else
548  ! Last arg is tau which is always 1 for MOM6
549  call generic_tracer_vertdiff_g(h_old, ea, eb, dt, gv%kg_m2_to_H, gv%m_to_H, 1)
550  endif
551 
552  ! Update bottom fields after vertical processes
553 
554  ! Second arg is tau which is always 1 for MOM6
555  call generic_tracer_update_from_bottom(dt, 1, get_diag_time_end(cs%diag))
556 
557  !Output diagnostics via diag_manager for all generic tracers and their fluxes
558  call g_tracer_send_diag(cs%g_tracer_list, get_diag_time_end(cs%diag), tau=1)
559 #ifdef _USE_MOM6_DIAG
560  call g_tracer_set_csdiag(cs%diag)
561 #endif
562 
563  end subroutine mom_generic_tracer_column_physics
564 
565  !> This subroutine calculates mass-weighted integral on the PE either
566  !! of all available tracer concentrations, or of a tracer that is
567  !! being requested specifically, returning the number of stocks it has
568  !! calculated. If the stock_index is present, only the stock corresponding
569  !! to that coded index is returned.
570  function mom_generic_tracer_stock(h, stocks, G, GV, CS, names, units, stock_index)
571  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
572  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
573  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
574  real, dimension(:), intent(out) :: stocks !< The mass-weighted integrated amount of each
575  !! tracer, in kg times concentration units [kg conc].
576  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
577  character(len=*), dimension(:), intent(out) :: names !< The names of the stocks calculated.
578  character(len=*), dimension(:), intent(out) :: units !< The units of the stocks calculated.
579  integer, optional, intent(in) :: stock_index !< The coded index of a specific stock
580  !! being sought.
581  integer :: mom_generic_tracer_stock !< Return value, the
582  !! number of stocks calculated here.
583 
584 ! Local variables
585  type(g_tracer_type), pointer :: g_tracer, g_tracer_next
586  real, dimension(:,:,:,:), pointer :: tr_field
587  real, dimension(:,:,:), pointer :: tr_ptr
588  character(len=128), parameter :: sub_name = 'MOM_generic_tracer_stock'
589 
590  integer :: i, j, k, is, ie, js, je, nz, m
591  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
592 
593  mom_generic_tracer_stock = 0
594  if (.not.associated(cs)) return
595 
596  if (present(stock_index)) then ; if (stock_index > 0) then
597  ! Check whether this stock is available from this routine.
598 
599  ! No stocks from this routine are being checked yet. Return 0.
600  return
601  endif ; endif
602 
603  if (.NOT. associated(cs%g_tracer_list)) return ! No stocks.
604 
605  m=1 ; g_tracer=>cs%g_tracer_list
606  do
607  call g_tracer_get_alias(g_tracer,names(m))
608  call g_tracer_get_values(g_tracer,names(m),'units',units(m))
609  units(m) = trim(units(m))//" kg"
610  call g_tracer_get_pointer(g_tracer,names(m),'field',tr_field)
611 
612  stocks(m) = 0.0
613  tr_ptr => tr_field(:,:,:,1)
614  do k=1,nz ; do j=js,je ; do i=is,ie
615  stocks(m) = stocks(m) + tr_ptr(i,j,k) * &
616  (g%mask2dT(i,j) * g%US%L_to_m**2*g%areaT(i,j) * h(i,j,k))
617  enddo ; enddo ; enddo
618  stocks(m) = gv%H_to_kg_m2 * stocks(m)
619 
620  !traverse the linked list till hit NULL
621  call g_tracer_get_next(g_tracer, g_tracer_next)
622  if (.NOT. associated(g_tracer_next)) exit
623  g_tracer=>g_tracer_next
624  m = m+1
625  enddo
626 
627  mom_generic_tracer_stock = m
628 
629  end function mom_generic_tracer_stock
630 
631  !> This subroutine find the global min and max of either of all
632  !! available tracer concentrations, or of a tracer that is being
633  !! requested specifically, returning the number of tracers it has gone through.
634  function mom_generic_tracer_min_max(ind_start, got_minmax, gmin, gmax, xgmin, ygmin, zgmin, &
635  xgmax, ygmax, zgmax , G, CS, names, units)
636  use mpp_utilities_mod, only: mpp_array_global_min_max
637  integer, intent(in) :: ind_start !< The index of the tracer to start with
638  logical, dimension(:), intent(out) :: got_minmax !< Indicates whether the global min and
639  !! max are found for each tracer
640  real, dimension(:), intent(out) :: gmin !< Global minimum of each tracer, in kg
641  !! times concentration units.
642  real, dimension(:), intent(out) :: gmax !< Global maximum of each tracer, in kg
643  !! times concentration units.
644  real, dimension(:), intent(out) :: xgmin !< The x-position of the global minimum
645  real, dimension(:), intent(out) :: ygmin !< The y-position of the global minimum
646  real, dimension(:), intent(out) :: zgmin !< The z-position of the global minimum
647  real, dimension(:), intent(out) :: xgmax !< The x-position of the global maximum
648  real, dimension(:), intent(out) :: ygmax !< The y-position of the global maximum
649  real, dimension(:), intent(out) :: zgmax !< The z-position of the global maximum
650  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
651  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
652  character(len=*), dimension(:), intent(out) :: names !< The names of the stocks calculated.
653  character(len=*), dimension(:), intent(out) :: units !< The units of the stocks calculated.
654  integer :: mom_generic_tracer_min_max !< Return value, the
655  !! number of tracers done here.
656 
657 ! Local variables
658  type(g_tracer_type), pointer :: g_tracer, g_tracer_next
659  real, dimension(:,:,:,:), pointer :: tr_field
660  real, dimension(:,:,:), pointer :: tr_ptr
661  character(len=128), parameter :: sub_name = 'MOM_generic_tracer_min_max'
662 
663  real, dimension(:,:,:),pointer :: grid_tmask
664  integer :: isc,iec,jsc,jec,isd,ied,jsd,jed,nk,ntau
665 
666  integer :: i, j, k, is, ie, js, je, nz, m
667  real, allocatable, dimension(:) :: geo_z
668 
669  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
670 
671  mom_generic_tracer_min_max = 0
672  if (.not.associated(cs)) return
673 
674  if (.NOT. associated(cs%g_tracer_list)) return ! No stocks.
675 
676 
677  call g_tracer_get_common(isc,iec,jsc,jec,isd,ied,jsd,jed,nk,ntau,grid_tmask=grid_tmask)
678 
679  ! Because the use of a simple z-coordinate can not be assumed, simply
680  ! use the layer index as the vertical label.
681  allocate(geo_z(nk))
682  do k=1,nk ; geo_z(k) = real(k) ; enddo
683 
684  m=ind_start ; g_tracer=>cs%g_tracer_list
685  do
686  call g_tracer_get_alias(g_tracer,names(m))
687  call g_tracer_get_values(g_tracer,names(m),'units',units(m))
688  units(m) = trim(units(m))//" kg"
689  call g_tracer_get_pointer(g_tracer,names(m),'field',tr_field)
690 
691  gmin(m) = -1.0
692  gmax(m) = -1.0
693 
694  tr_ptr => tr_field(:,:,:,1)
695 
696  call mpp_array_global_min_max(tr_ptr, grid_tmask,isd,jsd,isc,iec,jsc,jec,nk , gmin(m), gmax(m), &
697  g%geoLonT,g%geoLatT,geo_z,xgmin(m), ygmin(m), zgmin(m), &
698  xgmax(m), ygmax(m), zgmax(m))
699 
700  got_minmax(m) = .true.
701 
702  !traverse the linked list till hit NULL
703  call g_tracer_get_next(g_tracer, g_tracer_next)
704  if (.NOT. associated(g_tracer_next)) exit
705  g_tracer=>g_tracer_next
706  m = m+1
707  enddo
708 
709  mom_generic_tracer_min_max = m
710 
711  end function mom_generic_tracer_min_max
712 
713 
714  !> This subroutine calculates the surface state and sets coupler values for
715  !! those generic tracers that have flux exchange with atmosphere.
716  !!
717  !! This subroutine sets up the fields that the coupler needs to calculate the
718  !! CFC fluxes between the ocean and atmosphere.
719  subroutine mom_generic_tracer_surface_state(sfc_state, h, G, CS)
720  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
721  type(surface), intent(inout) :: sfc_state !< A structure containing fields that
722  !! describe the surface state of the ocean.
723  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
724  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
725 
726 ! Local variables
727  real :: sosga
728 
729  character(len=128), parameter :: sub_name = 'MOM_generic_tracer_surface_state'
730  real, dimension(G%isd:G%ied,G%jsd:G%jed,1:G%ke,1) :: rho0
731  real, dimension(G%isd:G%ied,G%jsd:G%jed,1:G%ke) :: dzt
732  type(g_tracer_type), pointer :: g_tracer
733 
734  !Set coupler values
735  !nnz: fake rho0
736  rho0=1.0
737 
738  dzt(:,:,:) = cs%H_to_m * h(:,:,:)
739 
740  sosga = global_area_mean(sfc_state%SSS, g)
741 
742  call generic_tracer_coupler_set(sfc_state%tr_fields,&
743  st=sfc_state%SST,&
744  ss=sfc_state%SSS,&
745  rho=rho0,& !nnz: required for MOM5 and previous versions.
746  ilb=g%isd, jlb=g%jsd,&
747  dzt=dzt,& !This is needed for the Mocsy method of carbonate system vars
748  tau=1,sosga=sosga,model_time=get_diag_time_end(cs%diag))
749 
750  !Output diagnostics via diag_manager for all tracers in this module
751 ! if (.NOT. associated(CS%g_tracer_list)) call MOM_error(FATAL, trim(sub_name)//&
752 ! "No tracer in the list.")
753 ! call g_tracer_send_diag(CS%g_tracer_list, get_diag_time_end(CS%diag), tau=1)
754  !Niki: The problem with calling diagnostic outputs here is that this subroutine is called every dt_cpld
755  ! hence if dt_therm > dt_cpld we get output (and contribution to the mean) at times that tracers
756  ! had not been updated.
757  ! Moving this to the end of column physics subrotuine fixes this issue.
758 
759  end subroutine mom_generic_tracer_surface_state
760 
761 !ALL PE subroutine on Ocean! Due to otpm design the fluxes should be initialized like this on ALL PE's!
762  subroutine mom_generic_flux_init(verbosity)
763  integer, optional, intent(in) :: verbosity !< A 0-9 integer indicating a level of verbosity.
764 
765  integer :: ind
766  character(len=fm_string_len) :: g_tracer_name,longname, package,units,old_package,file_in,file_out
767  real :: const_init_value
768  character(len=128), parameter :: sub_name = 'MOM_generic_flux_init'
769  type(g_tracer_type), pointer :: g_tracer_list,g_tracer,g_tracer_next
770 
771  if (.not. g_registered) then
772  call generic_tracer_register()
773  g_registered = .true.
774  endif
775 
776  call generic_tracer_get_list(g_tracer_list)
777  if (.NOT. associated(g_tracer_list)) then
778  call mom_error(warning, trim(sub_name)// ": No generic tracer in the list.")
779  return
780  endif
781 
782  g_tracer=>g_tracer_list
783  do
784 
785  call g_tracer_flux_init(g_tracer) !, verbosity=verbosity) !### Add this after ocean shared is updated.
786 
787  ! traverse the linked list till hit NULL
788  call g_tracer_get_next(g_tracer, g_tracer_next)
789  if (.NOT. associated(g_tracer_next)) exit
790  g_tracer=>g_tracer_next
791 
792  enddo
793 
794  end subroutine mom_generic_flux_init
795 
796  subroutine mom_generic_tracer_fluxes_accumulate(flux_tmp, weight)
797  type(forcing), intent(in) :: flux_tmp !< A structure containing pointers to
798  !! thermodynamic and tracer forcing fields.
799  real, intent(in) :: weight !< A weight for accumulating this flux
800 
801  call generic_tracer_coupler_accumulate(flux_tmp%tr_fluxes, weight)
802 
803  end subroutine mom_generic_tracer_fluxes_accumulate
804 
805  !> Copy the requested tracer into an array.
806  subroutine mom_generic_tracer_get(name,member,array, CS)
807  character(len=*), intent(in) :: name !< Name of requested tracer.
808  character(len=*), intent(in) :: member !< The tracer element to return.
809  real, dimension(:,:,:), intent(out) :: array !< Array filled by this routine.
810  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
811 
812  real, dimension(:,:,:), pointer :: array_ptr
813  character(len=128), parameter :: sub_name = 'MOM_generic_tracer_get'
814 
815  call g_tracer_get_pointer(cs%g_tracer_list,name,member,array_ptr)
816  array(:,:,:) = array_ptr(:,:,:)
817 
818  end subroutine mom_generic_tracer_get
819 
820  !> This subroutine deallocates the memory owned by this module.
821  subroutine end_mom_generic_tracer(CS)
822  type(mom_generic_tracer_cs), pointer :: cs !< Pointer to the control structure for this module.
823 
824  call generic_tracer_end()
825 
826  if (associated(cs)) then
827  deallocate(cs)
828  endif
829  end subroutine end_mom_generic_tracer
830 
831 !----------------------------------------------------------------
832 ! <CONTACT EMAIL="Niki.Zadeh@noaa.gov"> Niki Zadeh
833 ! </CONTACT>
834 !
835 ! <REVIEWER EMAIL="William.Cooke@noaa.gov"> William Cooke
836 ! </REVIEWER>
837 !
838 ! <OVERVIEW>
839 ! This module drives the generic version of tracers TOPAZ and CFC
840 ! </OVERVIEW>
841 !----------------------------------------------------------------
842 
843 end module mom_generic_tracer
Pointers to various fields which may be used describe the surface state of MOM, and which will be ret...
Functions and routines to take area, volume, mass-weighted, layerwise, zonal or meridional means.
Wraps the FMS time manager functions.
This module implements boundary forcing for MOM6.
Used to initialize tracers from a depth- (or z*-) space file.
Reverse of interface g_tracer_set_values for getting the tracer member arrays in the argument value.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Register fields for restarts.
Store the reference profile at h points for a variable.
This module contains I/O framework code.
Definition: MOM_io.F90:2
The MOM6 facility to parse input files for runtime parameters.
Defines the horizontal index type (hor_index_type) used for providing index ranges.
This module contains the routines used to apply sponge layers when using the ALE mode.
An overloaded interface to log the values of various types of parameters.
ALE sponge control structure.
Container for horizontal index ranges for data, computational and global domains.
Set the values of various (array) members of the tracer node g_tracer_type.
g_tracer_utils module consists of core utility subroutines to be used by all generic tracer modules....
Make a diagnostic available for averaging or output.
A restart registry and the control structure for restarts.
Definition: MOM_restart.F90:75
Describes various unit conversion factors.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
Drives the generic version of tracers TOPAZ and CFC and other GFDL BGC components.
A non-functioning template of the GFDL ocean BGC.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Each generic tracer node is an instant of a FORTRAN type with the following member variables....
Type to carry basic tracer information.
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Routines for error handling and I/O management.
This module contains routines that implement physical fluxes of tracers (e.g. due to surface fluxes o...
This control structure holds memory and parameters for the MOM_sponge module.
Definition: MOM_sponge.F90:41
The MOM6 facility for reading and writing restart files, and querying what has been read.
Definition: MOM_restart.F90:2
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Implements sponge regions in isopycnal mode.
Definition: MOM_sponge.F90:2
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Indicate whether a field has been read from a restart file.
Controls where open boundary conditions are applied.
Provides a transparent vertical ocean grid type and supporting routines.
Control structure for generic tracers.
Provides transparent structures with groups of MOM6 variables and supporting routines.
Initializes hydrography from z-coordinate climatology files.
Read a data field from a file.
Definition: MOM_io.F90:74
Return the pointer to the requested field of a particular tracer.
An overloaded interface to read and log the values of various types of parameters.