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 +...