From 91c9caa58bc8eeb006165f1a222eb6b4b549cfc0 Mon Sep 17 00:00:00 2001 From: sditkovsky <70655988+sditkovsky@users.noreply.github.com> Date: Tue, 16 Nov 2021 20:38:41 -0500 Subject: [PATCH] Merge gfdl updates (#2) * Add weighted d[uv]_dt_str diagnostics (#1539) This adds four new diagnostics building on the wind stress acceleration diagnostics du_dt_str, dv_dt_str (from #1437) - their thickness-weighted versions: h_du_dt_str, h_dv_dt_str (completing the set of diags from 3D thickness x momentum diagnostics #1398) - their viscous remnant fraction: du_dt_str_visc_rem, dv_dt_str_visc_rem (completing the set of diags from Visc_rem_[uv] multiplied momentum budget diagnostics ocean-eddy-cpt/MOM6#10) Nora did some quick tests with the CPT NeverWorld2 setup, which confirm that online and offline multiplication by 1) h or 2) visc_rem_[uv] coincide (up to 1) interpolation error and 2) numerical noise, respectively), and illustrated this beautifully with some figures that accompanied the first of the three commits that were squashed into one. * +Argument cleanup in vertical diffusivity code Cleaned up 26 falsely optional or unused arguments in the vertical diffusivity code, and related changes. Several descriptive comments were also corrected, including the correction of the units of 10 variables related to CVMix_KPP. This commit includes: - Made the Kd_int arguments to set_diffusivity() and 3 subsidiary routines mandatory and reordered the arguments so that the non-optional arguments come before the grid types - Made the halo_TS and double_diffuse arguments to set_diffusivity_init() mandatory. - Made the Time argument to ALE_sponge() mandatory. - Made the Kd and Kv arguments to calculate_CVMIX_conv() mandatory. - Removed the unused halo argument to adjust_salt(). - Removed the unused Kddt_convect argument to full_convection(). - Made the halo arguments to full_convection()and smoothed_dRdT_dRdS() mandatory. - Made the useALEalgorithm argument to geothermal_init() mandatory. - Removed the unused initialize_all arguments to Calculate_kappa_shear() and Calc_kappa_shear_vertex(). - Removed the unused I_Ld2_1d and dz_Int_1d arguments to kappa_shear_column(). - Made 3 arguments to calculate_projected_state() mandatory and reordered the arguments accordingly. - Eliminating the unused skip_diags arguments to calculateBuoyancyFlux() and extractFluxes(), which are now effectively always false. All answers are bitwise identical, and no output is changed. * +Move rotate_dyn_horgrid to MOM_dyn_horgrid module Moved the routine rotate_dyngrid() from the MOM_transcribe_grid module to rotate_dyn_horgrid() in the MOM_dyn_horgrid module so that this routine can also be used at some point by SIS2 to implement rotational consistency testing, and also to reflect that this routine only works with types from its new module. The two routines are the same apart from some added comments, and the old name of rotate_dyngrid() is still available from MOM_transcribe_grid via a module use statement. All answers are bitwise identical. * +Reduce use of dyn_horgrid in initialize_MOM Minimized the dependence on dyn_horgrid in initialize_MOM by working directly with the horizontal index type whereever possible and by moving the calls that create the MOM_grid_type earlier in the routine, to limit the duration of the dyn_horgrid_type, and to better co-locate grid-related parameters in the parameter_doc files. Also uses the new interface to rotate_dyn_horgrid from the MOM_dyn_horgrid module in place of the rotate_dyngrid interface from the MOM_transcribe_grid module. All answers are bitwise identical, but the order of some entries in the MOM_parameter_doc files has changed. * (*)Fix compile-time issues with MOM_sum_driver.F90 Modified drivers/unit_drivers/MOM_sum_driver.F90 to compile with the latest version of the rest of the MOM6 code by using the proper types in the various initialization calls, and verified that it runs as intended. Co-authored-by: Nora Loose Co-authored-by: Robert Hallberg --- .../drivers/unit_drivers/MOM_sum_driver.F90 | 39 ++-- src/core/MOM.F90 | 94 ++++---- src/core/MOM_forcing_type.F90 | 43 ++-- src/core/MOM_transcribe_grid.F90 | 111 +-------- src/framework/MOM_dyn_horgrid.F90 | 98 +++++++- .../vertical/MOM_ALE_sponge.F90 | 7 +- .../vertical/MOM_CVMix_KPP.F90 | 8 +- .../vertical/MOM_CVMix_conv.F90 | 28 +-- .../vertical/MOM_diabatic_aux.F90 | 8 +- .../vertical/MOM_diabatic_driver.F90 | 71 +++--- .../vertical/MOM_full_convection.F90 | 59 ++--- .../vertical/MOM_geothermal.F90 | 6 +- .../vertical/MOM_kappa_shear.F90 | 181 ++++++--------- .../vertical/MOM_set_diffusivity.F90 | 217 +++++++----------- .../vertical/MOM_vert_friction.F90 | 76 ++++++ 15 files changed, 493 insertions(+), 553 deletions(-) diff --git a/config_src/drivers/unit_drivers/MOM_sum_driver.F90 b/config_src/drivers/unit_drivers/MOM_sum_driver.F90 index 7e3c6d45b4..7291eb913a 100644 --- a/config_src/drivers/unit_drivers/MOM_sum_driver.F90 +++ b/config_src/drivers/unit_drivers/MOM_sum_driver.F90 @@ -18,13 +18,14 @@ program MOM_main use MOM_coms, only : EFP_type, operator(+), operator(-), assignment(=), EFP_to_real, real_to_EFP use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end use MOM_cpu_clock, only : CLOCK_COMPONENT - use MOM_domains, only : MOM_domains_init, MOM_infra_init, MOM_infra_end + use MOM_domains, only : MOM_domain_type, MOM_domains_init, MOM_infra_init, MOM_infra_end + use MOM_dyn_horgrid, only : dyn_horgrid_type, create_dyn_horgrid, destroy_dyn_horgrid use MOM_error_handler, only : MOM_error, MOM_mesg, WARNING, FATAL, is_root_pe use MOM_error_handler, only : MOM_set_verbosity use MOM_file_parser, only : read_param, get_param, log_param, log_version, param_file_type use MOM_file_parser, only : open_param_file, close_param_file - use MOM_grid, only : MOM_grid_init, ocean_grid_type use MOM_grid_initialize, only : set_grid_metrics + use MOM_hor_index, only : hor_index_type, hor_index_init use MOM_io, only : MOM_io_init, file_exists, open_file, close_file use MOM_io, only : check_nml_error, io_infra_init, io_infra_end use MOM_io, only : APPEND_FILE, ASCII_FILE, READONLY_FILE, SINGLE_FILE @@ -33,9 +34,10 @@ program MOM_main #include - type(ocean_grid_type) :: grid ! A structure containing metrics and grid info. - - type(param_file_type) :: param_file ! The structure indicating the file(s) + type(MOM_domain_type), pointer :: Domain => NULL() !< Ocean model domain + type(dyn_horgrid_type), pointer :: grid => NULL() ! A structure containing metrics and grid info + type(hor_index_type) :: HI ! A hor_index_type for array extents + type(param_file_type) :: param_file ! The structure indicating the file(s) ! containing all run-time parameters. real :: max_depth ! The maximum ocean depth [m] integer :: verbosity @@ -76,14 +78,16 @@ program MOM_main verbosity = 2 ; call read_param(param_file, "VERBOSITY", verbosity) call MOM_set_verbosity(verbosity) - call MOM_domains_init(grid%domain, param_file) + call MOM_domains_init(Domain, param_file) call MOM_io_init(param_file) ! call diag_mediator_init(param_file) - call MOM_grid_init(grid, param_file) + call hor_index_init(Domain, HI, param_file) + call create_dyn_horgrid(grid, HI) + grid%Domain => Domain - is = grid%isc ; ie = grid%iec ; js = grid%jsc ; je = grid%jec - isd = grid%isd ; ied = grid%ied ; jsd = grid%jsd ; jed = grid%jed + is = HI%isc ; ie = HI%iec ; js = HI%jsc ; je = HI%jec + isd = HI%isd ; ied = HI%ied ; jsd = HI%jsd ; jed = HI%jed ! Read all relevant parameters and write them to the model log. call log_version(param_file, "MOM", version, "") @@ -99,7 +103,7 @@ program MOM_main allocate(depth_tot_std(num_sums)) ; depth_tot_std(:) = 0.0 allocate(depth_tot_fastR(num_sums)) ; depth_tot_fastR(:) = 0.0 -! Set up the parameters of the physical domain (i.e. the grid), G +! Set up the parameters of the physical grid call set_grid_metrics(grid, param_file) ! Set up the bottom depth, grid%bathyT either analytically or from file @@ -157,14 +161,16 @@ program MOM_main endif enddo + call destroy_dyn_horgrid(grid) call io_infra_end ; call MOM_infra_end contains !> This subroutine sets up the benchmark test case topography for debugging subroutine benchmark_init_topog_local(D, G, param_file, max_depth) - type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure - real, dimension(SZI_(G),SZJ_(G)), intent(out) :: D !< The ocean bottom depth in m + type(dyn_horgrid_type), intent(in) :: G !< The dynamic horizontal grid type + real, dimension(G%isd:G%ied,G%jsd:G%jed), & + intent(out) :: D !< Ocean bottom depth in m or [Z ~> m] if US is present type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters real, intent(in) :: max_depth !< The maximum ocean depth [m] @@ -172,6 +178,7 @@ subroutine benchmark_init_topog_local(D, G, param_file, max_depth) real :: PI ! 3.1415926... calculated as 4*atan(1) real :: D0 ! A constant to make the maximum ! ! basin depth MAXIMUM_DEPTH. ! + real :: m_to_Z ! A dimensional rescaling factor. real :: x, y ! This include declares and sets the variable "version". # include "version_variable.h" @@ -180,12 +187,14 @@ subroutine benchmark_init_topog_local(D, G, param_file, max_depth) is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed - call log_version(param_file, mdl, version) + m_to_Z = 1.0 ! ; if (present(US)) m_to_Z = US%m_to_Z + + call log_version(param_file, mdl, version, "") call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, & - "The minimum depth of the ocean.", units="m", default=0.0) + "The minimum depth of the ocean.", units="m", default=0.0, scale=m_to_Z) PI = 4.0*atan(1.0) - D0 = max_depth / 0.5; + D0 = max_depth / 0.5 ! Calculate the depth of the bottom. do i=is,ie ; do j=js,je diff --git a/src/core/MOM.F90 b/src/core/MOM.F90 index ba2863a7f7..186c972b5e 100644 --- a/src/core/MOM.F90 +++ b/src/core/MOM.F90 @@ -75,6 +75,7 @@ module MOM use MOM_dynamics_unsplit_RK2, only : initialize_dyn_unsplit_RK2, end_dyn_unsplit_RK2 use MOM_dynamics_unsplit_RK2, only : MOM_dyn_unsplit_RK2_CS use MOM_dyn_horgrid, only : dyn_horgrid_type, create_dyn_horgrid, destroy_dyn_horgrid +use MOM_dyn_horgrid, only : rotate_dyn_horgrid use MOM_EOS, only : EOS_init, calculate_density, calculate_TFreeze, EOS_domain use MOM_fixed_initialization, only : MOM_initialize_fixed use MOM_forcing_type, only : allocate_forcing_type, allocate_mech_forcing @@ -123,7 +124,6 @@ module MOM use MOM_tracer_flow_control, only : tracer_flow_control_init, call_tracer_surface_state use MOM_tracer_flow_control, only : tracer_flow_control_end use MOM_transcribe_grid, only : copy_dyngrid_to_MOM_grid, copy_MOM_grid_to_dyngrid -use MOM_transcribe_grid, only : rotate_dyngrid use MOM_unit_scaling, only : unit_scale_type, unit_scaling_init use MOM_unit_scaling, only : unit_scaling_end, fix_restart_unit_scaling use MOM_variables, only : surface, allocate_surface_state, deallocate_surface_state @@ -1714,7 +1714,7 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & type(hor_index_type), pointer :: HI => NULL() ! A hor_index_type for array extents type(hor_index_type), target :: HI_in ! HI on the input grid type(verticalGrid_type), pointer :: GV => NULL() - type(dyn_horgrid_type), pointer :: dG => NULL() + type(dyn_horgrid_type), pointer :: dG => NULL(), test_dG => NULL() type(dyn_horgrid_type), pointer :: dG_in => NULL() type(diag_ctrl), pointer :: diag => NULL() type(unit_scale_type), pointer :: US => NULL() @@ -2174,8 +2174,7 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & ! Swap axes for quarter and 3-quarter turns if (CS%rotate_index) then allocate(CS%G) - call clone_MOM_domain(G_in%Domain, CS%G%Domain, turns=turns, & - domain_name="MOM_rot") + call clone_MOM_domain(G_in%Domain, CS%G%Domain, turns=turns, domain_name="MOM_rot") first_direction = modulo(first_direction + turns, 2) else CS%G => G_in @@ -2200,19 +2199,34 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & local_indexing=.not.global_indexing) call create_dyn_horgrid(dG_in, HI_in, bathymetry_at_vel=bathy_at_vel) call clone_MOM_domain(G_in%Domain, dG_in%Domain) + ! Also allocate the input ocean_grid_type type at this point based on the same information. + call MOM_grid_init(G_in, param_file, US, HI_in, bathymetry_at_vel=bathy_at_vel) ! Allocate initialize time-invariant MOM variables. call MOM_initialize_fixed(dG_in, US, OBC_in, param_file, .false., dirs%output_directory) + ! Copy the grid metrics and bathymetry to the ocean_grid_type + call copy_dyngrid_to_MOM_grid(dG_in, G_in, US) + call callTree_waypoint("returned from MOM_initialize_fixed() (initialize_MOM)") - ! Determine HI and dG for the model index map. + call verticalGridInit( param_file, CS%GV, US ) + GV => CS%GV + + ! Shift from using the temporary dynamic grid type to using the final (potentially static) + ! and properly rotated ocean-specific grid type and horizontal index type. if (CS%rotate_index) then allocate(HI) call rotate_hor_index(HI_in, turns, HI) + ! NOTE: If indices are rotated, then G and G_in must both be initialized separately, and + ! the dynamic grid must be created to handle the grid rotation. G%domain has already been + ! initialzed above. + call MOM_grid_init(G, param_file, US, HI, bathymetry_at_vel=bathy_at_vel) call create_dyn_horgrid(dG, HI, bathymetry_at_vel=bathy_at_vel) call clone_MOM_domain(G%Domain, dG%Domain) - call rotate_dyngrid(dG_in, dG, US, turns) + call rotate_dyn_horgrid(dG_in, dG, US, turns) + call copy_dyngrid_to_MOM_grid(dG, G, US) + if (associated(OBC_in)) then ! TODO: General OBC index rotations is not yet supported. if (modulo(turns, 4) /= 1) & @@ -2220,18 +2234,15 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & allocate(CS%OBC) call rotate_OBC_config(OBC_in, dG_in, CS%OBC, dG, turns) endif + + call destroy_dyn_horgrid(dG) else + ! If not rotated, then G_in and G are the same grid. HI => HI_in - dG => dG_in + G => G_in CS%OBC => OBC_in endif - - call verticalGridInit( param_file, CS%GV, US ) - GV => CS%GV - - ! Allocate the auxiliary non-symmetric domain for debugging or I/O purposes. - if (CS%debug .or. dG%symmetric) & - call clone_MOM_domain(dG%Domain, dG%Domain_aux, symmetric=.false.) + ! dG_in is retained for now so that it can be used with write_ocean_geometry_file() below. call callTree_waypoint("grids initialized (initialize_MOM)") @@ -2240,9 +2251,9 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & call tracer_registry_init(param_file, CS%tracer_Reg) ! Allocate and initialize space for the primary time-varying MOM variables. - is = dG%isc ; ie = dG%iec ; js = dG%jsc ; je = dG%jec ; nz = GV%ke - isd = dG%isd ; ied = dG%ied ; jsd = dG%jsd ; jed = dG%jed - IsdB = dG%IsdB ; IedB = dG%IedB ; JsdB = dG%JsdB ; JedB = dG%JedB + is = HI%isc ; ie = HI%iec ; js = HI%jsc ; je = HI%jec ; nz = GV%ke + isd = HI%isd ; ied = HI%ied ; jsd = HI%jsd ; jed = HI%jed + IsdB = HI%IsdB ; IedB = HI%IedB ; JsdB = HI%JsdB ; JedB = HI%JedB ALLOC_(CS%u(IsdB:IedB,jsd:jed,nz)) ; CS%u(:,:,:) = 0.0 ALLOC_(CS%v(isd:ied,JsdB:JedB,nz)) ; CS%v(:,:,:) = 0.0 ALLOC_(CS%h(isd:ied,jsd:jed,nz)) ; CS%h(:,:,:) = GV%Angstrom_H @@ -2279,12 +2290,12 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & else conv2salt = GV%H_to_kg_m2 endif - call register_tracer(CS%tv%T, CS%tracer_Reg, param_file, dG%HI, GV, & + call register_tracer(CS%tv%T, CS%tracer_Reg, param_file, HI, GV, & tr_desc=vd_T, registry_diags=.true., flux_nameroot='T', & flux_units='W', flux_longname='Heat', & flux_scale=conv2watt, convergence_units='W m-2', & convergence_scale=conv2watt, CMOR_tendprefix="opottemp", diag_form=2) - call register_tracer(CS%tv%S, CS%tracer_Reg, param_file, dG%HI, GV, & + call register_tracer(CS%tv%S, CS%tracer_Reg, param_file, HI, GV, & tr_desc=vd_S, registry_diags=.true., flux_nameroot='S', & flux_units=S_flux_units, flux_longname='Salt', & flux_scale=conv2salt, convergence_units='kg m-2 s-1', & @@ -2364,24 +2375,24 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & call restart_init(param_file, restart_CSp) call set_restart_fields(GV, US, param_file, CS, restart_CSp) if (CS%split) then - call register_restarts_dyn_split_RK2(dG%HI, GV, param_file, & + call register_restarts_dyn_split_RK2(HI, GV, param_file, & CS%dyn_split_RK2_CSp, restart_CSp, CS%uh, CS%vh) elseif (CS%use_RK2) then - call register_restarts_dyn_unsplit_RK2(dG%HI, GV, param_file, & + call register_restarts_dyn_unsplit_RK2(HI, GV, param_file, & CS%dyn_unsplit_RK2_CSp, restart_CSp) else - call register_restarts_dyn_unsplit(dG%HI, GV, param_file, & + call register_restarts_dyn_unsplit(HI, GV, param_file, & CS%dyn_unsplit_CSp, restart_CSp) endif ! This subroutine calls user-specified tracer registration routines. ! Additional calls can be added to MOM_tracer_flow_control.F90. - call call_tracer_register(dG%HI, GV, US, param_file, CS%tracer_flow_CSp, & + call call_tracer_register(HI, GV, US, param_file, CS%tracer_flow_CSp, & CS%tracer_Reg, restart_CSp) - call MEKE_alloc_register_restart(dG%HI, param_file, CS%MEKE, restart_CSp) - call set_visc_register_restarts(dG%HI, GV, param_file, CS%visc, restart_CSp) - call mixedlayer_restrat_register_restarts(dG%HI, param_file, & + call MEKE_alloc_register_restart(HI, param_file, CS%MEKE, restart_CSp) + call set_visc_register_restarts(HI, GV, param_file, CS%visc, restart_CSp) + call mixedlayer_restrat_register_restarts(HI, param_file, & CS%mixedlayer_restrat_CSp, restart_CSp) if (CS%rotate_index .and. associated(OBC_in) .and. use_temperature) then @@ -2410,33 +2421,16 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & ! This needs the number of tracers and to have called any code that sets whether ! reservoirs are used. - call open_boundary_register_restarts(dg%HI, GV, CS%OBC, CS%tracer_Reg, & + call open_boundary_register_restarts(HI, GV, CS%OBC, CS%tracer_Reg, & param_file, restart_CSp, use_temperature) endif call callTree_waypoint("restart registration complete (initialize_MOM)") call restart_registry_lock(restart_CSp) - ! Shift from using the temporary dynamic grid type to using the final - ! (potentially static) ocean-specific grid type. - ! The next line would be needed if G%Domain had not already been init'd above: - ! call clone_MOM_domain(dG%Domain, G%Domain) - - ! NOTE: If indices are rotated, then G and G_in must both be initialized. - ! If not rotated, then G_in and G are the same grid. - if (CS%rotate_index) then - call MOM_grid_init(G, param_file, US, HI, bathymetry_at_vel=bathy_at_vel) - call copy_dyngrid_to_MOM_grid(dG, G, US) - call destroy_dyn_horgrid(dG) - endif - call MOM_grid_init(G_in, param_file, US, HI_in, bathymetry_at_vel=bathy_at_vel) - call copy_dyngrid_to_MOM_grid(dG_in, G_in, US) - if (.not. CS%rotate_index) G => G_in - + ! Write out all of the grid data used by this run. new_sim = determine_is_new_run(dirs%input_filename, dirs%restart_input_dir, G_in, restart_CSp) write_geom_files = ((write_geom==2) .or. ((write_geom==1) .and. new_sim)) - - ! Write out all of the grid data used by this run. if (write_geom_files) call write_ocean_geometry_file(dG_in, param_file, dirs%output_directory, US=US) call destroy_dyn_horgrid(dG_in) @@ -2562,16 +2556,16 @@ subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, restart_CSp, & if (test_grid_copy) then ! Copy the data from the temporary grid to the dyn_hor_grid to CS%G. - call create_dyn_horgrid(dG, G%HI) - call clone_MOM_domain(G%Domain, dG%Domain) + call create_dyn_horgrid(test_dG, G%HI) + call clone_MOM_domain(G%Domain, test_dG%Domain) call clone_MOM_domain(G%Domain, CS%G%Domain) call MOM_grid_init(CS%G, param_file, US) - call copy_MOM_grid_to_dyngrid(G, dg, US) - call copy_dyngrid_to_MOM_grid(dg, CS%G, US) + call copy_MOM_grid_to_dyngrid(G, test_dG, US) + call copy_dyngrid_to_MOM_grid(test_dG, CS%G, US) - call destroy_dyn_horgrid(dG) + call destroy_dyn_horgrid(test_dG) call MOM_grid_end(G) ; deallocate(G) G => CS%G diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index 2429ce9d2d..a67d440dfe 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -390,7 +390,7 @@ subroutine extractFluxes1d(G, GV, US, fluxes, optics, nsw, j, dt, & FluxRescaleDepth, useRiverHeatContent, useCalvingHeatContent, & h, T, netMassInOut, netMassOut, net_heat, net_salt, pen_SW_bnd, tv, & aggregate_FW, nonpenSW, netmassInOut_rate, net_Heat_Rate, & - net_salt_rate, pen_sw_bnd_Rate, skip_diags) + net_salt_rate, pen_sw_bnd_Rate) type(ocean_grid_type), intent(in) :: G !< ocean grid structure type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure @@ -452,7 +452,6 @@ subroutine extractFluxes1d(G, GV, US, fluxes, optics, nsw, j, dt, & real, dimension(max(1,nsw),G%isd:G%ied), & optional, intent(out) :: pen_sw_bnd_rate !< Rate of penetrative shortwave heating !! [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]. - logical, optional, intent(in) :: skip_diags !< If present and true, skip calculating diagnostics ! local real :: htot(SZI_(G)) ! total ocean depth [H ~> m or kg m-2] @@ -492,7 +491,6 @@ subroutine extractFluxes1d(G, GV, US, fluxes, optics, nsw, j, dt, & is = G%isc ; ie = G%iec ; nz = GV%ke calculate_diags = .true. - if (present(skip_diags)) calculate_diags = .not. skip_diags ! error checking @@ -914,7 +912,7 @@ end subroutine extractFluxes2d !! extractFluxes routine allows us to get "stuf per time" rather than the time integrated !! fluxes needed in other routines that call extractFluxes. subroutine calculateBuoyancyFlux1d(G, GV, US, fluxes, optics, nsw, h, Temp, Salt, tv, j, & - buoyancyFlux, netHeatMinusSW, netSalt, skip_diags) + buoyancyFlux, netHeatMinusSW, netSalt) type(ocean_grid_type), intent(in) :: G !< ocean grid type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -928,12 +926,11 @@ subroutine calculateBuoyancyFlux1d(G, GV, US, fluxes, optics, nsw, h, Temp, Salt type(thermo_var_ptrs), intent(inout) :: tv !< thermodynamics type integer, intent(in) :: j !< j-row to work on real, dimension(SZI_(G),SZK_(GV)+1), intent(inout) :: buoyancyFlux !< buoyancy fluxes [L2 T-3 ~> m2 s-3] - real, dimension(SZI_(G)), intent(inout) :: netHeatMinusSW !< surf Heat flux + real, dimension(SZI_(G)), intent(inout) :: netHeatMinusSW !< Surface heat flux excluding shortwave !! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] - real, dimension(SZI_(G)), intent(inout) :: netSalt !< surf salt flux + real, dimension(SZI_(G)), intent(inout) :: netSalt !< surface salt flux !! [ppt H s-1 ~> ppt m s-1 or ppt kg m-2 s-1] - logical, optional, intent(in) :: skip_diags !< If present and true, skip calculating - !! diagnostics inside extractFluxes1d() + ! local variables integer :: k real, parameter :: dt = 1. ! to return a rate from extractFluxes1d @@ -942,12 +939,12 @@ subroutine calculateBuoyancyFlux1d(G, GV, US, fluxes, optics, nsw, h, Temp, Salt ! [H s-1 ~> m s-1 or kg m-2 s-1] real, dimension(SZI_(G)) :: netHeat ! net temp flux [degC H s-1 ~> degC m s-2 or degC kg m-2 s-1] real, dimension(max(nsw,1), SZI_(G)) :: penSWbnd ! penetrating SW radiation by band - ! [degC H ~> degC m or degC kg m-2] + ! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] real, dimension(SZI_(G)) :: pressure ! pressure at the surface [R L2 T-2 ~> Pa] real, dimension(SZI_(G)) :: dRhodT ! density partial derivative wrt temp [R degC-1 ~> kg m-3 degC-1] real, dimension(SZI_(G)) :: dRhodS ! density partial derivative wrt saln [R ppt-1 ~> kg m-3 ppt-1] real, dimension(SZI_(G),SZK_(GV)+1) :: netPen ! The net penetrating shortwave radiation at each level - ! [degC H ~> degC m or degC kg m-2] + ! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] logical :: useRiverHeatContent logical :: useCalvingHeatContent @@ -978,7 +975,7 @@ subroutine calculateBuoyancyFlux1d(G, GV, US, fluxes, optics, nsw, h, Temp, Salt call extractFluxes1d(G, GV, US, fluxes, optics, nsw, j, dt*US%s_to_T, & depthBeforeScalingFluxes, useRiverHeatContent, useCalvingHeatContent, & h(:,j,:), Temp(:,j,:), netH, netEvap, netHeatMinusSW, & - netSalt, penSWbnd, tv, .false., skip_diags=skip_diags) + netSalt, penSWbnd, tv, .false.) ! Sum over bands and attenuate as a function of depth ! netPen is the netSW as a function of depth @@ -1011,7 +1008,7 @@ end subroutine calculateBuoyancyFlux1d !> Calculates surface buoyancy flux by adding up the heat, FW and salt fluxes, !! for 2d arrays. This is a wrapper for calculateBuoyancyFlux1d. subroutine calculateBuoyancyFlux2d(G, GV, US, fluxes, optics, h, Temp, Salt, tv, & - buoyancyFlux, netHeatMinusSW, netSalt, skip_diags) + buoyancyFlux, netHeatMinusSW, netSalt) type(ocean_grid_type), intent(in) :: G !< ocean grid type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -1021,26 +1018,18 @@ subroutine calculateBuoyancyFlux2d(G, GV, US, fluxes, optics, h, Temp, Salt, tv, real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: Temp !< temperature [degC] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: Salt !< salinity [ppt] type(thermo_var_ptrs), intent(inout) :: tv !< thermodynamics type - real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(inout) :: buoyancyFlux !< buoyancy fluxes [L2 T-3 ~> m2 s-3] - real, dimension(SZI_(G),SZJ_(G)), optional, intent(inout) :: netHeatMinusSW !< surf temp flux - !! [degC H ~> degC m or degC kg m-2] - real, dimension(SZI_(G),SZJ_(G)), optional, intent(inout) :: netSalt !< surf salt flux - !! [ppt H ~> ppt m or ppt kg m-2] - logical, optional, intent(in) :: skip_diags !< If present and true, skip calculating - !! diagnostics inside extractFluxes1d() + real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(inout) :: buoyancyFlux !< buoyancy fluxes [L2 T-3 ~> m2 s-3] + real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: netHeatMinusSW !< surface heat flux excluding shortwave + !! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] + real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: netSalt !< Net surface salt flux + !! [ppt H s-1 ~> ppt m s-1 or ppt kg m-2 s-1] ! local variables - real, dimension( SZI_(G) ) :: netT ! net temperature flux [degC H s-1 ~> degC m s-2 or degC kg m-2 s-1] - real, dimension( SZI_(G) ) :: netS ! net saln flux !! [ppt H s-1 ~> ppt m s-1 or ppt kg m-2 s-1] integer :: j - netT(G%isc:G%iec) = 0. ; netS(G%isc:G%iec) = 0. - - !$OMP parallel do default(shared) firstprivate(netT,netS) + !$OMP parallel do default(shared) do j=G%jsc,G%jec call calculateBuoyancyFlux1d(G, GV, US, fluxes, optics, optics_nbands(optics), h, Temp, Salt, & - tv, j, buoyancyFlux(:,j,:), netT, netS, skip_diags=skip_diags) - if (present(netHeatMinusSW)) netHeatMinusSW(G%isc:G%iec,j) = netT(G%isc:G%iec) - if (present(netSalt)) netSalt(G%isc:G%iec,j) = netS(G%isc:G%iec) + tv, j, buoyancyFlux(:,j,:), netHeatMinusSW(:,j), netSalt(:,j)) enddo end subroutine calculateBuoyancyFlux2d diff --git a/src/core/MOM_transcribe_grid.F90 b/src/core/MOM_transcribe_grid.F90 index faa894d968..e19df5b6c6 100644 --- a/src/core/MOM_transcribe_grid.F90 +++ b/src/core/MOM_transcribe_grid.F90 @@ -4,14 +4,14 @@ module MOM_transcribe_grid ! This file is part of MOM6. See LICENSE.md for the license. -use MOM_array_transform, only: rotate_array, rotate_array_pair -use MOM_domains, only : pass_var, pass_vector -use MOM_domains, only : To_All, SCALAR_PAIR, CGRID_NE, AGRID, BGRID_NE, CORNER -use MOM_dyn_horgrid, only : dyn_horgrid_type, set_derived_dyn_horgrid -use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING -use MOM_grid, only : ocean_grid_type, set_derived_metrics -use MOM_unit_scaling, only : unit_scale_type - +use MOM_array_transform, only : rotate_array, rotate_array_pair +use MOM_domains, only : pass_var, pass_vector +use MOM_domains, only : To_All, SCALAR_PAIR, CGRID_NE, AGRID, BGRID_NE, CORNER +use MOM_dyn_horgrid, only : dyn_horgrid_type, set_derived_dyn_horgrid +use MOM_dyn_horgrid, only : rotate_dyngrid=>rotate_dyn_horgrid +use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING +use MOM_grid, only : ocean_grid_type, set_derived_metrics +use MOM_unit_scaling, only : unit_scale_type implicit none ; private @@ -325,99 +325,4 @@ subroutine copy_MOM_grid_to_dyngrid(oG, dG, US) end subroutine copy_MOM_grid_to_dyngrid -subroutine rotate_dyngrid(G_in, G, US, turns) - type(dyn_horgrid_type), intent(in) :: G_in !< Common horizontal grid type - type(dyn_horgrid_type), intent(inout) :: G !< Ocean grid type - type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - integer, intent(in) :: turns !< Number of quarter turns - - integer :: jsc, jec, jscB, jecB - integer :: qturn - - ! Center point - call rotate_array(G_in%geoLonT, turns, G%geoLonT) - call rotate_array(G_in%geoLatT, turns, G%geoLatT) - call rotate_array_pair(G_in%dxT, G_in%dyT, turns, G%dxT, G%dyT) - call rotate_array(G_in%areaT, turns, G%areaT) - call rotate_array(G_in%bathyT, turns, G%bathyT) - - call rotate_array_pair(G_in%df_dx, G_in%df_dy, turns, G%df_dx, G%df_dy) - call rotate_array(G_in%sin_rot, turns, G%sin_rot) - call rotate_array(G_in%cos_rot, turns, G%cos_rot) - call rotate_array(G_in%mask2dT, turns, G%mask2dT) - - ! Face point - call rotate_array_pair(G_in%geoLonCu, G_in%geoLonCv, turns, & - G%geoLonCu, G%geoLonCv) - call rotate_array_pair(G_in%geoLatCu, G_in%geoLatCv, turns, & - G%geoLatCu, G%geoLatCv) - call rotate_array_pair(G_in%dxCu, G_in%dyCv, turns, G%dxCu, G%dyCv) - call rotate_array_pair(G_in%dxCv, G_in%dyCu, turns, G%dxCv, G%dyCu) - call rotate_array_pair(G_in%dx_Cv, G_in%dy_Cu, turns, G%dx_Cv, G%dy_Cu) - - call rotate_array_pair(G_in%porous_DminV, G_in%porous_DminU, turns, & - G%porous_DminV, G%porous_DminU) - call rotate_array_pair(G_in%porous_DmaxV, G_in%porous_DmaxU, turns, & - G%porous_DmaxV, G%porous_DmaxU) - call rotate_array_pair(G_in%porous_DavgV, G_in%porous_DavgU, turns, & - G%porous_DavgV, G%porous_DavgU) - - call rotate_array_pair(G_in%mask2dCu, G_in%mask2dCv, turns, & - G%mask2dCu, G%mask2dCv) - call rotate_array_pair(G_in%areaCu, G_in%areaCv, turns, & - G%areaCu, G%areaCv) - call rotate_array_pair(G_in%IareaCu, G_in%IareaCv, turns, & - G%IareaCu, G%IareaCv) - - ! Vertex point - call rotate_array(G_in%geoLonBu, turns, G%geoLonBu) - call rotate_array(G_in%geoLatBu, turns, G%geoLatBu) - call rotate_array_pair(G_in%dxBu, G_in%dyBu, turns, G%dxBu, G%dyBu) - call rotate_array(G_in%areaBu, turns, G%areaBu) - call rotate_array(G_in%CoriolisBu, turns, G%CoriolisBu) - call rotate_array(G_in%mask2dBu, turns, G%mask2dBu) - - ! Topographic - G%bathymetry_at_vel = G_in%bathymetry_at_vel - if (G%bathymetry_at_vel) then - call rotate_array_pair(G_in%Dblock_u, G_in%Dblock_v, turns, & - G%Dblock_u, G%Dblock_v) - call rotate_array_pair(G_in%Dopen_u, G_in%Dopen_v, turns, & - G%Dopen_u, G%Dopen_v) - endif - - ! Nominal grid axes - ! TODO: We should not assign lat values to the lon axis, and vice versa. - ! We temporarily copy lat <-> lon since several components still expect - ! lat and lon sizes to match the first and second dimension sizes. - ! But we ought to instead leave them unchanged and adjust the references to - ! these axes. - if (modulo(turns, 2) /= 0) then - G%gridLonT(:) = G_in%gridLatT(G_in%jeg:G_in%jsg:-1) - G%gridLatT(:) = G_in%gridLonT(:) - G%gridLonB(:) = G_in%gridLatB(G_in%jeg:(G_in%jsg-1):-1) - G%gridLatB(:) = G_in%gridLonB(:) - else - G%gridLonT(:) = G_in%gridLonT(:) - G%gridLatT(:) = G_in%gridLatT(:) - G%gridLonB(:) = G_in%gridLonB(:) - G%gridLatB(:) = G_in%gridLatB(:) - endif - - G%x_axis_units = G_in%y_axis_units - G%y_axis_units = G_in%x_axis_units - G%south_lat = G_in%south_lat - G%west_lon = G_in%west_lon - G%len_lat = G_in%len_lat - G%len_lon = G_in%len_lon - - ! Rotation-invariant fields - G%areaT_global = G_in%areaT_global - G%IareaT_global = G_in%IareaT_global - G%Rad_Earth = G_in%Rad_Earth - G%max_depth = G_in%max_depth - - call set_derived_dyn_horgrid(G, US) -end subroutine rotate_dyngrid - end module MOM_transcribe_grid diff --git a/src/framework/MOM_dyn_horgrid.F90 b/src/framework/MOM_dyn_horgrid.F90 index 67659cbefd..49d3dc01c7 100644 --- a/src/framework/MOM_dyn_horgrid.F90 +++ b/src/framework/MOM_dyn_horgrid.F90 @@ -4,15 +4,16 @@ module MOM_dyn_horgrid ! This file is part of MOM6. See LICENSE.md for the license. -use MOM_hor_index, only : hor_index_type -use MOM_domains, only : MOM_domain_type, deallocate_MOM_domain -use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING -use MOM_unit_scaling, only : unit_scale_type +use MOM_array_transform, only : rotate_array, rotate_array_pair +use MOM_domains, only : MOM_domain_type, deallocate_MOM_domain +use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING +use MOM_hor_index, only : hor_index_type +use MOM_unit_scaling, only : unit_scale_type implicit none ; private public create_dyn_horgrid, destroy_dyn_horgrid, set_derived_dyn_horgrid -public rescale_dyn_horgrid_bathymetry +public rescale_dyn_horgrid_bathymetry, rotate_dyn_horgrid ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with @@ -298,6 +299,93 @@ subroutine create_dyn_horgrid(G, HI, bathymetry_at_vel) end subroutine create_dyn_horgrid + +!> Copy the rotated contents of one horizontal grid type into another. The input +!! and output grid type arguments can not use the same object. +subroutine rotate_dyn_horgrid(G_in, G, US, turns) + type(dyn_horgrid_type), intent(in) :: G_in !< The input horizontal grid type + type(dyn_horgrid_type), intent(inout) :: G !< An output rotated horizontal grid type + !! that has already been allocated, but whose + !! contents are largely replaced here. + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type + integer, intent(in) :: turns !< Number of quarter turns + + integer :: jsc, jec, jscB, jecB + integer :: qturn + + ! Center point + call rotate_array(G_in%geoLonT, turns, G%geoLonT) + call rotate_array(G_in%geoLatT, turns, G%geoLatT) + call rotate_array_pair(G_in%dxT, G_in%dyT, turns, G%dxT, G%dyT) + call rotate_array(G_in%areaT, turns, G%areaT) + call rotate_array(G_in%bathyT, turns, G%bathyT) + + call rotate_array_pair(G_in%df_dx, G_in%df_dy, turns, G%df_dx, G%df_dy) + call rotate_array(G_in%sin_rot, turns, G%sin_rot) + call rotate_array(G_in%cos_rot, turns, G%cos_rot) + call rotate_array(G_in%mask2dT, turns, G%mask2dT) + + ! Face points + call rotate_array_pair(G_in%geoLonCu, G_in%geoLonCv, turns, G%geoLonCu, G%geoLonCv) + call rotate_array_pair(G_in%geoLatCu, G_in%geoLatCv, turns, G%geoLatCu, G%geoLatCv) + call rotate_array_pair(G_in%dxCu, G_in%dyCv, turns, G%dxCu, G%dyCv) + call rotate_array_pair(G_in%dxCv, G_in%dyCu, turns, G%dxCv, G%dyCu) + call rotate_array_pair(G_in%dx_Cv, G_in%dy_Cu, turns, G%dx_Cv, G%dy_Cu) + + call rotate_array_pair(G_in%mask2dCu, G_in%mask2dCv, turns, G%mask2dCu, G%mask2dCv) + call rotate_array_pair(G_in%areaCu, G_in%areaCv, turns, G%areaCu, G%areaCv) + call rotate_array_pair(G_in%IareaCu, G_in%IareaCv, turns, G%IareaCu, G%IareaCv) + + ! Vertex point + call rotate_array(G_in%geoLonBu, turns, G%geoLonBu) + call rotate_array(G_in%geoLatBu, turns, G%geoLatBu) + call rotate_array_pair(G_in%dxBu, G_in%dyBu, turns, G%dxBu, G%dyBu) + call rotate_array(G_in%areaBu, turns, G%areaBu) + call rotate_array(G_in%CoriolisBu, turns, G%CoriolisBu) + call rotate_array(G_in%mask2dBu, turns, G%mask2dBu) + + ! Topography at the cell faces + G%bathymetry_at_vel = G_in%bathymetry_at_vel + if (G%bathymetry_at_vel) then + call rotate_array_pair(G_in%Dblock_u, G_in%Dblock_v, turns, G%Dblock_u, G%Dblock_v) + call rotate_array_pair(G_in%Dopen_u, G_in%Dopen_v, turns, G%Dopen_u, G%Dopen_v) + endif + + ! Nominal grid axes + ! TODO: We should not assign lat values to the lon axis, and vice versa. + ! We temporarily copy lat <-> lon since several components still expect + ! lat and lon sizes to match the first and second dimension sizes. + ! But we ought to instead leave them unchanged and adjust the references to + ! these axes. + if (modulo(turns, 2) /= 0) then + G%gridLonT(:) = G_in%gridLatT(G_in%jeg:G_in%jsg:-1) + G%gridLatT(:) = G_in%gridLonT(:) + G%gridLonB(:) = G_in%gridLatB(G_in%jeg:(G_in%jsg-1):-1) + G%gridLatB(:) = G_in%gridLonB(:) + else + G%gridLonT(:) = G_in%gridLonT(:) + G%gridLatT(:) = G_in%gridLatT(:) + G%gridLonB(:) = G_in%gridLonB(:) + G%gridLatB(:) = G_in%gridLatB(:) + endif + + G%x_axis_units = G_in%y_axis_units + G%y_axis_units = G_in%x_axis_units + G%south_lat = G_in%south_lat + G%west_lon = G_in%west_lon + G%len_lat = G_in%len_lat + G%len_lon = G_in%len_lon + + ! Rotation-invariant fields + G%areaT_global = G_in%areaT_global + G%IareaT_global = G_in%IareaT_global + G%Rad_Earth = G_in%Rad_Earth + G%max_depth = G_in%max_depth + + call set_derived_dyn_horgrid(G, US) +end subroutine rotate_dyn_horgrid + + !> rescale_dyn_horgrid_bathymetry permits a change in the internal units for the bathymetry on the !! grid, both rescaling the depths and recording the new internal depth units. subroutine rescale_dyn_horgrid_bathymetry(G, m_in_new_units) diff --git a/src/parameterizations/vertical/MOM_ALE_sponge.F90 b/src/parameterizations/vertical/MOM_ALE_sponge.F90 index 1225487eaf..4d179e2bfb 100644 --- a/src/parameterizations/vertical/MOM_ALE_sponge.F90 +++ b/src/parameterizations/vertical/MOM_ALE_sponge.F90 @@ -840,7 +840,7 @@ subroutine apply_ALE_sponge(h, dt, G, GV, US, CS, Time) real, intent(in) :: dt !< The amount of time covered by this call [T ~> s]. type(ALE_sponge_CS), pointer :: CS !< A pointer to the control structure for this module !! that is set by a previous call to initialize_ALE_sponge (in). - type(time_type), optional, intent(in) :: Time !< The current model date + type(time_type), intent(in) :: Time !< The current model date real :: damp ! The timestep times the local damping coefficient [nondim]. real :: I1pdamp ! I1pdamp is 1/(1 + damp). [nondim]. @@ -885,8 +885,6 @@ subroutine apply_ALE_sponge(h, dt, G, GV, US, CS, Time) endif if (CS%time_varying_sponges) then - if (.not. present(Time)) & - call MOM_error(FATAL,"apply_ALE_sponge: No time information provided") do m=1,CS%fldno nz_data = CS%Ref_val(m)%nz_data call horiz_interp_and_extrap_tracer(CS%Ref_val(m)%id, Time, 1.0, G, sp_val, mask_z, z_in, & @@ -971,9 +969,6 @@ subroutine apply_ALE_sponge(h, dt, G, GV, US, CS, Time) if (CS%sponge_uv) then if (CS%time_varying_sponges) then - if (.not. present(Time)) & - call MOM_error(FATAL,"apply_ALE_sponge: No time information provided") - nz_data = CS%Ref_val_u%nz_data ! Interpolate from the external horizontal grid and in time call horiz_interp_and_extrap_tracer(CS%Ref_val_u%id, Time, 1.0, G, sp_val, mask_z, z_in, & diff --git a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 index 53dddcf168..b9ceb85cc5 100644 --- a/src/parameterizations/vertical/MOM_CVMix_KPP.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_KPP.F90 @@ -1389,8 +1389,8 @@ subroutine KPP_NonLocalTransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, & type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer/level thickness [H ~> m or kg m-2] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(in) :: nonLocalTrans !< Non-local transport [nondim] - real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of scalar - !! [conc H s-1 ~> conc m s-1 or conc kg m-2 s-1] + real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of temperature + !! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] real, intent(in) :: dt !< Time-step [s] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: scalar !< temperature real, intent(in) :: C_p !< Seawater specific heat capacity [J kg-1 degC-1] @@ -1451,8 +1451,8 @@ subroutine KPP_NonLocalTransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer/level thickness [H ~> m or kg m-2] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(in) :: nonLocalTrans !< Non-local transport [nondim] - real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of scalar - !! [conc H s-1 ~> conc m s-1 or conc kg m-2 s-1] + real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of salt + !! [ppt H s-1 ~> ppt m s-1 or ppt kg m-2 s-1] real, intent(in) :: dt !< Time-step [s] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: scalar !< Scalar (scalar units [conc]) diff --git a/src/parameterizations/vertical/MOM_CVMix_conv.F90 b/src/parameterizations/vertical/MOM_CVMix_conv.F90 index a615c9f40b..138e932c22 100644 --- a/src/parameterizations/vertical/MOM_CVMix_conv.F90 +++ b/src/parameterizations/vertical/MOM_CVMix_conv.F90 @@ -150,10 +150,10 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) !! by a previous call to CVMix_conv_init. real, dimension(SZI_(G),SZJ_(G)), intent(in) :: hbl !< Depth of ocean boundary layer [Z ~> m] real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & - optional, intent(inout) :: Kd !< Diapycnal diffusivity at each interface that + intent(inout) :: Kd !< Diapycnal diffusivity at each interface that !! will be incremented here [Z2 T-1 ~> m2 s-1]. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & - optional, intent(inout) :: KV !< Viscosity at each interface that will be + intent(inout) :: KV !< Viscosity at each interface that will be !! incremented here [Z2 T-1 ~> m2 s-1]. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & optional, intent(inout) :: Kd_aux !< A second diapycnal diffusivity at each @@ -243,12 +243,10 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) max_nlev=GV%ke, & OBL_ind=kOBL) - if (present(Kd)) then - ! Increment the diffusivity outside of the boundary layer. - do K=max(1,kOBL+1),GV%ke+1 - Kd(i,j,K) = Kd(i,j,K) + US%m2_s_to_Z2_T * kd_col(K) - enddo - endif + ! Increment the diffusivity outside of the boundary layer. + do K=max(1,kOBL+1),GV%ke+1 + Kd(i,j,K) = Kd(i,j,K) + US%m2_s_to_Z2_T * kd_col(K) + enddo if (present(Kd_aux)) then ! Increment the other diffusivity outside of the boundary layer. do K=max(1,kOBL+1),GV%ke+1 @@ -256,12 +254,10 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) enddo endif - if (present(Kv)) then - ! Increment the viscosity outside of the boundary layer. - do K=max(1,kOBL+1),GV%ke+1 - Kv(i,j,K) = Kv(i,j,K) + US%m2_s_to_Z2_T * kv_col(K) - enddo - endif + ! Increment the viscosity outside of the boundary layer. + do K=max(1,kOBL+1),GV%ke+1 + Kv(i,j,K) = Kv(i,j,K) + US%m2_s_to_Z2_T * kv_col(K) + enddo ! Store 3-d arrays for diagnostics. if (CS%id_kv_conv > 0) then @@ -288,8 +284,8 @@ subroutine calculate_CVMix_conv(h, tv, G, GV, US, CS, hbl, Kd, Kv, Kd_aux) ! call hchksum(Kd_conv, "MOM_CVMix_conv: Kd_conv", G%HI, haloshift=0, scale=US%Z2_T_to_m2_s) ! if (CS%id_kv_conv > 0) & ! call hchksum(Kv_conv, "MOM_CVMix_conv: Kv_conv", G%HI, haloshift=0, scale=US%m2_s_to_Z2_T) - if (present(Kd)) call hchksum(Kd, "MOM_CVMix_conv: Kd", G%HI, haloshift=0, scale=US%Z2_T_to_m2_s) - if (present(Kv)) call hchksum(Kv, "MOM_CVMix_conv: Kv", G%HI, haloshift=0, scale=US%Z2_T_to_m2_s) + call hchksum(Kd, "MOM_CVMix_conv: Kd", G%HI, haloshift=0, scale=US%Z2_T_to_m2_s) + call hchksum(Kv, "MOM_CVMix_conv: Kv", G%HI, haloshift=0, scale=US%Z2_T_to_m2_s) endif ! send diagnostics to post_data diff --git a/src/parameterizations/vertical/MOM_diabatic_aux.F90 b/src/parameterizations/vertical/MOM_diabatic_aux.F90 index 8d53594ebb..4c822309d0 100644 --- a/src/parameterizations/vertical/MOM_diabatic_aux.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_aux.F90 @@ -318,7 +318,7 @@ end subroutine differential_diffuse_T_S !> This subroutine keeps salinity from falling below a small but positive threshold. !! This usually occurs when the ice model attempts to extract more salt then !! is actually available to it from the ocean. -subroutine adjust_salt(h, tv, G, GV, CS, halo) +subroutine adjust_salt(h, tv, G, GV, CS) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & @@ -327,7 +327,6 @@ subroutine adjust_salt(h, tv, G, GV, CS, halo) !! available thermodynamic fields. type(diabatic_aux_CS), intent(in) :: CS !< The control structure returned by a previous !! call to diabatic_aux_init. - integer, optional, intent(in) :: halo !< Halo width over which to work ! local variables real :: salt_add_col(SZI_(G),SZJ_(G)) !< The accumulated salt requirement [ppt R Z ~> gSalt m-2] @@ -336,9 +335,6 @@ subroutine adjust_salt(h, tv, G, GV, CS, halo) integer :: i, j, k, is, ie, js, je, nz is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke - if (present(halo)) then - is = G%isc-halo ; ie = G%iec+halo ; js = G%jsc-halo ; je = G%jec+halo - endif ! call cpu_clock_begin(id_clock_adjust_salt) @@ -1024,7 +1020,7 @@ subroutine applyBoundaryFluxesInOut(CS, G, GV, US, dt, fluxes, optics, nsw, h, t optional, intent(out) :: dSV_dS !< Partial derivative of specific volume with !! salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1]. real, dimension(SZI_(G),SZJ_(G)), & - optional, intent(out) :: SkinBuoyFlux !< Buoyancy flux at surface [Z2 T-3 ~> m2 s-3]. + optional, intent(out) :: SkinBuoyFlux !< Buoyancy flux at surface [Z2 T-3 ~> m2 s-3]. ! Local variables integer, parameter :: maxGroundings = 5 diff --git a/src/parameterizations/vertical/MOM_diabatic_driver.F90 b/src/parameterizations/vertical/MOM_diabatic_driver.F90 index ff8c270a89..d3f92e99cc 100644 --- a/src/parameterizations/vertical/MOM_diabatic_driver.F90 +++ b/src/parameterizations/vertical/MOM_diabatic_driver.F90 @@ -87,9 +87,9 @@ module MOM_diabatic_driver ! vary with the Boussinesq approximation, the Boussinesq variant is given first. !> Control structure for this module -type, public:: diabatic_CS; private +type, public :: diabatic_CS ; private - logical :: use_legacy_diabatic !< If true (default), use the a legacy version of the diabatic + logical :: use_legacy_diabatic !< If true (default), use a legacy version of the diabatic !! algorithm. This is temporary and is needed to avoid change !! in answers. logical :: bulkmixedlayer !< If true, a refined bulk mixed layer is used with @@ -242,11 +242,14 @@ module MOM_diabatic_driver type(group_pass_type) :: pass_Kv !< For group halo pass type(diag_grid_storage) :: diag_grids_prev!< Stores diagnostic grids at some previous point in the algorithm ! Data arrays for communicating between components - real, allocatable, dimension(:,:,:) :: KPP_NLTheat !< KPP non-local transport for heat [m s-1] - real, allocatable, dimension(:,:,:) :: KPP_NLTscalar !< KPP non-local transport for scalars [m s-1] + !### Why are these arrays in this control structure, and not local variables in the various routines? + real, allocatable, dimension(:,:,:) :: KPP_NLTheat !< KPP non-local transport for heat [nondim] + real, allocatable, dimension(:,:,:) :: KPP_NLTscalar !< KPP non-local transport for scalars [nondim] real, allocatable, dimension(:,:,:) :: KPP_buoy_flux !< KPP forcing buoyancy flux [L2 T-3 ~> m2 s-3] - real, allocatable, dimension(:,:) :: KPP_temp_flux !< KPP effective temperature flux [degC m s-1] - real, allocatable, dimension(:,:) :: KPP_salt_flux !< KPP effective salt flux [ppt m s-1] + real, allocatable, dimension(:,:) :: KPP_temp_flux !< KPP effective temperature flux + !! [degC H s-1 ~> degC m s-1 or degC kg m-2 s-1] + real, allocatable, dimension(:,:) :: KPP_salt_flux !< KPP effective salt flux + !! [ppt H s-1 ~> ppt m s-1 or ppt kg m-2 s-1] type(time_type), pointer :: Time !< Pointer to model time (needed for sponges) end type diabatic_CS @@ -274,8 +277,9 @@ subroutine diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, & real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [Z ~> m] type(forcing), intent(inout) :: fluxes !< points to forcing fields !! unused fields have NULL ptrs - type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and - type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum + type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities, + !! BBL properties and related fields + type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum !! equations, to enable the later derived !! diagnostics, like energy budgets type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations @@ -465,8 +469,9 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Tim real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [Z ~> m] type(forcing), intent(inout) :: fluxes !< points to forcing fields !! unused fields have NULL ptrs - type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and - type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum + type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities, + !! BBL properties and related fields + type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum !! equations, to enable the later derived !! diagnostics, like energy budgets type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations @@ -577,11 +582,11 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Tim if (CS%debug) & call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff) if (CS%double_diffuse) then - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, CS%set_diff_CSp, & - Kd_int=Kd_int, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, & + CS%set_diff_CSp, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) else - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, & - CS%set_diff_CSp, Kd_int=Kd_int) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, & + CS%set_diff_CSp) endif call cpu_clock_end(id_clock_set_diffusivity) if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)") @@ -718,7 +723,7 @@ subroutine diabatic_ALE_legacy(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Tim ! Calculate vertical mixing due to convection (computed via CVMix) if (CS%use_CVMix_conv) then ! Increment vertical diffusion and viscosity due to convection - call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd=Kd_int, Kv=visc%Kv_slow) + call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd_int, visc%Kv_slow) endif ! This block sets ent_t and ent_s from h and Kd_int. @@ -1049,8 +1054,9 @@ subroutine diabatic_ALE(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [Z ~> m] type(forcing), intent(inout) :: fluxes !< points to forcing fields !! unused fields have NULL ptrs - type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and - type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum + type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities, + !! BBL properties and related fields + type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum !! equations, to enable the later derived !! diagnostics, like energy budgets type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations @@ -1161,11 +1167,11 @@ subroutine diabatic_ALE(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, if (CS%debug) & call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff) if (CS%double_diffuse) then - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, CS%set_diff_CSp, & - Kd_int=Kd_heat, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_heat, G, GV, US, & + CS%set_diff_CSp, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) else - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, & - CS%set_diff_CSp, Kd_int=Kd_heat) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_heat, G, GV, US, & + CS%set_diff_CSp) endif call cpu_clock_end(id_clock_set_diffusivity) if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)") @@ -1270,9 +1276,9 @@ subroutine diabatic_ALE(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, if (CS%use_CVMix_conv) then ! Increment vertical diffusion and viscosity due to convection if (CS%useKPP) then - call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd=Kd_heat, Kv=visc%Kv_shear, Kd_aux=Kd_salt) + call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd_heat, visc%Kv_shear, Kd_aux=Kd_salt) else - call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd=Kd_heat, Kv=visc%Kv_slow, Kd_aux=Kd_salt) + call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd_heat, visc%Kv_slow, Kd_aux=Kd_salt) endif endif @@ -1558,8 +1564,9 @@ subroutine layered_diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_e real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [Z ~> m] type(forcing), intent(inout) :: fluxes !< points to forcing fields !! unused fields have NULL ptrs - type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and - type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum + type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities, + !! BBL properties and related fields + type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum !! equations, to enable the later derived !! diagnostics, like energy budgets type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations @@ -1764,11 +1771,11 @@ subroutine layered_diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_e if (CS%debug) & call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff) if (CS%double_diffuse) then - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, CS%set_diff_CSp, & - Kd_lay=Kd_lay, Kd_int=Kd_int, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, & + CS%set_diff_CSp, Kd_lay=Kd_lay, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S) else - call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, G, GV, US, & - CS%set_diff_CSp, Kd_lay=Kd_lay, Kd_int=Kd_int) + call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, & + CS%set_diff_CSp, Kd_lay=Kd_lay) endif call cpu_clock_end(id_clock_set_diffusivity) if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)") @@ -1859,7 +1866,7 @@ subroutine layered_diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_e ! Add vertical diff./visc. due to convection (computed via CVMix) if (CS%use_CVMix_conv) then - call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd=Kd_int, Kv=visc%Kv_slow) + call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv_CSp, Hml, Kd_int, visc%Kv_slow) endif if (CS%useKPP) then @@ -3194,7 +3201,7 @@ subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, di cmor_standard_name='ocean_vertical_heat_diffusivity', & cmor_long_name='Ocean vertical heat diffusivity') CS%id_Kd_salt = register_diag_field('ocean_model', 'Kd_salt', diag%axesTi, Time, & - 'Total diapycnal diffusivity for salt at interfaces', 'm2 s-1', conversion=US%Z2_T_to_m2_s, & + 'Total diapycnal diffusivity for salt at interfaces', 'm2 s-1', conversion=US%Z2_T_to_m2_s, & cmor_field_name='difvso', & cmor_standard_name='ocean_vertical_salt_diffusivity', & cmor_long_name='Ocean vertical salt diffusivity') @@ -3205,8 +3212,6 @@ subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, di if (CS%useKPP) then allocate(CS%KPP_NLTheat(isd:ied,jsd:jed,nz+1), source=0.0) allocate(CS%KPP_NLTscalar(isd:ied,jsd:jed,nz+1), source=0.0) - endif - if (CS%useKPP) then allocate(CS%KPP_buoy_flux(isd:ied,jsd:jed,nz+1), source=0.0) allocate(CS%KPP_temp_flux(isd:ied,jsd:jed), source=0.0) allocate(CS%KPP_salt_flux(isd:ied,jsd:jed), source=0.0) diff --git a/src/parameterizations/vertical/MOM_full_convection.F90 b/src/parameterizations/vertical/MOM_full_convection.F90 index ceb77b52b8..aa1dfbf809 100644 --- a/src/parameterizations/vertical/MOM_full_convection.F90 +++ b/src/parameterizations/vertical/MOM_full_convection.F90 @@ -18,8 +18,7 @@ module MOM_full_convection contains !> Calculate new temperatures and salinities that have been subject to full convective mixing. -subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, & - Kddt_convect, halo) +subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, halo) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -34,9 +33,7 @@ subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, real, dimension(:,:), pointer :: p_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa] (or NULL). real, intent(in) :: Kddt_smooth !< A smoothing vertical !! diffusivity times a timestep [H2 ~> m2 or kg2 m-4]. - real, optional, intent(in) :: Kddt_convect !< A large convecting vertical - !! diffusivity times a timestep [H2 ~> m2 or kg2 m-4]. - integer, optional, intent(in) :: halo !< Halo width over which to compute + integer, intent(in) :: halo !< Halo width over which to compute ! Local variables real, dimension(SZI_(G),SZK_(GV)+1) :: & @@ -46,61 +43,53 @@ subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, ! in roundoff and can be neglected [H ~> m or kg m-2]. ! logical :: use_EOS ! If true, density is calculated from T & S using an equation of state. real, dimension(SZI_(G),SZK0_(G)) :: & - Te_a, & ! A partially updated temperature estimate including the influnce from + Te_a, & ! A partially updated temperature estimate including the influence from ! mixing with layers above rescaled by a factor of d_a [degC]. - ! This array is discreted on tracer cells, but contains an extra + ! This array is discretized on tracer cells, but contains an extra ! layer at the top for algorithmic convenience. - Se_a ! A partially updated salinity estimate including the influnce from + Se_a ! A partially updated salinity estimate including the influence from ! mixing with layers above rescaled by a factor of d_a [ppt]. - ! This array is discreted on tracer cells, but contains an extra + ! This array is discretized on tracer cells, but contains an extra ! layer at the top for algorithmic convenience. real, dimension(SZI_(G),SZK_(GV)+1) :: & - Te_b, & ! A partially updated temperature estimate including the influnce from + Te_b, & ! A partially updated temperature estimate including the influence from ! mixing with layers below rescaled by a factor of d_b [degC]. - ! This array is discreted on tracer cells, but contains an extra + ! This array is discretized on tracer cells, but contains an extra ! layer at the bottom for algorithmic convenience. - Se_b ! A partially updated salinity estimate including the influnce from + Se_b ! A partially updated salinity estimate including the influence from ! mixing with layers below rescaled by a factor of d_b [ppt]. - ! This array is discreted on tracer cells, but contains an extra + ! This array is discretized on tracer cells, but contains an extra ! layer at the bottom for algorithmic convenience. real, dimension(SZI_(G),SZK_(GV)+1) :: & c_a, & ! The fractional influence of the properties of the layer below - ! in the final properies with a downward-first solver, nondim. + ! in the final properties with a downward-first solver [nondim] d_a, & ! The fractional influence of the properties of the layer in question - ! and layers above in the final properies with a downward-first solver, nondim. + ! and layers above in the final properties with a downward-first solver [nondim] ! d_a = 1.0 - c_a c_b, & ! The fractional influence of the properties of the layer above - ! in the final properies with a upward-first solver, nondim. + ! in the final properties with a upward-first solver [nondim] d_b ! The fractional influence of the properties of the layer in question - ! and layers below in the final properies with a upward-first solver, nondim. + ! and layers below in the final properties with a upward-first solver [nondim] ! d_b = 1.0 - c_b real, dimension(SZI_(G),SZK_(GV)+1) :: & mix !< The amount of mixing across the interface between layers [H ~> m or kg m-2]. real :: mix_len ! The length-scale of mixing, when it is active [H ~> m or kg m-2] - real :: h_b, h_a ! The thicknessses of the layers above and below an interface [H ~> m or kg m-2] + real :: h_b, h_a ! The thicknesses of the layers above and below an interface [H ~> m or kg m-2] real :: b_b, b_a ! Inverse pivots used by the tridiagonal solver [H-1 ~> m-1 or m2 kg-1]. - real :: kap_dt_x2 ! The product of 2*kappa*dt [H2 ~> m2 or kg2 m-4]. - logical, dimension(SZI_(G)) :: do_i ! Do more work on this column. logical, dimension(SZI_(G)) :: last_down ! The last setup pass was downward. integer, dimension(SZI_(G)) :: change_ct ! The number of interfaces where the ! mixing has changed this iteration. - integer :: changed_col ! The number of colums whose mixing changed. + integer :: changed_col ! The number of columns whose mixing changed. integer :: i, j, k, is, ie, js, je, nz, itt - if (present(halo)) then - is = G%isc-halo ; ie = G%iec+halo ; js = G%jsc-halo ; je = G%jec+halo - else - is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec - endif + is = G%isc-halo ; ie = G%iec+halo ; js = G%jsc-halo ; je = G%jec+halo nz = GV%ke if (.not.associated(tv%eqn_of_state)) return h_neglect = GV%H_subroundoff - kap_dt_x2 = 0.0 - if (present(Kddt_convect)) kap_dt_x2 = 2.0*Kddt_convect mix_len = (1.0e20 * nz) * (G%max_depth * GV%Z_to_H) h0 = 1.0e-16*sqrt(Kddt_smooth) + h_neglect @@ -135,7 +124,6 @@ subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, Te_a(i,k-2), Te_b(i,k+1), Se_a(i,k-2), Se_b(i,k+1), & d_a(i,K-1), d_b(i,K+1))) then mix(i,K) = mix_len - if (kap_dt_x2 > 0.0) mix(i,K) = kap_dt_x2 / ((h(i,j,k-1)+h(i,j,k)) + h0) change_ct(i) = change_ct(i) + 1 endif endif @@ -178,7 +166,6 @@ subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, Te_a(i,k-2), Te_b(i,k+1), Se_a(i,k-2), Se_b(i,k+1), & d_a(i,K-1), d_b(i,K+1))) then mix(i,K) = mix_len - if (kap_dt_x2 > 0.0) mix(i,K) = kap_dt_x2 / ((h(i,j,k-1)+h(i,j,k)) + h0) change_ct(i) = change_ct(i) + 1 endif endif @@ -260,7 +247,7 @@ subroutine full_convection(G, GV, US, h, tv, T_adj, S_adj, p_surf, Kddt_smooth, k = 1 ! A hook for debugging. - ! The following set of expressions for the final values are derived from the the partial + ! The following set of expressions for the final values are derived from the partial ! updates for the estimated temperatures and salinities around an interface, then directly ! solving for the final temperatures and salinities. They are here for later reference ! and to document an intermediate step in the stability calculation. @@ -336,7 +323,7 @@ subroutine smoothed_dRdT_dRdS(h, tv, Kddt, dR_dT, dR_dS, G, GV, US, j, p_surf, h type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type integer, intent(in) :: j !< The j-point to work on. real, dimension(:,:), pointer :: p_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]. - integer, optional, intent(in) :: halo !< Halo width over which to compute + integer, intent(in) :: halo !< Halo width over which to compute ! Local variables real :: mix(SZI_(G),SZK_(GV)+1) ! The diffusive mixing length (kappa*dt)/dz @@ -352,14 +339,10 @@ subroutine smoothed_dRdT_dRdS(h, tv, Kddt, dR_dT, dR_dS, G, GV, US, j, p_surf, h real :: h_neglect, h0 ! Negligible thicknesses to allow for zero thicknesses, ! [H ~> m or kg m-2]. real :: h_tr ! The thickness at tracer points, plus h_neglect [H ~> m or kg m-2]. - integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state + integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state integer :: i, k, is, ie, nz - if (present(halo)) then - is = G%isc-halo ; ie = G%iec+halo - else - is = G%isc ; ie = G%iec - endif + is = G%isc-halo ; ie = G%iec+halo nz = GV%ke h_neglect = GV%H_subroundoff diff --git a/src/parameterizations/vertical/MOM_geothermal.F90 b/src/parameterizations/vertical/MOM_geothermal.F90 index 7944d4b89f..90da24f170 100644 --- a/src/parameterizations/vertical/MOM_geothermal.F90 +++ b/src/parameterizations/vertical/MOM_geothermal.F90 @@ -499,7 +499,7 @@ subroutine geothermal_init(Time, G, GV, US, param_file, diag, CS, useALEalgorith type(diag_ctrl), target, intent(inout) :: diag !< Structure used to regulate diagnostic output. type(geothermal_CS), pointer :: CS !< Pointer pointing to the module control !! structure. - logical, optional, intent(in) :: useALEalgorithm !< logical for whether to use ALE remapping + logical, intent(in) :: useALEalgorithm !< logical for whether to use ALE remapping ! This include declares and sets the variable "version". #include "version_variable.h" @@ -587,13 +587,13 @@ subroutine geothermal_init(Time, G, GV, US, param_file, diag, CS, useALEalgorith 'internal_heat_temp_tendency', diag%axesTL, Time, & 'Temperature tendency (in 3D) due to internal (geothermal) sources', & 'degC s-1', conversion=US%s_to_T, v_extensive=.true.) - if (present(useALEalgorithm)) then ; if (.not.useALEalgorithm) then + if (.not.useALEalgorithm) then ! Do not offer this diagnostic if heating will be in place. CS%id_internal_heat_h_tendency=register_diag_field('ocean_model', & 'internal_heat_h_tendency', diag%axesTL, Time, & 'Thickness tendency (in 3D) due to internal (geothermal) sources', & trim(thickness_units)//' s-1', conversion=GV%H_to_MKS*US%s_to_T, v_extensive=.true.) - endif ; endif + endif end subroutine geothermal_init diff --git a/src/parameterizations/vertical/MOM_kappa_shear.F90 b/src/parameterizations/vertical/MOM_kappa_shear.F90 index 033f717091..a44a7aee95 100644 --- a/src/parameterizations/vertical/MOM_kappa_shear.F90 +++ b/src/parameterizations/vertical/MOM_kappa_shear.F90 @@ -107,7 +107,7 @@ module MOM_kappa_shear !> Subroutine for calculating shear-driven diffusivity and TKE in tracer columns subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & - kv_io, dt, G, GV, US, CS, initialize_all) + kv_io, dt, G, GV, US, CS) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure. type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure. type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -137,8 +137,6 @@ subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & real, intent(in) :: dt !< Time increment [T ~> s]. type(Kappa_shear_CS), pointer :: CS !< The control structure returned by a previous !! call to kappa_shear_init. - logical, optional, intent(in) :: initialize_all !< If present and false, the previous - !! value of kappa is used to start the iterations ! Local variables real, dimension(SZI_(G),SZK_(GV)) :: & @@ -168,8 +166,6 @@ subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & real :: dz_massless ! A layer thickness that is considered massless [Z ~> m]. logical :: use_temperature ! If true, temperature and salinity have been ! allocated and are being used as state variables. - logical :: new_kappa = .true. ! If true, ignore the value of kappa from the - ! last call to this subroutine. integer, dimension(SZK_(GV)+1) :: kc ! The index map between the original ! interfaces and the interfaces with massless layers @@ -180,14 +176,13 @@ subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & is = G%isc ; ie = G%iec; js = G%jsc ; je = G%jec ; nz = GV%ke - use_temperature = .false. ; if (associated(tv%T)) use_temperature = .true. - new_kappa = .true. ; if (present(initialize_all)) new_kappa = initialize_all + use_temperature = associated(tv%T) k0dt = dt*CS%kappa_0 dz_massless = 0.1*sqrt(k0dt) - !$OMP parallel do default(private) shared(js,je,is,ie,nz,h,u_in,v_in,use_temperature,new_kappa, & - !$OMP tv,G,GV,US,CS,kappa_io,dz_massless,k0dt,p_surf,dt,tke_io,kv_io) + !$OMP parallel do default(private) shared(js,je,is,ie,nz,h,u_in,v_in,use_temperature,tv,G,GV,US, & + !$OMP CS,kappa_io,dz_massless,k0dt,p_surf,dt,tke_io,kv_io) do j=js,je do k=1,nz ; do i=is,ie h_2d(i,k) = h(i,j,k)*GV%H_to_Z @@ -198,9 +193,6 @@ subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & enddo ; enddo ; else ; do k=1,nz ; do i=is,ie rho_2d(i,k) = GV%Rlay(k) ! Could be tv%Rho(i,j,k) ? enddo ; enddo ; endif - if (.not.new_kappa) then ; do K=1,nz+1 ; do i=is,ie - kappa_2d(i,K) = kappa_io(i,j,K) - enddo ; enddo ; endif !--------------------------------------- ! Work on each column. @@ -278,11 +270,7 @@ subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, & ! Set the initial guess for kappa, here defined at interfaces. ! ---------------------------------------------------- - if (new_kappa) then - do K=1,nzc+1 ; kappa(K) = US%m2_s_to_Z2_T*1.0 ; enddo - else - do K=1,nzc+1 ; kappa(K) = kappa_2d(i,K) ; enddo - endif + do K=1,nzc+1 ; kappa(K) = US%m2_s_to_Z2_T*1.0 ; enddo call kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & dz, u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, & @@ -340,7 +328,7 @@ end subroutine Calculate_kappa_shear !> Subroutine for calculating shear-driven diffusivity and TKE in corner columns subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_io, tke_io, & - kv_io, dt, G, GV, US, CS, initialize_all) + kv_io, dt, G, GV, US, CS) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure. type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure. type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -373,8 +361,6 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ real, intent(in) :: dt !< Time increment [T ~> s]. type(Kappa_shear_CS), pointer :: CS !< The control structure returned by a previous !! call to kappa_shear_init. - logical, optional, intent(in) :: initialize_all !< If present and false, the previous - !! value of kappa is used to start the iterations ! Local variables real, dimension(SZIB_(G),SZK_(GV)) :: & @@ -397,7 +383,7 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ tke, & ! The Turbulent Kinetic Energy per unit mass at an interface [Z2 T-2 ~> m2 s-2]. kappa_avg, & ! The time-weighted average of kappa [Z2 T-1 ~> m2 s-1]. tke_avg ! The time-weighted average of TKE [Z2 T-2 ~> m2 s-2]. - real :: f2 ! The squared Coriolis parameter of each column [T-2 ~> s-2]. + real :: f2 ! The squared Coriolis parameter of each column [T-2 ~> s-2]. real :: surface_pres ! The top surface pressure [R L2 T-2 ~> Pa]. real :: dz_in_lay ! The running sum of the thickness in a layer [Z ~> m]. @@ -407,8 +393,6 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ real :: I_Prandtl ! The inverse of the turbulent Prandtl number [nondim]. logical :: use_temperature ! If true, temperature and salinity have been ! allocated and are being used as state variables. - logical :: new_kappa = .true. ! If true, ignore the value of kappa from the - ! last call to this subroutine. logical :: do_i ! If true, work on this column. integer, dimension(SZK_(GV)+1) :: kc ! The index map between the original @@ -421,15 +405,14 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ ! Diagnostics that should be deleted? isB = G%isc-1 ; ieB = G%iecB ; jsB = G%jsc-1 ; jeB = G%jecB ; nz = GV%ke - use_temperature = .false. ; if (associated(tv%T)) use_temperature = .true. - new_kappa = .true. ; if (present(initialize_all)) new_kappa = initialize_all + use_temperature = associated(tv%T) k0dt = dt*CS%kappa_0 dz_massless = 0.1*sqrt(k0dt) I_Prandtl = 0.0 ; if (CS%Prandtl_turb > 0.0) I_Prandtl = 1.0 / CS%Prandtl_turb - !$OMP parallel do default(private) shared(jsB,jeB,isB,ieB,nz,h,u_in,v_in,use_temperature,new_kappa, & - !$OMP tv,G,GV,US,CS,kappa_io,dz_massless,k0dt,p_surf,dt,tke_io,kv_io,I_Prandtl) + !$OMP parallel do default(private) shared(jsB,jeB,isB,ieB,nz,h,u_in,v_in,use_temperature,tv,G,GV, & + !$OMP US,CS,kappa_io,dz_massless,k0dt,p_surf,dt,tke_io,kv_io,I_Prandtl) do J=JsB,JeB J2 = mod(J,2)+1 ; J2m1 = 3-J2 ! = mod(J-1,2)+1 @@ -467,9 +450,6 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ if (.not.use_temperature) then ; do k=1,nz ; do I=IsB,IeB rho_2d(I,k) = GV%Rlay(k) enddo ; enddo ; endif - if (.not.new_kappa) then ; do K=1,nz+1 ; do I=IsB,IeB - kappa_2d(I,K,J2) = kv_io(I,J,K) * I_Prandtl - enddo ; enddo ; endif !--------------------------------------- ! Work on each column. @@ -558,11 +538,7 @@ subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_ ! ---------------------------------------------------- ! Set the initial guess for kappa, here defined at interfaces. ! ---------------------------------------------------- - if (new_kappa) then - do K=1,nzc+1 ; kappa(K) = US%m2_s_to_Z2_T*1.0 ; enddo - else - do K=1,nzc+1 ; kappa(K) = kappa_2d(I,K,J2) ; enddo - endif + do K=1,nzc+1 ; kappa(K) = US%m2_s_to_Z2_T*1.0 ; enddo call kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & dz, u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, & @@ -621,9 +597,8 @@ end subroutine Calc_kappa_shear_vertex !> This subroutine calculates shear-driven diffusivity and TKE in a single column -subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & - dz, u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, & - tke_avg, tv, CS, GV, US, I_Ld2_1d, dz_Int_1d) +subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, dz, & + u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, tke_avg, tv, CS, GV, US) type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure. real, dimension(SZK_(GV)+1), & intent(inout) :: kappa !< The time-weighted average of kappa [Z2 T-1 ~> m2 s-1]. @@ -654,11 +629,6 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & type(Kappa_shear_CS), pointer :: CS !< The control structure returned by a previous !! call to kappa_shear_init. type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - real, dimension(SZK_(GV)+1), & - optional, intent(out) :: I_Ld2_1d !< The inverse of the squared mixing length [Z-2 ~> m-2]. - real, dimension(SZK_(GV)+1), & - optional, intent(out) :: dz_Int_1d !< The extent of a finite-volume space surrounding an interface, - !! as used in calculating kappa and TKE [Z ~> m]. ! Local variables real, dimension(nzc) :: & @@ -858,9 +828,8 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & ! enddo ! This call just calculates N2 and S2. - call calculate_projected_state(kappa, u, v, T, Sal, 0.0, nzc, dz, I_dz_int, & - dbuoy_dT, dbuoy_dS, u, v, T, Sal, GV, US, & - N2=N2, S2=S2, vel_underflow=CS%vel_underflow) + call calculate_projected_state(kappa, u, v, T, Sal, 0.0, nzc, dz, I_dz_int, dbuoy_dT, dbuoy_dS, & + CS%vel_underflow, u, v, T, Sal, N2, S2, GV, US) ! ---------------------------------------------------- ! Iterate ! ---------------------------------------------------- @@ -923,9 +892,8 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & ! value of max_KS_it may be unimportant, especially if it is large ! enough. call calculate_projected_state(kappa_out, u, v, T, Sal, 0.5*dt_test, nzc, dz, I_dz_int, & - dbuoy_dT, dbuoy_dS, u_test, v_test, T_test, S_test, & - GV, US, N2, S2, ks_int=ks_kappa, ke_int=ke_kappa, & - vel_underflow=CS%vel_underflow) + dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, & + T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa) valid_dt = .true. Idtt = 1.0 / dt_test do K=max(ks_kappa-1,2),min(ke_kappa+1,nzc) @@ -956,9 +924,9 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & if ((dt_test < dt_rem) .and. valid_dt) then dt_inc = 0.5*dt_test do itt_dt=1,dt_refinements - call calculate_projected_state(kappa_out, u, v, T, Sal, 0.5*(dt_test+dt_inc), & - nzc, dz, I_dz_int, dbuoy_dT, dbuoy_dS, u_test, v_test, T_test, S_test, & - GV, US, N2, S2, ks_int=ks_kappa, ke_int=ke_kappa, vel_underflow=CS%vel_underflow) + call calculate_projected_state(kappa_out, u, v, T, Sal, 0.5*(dt_test+dt_inc), nzc, dz, & + I_dz_int, dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, T_test, S_test, & + N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa) valid_dt = .true. Idtt = 1.0 / (dt_test+dt_inc) do K=max(ks_kappa-1,2),min(ke_kappa+1,nzc) @@ -1006,9 +974,8 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & else ! call cpu_clock_begin(id_clock_project) call calculate_projected_state(kappa_out, u, v, T, Sal, dt_now, nzc, dz, I_dz_int, & - dbuoy_dT, dbuoy_dS, u_test, v_test, T_test, S_test, & - GV, US, N2=N2, S2=S2, ks_int=ks_kappa, ke_int=ke_kappa, & - vel_underflow=CS%vel_underflow) + dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, & + T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa) ! call cpu_clock_end(id_clock_project) ! call cpu_clock_begin(id_clock_KQ) @@ -1026,9 +993,8 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & ! call cpu_clock_begin(id_clock_project) call calculate_projected_state(kappa_mid, u, v, T, Sal, dt_now, nzc, dz, I_dz_int, & - dbuoy_dT, dbuoy_dS, u_test, v_test, T_test, S_test, & - GV, US, N2=N2, S2=S2, ks_int=ks_kappa, ke_int=ke_kappa, & - vel_underflow=CS%vel_underflow) + dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, & + T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa) ! call cpu_clock_end(id_clock_project) ! call cpu_clock_begin(id_clock_KQ) @@ -1050,9 +1016,9 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & if (dt_rem > 0.0) then ! Update the values of u, v, T, Sal, N2, and S2 for the next iteration. ! call cpu_clock_begin(id_clock_project) - call calculate_projected_state(kappa_mid, u, v, T, Sal, dt_now, nzc, & - dz, I_dz_int, dbuoy_dT, dbuoy_dS, u, v, T, Sal, & - GV, US, N2, S2, vel_underflow=CS%vel_underflow) + call calculate_projected_state(kappa_mid, u, v, T, Sal, dt_now, nzc, dz, I_dz_int, & + dbuoy_dT, dbuoy_dS, CS%vel_underflow, u, v, T, Sal, N2, S2, & + GV, US) ! call cpu_clock_end(id_clock_project) endif @@ -1060,25 +1026,13 @@ subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, & enddo ! end itt loop - if (present(I_Ld2_1d)) then - do K=1,GV%ke+1 ; I_Ld2_1d(K) = 0.0 ; enddo - do K=2,nzc ; if (TKE(K) > 0.0) & - I_Ld2_1d(K) = I_L2_bdry(K) + (N2(K) / CS%lambda**2 + f2) / TKE(K) - enddo - endif - if (present(dz_Int_1d)) then - do K=1,nzc+1 ; dz_Int_1d(K) = dz_Int(K) ; enddo - do K=nzc+2,GV%ke ; dz_Int_1d(K) = 0.0 ; enddo - endif - end subroutine kappa_shear_column !> This subroutine calculates the velocities, temperature and salinity that !! the water column will have after mixing for dt with diffusivities kappa. It !! may also calculate the projected buoyancy frequency and shear. -subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, & - dz, I_dz_int, dbuoy_dT, dbuoy_dS, & - u, v, T, Sal, GV, US, N2, S2, ks_int, ke_int, vel_underflow) +subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, dz, I_dz_int, dbuoy_dT, dbuoy_dS, & + vel_under, u, v, T, Sal, N2, S2, GV, US, ks_int, ke_int) integer, intent(in) :: nz !< The number of layers (after eliminating massless !! layers?). real, dimension(nz+1), intent(in) :: kappa !< The diapycnal diffusivity at interfaces, @@ -1087,6 +1041,7 @@ subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, & real, dimension(nz), intent(in) :: v0 !< The initial meridional velocity [L T-1 ~> m s-1]. real, dimension(nz), intent(in) :: T0 !< The initial temperature [degC]. real, dimension(nz), intent(in) :: S0 !< The initial salinity [ppt]. + real, intent(in) :: dt !< The time step [T ~> s]. real, dimension(nz), intent(in) :: dz !< The grid spacing of layers [Z ~> m]. real, dimension(nz+1), intent(in) :: I_dz_int !< The inverse of the layer's thicknesses !! [Z-1 ~> m-1]. @@ -1094,36 +1049,30 @@ subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, & !! temperature [Z T-2 degC-1 ~> m s-2 degC-1]. real, dimension(nz+1), intent(in) :: dbuoy_dS !< The partial derivative of buoyancy with !! salinity [Z T-2 ppt-1 ~> m s-2 ppt-1]. - real, intent(in) :: dt !< The time step [T ~> s]. + real, intent(in) :: vel_under !< Any velocities that are smaller in magnitude + !! than this value are set to 0 [L T-1 ~> m s-1]. real, dimension(nz), intent(inout) :: u !< The zonal velocity after dt [L T-1 ~> m s-1]. real, dimension(nz), intent(inout) :: v !< The meridional velocity after dt [L T-1 ~> m s-1]. real, dimension(nz), intent(inout) :: T !< The temperature after dt [degC]. real, dimension(nz), intent(inout) :: Sal !< The salinity after dt [ppt]. + real, dimension(nz+1), intent(inout) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2]. + real, dimension(nz+1), intent(inout) :: S2 !< The squared shear at interfaces [T-2 ~> s-2]. type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure. type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type - real, dimension(nz+1), optional, & - intent(inout) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2]. - real, dimension(nz+1), optional, & - intent(inout) :: S2 !< The squared shear at interfaces [T-2 ~> s-2]. integer, optional, intent(in) :: ks_int !< The topmost k-index with a non-zero diffusivity. integer, optional, intent(in) :: ke_int !< The bottommost k-index with a non-zero !! diffusivity. - real, optional, intent(in) :: vel_underflow !< If present and true, any velocities that - !! are smaller in magnitude than this value are - !! set to 0 [L T-1 ~> m s-1]. ! Local variables real, dimension(nz+1) :: c1 real :: L2_to_Z2 ! A conversion factor from horizontal length units to vertical depth ! units squared [Z2 s2 T-2 m-2 ~> 1]. - real :: underflow_vel ! Velocities smaller in magnitude than underflow_vel are set to 0 [L T-1 ~> m s-1]. real :: a_a, a_b, b1, d1, bd1, b1nz_0 integer :: k, ks, ke ks = 1 ; ke = nz if (present(ks_int)) ks = max(ks_int-1,1) if (present(ke_int)) ke = min(ke_int,nz) - underflow_vel = 0.0 ; if (present(vel_underflow)) underflow_vel = vel_underflow if (ks > ke) return @@ -1166,51 +1115,49 @@ subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, & endif u(ke) = b1nz_0 * (dz(ke)*u0(ke) + a_a*u(ke-1)) v(ke) = b1nz_0 * (dz(ke)*v0(ke) + a_a*v(ke-1)) - if (abs(u(ke)) < underflow_vel) u(ke) = 0.0 - if (abs(v(ke)) < underflow_vel) v(ke) = 0.0 + if (abs(u(ke)) < vel_under) u(ke) = 0.0 + if (abs(v(ke)) < vel_under) v(ke) = 0.0 do k=ke-1,ks,-1 u(k) = u(k) + c1(k+1)*u(k+1) v(k) = v(k) + c1(k+1)*v(k+1) - if (abs(u(k)) < underflow_vel) u(k) = 0.0 - if (abs(v(k)) < underflow_vel) v(k) = 0.0 + if (abs(u(k)) < vel_under) u(k) = 0.0 + if (abs(v(k)) < vel_under) v(k) = 0.0 T(k) = T(k) + c1(k+1)*T(k+1) Sal(k) = Sal(k) + c1(k+1)*Sal(k+1) enddo else ! dt <= 0.0 do k=1,nz u(k) = u0(k) ; v(k) = v0(k) ; T(k) = T0(k) ; Sal(k) = S0(k) - if (abs(u(k)) < underflow_vel) u(k) = 0.0 - if (abs(v(k)) < underflow_vel) v(k) = 0.0 + if (abs(u(k)) < vel_under) u(k) = 0.0 + if (abs(v(k)) < vel_under) v(k) = 0.0 enddo endif - if (present(S2)) then - ! L2_to_Z2 = US%m_to_Z**2 * US%T_to_s**2 - L2_to_Z2 = US%L_to_Z**2 - S2(1) = 0.0 ; S2(nz+1) = 0.0 - if (ks > 1) & - S2(ks) = ((u(ks)-u0(ks-1))**2 + (v(ks)-v0(ks-1))**2) * (L2_to_Z2*I_dz_int(ks)**2) - do K=ks+1,ke - S2(K) = ((u(k)-u(k-1))**2 + (v(k)-v(k-1))**2) * (L2_to_Z2*I_dz_int(K)**2) - enddo - if (ke 1) & - N2(ks) = max(0.0, I_dz_int(ks) * & - (dbuoy_dT(ks) * (T0(ks-1)-T(ks)) + dbuoy_dS(ks) * (S0(ks-1)-Sal(ks)))) - do K=ks+1,ke - N2(K) = max(0.0, I_dz_int(K) * & - (dbuoy_dT(K) * (T(k-1)-T(k)) + dbuoy_dS(K) * (Sal(k-1)-Sal(k)))) - enddo - if (ke 1) & + S2(ks) = ((u(ks)-u0(ks-1))**2 + (v(ks)-v0(ks-1))**2) * (L2_to_Z2*I_dz_int(ks)**2) + do K=ks+1,ke + S2(K) = ((u(k)-u(k-1))**2 + (v(k)-v(k-1))**2) * (L2_to_Z2*I_dz_int(K)**2) + enddo + if (ke 1) & + N2(ks) = max(0.0, I_dz_int(ks) * & + (dbuoy_dT(ks) * (T0(ks-1)-T(ks)) + dbuoy_dS(ks) * (S0(ks-1)-Sal(ks)))) + do K=ks+1,ke + N2(K) = max(0.0, I_dz_int(K) * & + (dbuoy_dT(K) * (T(k-1)-T(k)) + dbuoy_dS(K) * (Sal(k-1)-Sal(k)))) + enddo + if (ke s]. + real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & + intent(out) :: Kd_int !< Diapycnal diffusivity at each interface [Z2 T-1 ~> m2 s-1]. type(set_diffusivity_CS), pointer :: CS !< Module control structure. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), & optional, intent(out) :: Kd_lay !< Diapycnal diffusivity of each layer [Z2 T-1 ~> m2 s-1]. - real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & - optional, intent(out) :: Kd_int !< Diapycnal diffusivity at each interface [Z2 T-1 ~> m2 s-1]. real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), & optional, intent(out) :: Kd_extra_T !< The extra diffusivity at interfaces of !! temperature due to double diffusion relative to @@ -302,7 +302,7 @@ subroutine set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, & ! Set Kd_lay, Kd_int and Kv_slow to constant values, mostly to fill the halos. if (present(Kd_lay)) Kd_lay(:,:,:) = CS%Kd - if (present(Kd_int)) Kd_int(:,:,:) = CS%Kd + Kd_int(:,:,:) = CS%Kd if (present(Kd_extra_T)) Kd_extra_T(:,:,:) = 0.0 if (present(Kd_extra_S)) Kd_extra_S(:,:,:) = 0.0 if (associated(visc%Kv_slow)) visc%Kv_slow(:,:,:) = CS%Kv @@ -468,98 +468,69 @@ subroutine set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, & ! Add the input turbulent diffusivity. if (CS%useKappaShear .or. CS%use_CVMix_shear) then - if (present(Kd_int)) then - do K=2,nz ; do i=is,ie - Kd_int_2d(i,K) = visc%Kd_shear(i,j,K) + 0.5 * (Kd_lay_2d(i,k-1) + Kd_lay_2d(i,k)) - enddo ; enddo - do i=is,ie - Kd_int_2d(i,1) = visc%Kd_shear(i,j,1) ! This isn't actually used. It could be 0. - Kd_int_2d(i,nz+1) = 0.0 - enddo - endif + do K=2,nz ; do i=is,ie + Kd_int_2d(i,K) = visc%Kd_shear(i,j,K) + 0.5 * (Kd_lay_2d(i,k-1) + Kd_lay_2d(i,k)) + enddo ; enddo + do i=is,ie + Kd_int_2d(i,1) = visc%Kd_shear(i,j,1) ! This isn't actually used. It could be 0. + Kd_int_2d(i,nz+1) = 0.0 + enddo do k=1,nz ; do i=is,ie Kd_lay_2d(i,k) = Kd_lay_2d(i,k) + 0.5 * (visc%Kd_shear(i,j,K) + visc%Kd_shear(i,j,K+1)) enddo ; enddo else - if (present(Kd_int)) then - do i=is,ie - Kd_int_2d(i,1) = Kd_lay_2d(i,1) ; Kd_int_2d(i,nz+1) = 0.0 - enddo - do K=2,nz ; do i=is,ie - Kd_int_2d(i,K) = 0.5 * (Kd_lay_2d(i,k-1) + Kd_lay_2d(i,k)) - enddo ; enddo - endif + do i=is,ie + Kd_int_2d(i,1) = Kd_lay_2d(i,1) ; Kd_int_2d(i,nz+1) = 0.0 + enddo + do K=2,nz ; do i=is,ie + Kd_int_2d(i,K) = 0.5 * (Kd_lay_2d(i,k-1) + Kd_lay_2d(i,k)) + enddo ; enddo endif - if (present(Kd_int)) then - ! Add the ML_Rad diffusivity. - if (CS%ML_radiation) & - call add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay_2d, Kd_int_2d) - - ! Add the Nikurashin and / or tidal bottom-driven mixing - if (CS%use_tidal_mixing) & - call calculate_tidal_mixing(h, N2_bot, j, TKE_to_Kd, maxTKE, G, GV, US, CS%tidal_mixing_CSp, & - N2_lay, N2_int, Kd_lay_2d, Kd_int_2d, CS%Kd_max, visc%Kv_slow) - - ! This adds the diffusion sustained by the energy extracted from the flow by the bottom drag. - if (CS%bottomdraglaw .and. (CS%BBL_effic>0.0)) then - if (CS%use_LOTW_BBL_diffusivity) then - call add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, G, GV, US, CS, & - dd%Kd_BBL, Kd_lay_2d, Kd_int_2d) - else - call add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & - maxTKE, kb, G, GV, US, CS, Kd_lay_2d, Kd_int_2d, dd%Kd_BBL) - endif - endif + ! Add the ML_Rad diffusivity. + if (CS%ML_radiation) & + call add_MLrad_diffusivity(h, fluxes, j, Kd_int_2d, G, GV, US, CS, TKE_to_Kd, Kd_lay_2d) - if (CS%limit_dissipation) then - ! This calculates the dissipation ONLY from Kd calculated in this routine - ! dissip has units of W/m3 (= kg/m3 * m2/s * 1/s2) - ! 1) a global constant, - ! 2) a dissipation proportional to N (aka Gargett) and - ! 3) dissipation corresponding to a (nearly) constant diffusivity. - do K=2,nz ; do i=is,ie - dissip = max( CS%dissip_min, & ! Const. floor on dissip. - CS%dissip_N0 + CS%dissip_N1 * sqrt(N2_int(i,K)), & ! Floor aka Gargett - CS%dissip_N2 * N2_int(i,K)) ! Floor of Kd_min*rho0/F_Ri - Kd_int_2d(i,K) = max(Kd_int_2d(i,K) , & ! Apply floor to Kd - dissip * (CS%FluxRi_max / (GV%Rho0 * (N2_int(i,K) + Omega2)))) - enddo ; enddo - endif + ! Add the Nikurashin and / or tidal bottom-driven mixing + if (CS%use_tidal_mixing) & + call calculate_tidal_mixing(h, N2_bot, j, TKE_to_Kd, maxTKE, G, GV, US, CS%tidal_mixing_CSp, & + N2_lay, N2_int, Kd_lay_2d, Kd_int_2d, CS%Kd_max, visc%Kv_slow) - ! Optionally add a uniform diffusivity at the interfaces. - if (CS%Kd_add > 0.0) then ; do K=1,nz+1 ; do i=is,ie - Kd_int_2d(i,K) = Kd_int_2d(i,K) + CS%Kd_add - enddo ; enddo ; endif + ! This adds the diffusion sustained by the energy extracted from the flow by the bottom drag. + if (CS%bottomdraglaw .and. (CS%BBL_effic>0.0)) then + if (CS%use_LOTW_BBL_diffusivity) then + call add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, Kd_int_2d, G, GV, US, CS, & + dd%Kd_BBL, Kd_lay_2d) + else + call add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & + maxTKE, kb, G, GV, US, CS, Kd_lay_2d, Kd_int_2d, dd%Kd_BBL) + endif + endif - ! Copy the 2-d slices into the 3-d array that is exported. - do K=1,nz+1 ; do i=is,ie - Kd_int(i,j,K) = Kd_int_2d(i,K) + if (CS%limit_dissipation) then + ! This calculates the dissipation ONLY from Kd calculated in this routine + ! dissip has units of W/m3 (= kg/m3 * m2/s * 1/s2) + ! 1) a global constant, + ! 2) a dissipation proportional to N (aka Gargett) and + ! 3) dissipation corresponding to a (nearly) constant diffusivity. + do K=2,nz ; do i=is,ie + dissip = max( CS%dissip_min, & ! Const. floor on dissip. + CS%dissip_N0 + CS%dissip_N1 * sqrt(N2_int(i,K)), & ! Floor aka Gargett + CS%dissip_N2 * N2_int(i,K)) ! Floor of Kd_min*rho0/F_Ri + Kd_int_2d(i,K) = max(Kd_int_2d(i,K) , & ! Apply floor to Kd + dissip * (CS%FluxRi_max / (GV%Rho0 * (N2_int(i,K) + Omega2)))) enddo ; enddo + endif - else ! Kd_int is not present. - - ! Add the ML_Rad diffusivity. - if (CS%ML_radiation) & - call add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay_2d) - - ! Add the Nikurashin and / or tidal bottom-driven mixing - if (CS%use_tidal_mixing) & - call calculate_tidal_mixing(h, N2_bot, j, TKE_to_Kd, maxTKE, G, GV, US, CS%tidal_mixing_CSp, & - N2_lay, N2_int, Kd_lay_2d, Kd_max=CS%Kd_max, Kv=visc%Kv_slow) - - ! This adds the diffusion sustained by the energy extracted from the flow by the bottom drag. - if (CS%bottomdraglaw .and. (CS%BBL_effic>0.0)) then - if (CS%use_LOTW_BBL_diffusivity) then - call add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, G, GV, US, CS, & - dd%Kd_BBL, Kd_lay_2d) - else - call add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & - maxTKE, kb, G, GV, US, CS, Kd_lay_2d, Kd_BBL=dd%Kd_BBL) - endif - endif + ! Optionally add a uniform diffusivity at the interfaces. + if (CS%Kd_add > 0.0) then ; do K=1,nz+1 ; do i=is,ie + Kd_int_2d(i,K) = Kd_int_2d(i,K) + CS%Kd_add + enddo ; enddo ; endif - endif + ! Copy the 2-d slices into the 3-d array that is exported. + do K=1,nz+1 ; do i=is,ie + Kd_int(i,j,K) = Kd_int_2d(i,K) + enddo ; enddo if (CS%limit_dissipation) then ! This calculates the layer dissipation ONLY from Kd calculated in this routine @@ -1163,7 +1134,7 @@ subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & !! thermodynamic fields. type(forcing), intent(in) :: fluxes !< A structure of thermodynamic surface fluxes type(vertvisc_type), intent(in) :: visc !< Structure containing vertical viscosities, bottom - !! boundary layer properies, and related fields + !! boundary layer properties and related fields integer, intent(in) :: j !< j-index of row to work on real, dimension(SZI_(G),SZK_(GV)), intent(in) :: TKE_to_Kd !< The conversion rate between the TKE !! TKE dissipated within a layer and the @@ -1177,8 +1148,7 @@ subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & type(set_diffusivity_CS), pointer :: CS !< Diffusivity control structure real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: Kd_lay !< The diapycnal diffusivity in layers, !! [Z2 T-1 ~> m2 s-1]. - real, dimension(SZI_(G),SZK_(GV)+1), & - optional, intent(inout) :: Kd_int !< The diapycnal diffusivity at interfaces, + real, dimension(SZI_(G),SZK_(GV)+1), intent(inout) :: Kd_int !< The diapycnal diffusivity at interfaces, !! [Z2 T-1 ~> m2 s-1]. real, dimension(:,:,:), pointer :: Kd_BBL !< Interface BBL diffusivity [Z2 T-1 ~> m2 s-1]. @@ -1330,10 +1300,8 @@ subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & else Kd_lay(i,k) = (TKE_to_layer + TKE_Ray) * TKE_to_Kd(i,k) endif - if (present(Kd_int)) then - Kd_int(i,K) = Kd_int(i,K) + 0.5 * delta_Kd - Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * delta_Kd - endif + Kd_int(i,K) = Kd_int(i,K) + 0.5 * delta_Kd + Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * delta_Kd if (do_diag_Kd_BBL) then Kd_BBL(i,j,K) = Kd_BBL(i,j,K) + 0.5 * delta_Kd Kd_BBL(i,j,K+1) = Kd_BBL(i,j,K+1) + 0.5 * delta_Kd @@ -1357,10 +1325,8 @@ subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, & delta_Kd = TKE_here * TKE_to_Kd(i,k) if (CS%Kd_max >= 0.0) delta_Kd = min(delta_Kd, CS%Kd_max) Kd_lay(i,k) = Kd_lay(i,k) + delta_Kd - if (present(Kd_int)) then - Kd_int(i,K) = Kd_int(i,K) + 0.5 * delta_Kd - Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * delta_Kd - endif + Kd_int(i,K) = Kd_int(i,K) + 0.5 * delta_Kd + Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * delta_Kd if (do_diag_Kd_BBL) then Kd_BBL(i,j,K) = Kd_BBL(i,j,K) + 0.5 * delta_Kd Kd_BBL(i,j,K+1) = Kd_BBL(i,j,K+1) + 0.5 * delta_Kd @@ -1386,8 +1352,8 @@ end subroutine add_drag_diffusivity !> Calculates a BBL diffusivity use a Prandtl number 1 diffusivity with a law of the !! wall turbulent viscosity, up to a BBL height where the energy used for mixing has !! consumed the mechanical TKE input. -subroutine add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, & - G, GV, US, CS, Kd_BBL, Kd_lay, Kd_int) +subroutine add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, Kd_int, & + G, GV, US, CS, Kd_BBL, Kd_lay) type(ocean_grid_type), intent(in) :: G !< Grid structure type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -1401,16 +1367,16 @@ subroutine add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, & !! thermodynamic fields. type(forcing), intent(in) :: fluxes !< Surface fluxes structure type(vertvisc_type), intent(in) :: visc !< Structure containing vertical viscosities, bottom - !! boundary layer properies, and related fields. + !! boundary layer properties and related fields. integer, intent(in) :: j !< j-index of row to work on real, dimension(SZI_(G),SZK_(GV)+1), & intent(in) :: N2_int !< Square of Brunt-Vaisala at interfaces [T-2 ~> s-2] + real, dimension(SZI_(G),SZK_(GV)+1), & + intent(inout) :: Kd_int !< Interface net diffusivity [Z2 T-1 ~> m2 s-1] type(set_diffusivity_CS), pointer :: CS !< Diffusivity control structure real, dimension(:,:,:), pointer :: Kd_BBL !< Interface BBL diffusivity [Z2 T-1 ~> m2 s-1] real, dimension(SZI_(G),SZK_(GV)), & optional, intent(inout) :: Kd_lay !< Layer net diffusivity [Z2 T-1 ~> m2 s-1] - real, dimension(SZI_(G),SZK_(GV)+1), & - optional, intent(inout) :: Kd_int !< Interface net diffusivity [Z2 T-1 ~> m2 s-1] ! Local variables real :: TKE_column ! net TKE input into the column [Z3 T-3 ~> m3 s-3] @@ -1537,7 +1503,7 @@ subroutine add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, & TKE_remaining = TKE_remaining - TKE_consumed ! Note this will be non-negative ! Add this BBL diffusivity to the model net diffusivity. - if (present(Kd_int)) Kd_int(i,K) = Kd_int(i,K) + Kd_wall + Kd_int(i,K) = Kd_int(i,K) + Kd_wall if (present(Kd_lay)) Kd_lay(i,k) = Kd_lay(i,k) + 0.5 * (Kd_wall + Kd_lower) Kd_lower = Kd_wall ! Store for next layer up. if (do_diag_Kd_BBL) Kd_BBL(i,j,K) = Kd_wall @@ -1547,7 +1513,7 @@ subroutine add_LOTW_BBL_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, & end subroutine add_LOTW_BBL_diffusivity !> This routine adds effects of mixed layer radiation to the layer diffusivities. -subroutine add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay, Kd_int) +subroutine add_MLrad_diffusivity(h, fluxes, j, Kd_int, G, GV, US, CS, TKE_to_Kd, Kd_lay) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type @@ -1555,6 +1521,8 @@ subroutine add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay, intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] type(forcing), intent(in) :: fluxes !< Surface fluxes structure integer, intent(in) :: j !< The j-index to work on + real, dimension(SZI_(G),SZK_(GV)+1), intent(inout) :: Kd_int !< The diapycnal diffusivity at interfaces + !! [Z2 T-1 ~> m2 s-1]. type(set_diffusivity_CS), pointer :: CS !< Diffusivity control structure real, dimension(SZI_(G),SZK_(GV)), intent(in) :: TKE_to_Kd !< The conversion rate between the TKE !! TKE dissipated within a layer and the @@ -1563,9 +1531,6 @@ subroutine add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay, !! [Z2 T-1 / Z3 T-3 = T2 Z-1 ~> s2 m-1] real, dimension(SZI_(G),SZK_(GV)), & optional, intent(inout) :: Kd_lay !< The diapycnal diffusivity in layers [Z2 T-1 ~> m2 s-1]. - real, dimension(SZI_(G),SZK_(GV)+1), & - optional, intent(inout) :: Kd_int !< The diapycnal diffusivity at interfaces - !! [Z2 T-1 ~> m2 s-1]. ! This routine adds effects of mixed layer radiation to the layer diffusivities. @@ -1639,14 +1604,12 @@ subroutine add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay, Kd_lay(i,k) = Kd_lay(i,k) + Kd_mlr_ml(i) endif ; enddo ; enddo endif - if (present(Kd_int)) then - do K=2,kml+1 ; do i=is,ie ; if (do_i(i)) then - Kd_int(i,K) = Kd_int(i,K) + Kd_mlr_ml(i) - endif ; enddo ; enddo - if (kml<=nz-1) then ; do i=is,ie ; if (do_i(i)) then - Kd_int(i,Kml+2) = Kd_int(i,Kml+2) + 0.5 * Kd_mlr_ml(i) - endif ; enddo ; endif - endif + do K=2,kml+1 ; do i=is,ie ; if (do_i(i)) then + Kd_int(i,K) = Kd_int(i,K) + Kd_mlr_ml(i) + endif ; enddo ; enddo + if (kml<=nz-1) then ; do i=is,ie ; if (do_i(i)) then + Kd_int(i,Kml+2) = Kd_int(i,Kml+2) + 0.5 * Kd_mlr_ml(i) + endif ; enddo ; endif do k=kml+2,nz-1 do_any = .false. @@ -1674,10 +1637,8 @@ subroutine add_MLrad_diffusivity(h, fluxes, j, G, GV, US, CS, TKE_to_Kd, Kd_lay, if (present(Kd_lay)) then Kd_lay(i,k) = Kd_lay(i,k) + Kd_mlr endif - if (present(Kd_int)) then - Kd_int(i,K) = Kd_int(i,K) + 0.5 * Kd_mlr - Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * Kd_mlr - endif + Kd_int(i,K) = Kd_int(i,K) + 0.5 * Kd_mlr + Kd_int(i,K+1) = Kd_int(i,K+1) + 0.5 * Kd_mlr TKE_ml_flux(i) = TKE_ml_flux(i) * exp(-z1) if (TKE_ml_flux(i) * I_decay(i) < 0.1 * CS%Kd_min * Omega2) then @@ -1703,7 +1664,7 @@ subroutine set_BBL_TKE(u, v, h, fluxes, visc, G, GV, US, CS, OBC) intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2] type(forcing), intent(in) :: fluxes !< A structure of thermodynamic surface fluxes type(vertvisc_type), intent(in) :: visc !< Structure containing vertical viscosities, bottom - !! boundary layer properies, and related fields. + !! boundary layer properties and related fields. type(set_diffusivity_CS), pointer :: CS !< Diffusivity control structure type(ocean_OBC_type), pointer :: OBC !< Open boundaries control structure. @@ -1995,10 +1956,10 @@ subroutine set_diffusivity_init(Time, G, GV, US, param_file, diag, CS, int_tide_ !! structure. type(int_tide_CS), pointer :: int_tide_CSp !< A pointer to the internal tides control !! structure - integer, optional, intent(out) :: halo_TS !< The halo size of tracer points that must be + integer, intent(out) :: halo_TS !< The halo size of tracer points that must be !! valid for the calculations in set_diffusivity. - logical, optional, intent(out) :: double_diffuse !< If present, this indicates whether - !! some version of double diffusion is being used. + logical, intent(out) :: double_diffuse !< This indicates whether some version + !! of double diffusion is being used. ! Local variables real :: decay_length @@ -2323,14 +2284,10 @@ subroutine set_diffusivity_init(Time, G, GV, US, param_file, diag, CS, int_tide_ 'Double-diffusion density ratio', 'nondim') endif - if (present(halo_TS)) then - halo_TS = 0 - if (CS%Vertex_Shear) halo_TS = 1 - endif + halo_TS = 0 + if (CS%Vertex_Shear) halo_TS = 1 - if (present(double_diffuse)) then - double_diffuse = (CS%double_diffusion .or. CS%use_CVMix_ddiff) - endif + double_diffuse = (CS%double_diffusion .or. CS%use_CVMix_ddiff) end subroutine set_diffusivity_init diff --git a/src/parameterizations/vertical/MOM_vert_friction.F90 b/src/parameterizations/vertical/MOM_vert_friction.F90 index f9512d8c06..d0d3943a26 100644 --- a/src/parameterizations/vertical/MOM_vert_friction.F90 +++ b/src/parameterizations/vertical/MOM_vert_friction.F90 @@ -128,6 +128,8 @@ module MOM_vert_friction ! integer :: id_hf_du_dt_visc = -1, id_hf_dv_dt_visc = -1 integer :: id_h_du_dt_visc = -1, id_h_dv_dt_visc = -1 integer :: id_hf_du_dt_visc_2d = -1, id_hf_dv_dt_visc_2d = -1 + integer :: id_h_du_dt_str = -1, id_h_dv_dt_str = -1 + integer :: id_du_dt_str_visc_rem = -1, id_dv_dt_str_visc_rem = -1 !>@} type(PointAccel_CS), pointer :: PointAccel_CSp => NULL() !< A pointer to the control structure @@ -219,6 +221,10 @@ subroutine vertvisc(u, v, h, forces, visc, dt, OBC, ADp, CDp, G, GV, US, CS, & real, allocatable, dimension(:,:,:) :: h_du_dt_visc ! h x du_dt_visc [H L T-2 ~> m2 s-2] real, allocatable, dimension(:,:,:) :: h_dv_dt_visc ! h x dv_dt_visc [H L T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: h_du_dt_str ! h x du_dt_str [H L T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: h_dv_dt_str ! h x dv_dt_str [H L T-2 ~> m2 s-2] + real, allocatable, dimension(:,:,:) :: du_dt_str_visc_rem ! du_dt_str x visc_rem_u [L T-2 ~> m s-2] + real, allocatable, dimension(:,:,:) :: dv_dt_str_visc_rem ! dv_dt_str x visc_rem_v [L T-2 ~> m s-2] logical :: do_i(SZIB_(G)) logical :: DoStokesMixing @@ -565,6 +571,44 @@ subroutine vertvisc(u, v, h, forces, visc, dt, OBC, ADp, CDp, G, GV, US, CS, & deallocate(h_dv_dt_visc) endif + if (CS%id_h_du_dt_str > 0) then + allocate(h_du_dt_str(G%IsdB:G%IedB,G%jsd:G%jed,GV%ke)) + h_du_dt_str(:,:,:) = 0.0 + do k=1,nz ; do j=js,je ; do I=Isq,Ieq + h_du_dt_str(I,j,k) = ADp%du_dt_str(I,j,k) * ADp%diag_hu(I,j,k) + enddo ; enddo ; enddo + call post_data(CS%id_h_du_dt_str, h_du_dt_str, CS%diag) + deallocate(h_du_dt_str) + endif + if (CS%id_h_dv_dt_str > 0) then + allocate(h_dv_dt_str(G%isd:G%ied,G%JsdB:G%JedB,GV%ke)) + h_dv_dt_str(:,:,:) = 0.0 + do k=1,nz ; do J=Jsq,Jeq ; do i=is,ie + h_dv_dt_str(i,J,k) = ADp%dv_dt_str(i,J,k) * ADp%diag_hv(i,J,k) + enddo ; enddo ; enddo + call post_data(CS%id_h_dv_dt_str, h_dv_dt_str, CS%diag) + deallocate(h_dv_dt_str) + endif + + if (CS%id_du_dt_str_visc_rem > 0) then + allocate(du_dt_str_visc_rem(G%IsdB:G%IedB,G%jsd:G%jed,GV%ke)) + du_dt_str_visc_rem(:,:,:) = 0.0 + do k=1,nz ; do j=js,je ; do I=Isq,Ieq + du_dt_str_visc_rem(I,j,k) = ADp%du_dt_str(I,j,k) * ADp%visc_rem_u(I,j,k) + enddo ; enddo ; enddo + call post_data(CS%id_du_dt_str_visc_rem, du_dt_str_visc_rem, CS%diag) + deallocate(du_dt_str_visc_rem) + endif + if (CS%id_dv_dt_str_visc_rem > 0) then + allocate(dv_dt_str_visc_rem(G%isd:G%ied,G%JsdB:G%JedB,GV%ke)) + dv_dt_str_visc_rem(:,:,:) = 0.0 + do k=1,nz ; do J=Jsq,Jeq ; do i=is,ie + dv_dt_str_visc_rem(i,J,k) = ADp%dv_dt_str(i,J,k) * ADp%visc_rem_v(i,J,k) + enddo ; enddo ; enddo + call post_data(CS%id_dv_dt_str_visc_rem, dv_dt_str_visc_rem, CS%diag) + deallocate(dv_dt_str_visc_rem) + endif + end subroutine vertvisc !> Calculate the fraction of momentum originally in a layer that remains in the water column @@ -1914,6 +1958,38 @@ subroutine vertvisc_init(MIS, Time, G, GV, US, param_file, diag, ADp, dirs, & call safe_alloc_ptr(ADp%diag_hv,isd,ied,JsdB,JedB,nz) endif + CS%id_h_du_dt_str = register_diag_field('ocean_model', 'h_du_dt_str', diag%axesCuL, Time, & + 'Thickness Multiplied Zonal Acceleration from Surface Wind Stresses', 'm2 s-2', & + conversion=GV%H_to_m*US%L_T2_to_m_s2) + if (CS%id_h_du_dt_str > 0) then + call safe_alloc_ptr(ADp%du_dt_str,IsdB,IedB,jsd,jed,nz) + call safe_alloc_ptr(ADp%diag_hu,IsdB,IedB,jsd,jed,nz) + endif + + CS%id_h_dv_dt_str = register_diag_field('ocean_model', 'h_dv_dt_str', diag%axesCvL, Time, & + 'Thickness Multiplied Meridional Acceleration from Surface Wind Stresses', 'm2 s-2', & + conversion=GV%H_to_m*US%L_T2_to_m_s2) + if (CS%id_h_dv_dt_str > 0) then + call safe_alloc_ptr(ADp%dv_dt_str,isd,ied,JsdB,JedB,nz) + call safe_alloc_ptr(ADp%diag_hv,isd,ied,JsdB,JedB,nz) + endif + + CS%id_du_dt_str_visc_rem = register_diag_field('ocean_model', 'du_dt_str_visc_rem', diag%axesCuL, Time, & + 'Zonal Acceleration from Surface Wind Stresses multiplied by viscous remnant', 'm s-2', & + conversion=US%L_T2_to_m_s2) + if (CS%id_du_dt_str_visc_rem > 0) then + call safe_alloc_ptr(ADp%du_dt_str,IsdB,IedB,jsd,jed,nz) + call safe_alloc_ptr(ADp%visc_rem_u,IsdB,IedB,jsd,jed,nz) + endif + + CS%id_dv_dt_str_visc_rem = register_diag_field('ocean_model', 'dv_dt_str_visc_rem', diag%axesCvL, Time, & + 'Meridional Acceleration from Surface Wind Stresses multiplied by viscous remnant', 'm s-2', & + conversion=US%L_T2_to_m_s2) + if (CS%id_dv_dt_str_visc_rem > 0) then + call safe_alloc_ptr(ADp%dv_dt_str,isd,ied,JsdB,JedB,nz) + call safe_alloc_ptr(ADp%visc_rem_v,isd,ied,JsdB,JedB,nz) + endif + if ((len_trim(CS%u_trunc_file) > 0) .or. (len_trim(CS%v_trunc_file) > 0)) & call PointAccel_init(MIS, Time, G, param_file, diag, dirs, CS%PointAccel_CSp)