diff --git a/cime_config/tests.py b/cime_config/tests.py
index 8055dd261b2..ca3dba503c4 100644
--- a/cime_config/tests.py
+++ b/cime_config/tests.py
@@ -729,6 +729,7 @@
"SMS_D_Ln5.ne4pg2_oQU480.F2010-SCREAMv1-MPASSI.scream-mam4xx-optics",
"SMS_D_Ln5.ne4pg2_oQU480.F2010-SCREAMv1-MPASSI.scream-mam4xx-aci",
"SMS_D_Ln5.ne4pg2_oQU480.F2010-SCREAMv1-MPASSI.scream-mam4xx-wetscav",
+ "SMS_D_Ln5.ne4pg2_oQU480.F2010-SCREAMv1-MPASSI.scream-mam4xx-drydep",
)
},
diff --git a/components/eamxx/cime_config/namelist_defaults_scream.xml b/components/eamxx/cime_config/namelist_defaults_scream.xml
index dfdd13eb2e1..f09d10b0b32 100644
--- a/components/eamxx/cime_config/namelist_defaults_scream.xml
+++ b/components/eamxx/cime_config/namelist_defaults_scream.xml
@@ -241,6 +241,10 @@ be lost if SCREAM_HACK_XML is not enabled.
0
+
+
+
+
@@ -498,7 +502,9 @@ be lost if SCREAM_HACK_XML is not enabled.
0.0
0.0,0.0
- 2.6e-08
+ 2.6e-08
+ 0.41417721820867320E-007
+ 0.15100083211582764E+004
0.0
0.0
0.0
diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/scream/mam4xx/drydep/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/scream/mam4xx/drydep/shell_commands
new file mode 100644
index 00000000000..c5acf055a88
--- /dev/null
+++ b/components/eamxx/cime_config/testdefs/testmods_dirs/scream/mam4xx/drydep/shell_commands
@@ -0,0 +1,17 @@
+
+#!/bin/sh
+#------------------------------------------------------
+# MAM4xx adds additionaltracers to the simulation
+# Increase number of tracers for MAM4xx simulations
+#------------------------------------------------------
+
+$CIMEROOT/../components/eamxx/cime_config/testdefs/testmods_dirs/scream/mam4xx/update_eamxx_num_tracers.sh -b
+
+#------------------------------------------------------
+#Update IC file and add drydep process
+#------------------------------------------------------
+$CIMEROOT/../components/eamxx/scripts/atmchange initial_conditions::Filename='$DIN_LOC_ROOT/atm/scream/init/screami_mam4xx_ne4np4L72_c20240208.nc' -b
+$CIMEROOT/../components/eamxx/scripts/atmchange physics::atm_procs_list="mac_aero_mic,rrtmgp,mam4_drydep" -b
+
+
+
diff --git a/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp b/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp
index 52deba16e8d..7573993a318 100644
--- a/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp
+++ b/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp
@@ -52,6 +52,11 @@ void SurfaceCouplingImporter::set_grids(const std::shared_ptr("snow_depth_land", scalar2d_layout, m, grid_name);
add_field("ocnfrac", scalar2d_layout, nondim, grid_name);
add_field("landfrac", scalar2d_layout, nondim, grid_name);
+ add_field("icefrac", scalar2d_layout, nondim, grid_name);
+ // Friction velocity [m/s]
+ add_field("fv", scalar2d_layout, m/s, grid_name);
+ // Aerodynamical resistance
+ add_field("ram1", scalar2d_layout, s/m, grid_name);
}
// =========================================================================================
void SurfaceCouplingImporter::setup_surface_coupling_data(const SCDataManager &sc_data_manager)
diff --git a/components/eamxx/src/mct_coupling/scream_cpl_indices.F90 b/components/eamxx/src/mct_coupling/scream_cpl_indices.F90
index df96edab0f0..dc5be4de373 100644
--- a/components/eamxx/src/mct_coupling/scream_cpl_indices.F90
+++ b/components/eamxx/src/mct_coupling/scream_cpl_indices.F90
@@ -6,7 +6,7 @@ module scream_cpl_indices
private
! Focus only on the ones that scream imports/exports (subsets of x2a and a2x)
- integer, parameter, public :: num_scream_imports = 16
+ integer, parameter, public :: num_scream_imports = 19
integer, parameter, public :: num_scream_exports = 17
integer, public :: num_cpl_imports, num_cpl_exports, import_field_size, export_field_size
@@ -89,6 +89,9 @@ subroutine scream_set_cpl_indices (x2a, a2x)
import_field_names(14) = 'surf_evap'
import_field_names(15) = 'ocnfrac'
import_field_names(16) = 'landfrac'
+ import_field_names(17) = 'icefrac'
+ import_field_names(18) = 'fv'
+ import_field_names(19) = 'ram1'
! CPL indices
import_cpl_indices(1) = mct_avect_indexra(x2a,'Sx_avsdr')
@@ -106,7 +109,10 @@ subroutine scream_set_cpl_indices (x2a, a2x)
import_cpl_indices(13) = mct_avect_indexra(x2a,'Faxx_sen')
import_cpl_indices(14) = mct_avect_indexra(x2a,'Faxx_evap')
import_cpl_indices(15) = mct_avect_indexra(x2a,'Sf_ofrac')
- import_cpl_indices(16) = mct_avect_indexra(x2a,'Sf_lfrac')
+ import_cpl_indices(16) = mct_avect_indexra(x2a,'Sf_lfrac')
+ import_cpl_indices(17) = mct_avect_indexra(x2a,'Sf_ifrac')
+ import_cpl_indices(18) = mct_avect_indexra(x2a,'Sl_fv')
+ import_cpl_indices(19) = mct_avect_indexra(x2a,'Sl_ram1')
! Vector components
import_vector_components(11) = 0
diff --git a/components/eamxx/src/physics/mam/CMakeLists.txt b/components/eamxx/src/physics/mam/CMakeLists.txt
index 3182e383794..c5feb52e12a 100644
--- a/components/eamxx/src/physics/mam/CMakeLists.txt
+++ b/components/eamxx/src/physics/mam/CMakeLists.txt
@@ -43,6 +43,7 @@ add_subdirectory(${EXTERNALS_SOURCE_DIR}/mam4xx ${CMAKE_BINARY_DIR}/externals/ma
add_library(mam
eamxx_mam_microphysics_process_interface.cpp
eamxx_mam_optics_process_interface.cpp
+ eamxx_mam_dry_deposition_process_interface.cpp
eamxx_mam_aci_process_interface.cpp
eamxx_mam_wetscav_process_interface.cpp)
target_compile_definitions(mam PUBLIC EAMXX_HAS_MAM)
diff --git a/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_functions.hpp b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_functions.hpp
new file mode 100644
index 00000000000..f5423e8eb1c
--- /dev/null
+++ b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_functions.hpp
@@ -0,0 +1,205 @@
+#ifndef EAMXX_MAM_DRY_DEPOSITION_FUNCTIONS_HPP
+#define EAMXX_MAM_DRY_DEPOSITION_FUNCTIONS_HPP
+
+#include
+#include
+#include
+#include
+
+namespace scream {
+
+namespace {
+void compute_tendencies(
+ // inputs
+ const int ncol, const int nlev, const double dt,
+ const MAMDryDep::const_view_1d obklen,
+ const MAMDryDep::const_view_1d surfric,
+ const MAMDryDep::const_view_1d landfrac,
+ const MAMDryDep::const_view_1d icefrac,
+ const MAMDryDep::const_view_1d ocnfrac,
+ const MAMDryDep::const_view_1d friction_velocity,
+ const MAMDryDep::const_view_1d aerodynamical_resistance,
+ MAMDryDep::view_3d qtracers, MAMDryDep::view_2d fraction_landuse_,
+ const MAMDryDep::const_view_3d dgncur_awet_,
+ const MAMDryDep::const_view_3d wet_dens_,
+ const mam_coupling::DryAtmosphere dry_atm,
+ const mam_coupling::AerosolState dry_aero,
+
+ // input-outputs
+ MAMDryDep::view_3d qqcw_,
+
+ // outputs
+ MAMDryDep::view_3d ptend_q, MAMDryDep::view_2d aerdepdrycw,
+ MAMDryDep::view_2d aerdepdryis,
+
+ // work arrays
+ MAMDryDep::view_2d rho_, MAMDryDep::view_4d vlc_dry_,
+ MAMDryDep::view_3d vlc_trb_, MAMDryDep::view_4d vlc_grv_,
+ MAMDryDep::view_3d dqdt_tmp_) {
+ static constexpr int num_aero_modes = mam_coupling::num_aero_modes();
+ const auto policy =
+ ekat::ExeSpaceUtils::get_default_team_policy(
+ ncol, nlev);
+
+ // Parallel loop over all the columns
+ Kokkos::parallel_for(
+ policy, KOKKOS_LAMBDA(const MAMDryDep::KT::MemberType &team) {
+ static constexpr int num_aero_species =
+ mam_coupling::num_aero_species();
+
+ const int icol = team.league_rank();
+ // Parallel loop over all the levels to populate qtracers array using
+ // dry_aero
+ Kokkos::parallel_for(
+ Kokkos::TeamVectorRange(team, nlev), [&](const int lev) {
+ for(int mode = 0; mode < num_aero_modes; ++mode) {
+ int icnst = mam4::ConvProc::numptrcw_amode(mode);
+ qtracers(icol, lev, icnst) =
+ dry_aero.int_aero_nmr[mode](icol, lev);
+ for(int species = 0; species < num_aero_species; ++species) {
+ icnst = mam4::ConvProc::lmassptrcw_amode(species, mode);
+ if(-1 < icnst) {
+ qtracers(icol, lev, icnst) =
+ dry_aero.int_aero_mmr[mode][species](icol, lev);
+ }
+ }
+ }
+ }); // parallel_for for nlevs
+ team.team_barrier();
+
+ // Create atm and progs objects
+ mam4::Atmosphere atm = atmosphere_for_column(dry_atm, icol);
+ mam4::Prognostics progs = aerosols_for_column(dry_aero, icol);
+
+ // Extract column data (or 1d view) from 2d views of data
+ mam4::ConstColumnView dgncur_awet[num_aero_modes];
+ mam4::ConstColumnView wet_dens[num_aero_modes];
+
+ for(int i = 0; i < num_aero_modes; ++i) {
+ dgncur_awet[i] = ekat::subview(dgncur_awet_, icol, i);
+ wet_dens[i] = ekat::subview(wet_dens_, icol, i);
+ }
+
+ mam4::ColumnView rho;
+ rho = ekat::subview(rho_, icol);
+
+ static constexpr int n_land_type = MAMDryDep::n_land_type;
+ Real fraction_landuse[n_land_type];
+ for(int i = 0; i < n_land_type; ++i) {
+ fraction_landuse[i] = fraction_landuse_(i, icol);
+ }
+
+ static constexpr int nmodes = mam4::AeroConfig::num_modes();
+ mam4::ColumnView vlc_dry[nmodes][MAMDryDep::aerosol_categories_];
+ mam4::ColumnView vlc_grv[nmodes][MAMDryDep::aerosol_categories_];
+ Real vlc_trb[nmodes][MAMDryDep::aerosol_categories_];
+
+ for(int i = 0; i < nmodes; ++i) {
+ for(int j = 0; j < MAMDryDep::aerosol_categories_; ++j) {
+ vlc_dry[i][j] = ekat::subview(vlc_dry_, i, j, icol);
+ vlc_trb[i][j] = vlc_trb_(i, j, icol);
+ vlc_grv[i][j] = ekat::subview(vlc_grv_, i, j, icol);
+ }
+ }
+ static constexpr int pcnst = mam4::aero_model::pcnst;
+ mam4::ColumnView qqcw[pcnst];
+ mam4::ColumnView dqdt_tmp[pcnst];
+ for(int i = 0; i < pcnst; ++i) {
+ qqcw[i] = ekat::subview(qqcw_, i, icol);
+ dqdt_tmp[i] = ekat::subview(dqdt_tmp_, i, icol);
+ }
+ // Extract qqcw from Prognostics
+ Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev), [&](int kk) {
+ for(int m = 0; m < nmodes; ++m) {
+ qqcw[mam4::ConvProc::numptrcw_amode(m)][kk] = progs.n_mode_c[m][kk];
+ for(int a = 0; a < mam4::AeroConfig::num_aerosol_ids(); ++a)
+ if(-1 < mam4::ConvProc::lmassptrcw_amode(a, m))
+ qqcw[mam4::ConvProc::lmassptrcw_amode(a, m)][kk] =
+ progs.q_aero_c[m][a][kk];
+ }
+ }); // parallel_for nlevs
+ team.team_barrier();
+ bool ptend_lq[pcnst]; // currently unused
+ mam4::aero_model_drydep(
+ // inputs
+ team, fraction_landuse, atm.temperature, atm.pressure,
+ atm.interface_pressure, atm.hydrostatic_dp,
+ ekat::subview(qtracers, icol), dgncur_awet, wet_dens, obklen[icol],
+ surfric[icol], landfrac[icol], icefrac[icol], ocnfrac[icol],
+ friction_velocity[icol], aerodynamical_resistance[icol], dt,
+ // input-outputs
+ qqcw,
+ // outputs
+ ekat::subview(ptend_q, icol), ptend_lq,
+ ekat::subview(aerdepdrycw, icol), ekat::subview(aerdepdryis, icol),
+ // work arrays
+ rho, vlc_dry, vlc_trb, vlc_grv, dqdt_tmp);
+ }); // parallel_for for ncols
+} // Compute_tendencies ends
+
+// Update interstitial aerosols using ptend_q tendencies
+void update_interstitial_mmrs(const MAMDryDep::view_3d ptend_q, const double dt,
+ const int ncol, const int nlev,
+ // output
+ const mam_coupling::AerosolState dry_aero) {
+ const auto policy =
+ ekat::ExeSpaceUtils::get_default_team_policy(
+ ncol, nlev);
+ static constexpr int nmodes = mam4::AeroConfig::num_modes();
+ Kokkos::parallel_for(
+ policy, KOKKOS_LAMBDA(const MAMDryDep::KT::MemberType &team) {
+ const int icol = team.league_rank();
+ Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev), [&](int kk) {
+ for(int m = 0; m < nmodes; ++m) {
+ dry_aero.int_aero_nmr[m](icol, kk) +=
+ ptend_q(icol, kk, mam4::ConvProc::numptrcw_amode(m)) * dt;
+ for(int a = 0; a < mam4::AeroConfig::num_aerosol_ids(); ++a)
+ if(-1 < mam4::ConvProc::lmassptrcw_amode(a, m))
+ dry_aero.int_aero_mmr[m][a](icol, kk) +=
+ ptend_q(icol, kk, mam4::ConvProc::lmassptrcw_amode(a, m)) *
+ dt;
+ }
+ }); // parallel_for nlevs
+ }); // parallel_for icol
+} // Update interstitial aerosols ends
+
+// Update cloud borne aerosols using qqcw
+void update_cloudborne_mmrs(const MAMDryDep::view_3d qqcw, const double dt,
+ const int nlev_,
+ // output
+ const mam_coupling::AerosolState dry_aero) {
+ for(int m = 0; m < mam_coupling::num_aero_modes(); ++m) {
+ Kokkos::deep_copy(dry_aero.cld_aero_nmr[m],
+ ekat::subview(qqcw, mam4::ConvProc::numptrcw_amode(m)));
+ for(int a = 0; a < mam_coupling::num_aero_species(); ++a) {
+ if(dry_aero.cld_aero_mmr[m][a].data()) {
+ Kokkos::deep_copy(
+ dry_aero.cld_aero_mmr[m][a],
+ ekat::subview(qqcw, mam4::ConvProc::lmassptrcw_amode(a, m)));
+ }
+ }
+ }
+} // Update cloud borne aerosols ends
+
+// FIXME: remove the following function after implementing file read for landuse
+void populated_fraction_landuse(MAMDryDep::view_2d flu, const int ncol) {
+ Kokkos::parallel_for(
+ "populated_fraction_landuse", 1, KOKKOS_LAMBDA(int) {
+ static constexpr int n_land_type = MAMDryDep::n_land_type;
+ const Real temp[n_land_type] = {
+ 0.28044346587077795E-003, 0.26634987180780171E-001,
+ 0.16803558403621365E-001, 0.18076055155371872E-001,
+ 0.00000000000000000E+000, 0.00000000000000000E+000,
+ 0.91803784897907303E+000, 0.17186036997038400E-002,
+ 0.00000000000000000E+000, 0.00000000000000000E+000,
+ 0.18448503115578840E-001};
+ for(int i = 0; i < n_land_type; ++i)
+ for(int j = 0; j < ncol; ++j) flu(i, j) = temp[i];
+ });
+ Kokkos::fence();
+}
+
+} // namespace
+} // namespace scream
+
+#endif
diff --git a/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.cpp b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.cpp
new file mode 100644
index 00000000000..034972f8525
--- /dev/null
+++ b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.cpp
@@ -0,0 +1,439 @@
+#include "physics/mam/eamxx_mam_dry_deposition_process_interface.hpp"
+
+// Drydep functions are stored in the following hpp file
+#include
+
+/*
+-----------------------------------------------------------------
+NOTES:
+1. Add a CIME test and multi-process tests
+2. Ensure that the submodule for MAM4xx is the main branch
+3. Read file for fractional landuse
+-----------------------------------------------------------------
+*/
+namespace scream {
+
+MAMDryDep::MAMDryDep(const ekat::Comm &comm, const ekat::ParameterList ¶ms)
+ : AtmosphereProcess(comm, params) {
+ /* Anything that can be initialized without grid information can be
+ * initialized here. Like universal constants, mam wetscav options.
+ */
+}
+
+// ================================================================
+// SET_GRIDS
+// ================================================================
+void MAMDryDep::set_grids(
+ const std::shared_ptr grids_manager) {
+ using namespace ekat::units;
+
+ // set grid for all the inputs and outputs
+ // use physics grid
+ grid_ = grids_manager->get_grid("Physics");
+
+ // Name of the grid
+ const auto &grid_name = grid_->name();
+
+ ncol_ = grid_->get_num_local_dofs(); // Number of columns on this rank
+ nlev_ = grid_->get_num_vertical_levels(); // Number of levels per column
+
+ // Define the different field layouts that will be used for this process
+ using namespace ShortFieldTagsNames;
+
+ // Layout for 2D (2d horiz) variable
+ const FieldLayout scalar2d = grid_->get_2d_scalar_layout();
+
+ // Layout for 3D (2d horiz X 1d vertical) variable defined at mid-level and
+ // interfaces
+ const FieldLayout scalar3d_mid = grid_->get_3d_scalar_layout(true);
+ const FieldLayout scalar3d_int = grid_->get_3d_scalar_layout(false);
+
+ // layout for 2D (ncol, pcnst)
+ constexpr int pcnst = mam4::aero_model::pcnst;
+ const FieldLayout vector2d_pcnst =
+ grid_->get_2d_vector_layout(pcnst, "num_phys_constants");
+
+ // Layout for 4D (2d horiz X 1d vertical x number of modes) variables
+ // at mid points
+ const int num_aero_modes = mam_coupling::num_aero_modes();
+ const FieldLayout vector3d_mid = grid_->get_3d_vector_layout(true, num_aero_modes, "num_modes");
+
+ using namespace ekat::units;
+
+ auto q_unit = kg / kg; // units of mass mixing ratios of tracers
+ auto n_unit = 1 / kg; // units of number mixing ratios of tracers
+
+ auto nondim = ekat::units::Units::nondimensional();
+
+ auto m3 = m * m * m; // meter cubed
+
+ // --------------------------------------------------------------------------
+ // These variables are "Required" or pure inputs for the process
+ // --------------------------------------------------------------------------
+
+ // ----------- Atmospheric quantities -------------
+ // Specific humidity [kg/kg](Require only for building DS)
+ add_field("qv", scalar3d_mid, q_unit, grid_name, "tracers");
+
+ // Cloud liquid mass mixing ratio [kg/kg](Require only for building DS)
+ add_field("qc", scalar3d_mid, q_unit, grid_name, "tracers");
+
+ // Cloud ice mass mixing ratio [kg/kg](Require only for building DS)
+ add_field("qi", scalar3d_mid, q_unit, grid_name, "tracers");
+
+ // Cloud liquid number mixing ratio [1/kg](Require only for building DS)
+ add_field("nc", scalar3d_mid, n_unit, grid_name, "tracers");
+
+ // Cloud ice number mixing ratio [1/kg](Require only for building DS)
+ add_field("ni", scalar3d_mid, n_unit, grid_name, "tracers");
+
+ // Temperature[K] at midpoints
+ add_field("T_mid", scalar3d_mid, K, grid_name);
+
+ // Vertical pressure velocity [Pa/s] at midpoints (Require only for building
+ // DS)
+ add_field("omega", scalar3d_mid, Pa / s, grid_name);
+
+ // Total pressure [Pa] at midpoints
+ add_field("p_mid", scalar3d_mid, Pa, grid_name);
+
+ // Total pressure [Pa] at interfaces
+ add_field("p_int", scalar3d_int, Pa, grid_name);
+
+ // Layer thickness(pdel) [Pa] at midpoints
+ add_field("pseudo_density", scalar3d_mid, Pa, grid_name);
+
+ // Planetary boundary layer height [m] (Require only for building DS)
+ add_field("pbl_height", scalar2d, m, grid_name);
+
+ static constexpr auto m2 = m * m;
+ static constexpr auto s2 = s * s;
+
+ // Surface geopotential [m2/s2] (Require only for building DS)
+ add_field("phis", scalar2d, m2 / s2, grid_name);
+
+ //----------- Variables from microphysics scheme -------------
+
+ // Total cloud fraction [fraction] (Require only for building DS)
+ add_field("cldfrac_tot", scalar3d_mid, nondim, grid_name);
+
+ //----------- Variables from coupler (land component)---------
+ // Obukhov length [m]
+ add_field("obklen", scalar2d, m, grid_name);
+
+ // Surface friction velocty or ustar[m/s]
+ add_field("ustar", scalar2d, m / s, grid_name);
+
+ // Land fraction [fraction]
+ add_field("landfrac", scalar2d, nondim, grid_name);
+
+ // Friction velocity from land model [m/s]
+ add_field("fv", scalar2d, m / s, grid_name);
+
+ // Aerodynamical resistance from land model [s/m]
+ add_field("ram1", scalar2d, s / m, grid_name);
+
+ //----------- Variables from coupler (ice component)---------
+
+ // Ice fraction [unitless]
+ add_field("icefrac", scalar2d, nondim, grid_name);
+
+ //----------- Variables from coupler (ocean component)---------
+ // Ocean fraction [unitless]
+ add_field("ocnfrac", scalar2d, nondim, grid_name);
+
+ //----------- Variables from other mam4xx processes ------------
+ // Geometric mean wet diameter for number distribution [m]
+ add_field("dgnumwet", vector3d_mid, m, grid_name);
+
+ // Wet density of interstitial aerosol [kg/m3]
+ add_field("wetdens", vector3d_mid, kg / m3, grid_name);
+
+ // ---------------------------------------------------------------------
+ // These variables are "updated" or inputs/outputs for the process
+ // ---------------------------------------------------------------------
+
+ // (interstitial) aerosol tracers of interest: mass (q) and number (n) mixing
+ // ratios
+ for(int m = 0; m < num_aero_modes; ++m) {
+ const char *int_nmr_field_name = mam_coupling::int_aero_nmr_field_name(m);
+
+ add_field(int_nmr_field_name, scalar3d_mid, n_unit, grid_name,
+ "tracers");
+ for(int a = 0; a < mam_coupling::num_aero_species(); ++a) {
+ const char *int_mmr_field_name =
+ mam_coupling::int_aero_mmr_field_name(m, a);
+
+ if(strlen(int_mmr_field_name) > 0) {
+ add_field(int_mmr_field_name, scalar3d_mid, q_unit, grid_name,
+ "tracers");
+ }
+ }
+ }
+ // (cloud) aerosol tracers of interest: mass (q) and number (n) mixing ratios
+ for(int m = 0; m < num_aero_modes; ++m) {
+ const char *cld_nmr_field_name = mam_coupling::cld_aero_nmr_field_name(m);
+
+ add_field(cld_nmr_field_name, scalar3d_mid, n_unit, grid_name);
+ for(int a = 0; a < mam_coupling::num_aero_species(); ++a) {
+ const char *cld_mmr_field_name =
+ mam_coupling::cld_aero_mmr_field_name(m, a);
+
+ if(strlen(cld_mmr_field_name) > 0) {
+ add_field(cld_mmr_field_name, scalar3d_mid, q_unit, grid_name);
+ }
+ }
+ }
+
+ // aerosol-related gases: mass mixing ratios
+ for(int g = 0; g < mam_coupling::num_aero_gases(); ++g) {
+ const char *gas_mmr_field_name = mam_coupling::gas_mmr_field_name(g);
+ add_field(gas_mmr_field_name, scalar3d_mid, q_unit, grid_name,
+ "tracers");
+ }
+
+ // -------------------------------------------------------------
+ // These variables are "Computed" or outputs for the process
+ // -------------------------------------------------------------
+ // FIXME: These are diagnostics, remove them from FM after initial evaluation
+ // surface deposition flux of cloud-borne aerosols, [kg/m2/s] or [1/m2/s]
+ add_field("deposition_flux_of_cloud_borne_aerosols", vector2d_pcnst,
+ 1 / m2 / s, grid_name);
+ // surface deposition flux of interstitial aerosols, [kg/m2/s] or [1/m2/s]
+ add_field("deposition_flux_of_interstitial_aerosols",
+ vector2d_pcnst, 1 / m2 / s, grid_name);
+} // set_grids
+
+// ================================================================
+// REQUEST_BUFFER_SIZE_IN_BYTES
+// ================================================================
+// ON HOST, returns the number of bytes of device memory needed by
+// the above. Buffer type given the number of columns and vertical
+// levels
+size_t MAMDryDep::requested_buffer_size_in_bytes() const {
+ return mam_coupling::buffer_size(ncol_, nlev_);
+} // requested_buffer_size_in_bytes
+
+// ================================================================
+// INIT_BUFFERS
+// ================================================================
+// ON HOST, initializeѕ the Buffer type with sufficient memory to
+// store intermediate (dry) quantities on the given number of
+// columns with the given number of vertical levels. Returns the
+// number of bytes allocated.
+void MAMDryDep::init_buffers(const ATMBufferManager &buffer_manager) {
+ EKAT_REQUIRE_MSG(
+ buffer_manager.allocated_bytes() >= requested_buffer_size_in_bytes(),
+ "Error! Insufficient buffer size.\n");
+
+ size_t used_mem =
+ mam_coupling::init_buffer(buffer_manager, ncol_, nlev_, buffer_);
+ EKAT_REQUIRE_MSG(used_mem == requested_buffer_size_in_bytes(),
+ "Error! Used memory != requested memory for MAMDryDep.");
+} // init_buffers
+
+// ================================================================
+// INITIALIZE_IMPL
+// ================================================================
+void MAMDryDep::initialize_impl(const RunType run_type) {
+ // ---------------------------------------------------------------
+ // Input fields read in from IC file, namelist or other processes
+ // ---------------------------------------------------------------
+
+ // Populate the wet atmosphere state with views from fields
+ // FIMXE: specifically look which among these are actually used by the process
+ wet_atm_.qv = get_field_in("qv").get_view();
+
+ // Following wet_atm vars are required only for building DS
+ wet_atm_.qc = get_field_in("qc").get_view();
+ wet_atm_.nc = get_field_in("nc").get_view();
+ wet_atm_.qi = get_field_in("qi").get_view();
+ wet_atm_.ni = get_field_in("ni").get_view();
+
+ // Populate the dry atmosphere state with views from fields
+ dry_atm_.T_mid = get_field_in("T_mid").get_view();
+ dry_atm_.p_mid = get_field_in("p_mid").get_view();
+ dry_atm_.p_del = get_field_in("pseudo_density").get_view();
+ dry_atm_.p_int = get_field_in("p_int").get_view();
+
+ // Following dry_atm vars are required only for building DS
+ dry_atm_.cldfrac = get_field_in("cldfrac_tot").get_view();
+ dry_atm_.pblh = get_field_in("pbl_height").get_view();
+ dry_atm_.omega = get_field_in("omega").get_view();
+
+ // store fields converted to dry mmr from wet mmr in dry_atm_
+ dry_atm_.z_mid = buffer_.z_mid;
+ dry_atm_.z_iface = buffer_.z_iface;
+ dry_atm_.dz = buffer_.dz;
+ dry_atm_.qv = buffer_.qv_dry;
+ dry_atm_.qc = buffer_.qc_dry;
+ dry_atm_.nc = buffer_.nc_dry;
+ dry_atm_.qi = buffer_.qi_dry;
+ dry_atm_.ni = buffer_.ni_dry;
+ dry_atm_.w_updraft = buffer_.w_updraft;
+ dry_atm_.z_surf = 0.0; // FIXME: for now
+
+ // ---- set wet/dry aerosol-related gas state data
+ for(int m = 0; m < mam_coupling::num_aero_modes(); ++m) {
+ // interstitial aerosol tracers of interest: number (n) mixing ratios
+ const char *int_nmr_field_name = mam_coupling::int_aero_nmr_field_name(m);
+ wet_aero_.int_aero_nmr[m] =
+ get_field_out(int_nmr_field_name).get_view();
+ dry_aero_.int_aero_nmr[m] = buffer_.dry_int_aero_nmr[m];
+
+ // cloudborne aerosol tracers of interest: number (n) mixing ratios
+ const char *cld_nmr_field_name = mam_coupling::cld_aero_nmr_field_name(m);
+ wet_aero_.cld_aero_nmr[m] =
+ get_field_out(cld_nmr_field_name).get_view();
+ dry_aero_.cld_aero_nmr[m] = buffer_.dry_cld_aero_nmr[m];
+
+ for(int a = 0; a < mam_coupling::num_aero_species(); ++a) {
+ // (interstitial) aerosol tracers of interest: mass (q) mixing ratios
+ const char *int_mmr_field_name =
+ mam_coupling::int_aero_mmr_field_name(m, a);
+ if(strlen(int_mmr_field_name) > 0) {
+ wet_aero_.int_aero_mmr[m][a] =
+ get_field_out(int_mmr_field_name).get_view();
+ dry_aero_.int_aero_mmr[m][a] = buffer_.dry_int_aero_mmr[m][a];
+ }
+
+ // (cloudborne) aerosol tracers of interest: mass (q) mixing ratios
+ const char *cld_mmr_field_name =
+ mam_coupling::cld_aero_mmr_field_name(m, a);
+ if(strlen(cld_mmr_field_name) > 0) {
+ wet_aero_.cld_aero_mmr[m][a] =
+ get_field_out(cld_mmr_field_name).get_view();
+ dry_aero_.cld_aero_mmr[m][a] = buffer_.dry_cld_aero_mmr[m][a];
+ }
+ }
+ }
+ for(int g = 0; g < mam_coupling::num_aero_gases(); ++g) {
+ const char *gas_mmr_field_name = mam_coupling::gas_mmr_field_name(g);
+ wet_aero_.gas_mmr[g] =
+ get_field_out(gas_mmr_field_name).get_view();
+ dry_aero_.gas_mmr[g] = buffer_.dry_gas_mmr[g];
+ }
+
+ //-----------------------------------------------------------------
+ // Allocate memory
+ //-----------------------------------------------------------------
+ const int pcnst = mam4::aero_model::pcnst;
+
+ // Output of the the mixing ratio tendencies [kg/kg/s or 1/kg/s]
+ ptend_q_ = view_3d("ptend_q_", ncol_, nlev_, pcnst);
+
+ // Deposition velocity of turbulent dry deposition [m/s]
+ vlc_trb_ = view_3d("vlc_trb_", mam4::AeroConfig::num_modes(),
+ aerosol_categories_, ncol_);
+ // Deposition velocity of gravitational settling [m/s]
+ vlc_grv_ = view_4d("vlc_grv_", mam4::AeroConfig::num_modes(),
+ aerosol_categories_, ncol_, nlev_);
+ // Deposition velocity, [m/s]
+ // Fraction landuse weighted sum of vlc_grv and vlc_trb
+ vlc_dry_ = view_4d("vlc_dry_", mam4::AeroConfig::num_modes(),
+ aerosol_categories_, ncol_, nlev_);
+
+ // Work array to hold the mixing ratios [kg/kg or 1/kg]
+ // Packs AerosolState::int_aero_nmr and AerosolState::int_aero_nmr
+ // into one array.
+ qtracers_ = view_3d("qtracers_", ncol_, nlev_, pcnst);
+
+ // Work array to hold the air density [kg/m3]
+ rho_ = view_2d("rho", ncol_, nlev_);
+
+ // Work array to hold cloud borne aerosols mixing ratios [kg/kg or 1/kg]
+ // Filled with Prognostics::n_mode_c and Prognostics::q_aero_c
+ qqcw_ = view_3d("qqcw_", pcnst, ncol_, nlev_);
+
+ // Work array to hold tendency for 1 species [kg/kg/s] or [1/kg/s]
+ dqdt_tmp_ = view_3d("dqdt_tmp_", pcnst, ncol_, nlev_);
+
+ static constexpr int n_land_type = mam4::DryDeposition::n_land_type;
+ // FIXME: This should come from a file reading
+ // The fraction of land use for the column. [non-dimentional]
+ fraction_landuse_ = view_2d("fraction_landuse_", n_land_type, ncol_);
+
+ //-----------------------------------------------------------------
+ // Setup preprocessing and post processing
+ //-----------------------------------------------------------------
+ preprocess_.initialize(ncol_, nlev_, wet_atm_, wet_aero_, dry_atm_,
+ dry_aero_);
+ postprocess_.initialize(ncol_, nlev_, wet_atm_, wet_aero_, dry_atm_,
+ dry_aero_);
+} // initialize_impl
+
+// =========================================================================================
+void MAMDryDep::run_impl(const double dt) {
+ const auto scan_policy = ekat::ExeSpaceUtils<
+ KT::ExeSpace>::get_thread_range_parallel_scan_team_policy(ncol_, nlev_);
+
+ // preprocess input -- needs a scan for the calculation of atm height
+ Kokkos::parallel_for("preprocess", scan_policy, preprocess_);
+ Kokkos::fence();
+
+ // -------------------------------------------------------------
+ // Inputs fields for the process
+ // -------------------------------------------------------------
+
+ // Geometric mean wet diameter for number distribution [m]
+ auto dgncur_awet_ = get_field_in("dgnumwet").get_view();
+ // Wet density of interstitial aerosol [kg/m3]
+ auto wet_dens_ = get_field_in("wetdens").get_view();
+ // Obukhov length [m]
+ auto obukhov_length_ = get_field_in("obklen").get_view();
+ // Land fraction [unitless]
+ auto land_fraction_ = get_field_in("landfrac").get_view();
+ // Ice fraction [unitless]
+ auto ice_fraction_ = get_field_in("icefrac").get_view();
+ // Ocean fraction [unitless]
+ auto ocean_fraction_ = get_field_in("ocnfrac").get_view();
+ // Friction velocity from land model [m/s]
+ auto friction_velocity_ = get_field_in("fv").get_view();
+ // Aerodynamical resistance from land model [s/m]
+ auto aerodynamical_resistance_ =
+ get_field_in("ram1").get_view();
+ // Sfc friction velocity or ustar [m/s]
+ auto surface_friction_velocty_ =
+ get_field_in("ustar").get_view();
+
+ // -------------------------------------------------------------
+ // Output fields for the process
+ // -------------------------------------------------------------
+ // Surface deposition flux of cloud-borne aerosols, [kg/m2/s] or [1/m2/s]
+ auto aerdepdrycw_ = get_field_out("deposition_flux_of_cloud_borne_aerosols")
+ .get_view();
+ // Surface deposition flux of interstitial aerosols, [kg/m2/s] or [1/m2/s]
+ auto aerdepdryis_ = get_field_out("deposition_flux_of_interstitial_aerosols")
+ .get_view();
+
+ // FIXME: remove it if it read from a file
+ populated_fraction_landuse(fraction_landuse_, ncol_);
+
+ // Call drydeposition and get tendencies
+ compute_tendencies(ncol_, nlev_, dt, obukhov_length_,
+ surface_friction_velocty_, land_fraction_, ice_fraction_,
+ ocean_fraction_, friction_velocity_,
+ aerodynamical_resistance_, qtracers_, fraction_landuse_,
+ dgncur_awet_, wet_dens_, dry_atm_, dry_aero_,
+ // Inouts-outputs
+ qqcw_,
+ // Outputs
+ ptend_q_, aerdepdrycw_, aerdepdryis_,
+ // work arrays
+ rho_, vlc_dry_, vlc_trb_, vlc_grv_, dqdt_tmp_);
+ Kokkos::fence();
+
+ // Update the interstitial aerosols using ptend.
+ update_interstitial_mmrs(ptend_q_, dt, ncol_, nlev_, // inputs
+ dry_aero_); // output
+
+ // Update the interstitial aerosols
+ update_cloudborne_mmrs(qqcw_, dt, nlev_, // inputs
+ dry_aero_); // output
+
+ // call post processing to convert dry mixing ratios to wet mixing ratios
+ // and update the state
+ Kokkos::parallel_for("postprocess", scan_policy, postprocess_);
+ Kokkos::fence(); // wait before returning to calling function
+} // run_impl
+} // namespace scream
diff --git a/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.hpp b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.hpp
new file mode 100644
index 00000000000..e39090cecde
--- /dev/null
+++ b/components/eamxx/src/physics/mam/eamxx_mam_dry_deposition_process_interface.hpp
@@ -0,0 +1,239 @@
+#ifndef EAMXX_MAM_DRYDEP_HPP
+#define EAMXX_MAM_DRYDEP_HPP
+
+// For declaring dry deposition class derived from atm process class
+#include
+
+// For MAM4 aerosol configuration
+#include
+
+// For component name
+#include
+
+namespace scream {
+
+// The process responsible for handling MAM4 dry deposition. The AD
+// stores exactly ONE instance of this class in its list of subcomponents.
+class MAMDryDep final : public scream::AtmosphereProcess {
+ public:
+ static constexpr int num_aero_modes = mam_coupling::num_aero_modes();
+ static constexpr int aerosol_categories_ =
+ mam4::DryDeposition::aerosol_categories;
+ static constexpr int n_land_type = mam4::DryDeposition::n_land_type;
+
+ using view_1d = Field::view_dev_t;
+ using view_2d = Field::view_dev_t;
+ using view_3d = Field::view_dev_t;
+ using view_4d = Field::view_dev_t;
+ using const_view_1d = Field::view_dev_t;
+ using const_view_3d = Field::view_dev_t;
+
+ private:
+ // number of horizontal columns and vertical levels
+ int ncol_, nlev_;
+
+ // Wet and dry states of atmosphere
+ mam_coupling::WetAtmosphere wet_atm_;
+ mam_coupling::DryAtmosphere dry_atm_;
+
+ // aerosol state variables
+ mam_coupling::AerosolState wet_aero_, dry_aero_;
+
+ // buffer for sotring temporary variables
+ mam_coupling::Buffer buffer_;
+
+ // physics grid for column information
+ std::shared_ptr grid_;
+
+
+ /* Note on mam4::DryDeposition::aerosol_categories = 4
+ used in deposition velocity dimension defined below. These
+ correspond to the two attachment states and two moments:
+ 0 - interstitial aerosol, 0th moment (i.e., number)
+ 1 - interstitial aerosol, 3rd moment (i.e., volume/mass)
+ 2 - cloud-borne aerosol, 0th moment (i.e., number)
+ 3 - cloud-borne aerosol, 3rd moment (i.e., volume/mass)
+ see comments in the DryDeposition class in mam4xx.
+ */
+ // Output deposition velocity of turbulent dry deposition [m/s]
+ // Dimensions
+ // [numer of modes, aerosol_categories_, num columns]
+ view_3d vlc_trb_;
+
+ // Output deposition velocity of gravitational settling [m/s]
+ // Dimensions
+ // [num_modes, aerosol_categories_, num columns, num levels]
+ view_4d vlc_grv_;
+
+ // Output deposition velocity, [m/s]
+ // fraction landuse weighted sum of vlc_grv and vlc_trb
+ // Dimensions
+ // [num_modes, aerosol_categories_, num columns, num levels]
+ view_4d vlc_dry_;
+
+
+ // Output of the the mixing ratio tendencies [kg/kg/s or 1/kg/s]
+ // Dimensions
+ // [num columns, num levels, mam4::aero_model::pcnst]
+ // Packed the same way qtracers_ is layed out.
+ view_3d ptend_q_;
+
+ // Work array to hold the mixing ratios [kg/kg or 1/kg]
+ // Dimensions
+ // [num columns, num levels, mam4::aero_model::pcnst]
+ // Packs AerosolState::int_aero_nmr
+ // and AerosolState::int_aero_nmr
+ // into one array, hence is mixed kg/kg and 1/kg.
+ view_3d qtracers_;
+
+ // Work array to hold the fraction [non-dimentional]
+ // of land use for column.
+ // Dimensions
+ // [MAMDryDep::n_land_type, num columns]
+ // Values should sum to 1.
+ view_2d fraction_landuse_;
+
+ // Work array to hold the air density [kg/m3]
+ // Dimensions
+ // [num columns, num levels]
+ // Calculated from air pressure at layer midpoint,
+ // Constants::r_gas_dry_air and air temperture.
+ view_2d rho_;
+
+ // Work array to hold tendency for 1 species [kg/kg/s] or [1/kg/s]
+ // Dimensions
+ // [mam4::aero_model::pcnst, num column, num level]
+ view_3d dqdt_tmp_;
+
+ // Work array to hold cloud borne aerosols mixing ratios [kg/kg or 1/kg]
+ // Dimensions
+ // [mam4::aero_model::pcnst, num column, num level]
+ // Filled with Prognostics::n_mode_c and Prognostics::q_aero_c
+ view_3d qqcw_;
+
+ public:
+ using KT = ekat::KokkosTypes;
+
+ // Constructor
+ MAMDryDep(const ekat::Comm &comm, const ekat::ParameterList ¶ms);
+
+ // --------------------------------------------------------------------------
+ // AtmosphereProcess overrides (see share/atm_process/atmosphere_process.hpp)
+ // --------------------------------------------------------------------------
+
+ // The type of subcomponent
+ AtmosphereProcessType type() const override {
+ return AtmosphereProcessType::Physics;
+ }
+
+ // The name of the subcomponent
+ std::string name() const override { return "mam_dry_deposition"; }
+
+ // grid
+ void set_grids(
+ const std::shared_ptr grids_manager) override;
+
+ // management of common atm process memory
+ size_t requested_buffer_size_in_bytes() const override;
+ void init_buffers(const ATMBufferManager &buffer_manager) override;
+
+ // Initialize variables
+ void initialize_impl(const RunType run_type) override;
+
+ // Run the process by one time step
+ void run_impl(const double dt) override;
+
+ // Finalize
+ void finalize_impl() override{/*Do nothing*/};
+
+ // Atmosphere processes often have a pre-processing step that constructs
+ // required variables from the set of fields stored in the field manager.
+ // This functor implements this step, which is called during run_impl.
+ struct Preprocess {
+ Preprocess() = default;
+ // on host: initializes preprocess functor with necessary state data
+ void initialize(const int ncol, const int nlev,
+ const mam_coupling::WetAtmosphere &wet_atm,
+ const mam_coupling::AerosolState &wet_aero,
+ const mam_coupling::DryAtmosphere &dry_atm,
+ const mam_coupling::AerosolState &dry_aero) {
+ ncol_pre_ = ncol;
+ nlev_pre_ = nlev;
+ wet_atm_pre_ = wet_atm;
+ wet_aero_pre_ = wet_aero;
+ dry_atm_pre_ = dry_atm;
+ dry_aero_pre_ = dry_aero;
+ }
+
+ KOKKOS_INLINE_FUNCTION
+ void operator()(
+ const Kokkos::TeamPolicy::member_type &team) const {
+ const int i = team.league_rank(); // column index
+
+ compute_dry_mixing_ratios(team, wet_atm_pre_, dry_atm_pre_, i);
+ compute_dry_mixing_ratios(team, wet_atm_pre_, wet_aero_pre_,
+ dry_aero_pre_, i);
+ team.team_barrier();
+ // vertical heights has to be computed after computing dry mixing ratios
+ // for atmosphere
+ compute_vertical_layer_heights(team, dry_atm_pre_, i);
+ compute_updraft_velocities(team, wet_atm_pre_, dry_atm_pre_, i);
+ } // Preprocess operator()
+
+ // local variables for preprocess struct
+ // number of horizontal columns and vertical levels
+ int ncol_pre_, nlev_pre_;
+
+ // local atmospheric and aerosol state data
+ mam_coupling::WetAtmosphere wet_atm_pre_;
+ mam_coupling::DryAtmosphere dry_atm_pre_;
+ mam_coupling::AerosolState wet_aero_pre_, dry_aero_pre_;
+ }; // Preprocess
+
+ // Atmosphere processes often have a post-processing step prepares output
+ // from this process for the Field Manager. This functor implements this
+ // step, which is called during run_impl.
+ // Postprocessing functor
+ struct Postprocess {
+ Postprocess() = default;
+
+ // on host: initializes postprocess functor with necessary state data
+ void initialize(const int ncol, const int nlev,
+ const mam_coupling::WetAtmosphere &wet_atm,
+ const mam_coupling::AerosolState &wet_aero,
+ const mam_coupling::DryAtmosphere &dry_atm,
+ const mam_coupling::AerosolState &dry_aero) {
+ ncol_post_ = ncol;
+ nlev_post_ = nlev;
+ wet_atm_post_ = wet_atm;
+ wet_aero_post_ = wet_aero;
+ dry_atm_post_ = dry_atm;
+ dry_aero_post_ = dry_aero;
+ }
+
+ KOKKOS_INLINE_FUNCTION
+ void operator()(
+ const Kokkos::TeamPolicy::member_type &team) const {
+ const int i = team.league_rank(); // column index
+ compute_wet_mixing_ratios(team, dry_atm_post_, dry_aero_post_,
+ wet_aero_post_, i);
+ } // operator() Postprocess
+
+ // number of horizontal columns and vertical levels
+ int ncol_post_, nlev_post_;
+
+ // local atmospheric and aerosol state data
+ mam_coupling::WetAtmosphere wet_atm_post_;
+ mam_coupling::DryAtmosphere dry_atm_post_;
+ mam_coupling::AerosolState wet_aero_post_, dry_aero_post_;
+ }; // Postprocess
+
+ private:
+ // pre- and postprocessing scratch pads
+ Preprocess preprocess_;
+ Postprocess postprocess_;
+}; // MAMDryDep
+
+} // namespace scream
+
+#endif // EAMXX_MAM_DRYDEP_HPP
diff --git a/components/eamxx/src/physics/mam/mam_coupling.hpp b/components/eamxx/src/physics/mam/mam_coupling.hpp
index e48b5c9f2e1..d490ab76155 100644
--- a/components/eamxx/src/physics/mam/mam_coupling.hpp
+++ b/components/eamxx/src/physics/mam/mam_coupling.hpp
@@ -638,21 +638,27 @@ void compute_vertical_layer_heights(const Team& team,
EKAT_KERNEL_ASSERT_MSG(column_index == team.league_rank(),
"Given column index does not correspond to given team!");
+ //outputs
const auto dz = ekat::subview(dry_atm.dz, column_index);
const auto z_iface = ekat::subview(dry_atm.z_iface, column_index);
const auto z_mid = ekat::subview(dry_atm.z_mid, column_index);
+ //inputs
const auto qv = ekat::subview(dry_atm.qv, column_index);
const auto p_mid = ekat::subview(dry_atm.p_mid, column_index);
const auto T_mid = ekat::subview(dry_atm.T_mid, column_index);
const auto pseudo_density = ekat::subview(dry_atm.p_del, column_index);
+
// NOTE: we are using dry qv. Does calculate_dz require dry or wet?
PF::calculate_dz(team, pseudo_density, p_mid, T_mid, qv, // inputs
dz);//output
team.team_barrier();
+ // NOTE: we are not currently allowing surface topography:
+ EKAT_KERNEL_ASSERT_MSG(dry_atm.z_surf == 0, "dry_atm.z_surf must be zero");
PF::calculate_z_int(team, mam4::nlev, dz, dry_atm.z_surf, //inputs
z_iface); //output
team.team_barrier(); // likely necessary to have z_iface up to date
- PF::calculate_z_mid(team, mam4::nlev, z_iface, z_mid);
+ PF::calculate_z_mid(team, mam4::nlev, z_iface, //input
+ z_mid); //output
}
// Given a thread team and wet and dry atmospheres, dispatches threads from the
diff --git a/components/eamxx/src/physics/register_physics.hpp b/components/eamxx/src/physics/register_physics.hpp
index 44becc2f3e6..aea9f2f543a 100644
--- a/components/eamxx/src/physics/register_physics.hpp
+++ b/components/eamxx/src/physics/register_physics.hpp
@@ -26,6 +26,7 @@
#ifdef EAMXX_HAS_MAM
#include "physics/mam/eamxx_mam_microphysics_process_interface.hpp"
#include "physics/mam/eamxx_mam_optics_process_interface.hpp"
+#include "physics/mam/eamxx_mam_dry_deposition_process_interface.hpp"
#include "physics/mam/eamxx_mam_aci_process_interface.hpp"
#include "physics/mam/eamxx_mam_wetscav_process_interface.hpp"
#endif
@@ -64,6 +65,7 @@ inline void register_physics () {
#ifdef EAMXX_HAS_MAM
proc_factory.register_product("mam4_micro",&create_atmosphere_process);
proc_factory.register_product("mam4_optics",&create_atmosphere_process);
+ proc_factory.register_product("mam4_drydep",&create_atmosphere_process);
proc_factory.register_product("mam4_aci",&create_atmosphere_process);
proc_factory.register_product("mam4_wetscav",&create_atmosphere_process);
#endif
diff --git a/components/eamxx/tests/multi-process/dynamics_physics/CMakeLists.txt b/components/eamxx/tests/multi-process/dynamics_physics/CMakeLists.txt
index b9b58f2fe86..841b7ea00c6 100644
--- a/components/eamxx/tests/multi-process/dynamics_physics/CMakeLists.txt
+++ b/components/eamxx/tests/multi-process/dynamics_physics/CMakeLists.txt
@@ -13,6 +13,7 @@ if (SCREAM_DOUBLE_PRECISION)
# initial conditions.
#add_subdirectory(homme_mam4xx_pg2)
add_subdirectory(mam/homme_shoc_cld_p3_mam_optics_rrtmgp)
+ add_subdirectory(mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep)
add_subdirectory(mam/homme_shoc_cld_spa_p3_rrtmgp_mam4_wetscav)
endif()
endif()
diff --git a/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/CMakeLists.txt b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/CMakeLists.txt
new file mode 100644
index 00000000000..e3c562cfcd1
--- /dev/null
+++ b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/CMakeLists.txt
@@ -0,0 +1,109 @@
+include (ScreamUtils)
+
+set (TEST_BASE_NAME homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep)
+set (FIXTURES_BASE_NAME ${TEST_BASE_NAME}_generate_output_nc_files)
+
+# Get or create the dynamics lib
+# HOMME_TARGET NP PLEV QSIZE_D
+CreateDynamicsLib("theta-l_kokkos" 4 72 41)
+
+# Create the test
+CreateADUnitTest(${TEST_BASE_NAME}
+ LIBS cld_fraction ${dynLibName} shoc p3 scream_rrtmgp mam
+ LABELS dynamics shoc cld p3 rrtmgp physics mam4_optics mam4_aci mam4_drydep
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ FIXTURES_SETUP_INDIVIDUAL ${FIXTURES_BASE_NAME}
+)
+
+# Set AD configurable options
+set (ATM_TIME_STEP 1800)
+SetVarDependingOnTestSize(NUM_STEPS 2 4 48) # 1h 2h 24h
+set (RUN_T0 2021-10-12-45000)
+
+# Determine num subcycles needed to keep shoc dt<=300s
+set (SHOC_MAX_DT 300)
+math (EXPR MAC_MIC_SUBCYCLES "(${ATM_TIME_STEP} + ${SHOC_MAX_DT} - 1) / ${SHOC_MAX_DT}")
+
+## Copy (and configure) yaml files needed by tests
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/input.yaml)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/output.yaml)
+
+# Set homme's test options, so that we can configure the namelist correctly
+# Discretization/algorithm settings
+set (HOMME_TEST_NE 2)
+set (HOMME_TEST_LIM 9)
+set (HOMME_TEST_REMAP_FACTOR 3)
+set (HOMME_TEST_TRACERS_FACTOR 1)
+set (HOMME_TEST_TIME_STEP 300)
+set (HOMME_THETA_FORM 1)
+set (HOMME_TTYPE 5)
+set (HOMME_SE_FTYPE 0)
+set (HOMME_TEST_TRANSPORT_ALG 0)
+set (HOMME_TEST_CUBED_SPHERE_MAP 0)
+
+# Hyperviscosity settings
+set (HOMME_TEST_HVSCALING 0)
+set (HOMME_TEST_HVS 1)
+set (HOMME_TEST_HVS_TOM 0)
+set (HOMME_TEST_HVS_Q 1)
+
+set (HOMME_TEST_NU 7e15)
+set (HOMME_TEST_NUDIV 1e15)
+set (HOMME_TEST_NUTOP 2.5e5)
+
+# Testcase settings
+set (HOMME_TEST_MOISTURE notdry)
+set (HOMME_THETA_HY_MODE true)
+
+# Vert coord settings
+set (HOMME_TEST_VCOORD_INT_FILE acme-72i.ascii)
+set (HOMME_TEST_VCOORD_MID_FILE acme-72m.ascii)
+
+# Configure the namelist into the test directory
+configure_file(${SCREAM_SRC_DIR}/dynamics/homme/tests/theta.nl
+ ${CMAKE_CURRENT_BINARY_DIR}/namelist.nl)
+
+# Ensure test input files are present in the data dir
+set (TEST_INPUT_FILES
+ scream/mam4xx/physprops/mam4_mode1_rrtmg_aeronetdust_c20240206.nc
+ scream/mam4xx/physprops/mam4_mode2_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/mam4_mode3_rrtmg_aeronetdust_c20240206.nc
+ scream/mam4xx/physprops/mam4_mode4_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/water_refindex_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/ocphi_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/dust_aeronet_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/ssam_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/sulfate_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/ocpho_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/bcpho_rrtmg_c20240206.nc
+ scream/mam4xx/physprops/poly_rrtmg_c20240206.nc
+)
+
+foreach (file IN ITEMS ${TEST_INPUT_FILES})
+ GetInputFile(${file})
+endforeach()
+
+# Ensure test input files are present in the data dir
+GetInputFile(scream/init/${EAMxx_tests_IC_FILE_72lev})
+GetInputFile(scream/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev})
+GetInputFile(cam/topo/${EAMxx_tests_TOPO_FILE})
+
+# Compare output files produced by npX tests, to ensure they are bfb
+include (CompareNCFiles)
+
+CompareNCFilesFamilyMpi (
+ TEST_BASE_NAME ${TEST_BASE_NAME}
+ FILE_META_NAME ${TEST_BASE_NAME}.INSTANT.nsteps_x${NUM_STEPS}.npMPIRANKS.${RUN_T0}.nc
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ LABELS dynamics physics shoc cld p3 rrtmgp mam4_optics
+ META_FIXTURES_REQUIRED ${FIXTURES_BASE_NAME}_npMPIRANKS_omp1
+)
+
+if (SCREAM_ENABLE_BASELINE_TESTS)
+ # Compare one of the output files with the baselines.
+ # Note: one is enough, since we already check that np1 is BFB with npX
+ set (OUT_FILE ${TEST_BASE_NAME}.INSTANT.nsteps_x${NUM_STEPS}.np${TEST_RANK_END}.${RUN_T0}.nc)
+ CreateBaselineTest(${TEST_BASE_NAME} ${TEST_RANK_END} ${OUT_FILE} ${FIXTURES_BASE_NAME})
+endif()
diff --git a/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/input.yaml b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/input.yaml
new file mode 100644
index 00000000000..1857bc534dd
--- /dev/null
+++ b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/input.yaml
@@ -0,0 +1,109 @@
+%YAML 1.1
+---
+driver_options:
+ atmosphere_dag_verbosity_level: 5
+ mass_column_conservation_error_tolerance: 1e-3
+ energy_column_conservation_error_tolerance: 1e-4
+ column_conservation_checks_fail_handling_type: Warning
+ property_check_data_fields: [phis]
+
+time_stepping:
+ time_step: ${ATM_TIME_STEP}
+ run_t0: ${RUN_T0} # YYYY-MM-DD-XXXXX
+ number_of_steps: ${NUM_STEPS}
+
+initial_conditions:
+ Filename: ${SCREAM_DATA_DIR}/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev}
+ topography_filename: ${TOPO_DATA_DIR}/${EAMxx_tests_TOPO_FILE}
+ pbl_height : 1.0
+ phis : 1.0
+
+ #variables required for shoc
+ surf_sens_flux: 0.0
+ surf_evap: 0.0
+
+ #variables required for p3
+ precip_ice_surf_mass: 0.0
+ precip_liq_surf_mass: 0.0
+
+ #variables required for mam4_aci
+ dgnum: 1e-3
+
+ #mam4 drydep
+ fv: 0.47569674433601039E+000
+ landfrac: 0.14675684171817760E+000
+ icefrac: 0.00000000000000000E+000
+ ocnfrac: 0.85324315828182240E+000
+ ram1: 0.45506166067091662E+002
+ dgnumwet: 0.41417721820867320E-007
+ wetdens: 0.15100083211582764E+004
+
+atmosphere_processes:
+ atm_procs_list: [homme,physics]
+ schedule_type: Sequential
+ homme:
+ Moisture: moist
+ physics:
+ atm_procs_list: [mac_mic,mam4_optics,rrtmgp,mam4_drydep]
+ schedule_type: Sequential
+ Type: Group
+ mac_mic:
+ atm_procs_list: [shoc,CldFraction,mam4_aci,p3]
+ schedule_type: Sequential
+ Type: Group
+ number_of_subcycles: ${MAC_MIC_SUBCYCLES}
+ mam4_aci:
+ wsubmin: 0.001
+ top_level_mam4xx: 6
+ p3:
+ do_prescribed_ccn: false
+ enable_column_conservation_checks: true
+ max_total_ni: 740.0e3
+ shoc:
+ enable_column_conservation_checks: true
+ lambda_low: 0.001
+ lambda_high: 0.04
+ lambda_slope: 2.65
+ lambda_thresh: 0.02
+ thl2tune: 1.0
+ qw2tune: 1.0
+ qwthl2tune: 1.0
+ w2tune: 1.0
+ length_fac: 0.5
+ c_diag_3rd_mom: 7.0
+ Ckh: 0.1
+ Ckm: 0.1
+
+ mam4_optics:
+ mam4_mode1_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/mam4_mode1_rrtmg_aeronetdust_c20240206.nc
+ mam4_mode2_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/mam4_mode2_rrtmg_c20240206.nc
+ mam4_mode3_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/mam4_mode3_rrtmg_aeronetdust_c20240206.nc
+ mam4_mode4_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/mam4_mode4_rrtmg_c20240206.nc
+ mam4_water_refindex_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/water_refindex_rrtmg_c20240206.nc
+ mam4_soa_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/ocphi_rrtmg_c20240206.nc
+ mam4_dust_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/dust_aeronet_rrtmg_c20240206.nc
+ mam4_nacl_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/ssam_rrtmg_c20240206.nc
+ mam4_so4_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/sulfate_rrtmg_c20240206.nc
+ mam4_pom_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/ocpho_rrtmg_c20240206.nc
+ mam4_bc_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/bcpho_rrtmg_c20240206.nc
+ mam4_mom_physical_properties_file : ${SCREAM_DATA_DIR}/mam4xx/physprops/poly_rrtmg_c20240206.nc
+
+ rrtmgp:
+ column_chunk_size: 123
+ active_gases: ["h2o", "co2", "o3", "n2o", "co" , "ch4", "o2", "n2"]
+ rrtmgp_coefficients_file_sw: ${SCREAM_DATA_DIR}/init/rrtmgp-data-sw-g112-210809.nc
+ rrtmgp_coefficients_file_lw: ${SCREAM_DATA_DIR}/init/rrtmgp-data-lw-g128-210809.nc
+ rrtmgp_cloud_optics_file_sw: ${SCREAM_DATA_DIR}/init/rrtmgp-cloud-optics-coeffs-sw.nc
+ rrtmgp_cloud_optics_file_lw: ${SCREAM_DATA_DIR}/init/rrtmgp-cloud-optics-coeffs-lw.nc
+ enable_column_conservation_checks: true
+
+grids_manager:
+ Type: Homme
+ physics_grid_type: GLL
+ dynamics_namelist_file_name: namelist.nl
+ vertical_coordinate_filename: IC_FILE
+
+# The parameters for I/O control
+Scorpio:
+ output_yaml_files: ["output.yaml"]
+...
diff --git a/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/output.yaml b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/output.yaml
new file mode 100644
index 00000000000..f2408ab189a
--- /dev/null
+++ b/components/eamxx/tests/multi-process/dynamics_physics/mam/homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep/output.yaml
@@ -0,0 +1,124 @@
+%YAML 1.1
+---
+filename_prefix: homme_shoc_cld_mam_aci_p3_mam_optics_rrtmgp_mam_drydep
+Averaging Type: Instant
+Max Snapshots Per File: 1
+Fields:
+ Physics GLL:
+ Field Names:
+ # HOMME
+ - ps
+ - pseudo_density
+ - omega
+ - p_int
+ - p_mid
+ - pseudo_density_dry
+ - p_dry_int
+ - p_dry_mid
+ # SHOC
+ - cldfrac_liq
+ - eddy_diff_mom
+ - sgs_buoy_flux
+ - tke
+ - inv_qc_relvar
+ - pbl_height
+ # CLD
+ - cldfrac_ice
+ - cldfrac_tot
+ # P3
+ - bm
+ - nc
+ - ni
+ - nr
+ - qi
+ - qm
+ - qr
+ - T_prev_micro_step
+ - qv_prev_micro_step
+ - eff_radius_qc
+ - eff_radius_qi
+ - eff_radius_qr
+ - micro_liq_ice_exchange
+ - micro_vap_ice_exchange
+ - micro_vap_liq_exchange
+ - precip_ice_surf_mass
+ - precip_liq_surf_mass
+ - rainfrac
+ # SHOC + HOMME
+ - horiz_winds
+ # SHOC + P3
+ - qc
+ - qv
+ # SHOC + P3 + RRTMGP + HOMME
+ - T_mid
+ #mam_optics
+ - aero_g_sw
+ - aero_ssa_sw
+ - aero_tau_lw
+ - aero_tau_sw
+ # RRTMGP
+ - sfc_alb_dif_nir
+ - sfc_alb_dif_vis
+ - sfc_alb_dir_nir
+ - sfc_alb_dir_vis
+ - LW_flux_dn
+ - LW_flux_up
+ - SW_flux_dn
+ - SW_flux_dn_dir
+ - SW_flux_up
+ - rad_heating_pdel
+ - sfc_flux_lw_dn
+ - sfc_flux_sw_net
+ # Diagnostics
+ - T_mid_at_lev_2
+ - T_mid_at_model_top
+ - T_mid_at_model_bot
+ - T_mid_at_500mb
+ - T_mid_at_500hPa
+ - T_mid_at_50000Pa
+ - PotentialTemperature
+ - AtmosphereDensity
+ - Exner
+ - VirtualTemperature
+ - z_int
+ - geopotential_int_at_lev_2
+ - z_mid_at_500mb
+ - geopotential_mid
+ - dz
+ - DryStaticEnergy
+ - SeaLevelPressure
+ - LiqWaterPath
+ - IceWaterPath
+ - VapWaterPath
+ - RainWaterPath
+ - RimeWaterPath
+ - ShortwaveCloudForcing
+ - LongwaveCloudForcing
+ - RelativeHumidity
+ - ZonalVapFlux
+ - MeridionalVapFlux
+ - PotentialTemperature_at_model_top
+ - PotentialTemperature_at_500mb
+ #drydep
+ - deposition_flux_of_cloud_borne_aerosols
+ - deposition_flux_of_interstitial_aerosols
+ # GLL output for homme states. These
+ # represent all current possible homme
+ # states available.
+ Dynamics:
+ Field Names:
+ - v_dyn
+ - vtheta_dp_dyn
+ - dp3d_dyn
+ - phi_int_dyn
+ - ps_dyn
+ - phis_dyn
+ - omega_dyn
+ - Qdp_dyn
+ IO Grid Name: Physics GLL
+
+output_control:
+ Frequency: ${NUM_STEPS}
+ frequency_units: nsteps
+ MPI Ranks in Filename: true
+...
diff --git a/components/eamxx/tests/multi-process/physics_only/CMakeLists.txt b/components/eamxx/tests/multi-process/physics_only/CMakeLists.txt
index d3b584bd09e..d6ed13dfb0a 100644
--- a/components/eamxx/tests/multi-process/physics_only/CMakeLists.txt
+++ b/components/eamxx/tests/multi-process/physics_only/CMakeLists.txt
@@ -5,6 +5,7 @@ if (SCREAM_DOUBLE_PRECISION)
if (SCREAM_ENABLE_MAM)
add_subdirectory(mam/optics_rrtmgp)
add_subdirectory(mam/shoc_mam4_aci)
+ add_subdirectory(mam/shoc_mam4_drydep)
add_subdirectory(mam/shoc_cldfrac_mam4_aci_p3)
add_subdirectory(mam/shoc_cldfrac_mam4_aci_p3_rrtmgp)
add_subdirectory(mam/shoc_cldfrac_mam4_aci_p3_mam4_optics_rrtmgp)
diff --git a/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/CMakeLists.txt b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/CMakeLists.txt
new file mode 100644
index 00000000000..9f6fb8733c2
--- /dev/null
+++ b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/CMakeLists.txt
@@ -0,0 +1,41 @@
+INCLUDE (ScreamUtils)
+
+set (TEST_BASE_NAME shoc_mam4_drydep)
+set (FIXTURES_BASE_NAME ${TEST_BASE_NAME}_generate_output_nc_files)
+
+# Create the test
+CreateADUnitTest(${TEST_BASE_NAME}
+ LIBS shoc mam
+ LABELS shoc physics mam4_drydep
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ FIXTURES_SETUP_INDIVIDUAL ${FIXTURES_BASE_NAME}
+)
+
+# Set AD configurable options
+set (ATM_TIME_STEP 1800)
+SetVarDependingOnTestSize(NUM_STEPS 2 5 48) # 1h 4h 24h
+set (RUN_T0 2021-10-12-45000)
+
+# Determine num subcycles needed to keep shoc dt<=300s
+set (SHOC_MAX_DT 300)
+math (EXPR MAC_MIC_SUBCYCLES "(${ATM_TIME_STEP} + ${SHOC_MAX_DT} - 1) / ${SHOC_MAX_DT}")
+
+# Ensure test input files are present in the data dir
+GetInputFile(scream/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev})
+GetInputFile(cam/topo/${EAMxx_tests_TOPO_FILE})
+
+## Copy (and configure) yaml files needed by tests
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/input.yaml)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/output.yaml)
+
+# Compare output files produced by npX tests, to ensure they are bfb
+include (CompareNCFiles)
+CompareNCFilesFamilyMpi (
+ TEST_BASE_NAME ${TEST_BASE_NAME}
+ FILE_META_NAME ${TEST_BASE_NAME}_output.INSTANT.nsteps_x${NUM_STEPS}.npMPIRANKS.${RUN_T0}.nc
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ LABELS shoc physics mam4_drydep
+ META_FIXTURES_REQUIRED ${FIXTURES_BASE_NAME}_npMPIRANKS_omp1
+)
diff --git a/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/input.yaml b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/input.yaml
new file mode 100644
index 00000000000..c451008adc7
--- /dev/null
+++ b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/input.yaml
@@ -0,0 +1,67 @@
+%YAML 1.1
+---
+driver_options:
+ atmosphere_dag_verbosity_level: 5
+
+time_stepping:
+ time_step: ${ATM_TIME_STEP}
+ run_t0: ${RUN_T0} # YYYY-MM-DD-XXXXX
+ number_of_steps: ${NUM_STEPS}
+
+atmosphere_processes:
+ atm_procs_list: [mac_mic,mam4_drydep]
+ schedule_type: Sequential
+ mac_mic:
+ atm_procs_list: [shoc]
+ Type: Group
+ schedule_type: Sequential
+ number_of_subcycles: ${MAC_MIC_SUBCYCLES}
+ shoc:
+ lambda_low: 0.001
+ lambda_high: 0.04
+ lambda_slope: 2.65
+ lambda_thresh: 0.02
+ thl2tune: 1.0
+ qw2tune: 1.0
+ qwthl2tune: 1.0
+ w2tune: 1.0
+ length_fac: 0.5
+ c_diag_3rd_mom: 7.0
+ Ckh: 0.1
+ Ckm: 0.1
+
+grids_manager:
+ Type: Mesh Free
+ geo_data_source: IC_FILE
+ grids_names: [Physics GLL]
+ Physics GLL:
+ aliases: [Physics]
+ type: point_grid
+ number_of_global_columns: 218
+ number_of_vertical_levels: 72
+
+initial_conditions:
+ # The name of the file containing the initial conditions for this test.
+ Filename: ${SCREAM_DATA_DIR}/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev}
+ topography_filename: ${TOPO_DATA_DIR}/${EAMxx_tests_TOPO_FILE}
+
+ #variables needed for SHOC
+ surf_sens_flux: 0.0
+ surf_evap: 0.0
+
+ #variables needed for mam4-drydep
+ fraction_landuse: 0.2
+ w_updraft: 1e-5
+ pbl_height: 0.0
+ fv: 0.47569674433601039E+000
+ landfrac: 0.14675684171817760E+000
+ icefrac: 0.00000000000000000E+000
+ ocnfrac: 0.85324315828182240E+000
+ ram1: 0.45506166067091662E+002
+ dgnumwet: 0.41417721820867320E-007
+ wetdens: 0.15100083211582764E+004
+
+# The parameters for I/O control
+Scorpio:
+ output_yaml_files: ["output.yaml"]
+...
diff --git a/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/output.yaml b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/output.yaml
new file mode 100644
index 00000000000..d8c1291bc3c
--- /dev/null
+++ b/components/eamxx/tests/multi-process/physics_only/mam/shoc_mam4_drydep/output.yaml
@@ -0,0 +1,69 @@
+%YAML 1.1
+---
+filename_prefix: shoc_mam4_drydep_output
+Averaging Type: Instant
+Field Names:
+ # SHOC
+ - cldfrac_liq
+ - eddy_diff_mom
+ - horiz_winds
+ - sgs_buoy_flux
+ - tke
+ - inv_qc_relvar
+ - pbl_height
+ - bc_a1
+ - bc_a3
+ - bc_a4
+ - dst_a1
+ - dst_a3
+ - so4_a1
+ - so4_a2
+ - so4_a3
+ - pom_a1
+ - pom_a3
+ - pom_a4
+ - soa_a1
+ - soa_a2
+ - soa_a3
+ - nacl_a1
+ - nacl_a2
+ - nacl_a3
+ - mom_a1
+ - mom_a2
+ - mom_a3
+ - mom_a4
+ - num_a1
+ - num_a2
+ - num_a3
+ - num_a4
+ - bc_c1
+ - bc_c3
+ - bc_c4
+ - dst_c1
+ - dst_c3
+ - so4_c1
+ - so4_c2
+ - so4_c3
+ - pom_c1
+ - pom_c3
+ - pom_c4
+ - soa_c1
+ - soa_c2
+ - soa_c3
+ - nacl_c1
+ - nacl_c2
+ - nacl_c3
+ - mom_c1
+ - mom_c2
+ - mom_c3
+ - mom_c4
+ - num_c1
+ - num_c2
+ - num_c3
+ - num_c4
+ - deposition_flux_of_cloud_borne_aerosols
+ - deposition_flux_of_interstitial_aerosols
+output_control:
+ Frequency: ${NUM_STEPS}
+ frequency_units: nsteps
+...
diff --git a/components/eamxx/tests/single-process/CMakeLists.txt b/components/eamxx/tests/single-process/CMakeLists.txt
index 3e1629ae0f3..95e4d81ccbb 100644
--- a/components/eamxx/tests/single-process/CMakeLists.txt
+++ b/components/eamxx/tests/single-process/CMakeLists.txt
@@ -21,6 +21,7 @@ if (SCREAM_ENABLE_MAM)
# initial conditions.
add_subdirectory(mam/optics)
add_subdirectory(mam/aci)
+ add_subdirectory(mam/drydep)
add_subdirectory(mam/wet_scav)
endif()
if (SCREAM_TEST_LEVEL GREATER_EQUAL SCREAM_TEST_LEVEL_EXPERIMENTAL)
diff --git a/components/eamxx/tests/single-process/mam/aci/CMakeLists.txt b/components/eamxx/tests/single-process/mam/aci/CMakeLists.txt
index 0d5d60ee7d5..490dc389d95 100644
--- a/components/eamxx/tests/single-process/mam/aci/CMakeLists.txt
+++ b/components/eamxx/tests/single-process/mam/aci/CMakeLists.txt
@@ -24,6 +24,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml
# Ensure test input files are present in the data dir
GetInputFile(scream/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev})
+GetInputFile(cam/topo/${EAMxx_tests_TOPO_FILE})
# Compare output files produced by npX tests, to ensure they are bfb
include (CompareNCFiles)
diff --git a/components/eamxx/tests/single-process/mam/drydep/CMakeLists.txt b/components/eamxx/tests/single-process/mam/drydep/CMakeLists.txt
new file mode 100644
index 00000000000..d05e6823642
--- /dev/null
+++ b/components/eamxx/tests/single-process/mam/drydep/CMakeLists.txt
@@ -0,0 +1,46 @@
+include (ScreamUtils)
+
+set (TEST_BASE_NAME mam4_drydep_standalone)
+set (FIXTURES_BASE_NAME ${TEST_BASE_NAME}_generate_output_nc_files)
+
+# Create the test
+CreateADUnitTest(${TEST_BASE_NAME}
+ LABELS mam4_drydep physics
+ LIBS mam
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ FIXTURES_SETUP_INDIVIDUAL ${FIXTURES_BASE_NAME}
+)
+
+# Set AD configurable options
+set (ATM_TIME_STEP 1800)
+SetVarDependingOnTestSize(NUM_STEPS 2 5 48) # 1h 2.5h 24h
+set (RUN_T0 2021-10-12-45000)
+
+## Copy (and configure) yaml files needed by tests
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/input.yaml)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml
+ ${CMAKE_CURRENT_BINARY_DIR}/output.yaml)
+
+# Ensure test input files are present in the data dir
+GetInputFile(scream/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev})
+GetInputFile(cam/topo/${EAMxx_tests_TOPO_FILE})
+
+# Compare output files produced by npX tests, to ensure they are bfb
+include (CompareNCFiles)
+
+CompareNCFilesFamilyMpi (
+ TEST_BASE_NAME ${TEST_BASE_NAME}
+ FILE_META_NAME ${TEST_BASE_NAME}_output.INSTANT.nsteps_x1.npMPIRANKS.${RUN_T0}.nc
+ MPI_RANKS ${TEST_RANK_START} ${TEST_RANK_END}
+ LABELS mam4_drydep physics
+ META_FIXTURES_REQUIRED ${FIXTURES_BASE_NAME}_npMPIRANKS_omp1
+)
+
+if (SCREAM_ENABLE_BASELINE_TESTS)
+ # Compare one of the output files with the baselines.
+ # Note: one is enough, since we already check that np1 is BFB with npX
+ set (OUT_FILE ${TEST_BASE_NAME}_output.INSTANT.nsteps_x1.np${TEST_RANK_END}.${RUN_T0}.nc)
+ CreateBaselineTest(${TEST_BASE_NAME} ${TEST_RANK_END} ${OUT_FILE} ${FIXTURES_BASE_NAME})
+endif()
+
diff --git a/components/eamxx/tests/single-process/mam/drydep/input.yaml b/components/eamxx/tests/single-process/mam/drydep/input.yaml
new file mode 100644
index 00000000000..86c6dd8766a
--- /dev/null
+++ b/components/eamxx/tests/single-process/mam/drydep/input.yaml
@@ -0,0 +1,44 @@
+%YAML 1.1
+---
+driver_options:
+ atmosphere_dag_verbosity_level: 5
+
+time_stepping:
+ time_step: ${ATM_TIME_STEP}
+ run_t0: ${RUN_T0} # YYYY-MM-DD-XXXXX
+ number_of_steps: ${NUM_STEPS}
+
+atmosphere_processes:
+ atm_procs_list: [mam4_drydep]
+
+grids_manager:
+ Type: Mesh Free
+ geo_data_source: IC_FILE
+ grids_names: [Physics GLL]
+ Physics GLL:
+ type: point_grid
+ aliases: [Physics]
+ number_of_global_columns: 218
+ number_of_vertical_levels: 72
+
+initial_conditions:
+ # The name of the file containing the initial conditions for this test.
+ Filename: ${SCREAM_DATA_DIR}/init/${EAMxx_tests_IC_FILE_MAM4xx_72lev}
+ topography_filename: ${TOPO_DATA_DIR}/${EAMxx_tests_TOPO_FILE}
+ fraction_landuse: 0.2
+ w_updraft: 1e-5
+ pbl_height: 0.0
+ obklen: -0.48167567011091336E+002
+ fv: 0.47569674433601039E+000
+ landfrac: 0.14675684171817760E+000
+ icefrac: 0.00000000000000000E+000
+ ocnfrac: 0.85324315828182240E+000
+ ustar: 0.27482164092221828E+000
+ ram1: 0.45506166067091662E+002
+ dgnumwet: 0.41417721820867320E-007
+ wetdens: 0.15100083211582764E+004
+
+# The parameters for I/O control
+Scorpio:
+ output_yaml_files: ["output.yaml"]
+...
diff --git a/components/eamxx/tests/single-process/mam/drydep/output.yaml b/components/eamxx/tests/single-process/mam/drydep/output.yaml
new file mode 100644
index 00000000000..6d8a79e8fe0
--- /dev/null
+++ b/components/eamxx/tests/single-process/mam/drydep/output.yaml
@@ -0,0 +1,64 @@
+%YAML 1.1
+---
+filename_prefix: mam4_drydep_standalone_output
+Averaging Type: Instant
+Fields:
+ Physics:
+ Field Names:
+ - bc_a1
+ - bc_a3
+ - bc_a4
+ - dst_a1
+ - dst_a3
+ - so4_a1
+ - so4_a2
+ - so4_a3
+ - pom_a1
+ - pom_a3
+ - pom_a4
+ - soa_a1
+ - soa_a2
+ - soa_a3
+ - nacl_a1
+ - nacl_a2
+ - nacl_a3
+ - mom_a1
+ - mom_a2
+ - mom_a3
+ - mom_a4
+ - num_a1
+ - num_a2
+ - num_a3
+ - num_a4
+ - bc_c1
+ - bc_c3
+ - bc_c4
+ - dst_c1
+ - dst_c3
+ - so4_c1
+ - so4_c2
+ - so4_c3
+ - pom_c1
+ - pom_c3
+ - pom_c4
+ - soa_c1
+ - soa_c2
+ - soa_c3
+ - nacl_c1
+ - nacl_c2
+ - nacl_c3
+ - mom_c1
+ - mom_c2
+ - mom_c3
+ - mom_c4
+ - num_c1
+ - num_c2
+ - num_c3
+ - num_c4
+ - deposition_flux_of_cloud_borne_aerosols
+ - deposition_flux_of_interstitial_aerosols
+
+output_control:
+ Frequency: 1
+ frequency_units: nsteps
+...