Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds a flag to control vertical mixing of interstitial aerosols during aerosol activation process #6926

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/eamxx/cime_config/namelist_defaults_scream.xml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ be lost if SCREAM_HACK_XML is not enabled.
<!-- MAM4xx-ACI -->
<mam4_aci inherit="atm_proc_base">
<wsubmin type="real" doc="Minimum diagnostic sub-grid vertical velocity">0.001</wsubmin>
<enable_aero_vertical_mix type="logical" doc="Enable vertical mixing of interstitial aerosols and liquid number during activation">true</enable_aero_vertical_mix>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this flag is to control the vertical mixing calculation of both aerosols and cloud droplet (?) in aci, it might be better change it to "enable_aci_vert_mix". Do we have a similar flag to control the vertical mixing calculation in SHOC?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good suggestion. Thanks. I will revise the flag name.

@tcclevenger is working on a method to disable the vertical mixing in SHOC. Once that is ready, we will have two ways to control vertical mixing.

<top_level_mam4xx type="integer" doc="Level corresponding to the top of troposphere clouds" nlev="72" >6</top_level_mam4xx>
<top_level_mam4xx type="integer" doc="level corresponding to the top of troposphere clouds" nlev="128" >0</top_level_mam4xx>
</mam4_aci>
Expand Down
17 changes: 7 additions & 10 deletions components/eamxx/src/physics/mam/eamxx_mam_aci_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ void call_function_dropmixnuc(
const MAMAci::view_2d wsub,
const MAMAci::view_2d cloud_frac, const MAMAci::view_2d cloud_frac_prev,
const mam_coupling::AerosolState &dry_aero, const int nlev,
const bool &enable_aero_vertical_mix,

// Following outputs are all diagnostics
MAMAci::view_2d coltend[mam4::ndrop::ncnst_tot],
Expand Down Expand Up @@ -318,7 +319,7 @@ void call_function_dropmixnuc(
num2vol_ratio_max_nmodes);
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

const bool local_enable_aero_vertical_mix = enable_aero_vertical_mix;
Kokkos::parallel_for(
team_policy, KOKKOS_LAMBDA(const haero::ThreadTeam &team) {
const int icol = team.league_rank();
Expand Down Expand Up @@ -406,10 +407,6 @@ void call_function_dropmixnuc(
}
});
team.team_barrier();
// HACK: dropmixnuc() requires the parameter enable_aero_vertical_mix,
// so we define it here until we have a better idea of where it
// might come from
const bool enable_aero_vertical_mix = true;
mam4::ndrop::dropmixnuc(
team, dt, ekat::subview(T_mid, icol), ekat::subview(p_mid, icol),
ekat::subview(p_int, icol), ekat::subview(pdel, icol),
Expand All @@ -421,11 +418,10 @@ void call_function_dropmixnuc(
spechygro, lmassptr_amode, num2vol_ratio_min_nmodes,
num2vol_ratio_max_nmodes, numptr_amode, nspec_amode, exp45logsig,
alogsig, aten, mam_idx, mam_cnst_idx,
enable_aero_vertical_mix,
ekat::subview(qcld, icol), // out
ekat::subview(wsub, icol), // in
ekat::subview(cloud_frac_prev, icol), // in
qqcw_view, // inout
local_enable_aero_vertical_mix, ekat::subview(qcld, icol), // out
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is local_enable_aero_vertical_mix out? I thought it would be in...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. It should be in, I will fix this.

ekat::subview(wsub, icol), // in
ekat::subview(cloud_frac_prev, icol), // in
qqcw_view, // inout
ptend_q_view, ekat::subview(tendnd, icol),
ekat::subview(factnum, icol), ekat::subview(ndropcol, icol),
ekat::subview(ndropmix, icol), ekat::subview(nsource, icol),
Expand Down Expand Up @@ -534,6 +530,7 @@ void call_hetfrz_compute_tendencies(
haero::Atmosphere haero_atm =
atmosphere_for_column(dry_atmosphere, icol);
haero::Surface surf{};
set_min_background_mmr(team, dry_aero,icol);
mam4::Prognostics progs =
mam_coupling::aerosols_for_column(dry_aero, icol);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ MAMAci::MAMAci(const ekat::Comm &comm, const ekat::ParameterList &params)
// Asserts for the runtime or namelist options
EKAT_REQUIRE_MSG(m_params.isParameter("wsubmin"),
"ERROR: wsubmin is missing from mam_aci parameter list.");
EKAT_REQUIRE_MSG(m_params.isParameter("enable_aero_vertical_mix"),
"ERROR: enable_aero_vertical_mixing is missing from mam_aci "
"parameter list.");
EKAT_REQUIRE_MSG(
m_params.isParameter("top_level_mam4xx"),
"ERROR: top_level_mam4xx is missing from mam_aci parameter list.");
Expand Down Expand Up @@ -271,8 +274,9 @@ void MAMAci::initialize_impl(const RunType run_type) {
// ## Runtime options
// ------------------------------------------------------------------------

wsubmin_ = m_params.get<double>("wsubmin");
top_lev_ = m_params.get<int>("top_level_mam4xx");
wsubmin_ = m_params.get<double>("wsubmin");
enable_aero_vertical_mix_ = m_params.get<bool>("enable_aero_vertical_mix");
top_lev_ = m_params.get<int>("top_level_mam4xx");

// ------------------------------------------------------------------------
// Input fields read in from IC file, namelist or other processes
Expand Down Expand Up @@ -600,7 +604,7 @@ void MAMAci::run_impl(const double dt) {
// aerosols tendencies
call_function_dropmixnuc(
team_policy, dt, dry_atm_, rpdel_, kvh_mid_, kvh_int_, wsub_, cloud_frac_,
cloud_frac_prev_, dry_aero_, nlev_,
cloud_frac_prev_, dry_aero_, nlev_, enable_aero_vertical_mix_,
// output
coltend_, coltend_cw_, qcld_, ndropcol_, ndropmix_, nsource_, wtke_, ccn_,
// ## output to be used by the other processes ##
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ class MAMAci final : public scream::AtmosphereProcess {
// ACI runtime ( or namelist) options
//------------------------------------------------------------------------

Real wsubmin_; // Minimum subgrid vertical velocity
int top_lev_; // Top level for MAM4xx
Real wsubmin_; // Minimum subgrid vertical velocity
bool enable_aero_vertical_mix_; // To enable vertical mixing of aerosols
int top_lev_; // Top level for MAM4xx

//------------------------------------------------------------------------
// END: ACI runtime ( or namelist) options
Expand Down Expand Up @@ -212,7 +213,9 @@ class MAMAci final : public scream::AtmosphereProcess {
// for atmosphere
compute_vertical_layer_heights(team, dry_atm_pre_, i);
compute_updraft_velocities(team, wet_atm_pre_, dry_atm_pre_, i);
} // operator()
set_min_background_mmr(team, dry_aero_pre_,
i); // dry_atm_pre_ is the output
} // operator()

// local variables for preprocess struct
// number of horizontal columns and vertical levels
Expand Down
26 changes: 26 additions & 0 deletions components/eamxx/src/physics/mam/mam_coupling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,32 @@ void compute_wet_mixing_ratios(const Team& team,
});
}

// Set minimum background MMR for the interstitial aerosols
KOKKOS_INLINE_FUNCTION
void set_min_background_mmr(const Team& team,
const AerosolState& dry_aero,
const int column_index) {

EKAT_KERNEL_ASSERT_MSG(column_index == team.league_rank(),
"Given column index does not correspond to given team!");

//Minimum background value for the interstitial aerosols
constexpr Real INTERSTITIAL_AERO_MIN_VAL = 1e-36;

constexpr int nlev = mam4::nlev;
const int icol = column_index;
Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev), [&] (const int klev) {
for (int imode = 0; imode < num_aero_modes(); ++imode) {
dry_aero.int_aero_nmr[imode](icol,klev) = haero::max(dry_aero.int_aero_nmr[imode](icol,klev), INTERSTITIAL_AERO_MIN_VAL);
for (int ispec = 0; ispec < num_aero_species(); ++ispec) {
if (dry_aero.int_aero_mmr[imode][ispec].data()) {
dry_aero.int_aero_mmr[imode][ispec](icol,klev) = haero::max(dry_aero.int_aero_mmr[imode][ispec](icol,klev), INTERSTITIAL_AERO_MIN_VAL);
}
Comment on lines +794 to +799
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like set_min_background_mmr is unrelated to stuff in the PR title and description. I am concerned about this because it is surprisingly complex (pretty hard to read):

  • why do think this minimum is needed? just matching stuff to old mam or is there some undesirable behavior?
  • what are the examples when this dry_aero.int_aero_mmr[imode][ispec].data() is true/false? do we have any mode with no species in it?
  • relatedly, what does dry_aero.int_aero_nmr[imode](icol,klev) access when dry_aero.int_aero_mmr[imode][ispec].data() is true?

I guess I am confused about both the data layout as well as any undesirable side effect of low values...

Copy link
Contributor Author

@singhbalwinder singhbalwinder Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When enable_aero_vertical_mix == false, the model crashes because the ACI codes (specifically the heterogeneous freezing code) expect positive mmrs for the interstitial aerosols. Therefore, I added this limiter to ensure that the interstitial aerosols are always positive.

num_aero_species() is the number of species for the mam mode that has the maximum species. For example, mode 1 has the maximum species (7), but mode 2 has 4 species. When we loop over num_aero_species() (i.e., 7) for mode 2, dry_aero.int_aero_mmr[imode][ispec].data() is false for 4th, 5th, and 6th (c-indexing)iterations.

dry_aero.int_aero_nmr[imode](icol,klev) is the interstitial aerosol number mixing ratio (represented by _nmr) of mode imode at colum icol and level klev.

I hope it makes sense, but let me know if you have questions.

}//ispec
}//imode
});
} // set_min_background_mmr

// Computes the reciprocal of pseudo density for a column
inline
void compute_recipical_pseudo_density(haero::ThreadTeamPolicy team_policy,
Expand Down
1 change: 1 addition & 0 deletions components/eamxx/tests/single-process/mam/aci/input.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ atmosphere_processes:
atm_procs_list: [mam4_aci]
mam4_aci:
wsubmin: 0.001
enable_aero_vertical_mix: true
top_level_mam4xx: 6

grids_manager:
Expand Down
Loading