portedportable, not yet portedexecuted, not portableexecutable, not hit by this run
| 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 | !> This module contains subroutines that handle registration of tracers | |
| 6 | !! and related subroutines. The primary subroutine, register_tracer, is | |
| 7 | !! called to indicate the tracers advected and diffused. | |
| 8 | !! It also makes public the types defined in MOM_tracer_types. | |
| 9 | module MOM_tracer_registry | |
| 10 | ||
| 11 | ! use MOM_diag_mediator, only : diag_ctrl | |
| 12 | use MOM_coms, only : reproducing_sum | |
| 13 | use MOM_debugging, only : hchksum | |
| 14 | use MOM_diag_mediator, only : diag_ctrl, register_diag_field, post_data, safe_alloc_ptr | |
| 15 | use MOM_diag_mediator, only : diag_grid_storage | |
| 16 | use MOM_diag_mediator, only : diag_copy_storage_to_diag, diag_save_grids, diag_restore_grids | |
| 17 | use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg, is_root_pe | |
| 18 | use MOM_file_parser, only : get_param, log_version, param_file_type | |
| 19 | use MOM_hor_index, only : hor_index_type | |
| 20 | use MOM_grid, only : ocean_grid_type | |
| 21 | use MOM_io, only : vardesc, query_vardesc, cmor_long_std | |
| 22 | use MOM_restart, only : register_restart_field, MOM_restart_CS | |
| 23 | use MOM_string_functions, only : lowercase | |
| 24 | use MOM_time_manager, only : time_type | |
| 25 | use MOM_unit_scaling, only : unit_scale_type | |
| 26 | use MOM_verticalGrid, only : verticalGrid_type | |
| 27 | use MOM_tracer_types, only : tracer_type, tracer_registry_type | |
| 28 | ||
| 29 | implicit none ; private | |
| 30 | ||
| 31 | #include <MOM_memory.h> | |
| 32 | ||
| 33 | public register_tracer | |
| 34 | public MOM_tracer_chksum, MOM_tracer_chkinv | |
| 35 | public register_tracer_diagnostics | |
| 36 | public post_tracer_diagnostics_at_sync, post_tracer_transport_diagnostics | |
| 37 | public preALE_tracer_diagnostics, postALE_tracer_diagnostics | |
| 38 | public tracer_registry_init, lock_tracer_registry, tracer_registry_end | |
| 39 | public tracer_name_lookup | |
| 40 | public tracer_type, tracer_registry_type | |
| 41 | ||
| 42 | !> Write out checksums for registered tracers | |
| 43 | interface MOM_tracer_chksum | |
| 44 | module procedure tracer_array_chksum, tracer_Reg_chksum | |
| 45 | end interface MOM_tracer_chksum | |
| 46 | ||
| 47 | !> Calculate and print the global inventories of registered tracers | |
| 48 | interface MOM_tracer_chkinv | |
| 49 | module procedure tracer_array_chkinv, tracer_Reg_chkinv | |
| 50 | end interface MOM_tracer_chkinv | |
| 51 | ||
| 52 | contains | |
| 53 | ||
| 54 | !> This subroutine registers a tracer to be advected and laterally diffused. | |
| 55 | 3 | subroutine register_tracer(tr_ptr, Reg, param_file, HI, GV, name, longname, units, & |
| 56 | cmor_name, cmor_units, cmor_longname, net_surfflux_name, & | |
| 57 | NLT_budget_name, net_surfflux_longname, tr_desc, OBC_inflow, & | |
| 58 | OBC_in_u, OBC_in_v, ad_x, ad_y, df_x, df_y, ad_2d_x, ad_2d_y, & | |
| 59 | df_2d_x, df_2d_y, advection_xy, registry_diags, & | |
| 60 | conc_scale, flux_nameroot, flux_longname, flux_units, flux_scale, & | |
| 61 | convergence_units, convergence_scale, cmor_tendprefix, diag_form, & | |
| 62 | restart_CS, mandatory, underflow_conc, Tr_out, advect_scheme) | |
| 63 | type(hor_index_type), intent(in) :: HI !< horizontal index type | |
| 64 | type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure | |
| 65 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 66 | real, dimension(SZI_(HI),SZJ_(HI),SZK_(GV)), & | |
| 67 | target :: tr_ptr !< target or pointer to the tracer array [CU ~> conc] | |
| 68 | type(param_file_type), intent(in) :: param_file !< file to parse for model parameter values | |
| 69 | character(len=*), optional, intent(in) :: name !< Short tracer name | |
| 70 | character(len=*), optional, intent(in) :: longname !< The long tracer name | |
| 71 | character(len=*), optional, intent(in) :: units !< The units of this tracer | |
| 72 | character(len=*), optional, intent(in) :: cmor_name !< CMOR name | |
| 73 | character(len=*), optional, intent(in) :: cmor_units !< CMOR physical dimensions of variable | |
| 74 | character(len=*), optional, intent(in) :: cmor_longname !< CMOR long name | |
| 75 | character(len=*), optional, intent(in) :: net_surfflux_name !< Name for net_surfflux diag | |
| 76 | character(len=*), optional, intent(in) :: NLT_budget_name !< Name for NLT_budget diag | |
| 77 | character(len=*), optional, intent(in) :: net_surfflux_longname !< Long name for net_surfflux diag | |
| 78 | type(vardesc), optional, intent(in) :: tr_desc !< A structure with metadata about the tracer | |
| 79 | ||
| 80 | real, optional, intent(in) :: OBC_inflow !< the tracer for all inflows via OBC for which OBC_in_u | |
| 81 | !! or OBC_in_v are not specified [CU ~> conc] | |
| 82 | real, dimension(:,:,:), optional, pointer :: OBC_in_u !< tracer at inflows through u-faces of | |
| 83 | !! tracer cells [CU ~> conc] | |
| 84 | real, dimension(:,:,:), optional, pointer :: OBC_in_v !< tracer at inflows through v-faces of | |
| 85 | !! tracer cells [CU ~> conc] | |
| 86 | ||
| 87 | ! The following are probably not necessary if registry_diags is present and true. | |
| 88 | real, dimension(:,:,:), optional, pointer :: ad_x !< diagnostic x-advective flux | |
| 89 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 90 | real, dimension(:,:,:), optional, pointer :: ad_y !< diagnostic y-advective flux | |
| 91 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 92 | real, dimension(:,:,:), optional, pointer :: df_x !< diagnostic x-diffusive flux | |
| 93 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 94 | real, dimension(:,:,:), optional, pointer :: df_y !< diagnostic y-diffusive flux | |
| 95 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 96 | real, dimension(:,:), optional, pointer :: ad_2d_x !< vert sum of diagnostic x-advect flux | |
| 97 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 98 | real, dimension(:,:), optional, pointer :: ad_2d_y !< vert sum of diagnostic y-advect flux | |
| 99 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 100 | real, dimension(:,:), optional, pointer :: df_2d_x !< vert sum of diagnostic x-diffuse flux | |
| 101 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 102 | real, dimension(:,:), optional, pointer :: df_2d_y !< vert sum of diagnostic y-diffuse flux | |
| 103 | !! [CU H L2 T-1 ~> conc m3 s-1 or conc kg s-1] | |
| 104 | ||
| 105 | real, dimension(:,:,:), optional, pointer :: advection_xy !< convergence of lateral advective tracer fluxes | |
| 106 | !! [CU H T-1 ~> conc m s-1 or conc kg m-2 s-1] | |
| 107 | logical, optional, intent(in) :: registry_diags !< If present and true, use the registry for | |
| 108 | !! the diagnostics of this tracer. | |
| 109 | real, optional, intent(in) :: conc_scale !< A scaling factor used to convert the concentration | |
| 110 | !! of this tracer to its desired units [conc CU-1 ~> 1] | |
| 111 | character(len=*), optional, intent(in) :: flux_nameroot !< Short tracer name snippet used construct the | |
| 112 | !! names of flux diagnostics. | |
| 113 | character(len=*), optional, intent(in) :: flux_longname !< A word or phrase used construct the long | |
| 114 | !! names of flux diagnostics. | |
| 115 | character(len=*), optional, intent(in) :: flux_units !< The units for the fluxes of this tracer. | |
| 116 | real, optional, intent(in) :: flux_scale !< A scaling factor used to convert the fluxes | |
| 117 | !! of this tracer to its desired units | |
| 118 | !! [conc m CU-1 H-1 ~> 1] or [conc kg m-2 CU-1 H-1 ~> 1] | |
| 119 | character(len=*), optional, intent(in) :: convergence_units !< The units for the flux convergence of | |
| 120 | !! this tracer. | |
| 121 | real, optional, intent(in) :: convergence_scale !< A scaling factor used to convert the flux | |
| 122 | !! convergence of this tracer to its desired units. | |
| 123 | !! [conc m CU-1 H-1 ~> 1] or [conc kg m-2 CU-1 H-1 ~> 1] | |
| 124 | character(len=*), optional, intent(in) :: cmor_tendprefix !< The CMOR name for the layer-integrated | |
| 125 | !! tendencies of this tracer. | |
| 126 | integer, optional, intent(in) :: diag_form !< An integer (1 or 2, 1 by default) indicating the | |
| 127 | !! character string template to use in | |
| 128 | !! labeling diagnostics | |
| 129 | type(MOM_restart_CS), optional, intent(inout) :: restart_CS !< MOM restart control struct | |
| 130 | logical, optional, intent(in) :: mandatory !< If true, this tracer must be read | |
| 131 | !! from a restart file. | |
| 132 | real, optional, intent(in) :: underflow_conc !< A tiny concentration, below which the tracer | |
| 133 | !! concentration underflows to 0 [CU ~> conc]. | |
| 134 | type(tracer_type), optional, pointer :: Tr_out !< If present, returns pointer into registry | |
| 135 | ||
| 136 | integer, optional, intent(in) :: advect_scheme !< Advection scheme for this tracer, the default is -1 | |
| 137 | !! indicating to use the scheme from MOM_tracer_advect | |
| 138 | ||
| 139 | logical :: mand | |
| 140 | type(tracer_type), pointer :: Tr=>NULL() | |
| 141 | character(len=256) :: mesg ! Message for error messages. | |
| 142 | ||
| 143 | 0 | if (.not. associated(Reg)) call tracer_registry_init(param_file, Reg) |
| 144 | ||
| 145 | 3 | if (Reg%ntr>=MAX_FIELDS_) then |
| 146 | write(mesg,'("Increase MAX_FIELDS_ in MOM_memory.h to at least ",I0," to allow for & | |
| 147 | 0 | &all the tracers being registered via register_tracer.")') Reg%ntr+1 |
| 148 | 0 | call MOM_error(FATAL,"MOM register_tracer: "//mesg) |
| 149 | endif | |
| 150 | 3 | Reg%ntr = Reg%ntr + 1 |
| 151 | ||
| 152 | 3 | Tr => Reg%Tr(Reg%ntr) |
| 153 | 3 | if (present(Tr_out)) Tr_out => Reg%Tr(Reg%ntr) |
| 154 | ||
| 155 | 3 | if (present(name)) then |
| 156 | 0 | Tr%name = name |
| 157 | 0 | Tr%longname = name ; if (present(longname)) Tr%longname = longname |
| 158 | 0 | Tr%units = "Conc" ; if (present(units)) Tr%units = units |
| 159 | ||
| 160 | 0 | Tr%cmor_name = "" |
| 161 | 0 | if (present(cmor_name)) Tr%cmor_name = cmor_name |
| 162 | ||
| 163 | 0 | Tr%cmor_units = Tr%units |
| 164 | 0 | if (present(cmor_units)) Tr%cmor_units = cmor_units |
| 165 | ||
| 166 | 0 | Tr%cmor_longname = "" |
| 167 | 0 | if (present(cmor_longname)) Tr%cmor_longname = cmor_longname |
| 168 | ||
| 169 | 0 | if (present(tr_desc)) call MOM_error(WARNING, "MOM register_tracer: "//& |
| 170 | 0 | "It is a bad idea to use both name and tr_desc when registring "//trim(name)) |
| 171 | 3 | elseif (present(tr_desc)) then |
| 172 | call query_vardesc(tr_desc, name=Tr%name, units=Tr%units, & | |
| 173 | longname=Tr%longname, cmor_field_name=Tr%cmor_name, & | |
| 174 | 3 | cmor_longname=Tr%cmor_longname, caller="register_tracer") |
| 175 | 3 | Tr%cmor_units = Tr%units |
| 176 | else | |
| 177 | call MOM_error(FATAL,"MOM register_tracer: Either name or "//& | |
| 178 | 0 | "tr_desc must be present when registering a tracer.") |
| 179 | endif | |
| 180 | ||
| 181 | 3 | if (Reg%locked) call MOM_error(FATAL, & |
| 182 | "MOM register_tracer was called for variable "//trim(Tr%name)//& | |
| 183 | 0 | " with a locked tracer registry.") |
| 184 | ||
| 185 | 3 | Tr%conc_scale = 1.0 |
| 186 | 3 | if (present(conc_scale)) Tr%conc_scale = conc_scale |
| 187 | ||
| 188 | 3 | Tr%conc_underflow = 0.0 |
| 189 | 3 | if (present(underflow_conc)) Tr%conc_underflow = underflow_conc |
| 190 | ||
| 191 | 3 | Tr%flux_nameroot = Tr%name |
| 192 | 3 | if (present(flux_nameroot)) then |
| 193 | 2 | if (len_trim(flux_nameroot) > 0) Tr%flux_nameroot = flux_nameroot |
| 194 | endif | |
| 195 | ||
| 196 | 3 | Tr%flux_longname = Tr%longname |
| 197 | 3 | if (present(flux_longname)) then |
| 198 | 2 | if (len_trim(flux_longname) > 0) Tr%flux_longname = flux_longname |
| 199 | endif | |
| 200 | ||
| 201 | 3 | Tr%net_surfflux_name = "KPP_net"//trim(Tr%name) |
| 202 | 3 | if (present(net_surfflux_name)) then |
| 203 | 2 | Tr%net_surfflux_name = net_surfflux_name |
| 204 | endif | |
| 205 | ||
| 206 | 3 | Tr%NLT_budget_name = 'KPP_NLT_'//trim(Tr%flux_nameroot)//'_budget' |
| 207 | 3 | if (present(NLT_budget_name)) then |
| 208 | 2 | Tr%NLT_budget_name = NLT_budget_name |
| 209 | endif | |
| 210 | ||
| 211 | Tr%net_surfflux_longname = 'Effective net surface '//trim(lowercase(Tr%flux_longname))//& | |
| 212 | 3 | ' flux, as used by [CVMix] KPP' |
| 213 | 3 | if (present(net_surfflux_longname)) then |
| 214 | 1 | Tr%net_surfflux_longname = net_surfflux_longname |
| 215 | endif | |
| 216 | ||
| 217 | 3 | Tr%flux_units = "" |
| 218 | 3 | if (present(flux_units)) Tr%flux_units = flux_units |
| 219 | ||
| 220 | 3 | Tr%flux_scale = GV%H_to_MKS*Tr%conc_scale |
| 221 | 3 | if (present(flux_scale)) Tr%flux_scale = flux_scale |
| 222 | ||
| 223 | 3 | Tr%conv_units = "" |
| 224 | 3 | if (present(convergence_units)) Tr%conv_units = convergence_units |
| 225 | ||
| 226 | 3 | Tr%cmor_tendprefix = "" |
| 227 | 3 | if (present(cmor_tendprefix)) Tr%cmor_tendprefix = cmor_tendprefix |
| 228 | ||
| 229 | 3 | Tr%conv_scale = GV%H_to_MKS*Tr%conc_scale |
| 230 | 3 | if (present(convergence_scale)) then |
| 231 | 2 | Tr%conv_scale = convergence_scale |
| 232 | 1 | elseif (present(flux_scale)) then |
| 233 | 1 | Tr%conv_scale = flux_scale |
| 234 | endif | |
| 235 | ||
| 236 | 3 | Tr%diag_form = 1 |
| 237 | 3 | if (present(diag_form)) Tr%diag_form = diag_form |
| 238 | ||
| 239 | 3 | Tr%advect_scheme = -1 |
| 240 | 3 | if (present(advect_scheme)) Tr%advect_scheme = advect_scheme |
| 241 | ||
| 242 | 3 | Tr%t => tr_ptr |
| 243 | ||
| 244 | 3 | if (present(registry_diags)) Tr%registry_diags = registry_diags |
| 245 | ||
| 246 | 3 | if (present(ad_x)) then ; if (associated(ad_x)) Tr%ad_x => ad_x ; endif |
| 247 | 3 | if (present(ad_y)) then ; if (associated(ad_y)) Tr%ad_y => ad_y ; endif |
| 248 | 3 | if (present(df_x)) then ; if (associated(df_x)) Tr%df_x => df_x ; endif |
| 249 | 3 | if (present(df_y)) then ; if (associated(df_y)) Tr%df_y => df_y ; endif |
| 250 | ! if (present(OBC_inflow)) Tr%OBC_inflow_conc = OBC_inflow | |
| 251 | ! if (present(OBC_in_u)) then ; if (associated(OBC_in_u)) Tr%OBC_in_u => OBC_in_u ; endif | |
| 252 | ! if (present(OBC_in_v)) then ; if (associated(OBC_in_v)) Tr%OBC_in_v => OBC_in_v ; endif | |
| 253 | 3 | if (present(ad_2d_x)) then ; if (associated(ad_2d_x)) Tr%ad2d_x => ad_2d_x ; endif |
| 254 | 3 | if (present(ad_2d_y)) then ; if (associated(ad_2d_y)) Tr%ad2d_y => ad_2d_y ; endif |
| 255 | 3 | if (present(df_2d_x)) then ; if (associated(df_2d_x)) Tr%df2d_x => df_2d_x ; endif |
| 256 | ||
| 257 | 3 | if (present(advection_xy)) then |
| 258 | 0 | if (associated(advection_xy)) Tr%advection_xy => advection_xy |
| 259 | endif | |
| 260 | ||
| 261 | 3 | if (present(restart_CS)) then |
| 262 | ! Register this tracer to be read from and written to restart files. | |
| 263 | 1 | mand = .true. ; if (present(mandatory)) mand = mandatory |
| 264 | ||
| 265 | call register_restart_field(tr_ptr, Tr%name, mand, restart_CS, & | |
| 266 | 1 | longname=Tr%longname, units=Tr%units, conversion=conc_scale) |
| 267 | endif | |
| 268 | 3 | end subroutine register_tracer |
| 269 | ||
| 270 | ||
| 271 | !> This subroutine locks the tracer registry to prevent the addition of more | |
| 272 | !! tracers. After locked=.true., can then register common diagnostics. | |
| 273 | 1 | subroutine lock_tracer_registry(Reg) |
| 274 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 275 | ||
| 276 | 1 | if (.not. associated(Reg)) call MOM_error(WARNING, & |
| 277 | 0 | "lock_tracer_registry called with an unassociated registry.") |
| 278 | ||
| 279 | 1 | Reg%locked = .True. |
| 280 | ||
| 281 | 1 | end subroutine lock_tracer_registry |
| 282 | ||
| 283 | !> register_tracer_diagnostics does a set of register_diag_field calls for any previously | |
| 284 | !! registered in a tracer registry with a value of registry_diags set to .true. | |
| 285 | 1 | subroutine register_tracer_diagnostics(Reg, h, Time, diag, G, GV, US, use_ALE, use_KPP) |
| 286 | type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure | |
| 287 | type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure | |
| 288 | type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type | |
| 289 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 290 | real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & | |
| 291 | intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] | |
| 292 | type(time_type), intent(in) :: Time !< current model time | |
| 293 | type(diag_ctrl), intent(in) :: diag !< structure to regulate diagnostic output | |
| 294 | logical, intent(in) :: use_ALE !< If true active diagnostics that only | |
| 295 | !! apply to ALE configurations | |
| 296 | logical, intent(in) :: use_KPP !< If true active diagnostics that only | |
| 297 | !! apply to CVMix KPP mixings | |
| 298 | ||
| 299 | character(len=24) :: name ! A variable's name in a NetCDF file. | |
| 300 | character(len=24) :: shortnm ! A shortened version of a variable's name for | |
| 301 | ! creating additional diagnostics. | |
| 302 | character(len=72) :: longname ! The long name of that tracer variable. | |
| 303 | character(len=72) :: flux_longname ! The tracer name in the long names of fluxes. | |
| 304 | character(len=48) :: units ! The dimensions of the tracer. | |
| 305 | character(len=48) :: flux_units ! The units for fluxes, either | |
| 306 | ! [units] m3 s-1 or [units] kg s-1. | |
| 307 | character(len=48) :: conv_units ! The units for flux convergences, either | |
| 308 | ! [units] m2 s-1 or [units] kg s-1. | |
| 309 | character(len=48) :: unit2 ! The dimensions of the tracer squared | |
| 310 | character(len=72) :: cmorname ! The CMOR name of this tracer. | |
| 311 | character(len=120) :: cmor_longname ! The CMOR long name of that variable. | |
| 312 | character(len=120) :: var_lname ! A temporary longname for a diagnostic. | |
| 313 | character(len=120) :: cmor_var_lname ! The temporary CMOR long name for a diagnostic | |
| 314 | real :: conversion ! Temporary term while we address a bug [conc m CU-1 H-1 ~> 1] or [conc kg m-2 CU-1 H-1 ~> 1] | |
| 315 | type(tracer_type), pointer :: Tr=>NULL() | |
| 316 | integer :: i, j, k, is, ie, js, je, nz, m, m2, nTr_in | |
| 317 | integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB | |
| 318 | 1 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 319 | 1 | isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed |
| 320 | 1 | IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB |
| 321 | ||
| 322 | 1 | if (.not. associated(Reg)) call MOM_error(FATAL, "register_tracer_diagnostics: "//& |
| 323 | 0 | "register_tracer must be called before register_tracer_diagnostics") |
| 324 | ||
| 325 | 1 | nTr_in = Reg%ntr |
| 326 | ||
| 327 | 4 | do m=1,nTr_in ; if (Reg%Tr(m)%registry_diags) then |
| 328 | 3 | Tr => Reg%Tr(m) |
| 329 | ! call query_vardesc(Tr%vd, name, units=units, longname=longname, & | |
| 330 | ! cmor_field_name=cmorname, cmor_longname=cmor_longname, & | |
| 331 | ! caller="register_tracer_diagnostics") | |
| 332 | 3 | name = Tr%name ; units=adjustl(Tr%units) ; longname = Tr%longname |
| 333 | 3 | cmorname = Tr%cmor_name ; cmor_longname = Tr%cmor_longname |
| 334 | 3 | shortnm = Tr%flux_nameroot |
| 335 | 3 | flux_longname = Tr%flux_longname |
| 336 | 3 | if (len_trim(cmor_longname) == 0) cmor_longname = longname |
| 337 | ||
| 338 | 3 | if (len_trim(Tr%flux_units) > 0) then ; flux_units = Tr%flux_units |
| 339 | 1 | elseif (GV%Boussinesq) then ; flux_units = trim(units)//" m3 s-1" |
| 340 | 0 | else ; flux_units = trim(units)//" kg s-1" ; endif |
| 341 | ||
| 342 | 3 | if (len_trim(Tr%conv_units) > 0) then ; conv_units = Tr%conv_units |
| 343 | 1 | elseif (GV%Boussinesq) then ; conv_units = trim(units)//" m s-1" |
| 344 | 0 | else ; conv_units = trim(units)//" kg m-2 s-1" ; endif |
| 345 | ||
| 346 | 3 | if (len_trim(cmorname) == 0) then |
| 347 | Tr%id_tr = register_diag_field("ocean_model", trim(name), diag%axesTL, & | |
| 348 | 0 | Time, trim(longname), trim(units), conversion=Tr%conc_scale) |
| 349 | else | |
| 350 | Tr%id_tr = register_diag_field("ocean_model", trim(name), diag%axesTL, & | |
| 351 | Time, trim(longname), trim(units), conversion=Tr%conc_scale, & | |
| 352 | cmor_field_name=cmorname, cmor_long_name=cmor_longname, & | |
| 353 | 3 | cmor_units=Tr%cmor_units, cmor_standard_name=cmor_long_std(cmor_longname)) |
| 354 | endif | |
| 355 | Tr%id_tr_post_horzn = register_diag_field("ocean_model", & | |
| 356 | trim(name)//"_post_horzn", diag%axesTL, Time, & | |
| 357 | trim(longname)//" after horizontal transport (advection/diffusion) has occurred", & | |
| 358 | 3 | trim(units), conversion=Tr%conc_scale) |
| 359 | 3 | if (Tr%diag_form == 1) then |
| 360 | Tr%id_adx = register_diag_field("ocean_model", trim(shortnm)//"_adx", & | |
| 361 | diag%axesCuL, Time, trim(flux_longname)//" advective zonal flux" , & | |
| 362 | trim(flux_units), v_extensive=.true., y_cell_method='sum', & | |
| 363 | 1 | conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) |
| 364 | Tr%id_ady = register_diag_field("ocean_model", trim(shortnm)//"_ady", & | |
| 365 | diag%axesCvL, Time, trim(flux_longname)//" advective meridional flux" , & | |
| 366 | trim(flux_units), v_extensive=.true., x_cell_method='sum', & | |
| 367 | 1 | conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T) |
| 368 | Tr%id_dfx = register_diag_field("ocean_model", trim(shortnm)//"_dfx", & | |
| 369 | diag%axesCuL, Time, trim(flux_longname)//" diffusive zonal flux" , & | |
| 370 | trim(flux_units), v_extensive=.true., y_cell_method='sum', & | |
| 371 | 1 | conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T) |
| 372 | Tr%id_dfy = register_diag_field("ocean_model", trim(shortnm)//"_dfy", & | |
| 373 | diag%axesCvL, Time, trim(flux_longname)//" diffusive meridional flux" , & | |
| 374 | trim(flux_units), v_extensive=.true., x_cell_method='sum', & | |
| 375 | 1 | conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T) |
| 376 | Tr%id_hbd_dfx = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffx", & | |
| 377 | diag%axesCuL, Time, trim(flux_longname)//" diffusive zonal flux " //& | |
| 378 | "from the horizontal boundary diffusion scheme", trim(flux_units), v_extensive=.true., & | |
| 379 | 1 | y_cell_method='sum', conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T) |
| 380 | Tr%id_hbd_dfy = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffy", & | |
| 381 | diag%axesCvL, Time, trim(flux_longname)//" diffusive meridional " //& | |
| 382 | "flux from the horizontal boundary diffusion scheme", trim(flux_units), & | |
| 383 | v_extensive=.true., & | |
| 384 | 1 | x_cell_method='sum', conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T) |
| 385 | else | |
| 386 | Tr%id_adx = register_diag_field("ocean_model", trim(shortnm)//"_adx", & | |
| 387 | diag%axesCuL, Time, "Advective (by residual mean) Zonal Flux of "//trim(flux_longname), & | |
| 388 | 2 | flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, y_cell_method='sum') |
| 389 | Tr%id_ady = register_diag_field("ocean_model", trim(shortnm)//"_ady", & | |
| 390 | diag%axesCvL, Time, "Advective (by residual mean) Meridional Flux of "//trim(flux_longname), & | |
| 391 | 2 | flux_units, v_extensive=.true., conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, x_cell_method='sum') |
| 392 | Tr%id_dfx = register_diag_field("ocean_model", trim(shortnm)//"_diffx", & | |
| 393 | diag%axesCuL, Time, "Diffusive Zonal Flux of "//trim(flux_longname), & | |
| 394 | flux_units, v_extensive=.true., conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 395 | 2 | y_cell_method='sum') |
| 396 | Tr%id_dfy = register_diag_field("ocean_model", trim(shortnm)//"_diffy", & | |
| 397 | diag%axesCvL, Time, "Diffusive Meridional Flux of "//trim(flux_longname), & | |
| 398 | flux_units, v_extensive=.true., conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 399 | 2 | x_cell_method='sum') |
| 400 | Tr%id_hbd_dfx = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffx", & | |
| 401 | diag%axesCuL, Time, & | |
| 402 | "Horizontal Boundary Diffusive Zonal Flux of "//trim(flux_longname), & | |
| 403 | flux_units, v_extensive=.true., conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 404 | 2 | y_cell_method='sum') |
| 405 | Tr%id_hbd_dfy = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffy", & | |
| 406 | diag%axesCvL, Time, & | |
| 407 | "Horizontal Boundary Diffusive Meridional Flux of "//trim(flux_longname), & | |
| 408 | flux_units, v_extensive=.true., conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 409 | 2 | x_cell_method='sum') |
| 410 | endif | |
| 411 | Tr%id_zint = register_diag_field("ocean_model", trim(shortnm)//"_zint", & | |
| 412 | diag%axesT1, Time, & | |
| 413 | "Thickness-weighted integral of " // trim(longname), & | |
| 414 | 3 | trim(units) // " m") |
| 415 | Tr%id_zint_100m = register_diag_field("ocean_model", trim(shortnm)//"_zint_100m", & | |
| 416 | diag%axesT1, Time, & | |
| 417 | "Thickness-weighted integral of "// trim(longname) // " over top 100m", & | |
| 418 | 3 | trim(units) // " m") |
| 419 | Tr%id_surf = register_diag_field("ocean_model", trim(shortnm)//"_SURF", & | |
| 420 | 3 | diag%axesT1, Time, "Surface values of "// trim(longname), trim(units)) |
| 421 | 3 | if (Tr%id_adx > 0) call safe_alloc_ptr(Tr%ad_x,IsdB,IedB,jsd,jed,nz) |
| 422 | 3 | if (Tr%id_ady > 0) call safe_alloc_ptr(Tr%ad_y,isd,ied,JsdB,JedB,nz) |
| 423 | 3 | if (Tr%id_dfx > 0) call safe_alloc_ptr(Tr%df_x,IsdB,IedB,jsd,jed,nz) |
| 424 | 3 | if (Tr%id_dfy > 0) call safe_alloc_ptr(Tr%df_y,isd,ied,JsdB,JedB,nz) |
| 425 | 3 | if (Tr%id_hbd_dfx > 0) call safe_alloc_ptr(Tr%hbd_dfx,IsdB,IedB,jsd,jed,nz) |
| 426 | 3 | if (Tr%id_hbd_dfy > 0) call safe_alloc_ptr(Tr%hbd_dfy,isd,ied,JsdB,JedB,nz) |
| 427 | ||
| 428 | Tr%id_adx_2d = register_diag_field("ocean_model", trim(shortnm)//"_adx_2d", & | |
| 429 | diag%axesCu1, Time, & | |
| 430 | "Vertically Integrated Advective Zonal Flux of "//trim(flux_longname), & | |
| 431 | 3 | flux_units, conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, y_cell_method='sum') |
| 432 | Tr%id_ady_2d = register_diag_field("ocean_model", trim(shortnm)//"_ady_2d", & | |
| 433 | diag%axesCv1, Time, & | |
| 434 | "Vertically Integrated Advective Meridional Flux of "//trim(flux_longname), & | |
| 435 | 3 | flux_units, conversion=Tr%flux_scale*(US%L_to_m**2)*US%s_to_T, x_cell_method='sum') |
| 436 | Tr%id_dfx_2d = register_diag_field("ocean_model", trim(shortnm)//"_diffx_2d", & | |
| 437 | diag%axesCu1, Time, & | |
| 438 | "Vertically Integrated Diffusive Zonal Flux of "//trim(flux_longname), & | |
| 439 | flux_units, conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 440 | 3 | y_cell_method='sum') |
| 441 | Tr%id_dfy_2d = register_diag_field("ocean_model", trim(shortnm)//"_diffy_2d", & | |
| 442 | diag%axesCv1, Time, & | |
| 443 | "Vertically Integrated Diffusive Meridional Flux of "//trim(flux_longname), & | |
| 444 | flux_units, conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 445 | 3 | x_cell_method='sum') |
| 446 | Tr%id_hbd_dfx_2d = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffx_2d", & | |
| 447 | diag%axesCu1, Time, "Vertically-integrated zonal diffusive flux from the horizontal boundary diffusion "//& | |
| 448 | "scheme for "//trim(flux_longname), flux_units, conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 449 | 3 | y_cell_method='sum') |
| 450 | Tr%id_hbd_dfy_2d = register_diag_field("ocean_model", trim(shortnm)//"_hbd_diffy_2d", & | |
| 451 | diag%axesCv1, Time, "Vertically-integrated meridional diffusive flux from the horizontal boundary diffusion "//& | |
| 452 | "scheme for "//trim(flux_longname), flux_units, conversion=(US%L_to_m**2)*Tr%flux_scale*US%s_to_T, & | |
| 453 | 3 | x_cell_method='sum') |
| 454 | ||
| 455 | 3 | if (Tr%id_adx_2d > 0) call safe_alloc_ptr(Tr%ad2d_x,IsdB,IedB,jsd,jed) |
| 456 | 3 | if (Tr%id_ady_2d > 0) call safe_alloc_ptr(Tr%ad2d_y,isd,ied,JsdB,JedB) |
| 457 | 3 | if (Tr%id_dfx_2d > 0) call safe_alloc_ptr(Tr%df2d_x,IsdB,IedB,jsd,jed) |
| 458 | 3 | if (Tr%id_dfy_2d > 0) call safe_alloc_ptr(Tr%df2d_y,isd,ied,JsdB,JedB) |
| 459 | 3 | if (Tr%id_hbd_dfx_2d > 0) call safe_alloc_ptr(Tr%hbd_dfx_2d,IsdB,IedB,jsd,jed) |
| 460 | 3 | if (Tr%id_hbd_dfy_2d > 0) call safe_alloc_ptr(Tr%hbd_dfy_2d,isd,ied,JsdB,JedB) |
| 461 | ||
| 462 | Tr%id_adv_xy = register_diag_field('ocean_model', trim(shortnm)//"_advection_xy", & | |
| 463 | diag%axesTL, Time, & | |
| 464 | 'Horizontal convergence of residual mean advective fluxes of '//& | |
| 465 | trim(lowercase(flux_longname)), & | |
| 466 | 3 | conv_units, v_extensive=.true., conversion=Tr%conv_scale*US%s_to_T) |
| 467 | Tr%id_adv_xy_2d = register_diag_field('ocean_model', trim(shortnm)//"_advection_xy_2d", & | |
| 468 | diag%axesT1, Time, & | |
| 469 | 'Vertical sum of horizontal convergence of residual mean advective fluxes of '//& | |
| 470 | 3 | trim(lowercase(flux_longname)), conv_units, conversion=Tr%conv_scale*US%s_to_T) |
| 471 | 3 | if ((Tr%id_adv_xy > 0) .or. (Tr%id_adv_xy_2d > 0)) & |
| 472 | 0 | call safe_alloc_ptr(Tr%advection_xy,isd,ied,jsd,jed,nz) |
| 473 | ||
| 474 | Tr%id_tendency = register_diag_field('ocean_model', trim(shortnm)//'_tendency', & | |
| 475 | diag%axesTL, Time, & | |
| 476 | 'Net time tendency for '//trim(lowercase(longname)), & | |
| 477 | 3 | trim(units)//' s-1', conversion=Tr%conc_scale*US%s_to_T) |
| 478 | ||
| 479 | 3 | if (Tr%id_tendency > 0) then |
| 480 | 0 | call safe_alloc_ptr(Tr%t_prev,isd,ied,jsd,jed,nz) |
| 481 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 482 | 0 | Tr%t_prev(i,j,k) = Tr%t(i,j,k) |
| 483 | enddo ; enddo ; enddo | |
| 484 | endif | |
| 485 | ||
| 486 | ! Neutral/Horizontal diffusion convergence tendencies | |
| 487 | 3 | if (Tr%diag_form == 1) then |
| 488 | Tr%id_dfxy_cont = register_diag_field("ocean_model", trim(shortnm)//'_dfxy_cont_tendency', & | |
| 489 | diag%axesTL, Time, "Neutral diffusion tracer content tendency for "//trim(shortnm), & | |
| 490 | conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 491 | 1 | x_cell_method='sum', y_cell_method='sum', v_extensive=.true.) |
| 492 | ||
| 493 | Tr%id_dfxy_cont_2d = register_diag_field("ocean_model", & | |
| 494 | trim(shortnm)//'_dfxy_cont_tendency_2d', & | |
| 495 | diag%axesT1, Time, "Depth integrated neutral diffusion tracer content "//& | |
| 496 | "tendency for "//trim(shortnm), conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 497 | 1 | x_cell_method='sum', y_cell_method='sum') |
| 498 | ||
| 499 | Tr%id_hbdxy_cont = register_diag_field("ocean_model", trim(shortnm)//'_hbdxy_cont_tendency', & | |
| 500 | diag%axesTL, Time, "Horizontal boundary diffusion tracer content tendency for "//& | |
| 501 | trim(shortnm), & | |
| 502 | conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 503 | 1 | x_cell_method='sum', y_cell_method='sum', v_extensive=.true.) |
| 504 | ||
| 505 | Tr%id_hbdxy_cont_2d = register_diag_field("ocean_model", & | |
| 506 | trim(shortnm)//'_hbdxy_cont_tendency_2d', & | |
| 507 | diag%axesT1, Time, "Depth integrated horizontal boundary diffusion tracer content "//& | |
| 508 | "tendency for "//trim(shortnm), conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 509 | 1 | x_cell_method='sum', y_cell_method='sum') |
| 510 | else | |
| 511 | cmor_var_lname = 'Tendency of '//trim(lowercase(cmor_longname))//' expressed as '//& | |
| 512 | trim(lowercase(flux_longname))//& | |
| 513 | 2 | ' content due to parameterized mesoscale neutral diffusion' |
| 514 | Tr%id_dfxy_cont = register_diag_field("ocean_model", trim(shortnm)//'_dfxy_cont_tendency', & | |
| 515 | diag%axesTL, Time, "Neutral diffusion tracer content tendency for "//trim(shortnm), & | |
| 516 | conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 517 | cmor_field_name=trim(Tr%cmor_tendprefix)//'pmdiff', & | |
| 518 | cmor_long_name=trim(cmor_var_lname), & | |
| 519 | cmor_standard_name=trim(cmor_long_std(cmor_var_lname)), & | |
| 520 | 2 | x_cell_method='sum', y_cell_method='sum', v_extensive=.true.) |
| 521 | ||
| 522 | cmor_var_lname = 'Tendency of '//trim(lowercase(cmor_longname))//' expressed as '//& | |
| 523 | trim(lowercase(flux_longname))//& | |
| 524 | 2 | ' content due to parameterized mesoscale neutral diffusion' |
| 525 | Tr%id_dfxy_cont_2d = register_diag_field("ocean_model", & | |
| 526 | trim(shortnm)//'_dfxy_cont_tendency_2d', & | |
| 527 | diag%axesT1, Time, "Depth integrated neutral diffusion tracer "//& | |
| 528 | "content tendency for "//trim(shortnm), conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 529 | cmor_field_name=trim(Tr%cmor_tendprefix)//'pmdiff_2d', & | |
| 530 | cmor_long_name=trim(cmor_var_lname), & | |
| 531 | cmor_standard_name=trim(cmor_long_std(cmor_var_lname)), & | |
| 532 | 2 | x_cell_method='sum', y_cell_method='sum') |
| 533 | ||
| 534 | Tr%id_hbdxy_cont = register_diag_field("ocean_model", trim(shortnm)//'_hbdxy_cont_tendency', & | |
| 535 | diag%axesTL, Time, & | |
| 536 | "Horizontal boundary diffusion tracer content tendency for "//trim(shortnm), & | |
| 537 | conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 538 | 2 | x_cell_method='sum', y_cell_method='sum', v_extensive=.true.) |
| 539 | ||
| 540 | Tr%id_hbdxy_cont_2d = register_diag_field("ocean_model", & | |
| 541 | trim(shortnm)//'_hbdxy_cont_tendency_2d', & | |
| 542 | diag%axesT1, Time, "Depth integrated horizontal boundary diffusion of tracer "//& | |
| 543 | "content tendency for "//trim(shortnm), conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 544 | 2 | x_cell_method='sum', y_cell_method='sum') |
| 545 | endif | |
| 546 | Tr%id_dfxy_conc = register_diag_field("ocean_model", trim(shortnm)//'_dfxy_conc_tendency', & | |
| 547 | diag%axesTL, Time, "Neutral diffusion tracer concentration tendency for "//trim(shortnm), & | |
| 548 | 3 | trim(units)//' s-1', conversion=Tr%conc_scale*US%s_to_T) |
| 549 | ||
| 550 | Tr%id_hbdxy_conc = register_diag_field("ocean_model", trim(shortnm)//'_hbdxy_conc_tendency', & | |
| 551 | diag%axesTL, Time, & | |
| 552 | "Horizontal diffusion tracer concentration tendency for "//trim(shortnm), & | |
| 553 | 3 | trim(units)//' s-1', conversion=Tr%conc_scale*US%s_to_T) |
| 554 | ||
| 555 | 3 | var_lname = "Net time tendency for "//lowercase(flux_longname) |
| 556 | 3 | if (len_trim(Tr%cmor_tendprefix) == 0) then |
| 557 | Tr%id_trxh_tendency = register_diag_field('ocean_model', trim(shortnm)//'h_tendency', & | |
| 558 | diag%axesTL, Time, var_lname, conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 559 | 1 | v_extensive=.true.) |
| 560 | Tr%id_trxh_tendency_2d = register_diag_field('ocean_model', trim(shortnm)//'h_tendency_2d', & | |
| 561 | diag%axesT1, Time, "Vertical sum of "//trim(lowercase(var_lname)), & | |
| 562 | 1 | conv_units, conversion=Tr%conv_scale*US%s_to_T) |
| 563 | else | |
| 564 | cmor_var_lname = "Tendency of "//trim(cmor_longname)//" Expressed as "//& | |
| 565 | 2 | trim(flux_longname)//" Content" |
| 566 | Tr%id_trxh_tendency = register_diag_field('ocean_model', trim(shortnm)//'h_tendency', & | |
| 567 | diag%axesTL, Time, var_lname, conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 568 | cmor_field_name=trim(Tr%cmor_tendprefix)//"tend", & | |
| 569 | cmor_standard_name=cmor_long_std(cmor_var_lname), cmor_long_name=cmor_var_lname, & | |
| 570 | 2 | v_extensive=.true.) |
| 571 | 2 | cmor_var_lname = trim(cmor_var_lname)//" Vertical Sum" |
| 572 | Tr%id_trxh_tendency_2d = register_diag_field('ocean_model', trim(shortnm)//'h_tendency_2d', & | |
| 573 | diag%axesT1, Time, "Vertical sum of "//trim(lowercase(var_lname)), & | |
| 574 | conv_units, conversion=Tr%conv_scale*US%s_to_T, & | |
| 575 | cmor_field_name=trim(Tr%cmor_tendprefix)//"tend_2d", & | |
| 576 | 2 | cmor_standard_name=cmor_long_std(cmor_var_lname), cmor_long_name=cmor_var_lname) |
| 577 | endif | |
| 578 | 3 | if ((Tr%id_trxh_tendency > 0) .or. (Tr%id_trxh_tendency_2d > 0)) then |
| 579 | 0 | call safe_alloc_ptr(Tr%Trxh_prev,isd,ied,jsd,jed,nz) |
| 580 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 581 | 0 | Tr%Trxh_prev(i,j,k) = Tr%t(i,j,k) * h(i,j,k) |
| 582 | enddo ; enddo ; enddo | |
| 583 | endif | |
| 584 | ||
| 585 | ! Vertical regridding/remapping tendencies | |
| 586 | 3 | if (use_ALE .and. Tr%remap_tr) then |
| 587 | 3 | var_lname = "Vertical remapping tracer concentration tendency for "//trim(Reg%Tr(m)%name) |
| 588 | Tr%id_remap_conc= register_diag_field('ocean_model', & | |
| 589 | trim(Tr%flux_nameroot)//'_tendency_vert_remap', diag%axesTL, Time, var_lname, & | |
| 590 | 3 | trim(units)//' s-1', conversion=Tr%conc_scale*US%s_to_T) |
| 591 | ||
| 592 | 3 | var_lname = "Vertical remapping tracer content tendency for "//trim(Reg%Tr(m)%flux_longname) |
| 593 | Tr%id_remap_cont = register_diag_field('ocean_model', & | |
| 594 | trim(Tr%flux_nameroot)//'h_tendency_vert_remap', & | |
| 595 | 3 | diag%axesTL, Time, var_lname, conv_units, v_extensive=.true., conversion=Tr%conv_scale*US%s_to_T) |
| 596 | ||
| 597 | var_lname = "Vertical sum of vertical remapping tracer content tendency for "//& | |
| 598 | 3 | trim(Reg%Tr(m)%flux_longname) |
| 599 | Tr%id_remap_cont_2d = register_diag_field('ocean_model', & | |
| 600 | trim(Tr%flux_nameroot)//'h_tendency_vert_remap_2d', & | |
| 601 | 3 | diag%axesT1, Time, var_lname, conv_units, conversion=Tr%conv_scale*US%s_to_T) |
| 602 | ||
| 603 | endif | |
| 604 | ||
| 605 | 3 | if (use_ALE .and. (Reg%ntr<MAX_FIELDS_) .and. Tr%remap_tr) then |
| 606 | 3 | unit2 = trim(units)//"2" |
| 607 | 3 | if (index(units(1:len_trim(units))," ") > 0) unit2 = "("//trim(units)//")2" |
| 608 | Tr%id_tr_vardec = register_diag_field('ocean_model', trim(shortnm)//"_vardec", diag%axesTL, & | |
| 609 | Time, "ALE variance decay for "//lowercase(longname), & | |
| 610 | 3 | trim(unit2)//" s-1", conversion=Tr%conc_scale**2*US%s_to_T) |
| 611 | 3 | if (Tr%id_tr_vardec > 0) then |
| 612 | ! Set up a new tracer for this tracer squared | |
| 613 | 0 | m2 = Reg%ntr+1 |
| 614 | 0 | Tr%ind_tr_squared = m2 |
| 615 | 0 | call safe_alloc_ptr(Reg%Tr(m2)%t,isd,ied,jsd,jed,nz) ; Reg%Tr(m2)%t(:,:,:) = 0.0 |
| 616 | 0 | Reg%Tr(m2)%name = trim(shortnm)//"2" |
| 617 | 0 | Reg%Tr(m2)%longname = "Squared "//trim(longname) |
| 618 | 0 | Reg%Tr(m2)%units = unit2 |
| 619 | 0 | Reg%Tr(m2)%registry_diags = .false. |
| 620 | 0 | Reg%Tr(m2)%ind_tr_squared = -1 |
| 621 | ! Augment the total number of tracers, including the squared tracers. | |
| 622 | 0 | Reg%ntr = Reg%ntr + 1 |
| 623 | endif | |
| 624 | endif | |
| 625 | ||
| 626 | ! KPP nonlocal term diagnostics | |
| 627 | 3 | if (use_KPP) then |
| 628 | Tr%id_net_surfflux = register_diag_field('ocean_model', Tr%net_surfflux_name, diag%axesT1, Time, & | |
| 629 | 0 | Tr%net_surfflux_longname, trim(units)//' m s-1', conversion=Tr%conc_scale*GV%H_to_m*US%s_to_T) |
| 630 | Tr%id_NLT_tendency = register_diag_field('ocean_model', "KPP_NLT_d"//trim(shortnm)//"dt", & | |
| 631 | diag%axesTL, Time, & | |
| 632 | trim(longname)//' tendency due to non-local transport of '//trim(lowercase(flux_longname))//& | |
| 633 | 0 | ', as calculated by [CVMix] KPP', trim(units)//' s-1', conversion=Tr%conc_scale*US%s_to_T) |
| 634 | 0 | if (Tr%conv_scale == 0.001*GV%H_to_kg_m2) then |
| 635 | 0 | conversion = GV%H_to_kg_m2 |
| 636 | else | |
| 637 | 0 | conversion = Tr%conv_scale |
| 638 | endif | |
| 639 | ! We actually want conversion=Tr%conv_scale for all tracers, but introducing the local variable | |
| 640 | ! 'conversion' and setting it to GV%H_to_kg_m2 instead of 0.001*GV%H_to_kg_m2 for salt tracers | |
| 641 | ! keeps changes introduced by this refactoring limited to round-off level; as it turns out, | |
| 642 | ! there is a bug in the code and the NLT budget term for salinity is off by a factor of 10^3 | |
| 643 | ! so introducing the 0.001 here will fix that bug. | |
| 644 | Tr%id_NLT_budget = register_diag_field('ocean_model', Tr%NLT_budget_name, & | |
| 645 | diag%axesTL, Time, & | |
| 646 | trim(flux_longname)//& | |
| 647 | ' content change due to non-local transport, as calculated by [CVMix] KPP', & | |
| 648 | 0 | conv_units, conversion=conversion*US%s_to_T, v_extensive=.true.) |
| 649 | endif | |
| 650 | ||
| 651 | endif ; enddo | |
| 652 | ||
| 653 | 1 | end subroutine register_tracer_diagnostics |
| 654 | ||
| 655 | 12 | subroutine preALE_tracer_diagnostics(Reg, G, GV) |
| 656 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 657 | type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure | |
| 658 | type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure | |
| 659 | ||
| 660 | integer :: i, j, k, is, ie, js, je, nz, m, m2 | |
| 661 | 12 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 662 | ||
| 663 | 48 | do m=1,Reg%ntr ; if (Reg%Tr(m)%ind_tr_squared > 0) then |
| 664 | 0 | m2 = Reg%Tr(m)%ind_tr_squared |
| 665 | ! Update squared quantities | |
| 666 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 667 | 0 | Reg%Tr(m2)%T(i,j,k) = Reg%Tr(m)%T(i,j,k)**2 |
| 668 | enddo ; enddo ; enddo | |
| 669 | endif ; enddo | |
| 670 | ||
| 671 | 12 | end subroutine preALE_tracer_diagnostics |
| 672 | ||
| 673 | 12 | subroutine postALE_tracer_diagnostics(Reg, G, GV, diag, dt) |
| 674 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 675 | type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure | |
| 676 | type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure | |
| 677 | type(diag_ctrl), intent(in) :: diag !< regulates diagnostic output | |
| 678 | real, intent(in) :: dt !< total time interval for these diagnostics [T ~> s] | |
| 679 | ||
| 680 | 24 | real :: work(SZI_(G),SZJ_(G),SZK_(GV)) ! Variance decay [CU2 T-1 ~> conc2 s-1] |
| 681 | real :: Idt ! The inverse of the time step [T-1 ~> s-1] | |
| 682 | integer :: i, j, k, is, ie, js, je, nz, m, m2 | |
| 683 | 12 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 684 | ||
| 685 | ! The "if" is to avoid NaNs if the diagnostic is called for a zero length interval | |
| 686 | 12 | Idt = 0.0 ; if (dt /= 0.0) Idt = 1.0 / dt |
| 687 | ||
| 688 | 48 | do m=1,Reg%ntr ; if (Reg%Tr(m)%id_tr_vardec > 0) then |
| 689 | 0 | m2 = Reg%Tr(m)%ind_tr_squared |
| 690 | 0 | if (m2 < 1) call MOM_error(FATAL, "Bad value of Tr%ind_tr_squared for "//trim(Reg%Tr(m)%name)) |
| 691 | ! Update squared quantities | |
| 692 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 693 | 0 | work(i,j,k) = (Reg%Tr(m2)%T(i,j,k) - Reg%Tr(m)%T(i,j,k)**2) * Idt |
| 694 | enddo ; enddo ; enddo | |
| 695 | 0 | call post_data(Reg%Tr(m)%id_tr_vardec, work, diag) |
| 696 | endif ; enddo | |
| 697 | ||
| 698 | 12 | end subroutine postALE_tracer_diagnostics |
| 699 | ||
| 700 | !> Post tracer diganostics when that should only be posted when MOM's state | |
| 701 | !! is self-consistent (also referred to as 'synchronized') | |
| 702 | 12 | subroutine post_tracer_diagnostics_at_sync(Reg, h, diag_prev, diag, G, GV, dt) |
| 703 | type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure | |
| 704 | type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure | |
| 705 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 706 | real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & | |
| 707 | intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] | |
| 708 | type(diag_grid_storage), intent(in) :: diag_prev !< Contains diagnostic grids from previous timestep | |
| 709 | type(diag_ctrl), intent(inout) :: diag !< structure to regulate diagnostic output | |
| 710 | real, intent(in) :: dt !< total time step for tracer updates [T ~> s] | |
| 711 | ||
| 712 | 24 | real :: work3d(SZI_(G),SZJ_(G),SZK_(GV)) ! The time tendency of a diagnostic [CU T-1 ~> conc s-1] |
| 713 | 24 | real :: work2d(SZI_(G),SZJ_(G)) ! The vertically integrated time tendency of a diagnostic |
| 714 | ! in [CU H T-1 ~> conc m s-1 or conc kg m-2 s-1] | |
| 715 | real :: Idt ! The inverse of the time step [T-1 ~> s-1] | |
| 716 | type(tracer_type), pointer :: Tr=>NULL() | |
| 717 | integer :: i, j, k, is, ie, js, je, nz, m | |
| 718 | 12 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 719 | ||
| 720 | 12 | Idt = 0. ; if (dt/=0.) Idt = 1.0 / dt ! The "if" is in case the diagnostic is called for a zero length interval |
| 721 | ||
| 722 | ! Tendency diagnostics need to be posted on the grid from the last call to this routine | |
| 723 | 12 | call diag_save_grids(diag) |
| 724 | 12 | call diag_copy_storage_to_diag(diag, diag_prev) |
| 725 | 48 | do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then |
| 726 | 36 | Tr => Reg%Tr(m) |
| 727 | 36 | if (Tr%id_tr > 0) call post_data(Tr%id_tr, Tr%t, diag) |
| 728 | 36 | if (Tr%id_tendency > 0) then |
| 729 | 0 | work3d(:,:,:) = 0.0 |
| 730 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 731 | 0 | work3d(i,j,k) = (Tr%t(i,j,k) - Tr%t_prev(i,j,k))*Idt |
| 732 | 0 | tr%t_prev(i,j,k) = Tr%t(i,j,k) |
| 733 | enddo ; enddo ; enddo | |
| 734 | 0 | call post_data(Tr%id_tendency, work3d, diag, alt_h=diag_prev%h_state) |
| 735 | endif | |
| 736 | 36 | if ((Tr%id_trxh_tendency > 0) .or. (Tr%id_trxh_tendency_2d > 0)) then |
| 737 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 738 | 0 | work3d(i,j,k) = (Tr%t(i,j,k)*h(i,j,k) - Tr%Trxh_prev(i,j,k)) * Idt |
| 739 | 0 | Tr%Trxh_prev(i,j,k) = Tr%t(i,j,k) * h(i,j,k) |
| 740 | enddo ; enddo ; enddo | |
| 741 | 0 | if (Tr%id_trxh_tendency > 0) call post_data(Tr%id_trxh_tendency, work3d, diag, & |
| 742 | 0 | alt_h=diag_prev%h_state) |
| 743 | 0 | if (Tr%id_trxh_tendency_2d > 0) then |
| 744 | 0 | work2d(:,:) = 0.0 |
| 745 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 746 | 0 | work2d(i,j) = work2d(i,j) + work3d(i,j,k) |
| 747 | enddo ; enddo ; enddo | |
| 748 | 0 | call post_data(Tr%id_trxh_tendency_2d, work2d, diag) |
| 749 | endif | |
| 750 | endif | |
| 751 | endif ; enddo | |
| 752 | 12 | call diag_restore_grids(diag) |
| 753 | ||
| 754 | 12 | end subroutine post_tracer_diagnostics_at_sync |
| 755 | ||
| 756 | !> Post the advective and diffusive tendencies | |
| 757 | 12 | subroutine post_tracer_transport_diagnostics(G, GV, Reg, h_diag, diag) |
| 758 | type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure | |
| 759 | type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure | |
| 760 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 761 | real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & | |
| 762 | intent(in) :: h_diag !< Layer thicknesses on which to post fields [H ~> m or kg m-2] | |
| 763 | type(diag_ctrl), intent(in) :: diag !< structure to regulate diagnostic output | |
| 764 | ||
| 765 | integer :: i, j, k, is, ie, js, je, nz, m, khi | |
| 766 | 24 | real :: work2d(SZI_(G),SZJ_(G)) ! The vertically integrated convergence of lateral advective |
| 767 | ! tracer fluxes [CU H T-1 ~> conc m s-1 or conc kg m-2 s-1] | |
| 768 | 24 | real :: frac_under_100m(SZI_(G),SZJ_(G),SZK_(GV)) ! weights used to compute 100m vertical integrals [nondim] |
| 769 | 24 | real :: ztop(SZI_(G),SZJ_(G)) ! position of the top interface [H ~> m or kg m-2] |
| 770 | 24 | real :: zbot(SZI_(G),SZJ_(G)) ! position of the bottom interface [H ~> m or kg m-2] |
| 771 | type(tracer_type), pointer :: Tr=>NULL() | |
| 772 | ||
| 773 | 12 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 774 | ||
| 775 | ! If any tracers are posting 100m vertical integrals, compute weights | |
| 776 | 7895712 | frac_under_100m(:,:,:) = 0.0 |
| 777 | ! khi will be the largest layer index corresponding where ztop < 100m and ztop >= 100m | |
| 778 | ! in any column (we can reduce computation of 100m integrals by only looping through khi | |
| 779 | ! rather than GV%ke) | |
| 780 | 12 | khi = 0 |
| 781 | 48 | do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then |
| 782 | 36 | Tr => Reg%Tr(m) |
| 783 | 36 | if (Tr%id_zint_100m > 0) then |
| 784 | 0 | zbot(:,:) = 0.0 |
| 785 | 0 | do k=1, nz |
| 786 | 0 | do j=js,je ; do i=is,ie |
| 787 | 0 | ztop(i,j) = zbot(i,j) |
| 788 | 0 | zbot(i,j) = ztop(i,j) + h_diag(i,j,k)*GV%H_to_m |
| 789 | 0 | if (zbot(i,j) <= 100.0) then |
| 790 | 0 | frac_under_100m(i,j,k) = 1.0 |
| 791 | 0 | elseif (ztop(i,j) < 100.0) then |
| 792 | 0 | frac_under_100m(i,j,k) = (100.0 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)) |
| 793 | else | |
| 794 | 0 | frac_under_100m(i,j,k) = 0.0 |
| 795 | endif | |
| 796 | ! frac_under_100m(i,j,k) = max(0, min(1.0, (100.0 - ztop(i,j)) / (zbot(i,j) - ztop(i,j)))) | |
| 797 | enddo ; enddo | |
| 798 | 0 | if (any(frac_under_100m(:,:,k) > 0)) khi = k |
| 799 | enddo | |
| 800 | 0 | exit |
| 801 | endif | |
| 802 | endif ; enddo | |
| 803 | ||
| 804 | 48 | do m=1,Reg%ntr ; if (Reg%Tr(m)%registry_diags) then |
| 805 | 36 | Tr => Reg%Tr(m) |
| 806 | 36 | if (Tr%id_tr_post_horzn> 0) call post_data(Tr%id_tr_post_horzn, Tr%t, diag) |
| 807 | 36 | if (Tr%id_adx > 0) call post_data(Tr%id_adx, Tr%ad_x, diag, alt_h=h_diag) |
| 808 | 36 | if (Tr%id_ady > 0) call post_data(Tr%id_ady, Tr%ad_y, diag, alt_h=h_diag) |
| 809 | 36 | if (Tr%id_dfx > 0) call post_data(Tr%id_dfx, Tr%df_x, diag, alt_h=h_diag) |
| 810 | 36 | if (Tr%id_dfy > 0) call post_data(Tr%id_dfy, Tr%df_y, diag, alt_h=h_diag) |
| 811 | 36 | if (Tr%id_adx_2d > 0) call post_data(Tr%id_adx_2d, Tr%ad2d_x, diag) |
| 812 | 36 | if (Tr%id_ady_2d > 0) call post_data(Tr%id_ady_2d, Tr%ad2d_y, diag) |
| 813 | 36 | if (Tr%id_dfx_2d > 0) call post_data(Tr%id_dfx_2d, Tr%df2d_x, diag) |
| 814 | 36 | if (Tr%id_dfy_2d > 0) call post_data(Tr%id_dfy_2d, Tr%df2d_y, diag) |
| 815 | 36 | if (Tr%id_adv_xy > 0) call post_data(Tr%id_adv_xy, Tr%advection_xy, diag, alt_h=h_diag) |
| 816 | 36 | if (Tr%id_adv_xy_2d > 0) then |
| 817 | 0 | work2d(:,:) = 0.0 |
| 818 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 819 | 0 | work2d(i,j) = work2d(i,j) + Tr%advection_xy(i,j,k) |
| 820 | enddo ; enddo ; enddo | |
| 821 | 0 | call post_data(Tr%id_adv_xy_2d, work2d, diag) |
| 822 | endif | |
| 823 | ||
| 824 | ! A few diagnostics introduce with MARBL driver | |
| 825 | ! Compute full-depth vertical integral | |
| 826 | 36 | if (Tr%id_zint > 0) then |
| 827 | 0 | work2d(:,:) = 0.0 |
| 828 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 829 | 0 | work2d(i,j) = work2d(i,j) + (h_diag(i,j,k)*GV%H_to_m)*tr%t(i,j,k) |
| 830 | enddo ; enddo ; enddo | |
| 831 | 0 | call post_data(Tr%id_zint, work2d, diag) |
| 832 | endif | |
| 833 | ||
| 834 | ! Compute 100m vertical integral | |
| 835 | 36 | if (Tr%id_zint_100m > 0) then |
| 836 | 0 | work2d(:,:) = 0.0 |
| 837 | 0 | do k=1,khi ; do j=js,je ; do i=is,ie |
| 838 | 0 | work2d(i,j) = work2d(i,j) + frac_under_100m(i,j,k)*((h_diag(i,j,k)*GV%H_to_m)*tr%t(i,j,k)) |
| 839 | enddo ; enddo ; enddo | |
| 840 | 0 | call post_data(Tr%id_zint_100m, work2d, diag) |
| 841 | endif | |
| 842 | ||
| 843 | ! Surface values of tracers | |
| 844 | 36 | if (Tr%id_SURF > 0) call post_data(Tr%id_SURF, Tr%t(:,:,1), diag) |
| 845 | endif ; enddo | |
| 846 | ||
| 847 | 12 | end subroutine post_tracer_transport_diagnostics |
| 848 | ||
| 849 | !> This subroutine writes out chksums for the first ntr registered tracers. | |
| 850 | 0 | subroutine tracer_array_chksum(mesg, Tr, ntr, G) |
| 851 | character(len=*), intent(in) :: mesg !< message that appears on the chksum lines | |
| 852 | type(tracer_type), intent(in) :: Tr(:) !< array of all of registered tracers | |
| 853 | integer, intent(in) :: ntr !< number of registered tracers | |
| 854 | type(ocean_grid_type), intent(in) :: G !< ocean grid structure | |
| 855 | ||
| 856 | integer :: m | |
| 857 | ||
| 858 | 0 | do m=1,ntr |
| 859 | 0 | call hchksum(Tr(m)%t, mesg//trim(Tr(m)%name), G%HI, unscale=Tr(m)%conc_scale) |
| 860 | enddo | |
| 861 | ||
| 862 | 0 | end subroutine tracer_array_chksum |
| 863 | ||
| 864 | !> This subroutine writes out chksums for all the registered tracers. | |
| 865 | 0 | subroutine tracer_Reg_chksum(mesg, Reg, G) |
| 866 | character(len=*), intent(in) :: mesg !< message that appears on the chksum lines | |
| 867 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 868 | type(ocean_grid_type), intent(in) :: G !< ocean grid structure | |
| 869 | ||
| 870 | integer :: m | |
| 871 | ||
| 872 | 0 | if (.not.associated(Reg)) return |
| 873 | ||
| 874 | 0 | do m=1,Reg%ntr |
| 875 | 0 | call hchksum(Reg%Tr(m)%t, mesg//trim(Reg%Tr(m)%name), G%HI, unscale=Reg%Tr(m)%conc_scale) |
| 876 | enddo | |
| 877 | ||
| 878 | 0 | end subroutine tracer_Reg_chksum |
| 879 | ||
| 880 | !> Calculates and prints the global inventory of the first ntr tracers in the registry. | |
| 881 | 0 | subroutine tracer_array_chkinv(mesg, G, GV, h, Tr, ntr) |
| 882 | character(len=*), intent(in) :: mesg !< message that appears on the chksum lines | |
| 883 | type(ocean_grid_type), intent(in) :: G !< ocean grid structure | |
| 884 | type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure | |
| 885 | type(tracer_type), dimension(:), intent(in) :: Tr !< array of all of registered tracers | |
| 886 | real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] | |
| 887 | integer, intent(in) :: ntr !< number of registered tracers | |
| 888 | ||
| 889 | ! Local variables | |
| 890 | real :: vol_scale ! The dimensional scaling factor to convert volumes to m3 [m3 H-1 L-2 ~> 1] or cell | |
| 891 | ! masses to kg [kg H-1 L-2 ~> 1], depending on whether the Boussinesq approximation is used | |
| 892 | 0 | real :: tr_inv(SZI_(G),SZJ_(G),SZK_(GV)) ! Volumetric or mass-based tracer inventory in |
| 893 | ! each cell [conc m3] or [conc kg] | |
| 894 | real :: total_inv ! The total amount of tracer [conc m3] or [conc kg] | |
| 895 | integer :: is, ie, js, je, nz | |
| 896 | integer :: i, j, k, m | |
| 897 | ||
| 898 | 0 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 899 | 0 | vol_scale = GV%H_to_MKS*G%US%L_to_m**2 |
| 900 | 0 | do m=1,ntr |
| 901 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 902 | tr_inv(i,j,k) = Tr(m)%conc_scale*Tr(m)%t(i,j,k) * & | |
| 903 | 0 | (vol_scale * h(i,j,k) * G%areaT(i,j)*G%mask2dT(i,j)) |
| 904 | enddo ; enddo ; enddo | |
| 905 | 0 | total_inv = reproducing_sum(tr_inv, is+(1-G%isd), ie+(1-G%isd), js+(1-G%jsd), je+(1-G%jsd)) |
| 906 | 0 | if (is_root_pe()) write(0,'(A,1X,A5,1X,ES25.16,1X,A)') & |
| 907 | 0 | "h-point: inventory", Tr(m)%name, total_inv, mesg |
| 908 | enddo | |
| 909 | ||
| 910 | 0 | end subroutine tracer_array_chkinv |
| 911 | ||
| 912 | ||
| 913 | !> Calculates and prints the global inventory of all tracers in the registry. | |
| 914 | 0 | subroutine tracer_Reg_chkinv(mesg, G, GV, h, Reg) |
| 915 | character(len=*), intent(in) :: mesg !< message that appears on the chksum lines | |
| 916 | type(ocean_grid_type), intent(in) :: G !< ocean grid structure | |
| 917 | type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure | |
| 918 | type(tracer_registry_type), pointer :: Reg !< pointer to the tracer registry | |
| 919 | real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] | |
| 920 | ||
| 921 | ! Local variables | |
| 922 | real :: vol_scale ! The dimensional scaling factor to convert volumes to m3 [m3 H-1 L-2 ~> 1] or cell | |
| 923 | ! masses to kg [kg H-1 L-2 ~> 1], depending on whether the Boussinesq approximation is used | |
| 924 | 0 | real :: tr_inv(SZI_(G),SZJ_(G),SZK_(GV)) ! Volumetric or mass-based tracer inventory in |
| 925 | ! each cell [conc m3] or [conc kg] | |
| 926 | real :: total_inv ! The total amount of tracer [conc m3] or [conc kg] | |
| 927 | integer :: is, ie, js, je, nz | |
| 928 | integer :: i, j, k, m | |
| 929 | ||
| 930 | 0 | if (.not.associated(Reg)) return |
| 931 | ||
| 932 | 0 | is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke |
| 933 | 0 | vol_scale = GV%H_to_MKS*G%US%L_to_m**2 |
| 934 | 0 | do m=1,Reg%ntr |
| 935 | 0 | do k=1,nz ; do j=js,je ; do i=is,ie |
| 936 | tr_inv(i,j,k) = Reg%Tr(m)%conc_scale*Reg%Tr(m)%t(i,j,k) * & | |
| 937 | 0 | (vol_scale * h(i,j,k) * G%areaT(i,j)*G%mask2dT(i,j)) |
| 938 | enddo ; enddo ; enddo | |
| 939 | 0 | total_inv = reproducing_sum(tr_inv, is+(1-G%isd), ie+(1-G%isd), js+(1-G%jsd), je+(1-G%jsd)) |
| 940 | 0 | if (is_root_pe()) write(0,'(A,1X,A5,1X,ES25.16,1X,A)') & |
| 941 | 0 | "h-point: inventory", Reg%Tr(m)%name, total_inv, mesg |
| 942 | enddo | |
| 943 | ||
| 944 | 0 | end subroutine tracer_Reg_chkinv |
| 945 | ||
| 946 | ||
| 947 | !> Find a tracer in the tracer registry by name. | |
| 948 | 0 | subroutine tracer_name_lookup(Reg, n, tr_ptr, name) |
| 949 | type(tracer_registry_type), pointer :: Reg !< pointer to tracer registry | |
| 950 | type(tracer_type), pointer :: tr_ptr !< target or pointer to the tracer array | |
| 951 | character(len=32), intent(in) :: name !< tracer name | |
| 952 | integer, intent(out) :: n !< index to tracer registery | |
| 953 | ||
| 954 | 0 | do n=1,Reg%ntr |
| 955 | 0 | if (lowercase(Reg%Tr(n)%name) == lowercase(name)) then |
| 956 | 0 | tr_ptr => Reg%Tr(n) |
| 957 | 0 | return |
| 958 | endif | |
| 959 | enddo | |
| 960 | ||
| 961 | 0 | call MOM_error(FATAL,"MOM cannot find registered tracer: "//name) |
| 962 | ||
| 963 | end subroutine tracer_name_lookup | |
| 964 | ||
| 965 | !> Initialize the tracer registry. | |
| 966 | 1 | subroutine tracer_registry_init(param_file, Reg) |
| 967 | type(param_file_type), intent(in) :: param_file !< open file to parse for model parameters | |
| 968 | type(tracer_registry_type), pointer :: Reg !< pointer to tracer registry | |
| 969 | ||
| 970 | integer, save :: init_calls = 0 | |
| 971 | ||
| 972 | ! This include declares and sets the variable "version". | |
| 973 | #include "version_variable.h" | |
| 974 | character(len=40) :: mdl = "MOM_tracer_registry" ! This module's name. | |
| 975 | character(len=256) :: mesg ! Message for error messages. | |
| 976 | ||
| 977 | 51 | if (.not.associated(Reg)) then ; allocate(Reg) |
| 978 | 0 | else ; return ; endif |
| 979 | ||
| 980 | ! Read all relevant parameters and write them to the model log. | |
| 981 | 1 | call log_version(param_file, mdl, version, "", all_default=.true.) |
| 982 | ||
| 983 | 1 | init_calls = init_calls + 1 |
| 984 | 1 | if (init_calls > 1) then |
| 985 | write(mesg,'("tracer_registry_init called ",I0, & | |
| 986 | 0 | &" times with different registry pointers.")') init_calls |
| 987 | 0 | if (is_root_pe()) call MOM_error(WARNING,"MOM_tracer "//mesg) |
| 988 | endif | |
| 989 | ||
| 990 | end subroutine tracer_registry_init | |
| 991 | ||
| 992 | ||
| 993 | !> This routine closes the tracer registry module. | |
| 994 | 1 | subroutine tracer_registry_end(Reg) |
| 995 | type(tracer_registry_type), pointer :: Reg !< The tracer registry that will be deallocated | |
| 996 | 1 | if (associated(Reg)) deallocate(Reg) |
| 997 | 1 | end subroutine tracer_registry_end |
| 998 | ||
| 999 | 0 | end module MOM_tracer_registry |