diff --git a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp index 3b763a5ecdb9..26c86c4f5bf4 100644 --- a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp +++ b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp @@ -202,22 +202,31 @@ void MAMMicrophysics::set_grids( add_field("dqdt_h2so4_uptake", vector2d_nmodes, kg/m2/s, grid_name); // Diagnostic fields for aerosol microphysics + + //Flag to indicate if we want to compute extra diagnostics extra_mam4_aero_microphys_diags_ = m_params.get("extra_mam4_aero_microphys_diags", false); if (extra_mam4_aero_microphys_diags_) { const FieldLayout vector3d_num_gas_aerosol_constituents = grid_->get_3d_vector_layout(true, mam_coupling::gas_pcnst(), "num_gas_aerosol_constituents"); - // Diagnostics: tendencies due to gas phase chemistry [kg/kg/s] - add_field("mam4_microphysics_tendency_gas_phase_chemistry", vector3d_num_gas_aerosol_constituents, kg / kg / s, grid_name); + // Diagnostics: tendencies due to gas phase chemistry [mixed units: kg/kg/s or #/kg/s] + add_field("mam4_microphysics_tendency_gas_phase_chemistry", vector3d_num_gas_aerosol_constituents, nondim, grid_name); + + // Diagnostics: tendencies due to aqueous chemistry [mixed units: kg/kg/s or #/kg/s] + add_field("mam4_microphysics_tendency_aqueous_chemistry", vector3d_num_gas_aerosol_constituents, nondim, grid_name); - // Diagnostics: tendencies due to aqueous chemistry [kg/kg/s] - add_field("mam4_microphysics_tendency_aqueous_chemistry", vector3d_num_gas_aerosol_constituents, kg / kg / s, grid_name); + // Diagnostics: SO4 in-cloud tendencies [mixed units: kg/kg/s or #/kg/s] + add_field("mam4_microphysics_tendency_aqso4", vector3d_mid_nmodes, nondim, grid_name); - // Diagnostics: SO4 in-cloud tendencies[kg/kg/s] - add_field("mam4_microphysics_tendency_aqso4", vector3d_mid_nmodes, kg / kg / s, grid_name); + // Diagnostics: H2SO4 in-cloud tendencies [mixed units: kg/kg/s or #/kg/s] + add_field("mam4_microphysics_tendency_aqh2so4", vector3d_mid_nmodes, nondim, grid_name); - // Diagnostics: H2SO4 in-cloud tendencies[kg/kg/s] - add_field("mam4_microphysics_tendency_aqh2so4", vector3d_mid_nmodes, kg / kg / s, grid_name); + // Diagnostics: tendencies due to aerosol microphysics (gas aerosol exchange) [mixed units: mol/mol/s or #/mol/s] + add_field("mam4_microphysics_tendency_condensation", vector3d_num_gas_aerosol_constituents, nondim, grid_name); + add_field("mam4_microphysics_tendency_renaming", vector3d_num_gas_aerosol_constituents, nondim, grid_name); + add_field("mam4_microphysics_tendency_nucleation", vector3d_num_gas_aerosol_constituents, nondim, grid_name); + add_field("mam4_microphysics_tendency_coagulation", vector3d_num_gas_aerosol_constituents, nondim, grid_name); + add_field("mam4_microphysics_tendency_renaming_cloud_borne", vector3d_num_gas_aerosol_constituents, nondim, grid_name); } // Creating a Linoz reader and setting Linoz parameters involves reading data @@ -516,6 +525,45 @@ void MAMMicrophysics::initialize_impl(const RunType run_type) { // cloudborne aerosol, e.g., soa_c_1 populate_cloudborne_dry_aero(dry_aero_, buffer_); + if (extra_mam4_aero_microphys_diags_) { + //Some dignostics fields have mixed units (kg/kg/s, #/kg/s, etc.) + //For these fields, we add a docstring to the field to indicate that + //the units are mixed and the user should be careful when using these fields. + //Following map contains the map of fields with mixed units and their long names. + const std::map mixed_units_fields = { + {"mam4_microphysics_tendency_gas_phase_chemistry", + "MAM4xx microphysics tendencies due to gas phase chemistry [mixed units: kg/kg/s or #/kg/s]"}, + + {"mam4_microphysics_tendency_aqueous_chemistry", + "MAM4xx microphysics tendencies due to aqueous chemistry [mixed units: kg/kg/s or #/kg/s]"}, + + {"mam4_microphysics_tendency_aqso4", + "MAM4xx microphysics tendencies due to aqueous SO4 [mixed units: kg/kg/s or #/kg/s]"}, + + {"mam4_microphysics_tendency_aqh2so4", + "MAM4xx microphysics tendencies due to aqueous H2SO4 [mixed units: kg/kg/s or #/kg/s]"}, + + {"mam4_microphysics_tendency_condensation", + "MAM4xx microphysics tendencies due to gas aerosol exchange (condensation) [mixed units: mol/mol/s or #/mol/s]"}, + + {"mam4_microphysics_tendency_renaming", + "MAM4xx microphysics tendencies due to gas aerosol exchange (renaming) [mixed units: mol/mol/s or #/mol/s]"}, + + {"mam4_microphysics_tendency_nucleation", + "MAM4xx microphysics tendencies due to gas aerosol exchange (nucleation) [mixed units: mol/mol/s or #/mol/s]"}, + + {"mam4_microphysics_tendency_coagulation", + "MAM4xx microphysics tendencies due to gas aerosol exchange (coagulation) [mixed units: mol/mol/s or #/mol/s]"}, + + {"mam4_microphysics_tendency_renaming_cloud_borne", + "MAM4xx microphysics tendencies due to gas aerosol exchange (renaming cloud borne) [mixed units: mol/mol/s or #/mol/s]"}, + + }; + // Add docstring to the fields with mixed units + add_io_docstring_to_fields_with_mixed_units(mixed_units_fields); + } + + // set field property checks for the fields in this process /* e.g. using Interval = FieldWithinIntervalCheck; @@ -593,7 +641,7 @@ void MAMMicrophysics::run_impl(const double dt) { const int team_size=nlev; #else const int team_size=1; -#endif +#endif const auto policy = ekat::ExeSpaceUtils::get_team_policy_force_team_size(ncol, team_size); @@ -663,13 +711,23 @@ void MAMMicrophysics::run_impl(const double dt) { // - dvmr/dt: Tendencies for mixing ratios [kg/kg/s] view_3d gas_phase_chemistry_dvmrdt, aqueous_chemistry_dvmrdt; view_3d aqso4_incloud_mmr_tendency, aqh2so4_incloud_mmr_tendency; + view_3d gas_aero_exchange_condensation, gas_aero_exchange_renaming, + gas_aero_exchange_nucleation, gas_aero_exchange_coagulation, + gas_aero_exchange_renaming_cloud_borne; + if (extra_mam4_aero_microphys_diags_) { gas_phase_chemistry_dvmrdt = get_field_out("mam4_microphysics_tendency_gas_phase_chemistry").get_view(); aqueous_chemistry_dvmrdt = get_field_out("mam4_microphysics_tendency_aqueous_chemistry").get_view(); aqso4_incloud_mmr_tendency = get_field_out("mam4_microphysics_tendency_aqso4").get_view(); aqh2so4_incloud_mmr_tendency = get_field_out("mam4_microphysics_tendency_aqh2so4").get_view(); + gas_aero_exchange_condensation = get_field_out("mam4_microphysics_tendency_condensation").get_view(); + gas_aero_exchange_renaming = get_field_out("mam4_microphysics_tendency_renaming").get_view(); + gas_aero_exchange_nucleation = get_field_out("mam4_microphysics_tendency_nucleation").get_view(); + gas_aero_exchange_coagulation = get_field_out("mam4_microphysics_tendency_coagulation").get_view(); + gas_aero_exchange_renaming_cloud_borne = get_field_out("mam4_microphysics_tendency_renaming_cloud_borne").get_view(); } + // climatology data for linear stratospheric chemistry // ozone (climatology) [vmr] auto linoz_o3_clim = buffer_.scratch[0]; @@ -910,13 +968,22 @@ void MAMMicrophysics::run_impl(const double dt) { const auto work_set_het_icol = ekat::subview(work_set_het, icol); mam4::MicrophysDiagnosticArrays diag_arrays; + if (extra_mam4_aero_microphys_diags) { diag_arrays.gas_phase_chemistry_dvmrdt = ekat::subview(gas_phase_chemistry_dvmrdt, icol); + diag_arrays.aqueous_chemistry_dvmrdt = ekat::subview(aqueous_chemistry_dvmrdt, icol); diag_arrays.aqso4_incloud_mmr_tendency = ekat::subview(aqso4_incloud_mmr_tendency, icol); diag_arrays.aqh2so4_incloud_mmr_tendency = ekat::subview(aqh2so4_incloud_mmr_tendency, icol); + + diag_arrays.gas_aero_exchange_condensation = ekat::subview(gas_aero_exchange_condensation, icol); + diag_arrays.gas_aero_exchange_renaming = ekat::subview(gas_aero_exchange_renaming, icol); + diag_arrays.gas_aero_exchange_nucleation = ekat::subview(gas_aero_exchange_nucleation, icol); + diag_arrays.gas_aero_exchange_coagulation = ekat::subview(gas_aero_exchange_coagulation, icol); + diag_arrays.gas_aero_exchange_renaming_cloud_borne = ekat::subview(gas_aero_exchange_renaming_cloud_borne, icol); } + // Wind speed at the surface const Real wind_speed = haero::sqrt(u_wind(icol, surface_lev) * u_wind(icol, surface_lev) + @@ -980,8 +1047,8 @@ void MAMMicrophysics::run_impl(const double dt) { offset_aerosol, config.linoz.o3_sfc, config.linoz.o3_tau, config.linoz.o3_lbl, dry_diameter_icol, wet_diameter_icol, wetdens_icol, dry_atm.phis(icol), cmfdqr, prain_icol, nevapr_icol, - work_set_het_icol, drydep_data, aqso4_flx_col, aqh2so4_flx_col, diag_arrays, - dvel_col, dflx_col, progs); + work_set_het_icol, drydep_data, aqso4_flx_col, aqh2so4_flx_col, + diag_arrays, dvel_col, dflx_col, progs); team.team_barrier(); // Update constituent fluxes with gas drydep fluxes (dflx) diff --git a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.hpp b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.hpp index e5c8a321615b..01bf006d3711 100644 --- a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.hpp +++ b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.hpp @@ -163,6 +163,17 @@ class MAMMicrophysics final : public MAMGenericInterface { void init_temporary_views(); int len_temporary_views_{0}; + void add_io_docstring_to_fields_with_mixed_units(const std::map &flds) { + using str_atts_t = std::map; + for (const auto &pair : flds) { + // Get the field, and add a docstring to its string attributes + // This is used to document that the field contains heterogeneous + // quantities, i.e., species have different units. + auto &f = get_field_out(pair.first); + auto &io_str_atts = f.get_header().get_extra_data("io: string attributes"); + io_str_atts["doc"] = pair.second; + } + } }; // MAMMicrophysics } // namespace scream diff --git a/externals/mam4xx b/externals/mam4xx index 394152637fd9..14cb9c8bdc90 160000 --- a/externals/mam4xx +++ b/externals/mam4xx @@ -1 +1 @@ -Subproject commit 394152637fd9a4b9d31b611ee42031579dbfb077 +Subproject commit 14cb9c8bdc909130db80d91c8204637f593407a3