From 315e1cd3748549a066051835a3e9aba054505082 Mon Sep 17 00:00:00 2001 From: Michael Levy Date: Thu, 4 Apr 2024 11:42:08 -0600 Subject: [PATCH] Updates for dimensional scaling test Currently fails T-scaling test with solo driver, probably fails lots of other scaling tests as well. This commit 1. Adds debug output to MARBL_tracers.F90 2. Gets dimensions correct in comments of MOM_forcing_type, MARBL_forcing_mod, and MARBL_tracers 3. Scales forcings correctly for the MARBL surface_flux_compute() step (at least in T); output highlights issues in computing source / sink term from interior_tendency_compute() One of the biggest changes from this commit is the handling of units for the nitrogen deposition fluxes. It looks like they were coming in as kg/m^2/s, being converted to mol/L^2/T in fluxes%{nhx_dep,noy_dep}, and then converted to mmol/m^2/s when copied into MARBL. Now the intermediate stage is mmol/m^3 Z/T; this is not bit-for-bit with the previous setup because I went from multiplying by (1000/14) (kg -> mol) and then another 1000 in the third step (mol -> mmol) to just multiplying by 1e6/14 (kg -> mmol) in the second step. --- .../nuopc_cap/mom_surface_forcing_nuopc.F90 | 3 +- .../solo_driver/MOM_surface_forcing.F90 | 35 +++++----- src/core/MOM_forcing_type.F90 | 8 +-- src/tracer/MARBL_forcing_mod.F90 | 56 +++++++--------- src/tracer/MARBL_tracers.F90 | 67 ++++++++++++++----- 5 files changed, 100 insertions(+), 69 deletions(-) diff --git a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 index 91944282e7..f9bd777a9b 100644 --- a/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 +++ b/config_src/drivers/nuopc_cap/mom_surface_forcing_nuopc.F90 @@ -1422,7 +1422,8 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, restore_salt, endif ! Set up MARBL forcing control structure - call MARBL_forcing_init(G, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, CS%marbl_forcing_CSp) + call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, & + CS%marbl_forcing_CSp) if (present(restore_salt)) then ; if (restore_salt) then salt_file = trim(CS%inputdir) // trim(CS%salt_restore_file) diff --git a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 index 414f077884..60cc46e274 100644 --- a/config_src/drivers/solo_driver/MOM_surface_forcing.F90 +++ b/config_src/drivers/solo_driver/MOM_surface_forcing.F90 @@ -1562,13 +1562,13 @@ subroutine MARBL_forcing_from_data_override(fluxes, day, G, US, CS) ! Local variables real, pointer, dimension(:,:) :: atm_co2_prog =>NULL() !< Prognostic atmospheric CO2 concentration [ppm] real, pointer, dimension(:,:) :: atm_co2_diag =>NULL() !< Diagnostic atmospheric CO2 concentration [ppm] - real, pointer, dimension(:,:) :: atm_fine_dust_flux =>NULL() !< Fine dust flux from atmosphere [kg/m^2/s] - real, pointer, dimension(:,:) :: atm_coarse_dust_flux =>NULL() !< Coarse dust flux from atmosphere [kg/m^2/s] - real, pointer, dimension(:,:) :: seaice_dust_flux =>NULL() !< Dust flux from seaice [kg/m^2/s] - real, pointer, dimension(:,:) :: atm_bc_flux =>NULL() !< Black carbon flux from atmosphere [kg/m^2/s] - real, pointer, dimension(:,:) :: seaice_bc_flux =>NULL() !< Black carbon flux from seaice [kg/m^2/s] - real, pointer, dimension(:,:) :: nhx_dep =>NULL() !< Nitrogen deposition [kg/m^2/s] - real, pointer, dimension(:,:) :: noy_dep =>NULL() !< Nitrogen deposition [kg/m^2/s] + real, pointer, dimension(:,:) :: atm_fine_dust_flux =>NULL() !< Fine dust flux from atmosphere [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: atm_coarse_dust_flux =>NULL() !< Coarse dust flux from atmosphere [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: seaice_dust_flux =>NULL() !< Dust flux from seaice [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: atm_bc_flux =>NULL() !< Black carbon flux from atmosphere [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: seaice_bc_flux =>NULL() !< Black carbon flux from seaice [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: nhx_dep =>NULL() !< Nitrogen deposition [kg/m^2/s ~> RZ/T] + real, pointer, dimension(:,:) :: noy_dep =>NULL() !< Nitrogen deposition [kg/m^2/s ~> RZ/T] integer :: isc, iec, jsc, jec ! Necessary null pointers for arguments to convert_marbl_IOB_to_forcings() @@ -1608,16 +1608,18 @@ subroutine MARBL_forcing_from_data_override(fluxes, day, G, US, CS) noy_dep(:,:) = 0.0 call data_override(G%Domain, 'ice_fraction', fluxes%ice_fraction, day) - call data_override(G%Domain, 'u10_sqr', fluxes%u10_sqr, day) + call data_override(G%Domain, 'u10_sqr', fluxes%u10_sqr, day, scale=US%m_s_to_L_T**2) call data_override(G%Domain, 'atm_co2_prog', atm_co2_prog, day) call data_override(G%Domain, 'atm_co2_diag', atm_co2_diag, day) - call data_override(G%Domain, 'atm_fine_dust_flux', atm_fine_dust_flux, day) - call data_override(G%Domain, 'atm_coarse_dust_flux', atm_coarse_dust_flux, day) - call data_override(G%Domain, 'atm_bc_flux', atm_bc_flux, day) - call data_override(G%Domain, 'seaice_dust_flux', seaice_dust_flux, day) - call data_override(G%Domain, 'seaice_bc_flux', seaice_bc_flux, day) - call data_override(G%Domain, 'nhx_dep', nhx_dep, day) - call data_override(G%Domain, 'noy_dep', noy_dep, day) + call data_override(G%Domain, 'atm_fine_dust_flux', atm_fine_dust_flux, day, & + scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'atm_coarse_dust_flux', atm_coarse_dust_flux, day, & + scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'atm_bc_flux', atm_bc_flux, day, scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'seaice_dust_flux', seaice_dust_flux, day, scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'seaice_bc_flux', seaice_bc_flux, day, scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'nhx_dep', nhx_dep, day, scale=US%kg_m2s_to_RZ_T) + call data_override(G%Domain, 'noy_dep', noy_dep, day, scale=US%kg_m2s_to_RZ_T) call convert_marbl_IOB_to_forcings(atm_fine_dust_flux, atm_coarse_dust_flux, & seaice_dust_flux, atm_bc_flux, seaice_bc_flux, & @@ -2078,7 +2080,8 @@ subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, tracer_flow_C endif ! Set up MARBL forcing control structure - call MARBL_forcing_init(G, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, CS%marbl_forcing_CSp) + call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, & + CS%marbl_forcing_CSp) call register_forcing_type_diags(Time, diag, US, CS%use_temperature, CS%handles) diff --git a/src/core/MOM_forcing_type.F90 b/src/core/MOM_forcing_type.F90 index 4c137745d2..6bbe14e802 100644 --- a/src/core/MOM_forcing_type.F90 +++ b/src/core/MOM_forcing_type.F90 @@ -220,12 +220,12 @@ module MOM_forcing_type ! Forcing fields required for MARBL real, pointer, dimension(:,:) :: & - noy_dep => NULL(), & !< NOy Deposition [R Z T-1 ~> kgN m-2 s-1] - nhx_dep => NULL(), & !< NHx Deposition [R Z T-1 ~> kgN m-2 s-1] + noy_dep => NULL(), & !< NOy Deposition [conc Z T-1 ~> conc m s-1] + nhx_dep => NULL(), & !< NHx Deposition [conc Z T-1 ~> conc m s-1] atm_co2 => NULL(), & !< Atmospheric CO2 Concentration [ppm] atm_alt_co2 => NULL(), & !< Alternate atmospheric CO2 Concentration [ppm] - dust_flux => NULL(), & !< Flux of dust into the ocean [m2 m-2] - iron_flux => NULL() !< Flux of dust into the ocean [m2 m-2] + dust_flux => NULL(), & !< Flux of dust into the ocean [R Z T-1 ~> kgN m-2 s-1] + iron_flux => NULL() !< Flux of dust into the ocean [conc Z T-1 ~> conc m s-1] real, pointer, dimension(:,:,:) :: & fracr_cat => NULL(), & !< per-category ice fraction diff --git a/src/tracer/MARBL_forcing_mod.F90 b/src/tracer/MARBL_forcing_mod.F90 index 466578c0ea..2ef8b302ff 100644 --- a/src/tracer/MARBL_forcing_mod.F90 +++ b/src/tracer/MARBL_forcing_mod.F90 @@ -69,8 +69,9 @@ module MARBL_forcing_mod contains - subroutine MARBL_forcing_init(G, param_file, diag, day, inputdir, use_marbl, CS) + subroutine MARBL_forcing_init(G, US, param_file, diag, day, inputdir, use_marbl, CS) type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure + type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters type(diag_ctrl), target, intent(in) :: diag !< Structure used to regulate diagnostic output. type(time_type), target, intent(in) :: day !< Time of the start of the run. @@ -162,20 +163,20 @@ subroutine MARBL_forcing_init(G, param_file, diag, day, inputdir, use_marbl, CS) ! Register diagnostic fields for outputing forcing values CS%diag_ids%atm_fine_dust = register_diag_field("ocean_model", "ATM_FINE_DUST_FLUX_CPL", & CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_FINE_DUST_FLUX from cpl", "kg/m^2/s") + day, "ATM_FINE_DUST_FLUX from cpl", "kg/m^2/s", conversion=US%RZ_T_to_kg_m2s) CS%diag_ids%atm_coarse_dust = register_diag_field("ocean_model", "ATM_COARSE_DUST_FLUX_CPL", & CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_COARSE_DUST_FLUX from cpl", "kg/m^2/s") + day, "ATM_COARSE_DUST_FLUX from cpl", "kg/m^2/s", conversion=US%RZ_T_to_kg_m2s) CS%diag_ids%atm_bc = register_diag_field("ocean_model", "ATM_BLACK_CARBON_FLUX_CPL", & CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "ATM_BLACK_CARBON_FLUX from cpl", "kg/m^2/s") + day, "ATM_BLACK_CARBON_FLUX from cpl", "kg/m^2/s", conversion=US%RZ_T_to_kg_m2s) CS%diag_ids%ice_dust = register_diag_field("ocean_model", "SEAICE_DUST_FLUX_CPL", & CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "SEAICE_DUST_FLUX from cpl", "kg/m^2/s") + day, "SEAICE_DUST_FLUX from cpl", "kg/m^2/s", conversion=US%RZ_T_to_kg_m2s) CS%diag_ids%ice_bc = register_diag_field("ocean_model", "SEAICE_BLACK_CARBON_FLUX_CPL", & CS%diag%axesT1, & ! T=> tracer grid? 1 => no vertical grid - day, "SEAICE_BLACK_CARBON_FLUX from cpl", "kg/m^2/s") + day, "SEAICE_BLACK_CARBON_FLUX from cpl", "kg/m^2/s", conversion=US%RZ_T_to_kg_m2s) end subroutine MARBL_forcing_init @@ -186,14 +187,14 @@ subroutine convert_marbl_IOB_to_forcings(atm_fine_dust_flux, atm_coarse_dust_flu afracr, swnet_afracr, ifrac_n, & swpen_ifrac_n, Time, G, US, i0, j0, fluxes, CS) - real, dimension(:,:), pointer, intent(in) :: atm_fine_dust_flux !< atmosphere fine dust flux from IOB - real, dimension(:,:), pointer, intent(in) :: atm_coarse_dust_flux !< atmosphere coarse dust flux from IOB - real, dimension(:,:), pointer, intent(in) :: seaice_dust_flux !< sea ice dust flux from IOB - real, dimension(:,:), pointer, intent(in) :: atm_bc_flux !< atmosphere black carbon flux from IOB - real, dimension(:,:), pointer, intent(in) :: seaice_bc_flux !< sea ice black carbon flux from IOB + real, dimension(:,:), pointer, intent(in) :: atm_fine_dust_flux !< atmosphere fine dust flux from IOB [R Z T-1] + real, dimension(:,:), pointer, intent(in) :: atm_coarse_dust_flux !< atmosphere coarse dust flux from IOB [R Z T-1] + real, dimension(:,:), pointer, intent(in) :: seaice_dust_flux !< sea ice dust flux from IOB [R Z T-1] + real, dimension(:,:), pointer, intent(in) :: atm_bc_flux !< atmosphere black carbon flux from IOB [R Z T-1] + real, dimension(:,:), pointer, intent(in) :: seaice_bc_flux !< sea ice black carbon flux from IOB [R Z T-1] real, dimension(:,:), pointer, intent(in) :: afracr !< open ocean fraction - real, dimension(:,:), pointer, intent(in) :: nhx_dep !< NHx flux from atmosphere - real, dimension(:,:), pointer, intent(in) :: noy_dep !< NOy flux from atmosphere + real, dimension(:,:), pointer, intent(in) :: nhx_dep !< NHx flux from atmosphere [R Z T-1] + real, dimension(:,:), pointer, intent(in) :: noy_dep !< NOy flux from atmosphere [R Z T-1] real, dimension(:,:), pointer, intent(in) :: atm_co2_prog !< Prognostic atmospheric CO2 concentration real, dimension(:,:), pointer, intent(in) :: atm_co2_diag !< Diagnostic atmospheric CO2 concentration real, dimension(:,:), pointer, intent(in) :: swnet_afracr !< shortwave flux * open ocean fraction @@ -221,29 +222,25 @@ subroutine convert_marbl_IOB_to_forcings(atm_fine_dust_flux, atm_coarse_dust_flu if (.not. CS%use_marbl_tracers) return is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec - ndep_conversion = (1000./14.) * ((US%L_to_m**2) * US%T_to_s) - iron_flux_conversion = US%kg_m2s_to_RZ_T * 1.e6 / molw_Fe ! kg / m^2 / s -> mmol / m^2 / s + ndep_conversion = (US%RZ_T_to_kg_m2s * US%m_to_Z * US%T_to_s) * (1.e6/14.) ! R Z / T -> mmol / m^3 Z / T + iron_flux_conversion = (US%RZ_T_to_kg_m2s * US%m_to_Z * US%T_to_s) * 1.e6 / molw_Fe ! R Z / T -> mmol / m^3 Z / T ! Post fields from coupler to diagnostics ! TODO: units from diag register are incorrect; we should be converting these in the cap, I think if (CS%diag_ids%atm_fine_dust > 0) & - call post_data(CS%diag_ids%atm_fine_dust, & - US%kg_m2s_to_RZ_T * atm_fine_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) + call post_data(CS%diag_ids%atm_fine_dust, atm_fine_dust_flux(is-i0:ie-i0,js-j0:je-j0), & + CS%diag, mask=G%mask2dT(is:ie,js:je)) if (CS%diag_ids%atm_coarse_dust > 0) & - call post_data(CS%diag_ids%atm_coarse_dust, & - US%kg_m2s_to_RZ_T * atm_coarse_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & - mask=G%mask2dT(is:ie,js:je)) - if (CS%diag_ids%atm_bc > 0) & - call post_data(CS%diag_ids%atm_bc, US%kg_m2s_to_RZ_T * atm_bc_flux(is-i0:ie-i0,js-j0:je-j0), & + call post_data(CS%diag_ids%atm_coarse_dust, atm_coarse_dust_flux(is-i0:ie-i0,js-j0:je-j0), & CS%diag, mask=G%mask2dT(is:ie,js:je)) + if (CS%diag_ids%atm_bc > 0) & + call post_data(CS%diag_ids%atm_bc, atm_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + mask=G%mask2dT(is:ie,js:je)) if (CS%diag_ids%ice_dust > 0) & - call post_data(CS%diag_ids%ice_dust, & - US%kg_m2s_to_RZ_T * seaice_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + call post_data(CS%diag_ids%ice_dust, seaice_dust_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & mask=G%mask2dT(is:ie,js:je)) if (CS%diag_ids%ice_bc > 0) & - call post_data(CS%diag_ids%ice_bc, & - US%kg_m2s_to_RZ_T * seaice_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & + call post_data(CS%diag_ids%ice_bc, seaice_bc_flux(is-i0:ie-i0,js-j0:je-j0), CS%diag, & mask=G%mask2dT(is:ie,js:je)) do j=js,je ; do i=is,ie @@ -306,9 +303,8 @@ subroutine convert_marbl_IOB_to_forcings(atm_fine_dust_flux, atm_coarse_dust_flu if (associated(atm_fine_dust_flux)) then do j=js,je ; do i=is,ie - fluxes%dust_flux(i,j) = (G%mask2dT(i,j) * US%kg_m2s_to_RZ_T) * & - (atm_fine_dust_flux(i-i0,j-j0) + atm_coarse_dust_flux(i-i0,j-j0) + & - seaice_dust_flux(i-i0,j-j0)) + fluxes%dust_flux(i,j) = G%mask2dT(i,j) * (atm_fine_dust_flux(i-i0,j-j0) + & + atm_coarse_dust_flux(i-i0,j-j0) + seaice_dust_flux(i-i0,j-j0)) enddo ; enddo endif diff --git a/src/tracer/MARBL_tracers.F90 b/src/tracer/MARBL_tracers.F90 index 78df8b6781..c14b6d4d2a 100644 --- a/src/tracer/MARBL_tracers.F90 +++ b/src/tracer/MARBL_tracers.F90 @@ -8,6 +8,7 @@ module MARBL_tracers ! This file is part of MOM6. See LICENSE.md for the license. use MOM_coms, only : root_PE, broadcast +use MOM_debugging, only : hchksum use MOM_diag_mediator, only : diag_ctrl use MOM_error_handler, only : is_root_PE, MOM_error, FATAL, WARNING, NOTE use MOM_file_parser, only : get_param, log_param, log_version, param_file_type @@ -104,6 +105,7 @@ module MARBL_tracers !> The control structure for the MARBL tracer package type, public :: MARBL_tracers_CS ; private integer :: ntr !< The number of tracers that are actually used. + logical :: debug !< If true, write verbose checksums for debugging purposes. logical :: base_bio_on !< Will MARBL use base biotic tracers? logical :: abio_dic_on !< Will MARBL use abiotic DIC / DI14C tracers? logical :: ciso_on !< Will MARBL use isotopic tracers? @@ -188,7 +190,7 @@ module MARBL_tracers integer, allocatable :: qsw_cat_id(:) !< register_diag index for per-category shortwave real, allocatable :: STF(:,:,:) !< surface fluxes returned from MARBL to use in tracer_vertdiff - !! (dims: i, j, tracer) [conc m/s] + !! (dims: i, j, tracer) [conc Z T-1 ~> conc m s-1] real, allocatable :: SFO(:,:,:) !< surface flux output returned from MARBL for use in GCM !! e.g. CO2 flux to pass to atmosphere (dims: i, j, num_sfo) real, allocatable :: ITO(:,:,:,:) !< interior tendency output returned from MARBL for use in GCM @@ -257,7 +259,7 @@ module MARBL_tracers real, allocatable :: d14c(:,:) !< d14c forcing for abiotic DIC and carbon isotope tracer modules real, allocatable :: RIV_FLUXES(:,:,:) !< river flux forcing for applyTracerBoundaryFluxesInOut !! (needs to be time-integrated when passed to function!) - !! (dims: i, j, tracer) [conc m/s] + !! (dims: i, j, tracer) [conc m s-1] character(len=15), allocatable :: tracer_restoring_varname(:) !< name of variable being restored real, allocatable :: rtau(:,:,:) !< 1 / restoring time scale for marbl tracers (dims: i, j, k) [1/s] real, allocatable, dimension(:,:,:,:) :: restoring_in !< Restoring fields read from file @@ -306,6 +308,9 @@ subroutine configure_MARBL_tracers(GV, param_file, CS) ! (1) Read parameters necessary for general setup of MARBL call log_version(param_file, mdl, version, "") + call get_param(param_file, mdl, "DEBUG", CS%debug, & + "If true, write out verbose debugging data.", & + default=.false., debuggingParam=.true.) call get_param(param_file, mdl, "MARBL_SETTINGS_FILE", CS%marbl_settings_file, & "The name of a file from which to read the run-time settings for MARBL.", default="marbl_in") call get_param(param_file, mdl, "BOT_FLUX_MIX_THICKNESS", CS%bot_flux_mix_thickness, & @@ -675,7 +680,7 @@ function register_MARBL_tracers(HI, GV, US, param_file, CS, tr_Reg, restart_CS) endif do m=1,3 write(var_name, "(A,I0)") "MARBL_D14C_FILE_", m - write(file_name, "(A,I0,A)"), "atm_delta_C14_CMIP6_sector", m, & + write(file_name, "(A,I0,A)") "atm_delta_C14_CMIP6_sector", m, & "_global_1850-2015_yearly_v2.0_c240202.nc" call get_param(param_file, mdl, var_name, CS%d14c_dataset(m)%file_name, & "The file in which the d14c forcing field can be found.", default=file_name) @@ -846,7 +851,7 @@ subroutine initialize_MARBL_tracers(restart, day, G, GV, US, h, param_file, diag write(units, "(2A)") trim(MARBL_instances%tracer_metadata(m)%units), " m/s" CS%id_surface_flux_out(m) = register_diag_field("ocean_model", trim(name), & diag%axesT1, & ! T => tracer grid? 1 => no vertical grid - day, trim(longname), trim(units)) + day, trim(longname), trim(units), conversion=US%Z_to_m*US%s_to_T) write(name, "(2A)") "J_", trim(MARBL_instances%tracer_metadata(m)%short_name) write(longname, "(2A)") trim(MARBL_instances%tracer_metadata(m)%long_name), " Source Sink Term" @@ -1218,11 +1223,8 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, real, dimension(0:GV%ke) :: zi ! z-coordinate interface depth real, dimension(GV%ke) :: zc, dz ! z-coordinate layer center depth and cell thickness integer :: i, j, k, is, ie, js, je, nz, m - real :: ndep_conversion ! mol L-2 T-1 -> mmol m-2 s-1 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke - ! First two terms get us to mol m-2 s-1; 1e3 gets us mmol m-2 s-1, which is what MARBL wants - ndep_conversion = ((US%m_to_L)**2) * US%s_to_T * 1.e3 if (.not.associated(CS)) return if (CS%ntr < 1) return @@ -1250,7 +1252,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, ! MARBL wants u10_sqr in (m/s)^2 if (CS%u10_sqr_ind > 0) & MARBL_instances%surface_flux_forcings(CS%u10_sqr_ind)%field_0d(1) = fluxes%u10_sqr(i,j) * & - ((US%L_t_to_m_s)**2) + ((US%L_T_to_m_s)**2) ! mct_driver/ocn_cap_methods:93 -- ice_ocean_boundary%p(i,j) comes from coupler ! We may need a new ice_ocean_boundary%p_atm because %p includes ice in GFDL driver @@ -1260,8 +1262,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, fluxes%p_surf_full(i,j) * ((US%R_to_kg_m3 * (US%L_T_to_m_s**2)) * atm_per_Pa) else ! hardcode value of 1 atm (can't figure out how to get this from solo_driver) - MARBL_instances%surface_flux_forcings(CS%atmpress_ind)%field_0d(1) = & - 1. * (US%R_to_kg_m3 * (US%L_T_to_m_s**2)) + MARBL_instances%surface_flux_forcings(CS%atmpress_ind)%field_0d(1) = 1. endif endif @@ -1273,18 +1274,20 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, ! These are okay, but need option to read in from file if (CS%dust_dep_ind > 0) & - MARBL_instances%surface_flux_forcings(CS%dust_dep_ind)%field_0d(1) = fluxes%dust_flux(i,j) + MARBL_instances%surface_flux_forcings(CS%dust_dep_ind)%field_0d(1) = & + fluxes%dust_flux(i,j) * US%RZ_T_to_kg_m2s if (CS%fe_dep_ind > 0) & - MARBL_instances%surface_flux_forcings(CS%fe_dep_ind)%field_0d(1) = fluxes%iron_flux(i,j) + MARBL_instances%surface_flux_forcings(CS%fe_dep_ind)%field_0d(1) = & + fluxes%iron_flux(i,j) * (US%Z_to_m * US%s_to_T) ! MARBL wants ndep in (mmol/m^2/s) if (CS%nox_flux_ind > 0) & MARBL_instances%surface_flux_forcings(CS%nox_flux_ind)%field_0d(1) = fluxes%noy_dep(i,j) * & - ndep_conversion + (US%Z_to_m * US%s_to_T) if (CS%nhy_flux_ind > 0) & MARBL_instances%surface_flux_forcings(CS%nhy_flux_ind)%field_0d(1) = fluxes%nhx_dep(i,j) * & - ndep_conversion + (US%Z_to_m * US%s_to_T) if (CS%d14c_ind > 0) & MARBL_instances%surface_flux_forcings(CS%d14c_ind)%field_0d(1) = CS%d14c(i,j) @@ -1327,7 +1330,7 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, enddo ! * Surface tracer flux - CS%STF(i,j,:) = MARBL_instances%surface_fluxes(1,:) + CS%STF(i,j,:) = MARBL_instances%surface_fluxes(1,:) * (US%m_to_Z * US%T_to_s) ! * Surface flux output do m=1,CS%sfo_cnt @@ -1337,6 +1340,14 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, enddo enddo + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%STF(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//" sfc_flux", G%HI, & + scale=US%Z_to_m*US%s_to_T) + enddo + endif + ! (2) Post surface fluxes and their diagnostics (currently all 2D) do m=1,CS%ntr if (CS%id_surface_flux_out(m) > 0) & @@ -1354,7 +1365,13 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, do m=1,CS%ntr call KPP_NonLocalTransport(KPP_CSp, G, GV, h_old, nonLocalTrans, CS%STF(:,:,m), dt, & CS%diag, CS%tracer_data(m)%tr_ptr, CS%tracer_data(m)%tr(:,:,:), & - flux_scale=GV%Z_to_H * US%T_to_s) + flux_scale=GV%Z_to_H) + enddo + endif + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%tracer_data(m)%tr(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' post KPP', G%HI) enddo endif endif @@ -1369,12 +1386,19 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, call applyTracerBoundaryFluxesInOut(G, GV, CS%tracer_data(m)%tr(:,:,:) , dt, fluxes, h_work, & evap_CFL_limit, minimum_forcing_depth, in_flux_optional=riv_flux_loc) call tracer_vertdiff(h_work, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & - sfc_flux=GV%Rho0 * CS%STF(:,:,m) * US%T_to_s) + sfc_flux=GV%Rho0 * CS%STF(:,:,m)) enddo else do m=1,CS%ntr call tracer_vertdiff(h_old, ea, eb, dt, CS%tracer_data(m)%tr(:,:,:), G, GV, & - sfc_flux=GV%Rho0 * CS%STF(:,:,m) * US%T_to_s) + sfc_flux=GV%Rho0 * CS%STF(:,:,m)) + enddo + endif + + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%tracer_data(m)%tr(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' post tracer_vertdiff', G%HI) enddo endif @@ -1585,6 +1609,13 @@ subroutine MARBL_tracers_column_physics(h_old, h_new, ea, eb, fluxes, dt, G, GV, enddo enddo + if (CS%debug) then + do m=1,CS%ntr + call hchksum(CS%tracer_data(m)%tr(:,:,m), & + trim(MARBL_instances%tracer_metadata(m)%short_name)//' post source-sink', G%HI) + enddo + endif + ! (5) Post diagnostics from our buffer ! i. Interior tendency diagnostics (mix of 2D and 3D) ! ii. Interior tendencies themselves