Skip to content

Commit c93f12f

Browse files
committed
use vert_contraction() for diagnostic outputs--almost finished
1 parent 22cde10 commit c93f12f

File tree

2 files changed

+108
-85
lines changed

2 files changed

+108
-85
lines changed

components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp

Lines changed: 92 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,53 @@ void MAMMicrophysics::set_grids(
188188
add_field<Updated>("constituent_fluxes", scalar2d_pcnst, kg / m2 / s,
189189
grid_name);
190190

191+
// FIXME: moved this to class
191192
// Number of externally forced chemical species
192-
constexpr int extcnt = mam4::gas_chemistry::extcnt;
193+
// constexpr int extcnt = mam4::gas_chemistry::extcnt;
193194

194-
FieldLayout scalar3d_extcnt = grid_->get_3d_vector_layout(true, extcnt, "ext_cnt");
195+
FieldLayout scalar3d_extcnt = grid_->get_3d_vector_layout(true, extcnt_, "ext_cnt");
195196

196197
// Register computed fields for external forcing
197198
// - extfrc: 3D instantaneous forcing rate [kg/m³/s]
198199
add_field<Computed>("mam4_external_forcing", scalar3d_extcnt, kg / m3 / s, grid_name);
199200

201+
// extents are [ncol, nlev, gas_pcnst, nq<...>]
202+
FieldLayout tensor3d_gas_tend =
203+
grid_->get_3d_tensor_layout(true, {num_gas_spec_, mam4::microphysics::nqtendaa()},
204+
{"num_gas_spec", "nqtendaa"});
205+
FieldLayout tensor3d_gas_tend_cw =
206+
grid_->get_3d_tensor_layout(true, {num_gas_spec_, mam4::microphysics::nqqcwtendaa()},
207+
{"num_gas_spec", "nqqcwtendaa"});
208+
FieldLayout tensor2d_gas_tend =
209+
grid_->get_3d_tensor_layout(true, {num_gas_spec_, mam4::microphysics::nqtendaa()},
210+
{"num_gas_spec", "nqtendaa"});
211+
FieldLayout tensor2d_gas_tend_cw =
212+
grid_->get_3d_tensor_layout(true, {num_gas_spec_, mam4::microphysics::nqqcwtendaa()},
213+
{"num_gas_spec", "nqqcwtendaa"});
214+
FieldLayout vector3d_gas_tend = grid_->get_3d_vector_layout(true, num_gas_spec_, "num_gas_spec");
215+
216+
// fields for holding diagnostic quantities relating to gas-species tendencies
217+
// NOTE: denoting this as non-dimensional because the original fortran MAM used these to store
218+
// different "tracer mixing ratios" that could be [mol/mol], [#/kmol], etc.
219+
// consider breaking this into separate 3D-vector fields?
220+
add_field<Computed>("gas_spec_tendencies", tensor3d_gas_tend, nondim, grid_name);
221+
add_field<Computed>("gas_spec_tendencies_cw", tensor3d_gas_tend_cw, nondim, grid_name);
222+
// these are the column-integrated fields returned by vert_contraction()
223+
add_field<Computed>("col_int_gas_spec_tend", tensor2d_gas_tend, nondim, grid_name);
224+
add_field<Computed>("col_int_gas_spec_tend_cw", tensor2d_gas_tend_cw, nondim, grid_name);
225+
// and finally, the weights used by vert_contraction()
226+
add_field<Computed>("wts_gas_spec_tends", vector3d_gas_tend, nondim, grid_name);
227+
228+
// ===============================================================================================
229+
// mam::microphysics wants the full column of these tendencies
230+
// TODO: is it better for each column's threadTeam to have its own 3d view,
231+
// or subview into a 4d view that contains all 'ncol' columns of these?
232+
// view_3d qgcm_tendaa("diag_tendency-col", nlev, num_gas_spec_, mam4::microphysics::nqtendaa());
233+
// view_3d qqcwgcm_tendaa("diag_tendency_cw-col", nlev, num_gas_spec_, mam4::microphysics::nqqcwtendaa());
234+
// Kokkos::deep_copy(qgcm_tendaa, 0.0);
235+
// Kokkos::deep_copy(qqcwgcm_tendaa, 0.0);
236+
// ===============================================================================================
237+
200238
// Creating a Linoz reader and setting Linoz parameters involves reading data
201239
// from a file and configuring the necessary parameters for the Linoz model.
202240
{
@@ -387,7 +425,8 @@ void MAMMicrophysics::init_buffers(const ATMBufferManager &buffer_manager) {
387425
int MAMMicrophysics::get_len_temporary_views() {
388426
const int photo_table_len = get_photo_table_work_len(photo_table_);
389427
const int sethet_work_len = mam4::mo_sethet::get_total_work_len_sethet();
390-
constexpr int extcnt = mam4::gas_chemistry::extcnt;
428+
// FIXME: moved this to class
429+
// constexpr int extcnt = mam4::gas_chemistry::extcnt;
391430
int work_len = 0;
392431
// work_photo_table_
393432
work_len += ncol_ * photo_table_len;
@@ -398,13 +437,14 @@ int MAMMicrophysics::get_len_temporary_views() {
398437
// invariants_
399438
work_len += ncol_ * nlev_ * mam4::gas_chemistry::nfs;
400439
// extfrc_
401-
work_len += ncol_ * nlev_ * extcnt;
440+
work_len += ncol_ * nlev_ * extcnt_;
402441
return work_len;
403442
}
404443
void MAMMicrophysics::init_temporary_views() {
405444
const int photo_table_len = get_photo_table_work_len(photo_table_);
406445
const int sethet_work_len = mam4::mo_sethet::get_total_work_len_sethet();
407-
constexpr int extcnt = mam4::gas_chemistry::extcnt;
446+
// FIXME: moved this to class
447+
// constexpr int extcnt = mam4::gas_chemistry::extcnt;
408448
auto work_ptr = (Real *)buffer_.temporary_views.data();
409449

410450
work_photo_table_ = view_2d(work_ptr, ncol_, photo_table_len);
@@ -416,8 +456,8 @@ void MAMMicrophysics::init_temporary_views() {
416456
work_ptr += ncol_ * nlev_ * mam4::mo_photo::phtcnt;
417457
invariants_ = view_3d(work_ptr, ncol_, nlev_, mam4::gas_chemistry::nfs);
418458
work_ptr += ncol_ * nlev_ * mam4::gas_chemistry::nfs;
419-
extfrc_ = view_3d(work_ptr, ncol_, nlev_, extcnt);
420-
work_ptr += ncol_ * nlev_ * extcnt;
459+
extfrc_ = view_3d(work_ptr, ncol_, nlev_, extcnt_);
460+
work_ptr += ncol_ * nlev_ * extcnt_;
421461

422462
// Error check
423463
// NOTE: workspace_provided can be larger than workspace_used, but let's try
@@ -774,18 +814,18 @@ void MAMMicrophysics::run_impl(const double dt) {
774814
Kokkos::deep_copy(acos_cosine_zenith_, acos_cosine_zenith_host_);
775815
}
776816
const auto zenith_angle = acos_cosine_zenith_;
777-
constexpr int gas_pcnst = mam_coupling::gas_pcnst();
778817

779-
const auto &extfrc = extfrc_;
780-
const auto &forcings = forcings_;
781-
constexpr int extcnt = mam4::gas_chemistry::extcnt;
818+
const auto &extfrc = extfrc_;
819+
const auto &forcings = forcings_;
820+
// FIXME: moved this to class
821+
// constexpr int extcnt = mam4::gas_chemistry::extcnt;
782822

783823
const int offset_aerosol = mam4::utils::gasses_start_ind();
784-
Real adv_mass_kg_per_moles[gas_pcnst];
824+
Real adv_mass_kg_per_moles[num_gas_spec_];
785825
// NOTE: Making copies of clsmap_4 and permute_4 to fix undefined arrays on
786826
// the device.
787-
int clsmap_4[gas_pcnst], permute_4[gas_pcnst];
788-
for(int i = 0; i < gas_pcnst; ++i) {
827+
int clsmap_4[num_gas_spec_], permute_4[num_gas_spec_];
828+
for(int i = 0; i < num_gas_spec_; ++i) {
789829
// NOTE: state_q is kg/kg-dry-air; adv_mass is in g/mole.
790830
// Convert adv_mass to kg/mole as vmr_from_mmr function uses
791831
// molec_weight_dry_air with kg/mole units
@@ -803,13 +843,22 @@ void MAMMicrophysics::run_impl(const double dt) {
803843
const auto &index_season_lai = index_season_lai_;
804844
const int pcnst = mam4::pcnst;
805845

806-
Kokkos::Array<Real, gas_pcnst> molar_mass_g_per_mol_tmp;
807-
for (int i = 0; i < gas_pcnst; ++i) {
846+
Kokkos::Array<Real, num_gas_spec_> molar_mass_g_per_mol_tmp;
847+
for (int i = 0; i < num_gas_spec_; ++i) {
808848
molar_mass_g_per_mol_tmp[i] = mam4::gas_chemistry::adv_mass[i]; // host-only access
809849
}
810850

851+
// these are computed in the column loop and used afterward, so declare here
852+
// TODO: consider enabling/disabling this based on whether output is required--this would
853+
// require another version of perform_atmospheric_chemistry_and_microphysics(), potentially
854+
// templated on the forthcoming diagnostics struct
855+
// nonetheless, skip for now
856+
// Slice into the diagnostic fields to pass a single column to mam4xx::microphysics
857+
auto gas_spec_tend = get_field_out("gas_spec_tendencies");
858+
auto gas_spec_tend_cw = get_field_out("gas_spec_tendencies_cw");
859+
auto gas_spec_tend_wts = get_field_out("wts_gas_spec_tends");
811860
//NOTE: we need to initialize photo_rates_
812-
Kokkos::deep_copy(photo_rates_,0.0);
861+
Kokkos::deep_copy(photo_rates_, 0.0);
813862
// loop over atmosphere columns and compute aerosol microphyscs
814863
Kokkos::parallel_for(
815864
"MAMMicrophysics::run_impl", policy,
@@ -833,9 +882,9 @@ void MAMMicrophysics::run_impl(const double dt) {
833882
mam_coupling::aerosols_for_column(dry_aero, icol);
834883

835884
const auto invariants_icol = ekat::subview(invariants, icol);
836-
mam4::mo_setext::Forcing forcings_in[extcnt];
885+
mam4::mo_setext::Forcing forcings_in[extcnt_];
837886

838-
for(int i = 0; i < extcnt; ++i) {
887+
for(int i = 0; i < extcnt_; ++i) {
839888
const int nsectors = forcings[i].nsectors;
840889
const int frc_ndx = forcings[i].frc_ndx;
841890
const auto file_alt_data = forcings[i].file_alt_data;
@@ -921,20 +970,19 @@ void MAMMicrophysics::run_impl(const double dt) {
921970
}
922971
}
923972
}
973+
974+
auto gas_spec_tend_V = gas_spec_tend.get_view<Real****>();
975+
auto gas_spec_tend_cw_V = gas_spec_tend_cw.get_view<Real****>();
976+
auto gas_spec_tend_wts_V = gas_spec_tend_wts.get_view<Real***>();
977+
// NOTE: these are called "qgcm_tendaa" and "qqcwgcm_tendaa" in mam4xx
978+
auto gas_spec_tend_col = ekat::subview(gas_spec_tend_V, icol);
979+
auto gas_spec_tend_cw_col = ekat::subview(gas_spec_tend_cw_V, icol);
980+
924981
// These output values need to be put somewhere:
925-
const auto aqso4_flx_col = ekat::subview(aqso4_flx, icol); // deposition flux of so4 [mole/mole/s]
926-
const auto aqh2so4_flx_col = ekat::subview(aqh2so4_flx, icol); // deposition flux of h2so4 [mole/mole/s]
927-
Real dflx_col[gas_pcnst] = {}; // deposition velocity [1/cm/s]
928-
Real dvel_col[gas_pcnst] = {}; // deposition flux [1/cm^2/s]
929-
// mam::microphysics wants the full column of these tendencies
930-
// TODO: is it better for each column's threadTeam to have its own 3d view,
931-
// or subview into a 4d view that contains all 'ncol' columns of these?
932-
view_3d qgcm_tendaa("diag_tendency-col", nlev, gas_pcnst, mam4::microphysics::nqtendaa());
933-
view_3d qqcwgcm_tendaa("diag_tendency_cw-col", nlev, gas_pcnst, mam4::microphysics::nqqcwtendaa());
934-
Kokkos::deep_copy(qgcm_tendaa, 0.0);
935-
Kokkos::deep_copy(qqcwgcm_tendaa, 0.0);
982+
Real dflx_col[num_gas_spec_] = {}; // deposition velocity [1/cm/s]
983+
Real dvel_col[num_gas_spec_] = {}; // deposition flux [1/cm^2/s]
936984
// Output: values are dvel, dflx
937-
// Diagnostic Output: qgcm_tendaa, qqcwgcm_tendaa
985+
// Diagnostic Output: gas_spec_tend_col, gas_spec_tend_cw_col
938986
// Input/Output: progs::stateq, progs::qqcw
939987
team.team_barrier();
940988
mam4::microphysics::perform_atmospheric_chemistry_and_microphysics(
@@ -955,31 +1003,41 @@ void MAMMicrophysics::run_impl(const double dt) {
9551003
dvel_col, dflx_col, qgcm_tendaa, qqcwgcm_tendaa, progs);
9561004

9571005
team.team_barrier();
1006+
const auto pdel_col = ekat::subview(dry_atm.p_del, icol);
1007+
auto wts_col = ekat::subview(gas_spec_tend_wts_V, icol);
1008+
set_vert_contraction_weights(wts_col, molar_mass_g_per_mol_tmp, pdel_col, nlev_);
1009+
9581010
// Update constituent fluxes with gas drydep fluxes (dflx)
9591011
// FIXME: Possible units mismatch (dflx is in kg/cm2/s but
9601012
// constituent_fluxes is kg/m2/s) (Following mimics Fortran code
9611013
// behavior but we should look into it)
9621014
Kokkos::parallel_for(Kokkos::TeamVectorRange(team, offset_aerosol, pcnst), [&](int ispc) {
9631015
constituent_fluxes(icol, ispc) -= dflx_col[ispc - offset_aerosol];
9641016
});
965-
9661017
}); // parallel_for for the column loop
9671018
Kokkos::fence();
9681019

1020+
// the variables in these column-integrated tendencies correspond to these MAM diagnostics:
1021+
// ['<xyz>_sfgaex1', '<xyz>_sfgaex2', '<xyz>_sfnnuc1', '<xyz>_sfcoag1']
1022+
auto col_int_gas_spec_tend = get_field_out("col_int_gas_spec_tend");
1023+
auto col_int_gas_spec_tend_cw = get_field_out("col_int_gas_spec_tend_cw");
1024+
vert_contraction<Real>(col_int_gas_spec_tend, gas_spec_tend, gas_spec_tend_wts);
1025+
vert_contraction<Real>(col_int_gas_spec_tend_cw, gas_spec_tend_cw, gas_spec_tend_wts);
1026+
9691027
auto extfrc_fm = get_field_out("mam4_external_forcing").get_view<Real***>();
9701028

9711029
// Avogadro's number [molecules/mol]
9721030
const Real Avogadro = haero::Constants::avogadro;
9731031
// Mapping from external forcing species index to physics constituent index
9741032
// NOTE: These indices should match the species in extfrc_lst
9751033
// TODO: getting rid of hard-coded indices
976-
Kokkos::Array<int, extcnt> extfrc_pcnst_index = {3, 6, 14, 27, 28, 13, 18, 30, 5};
1034+
Kokkos::Array<int, extcnt_> extfrc_pcnst_index = {3, 6, 14, 27, 28, 13, 18, 30, 5};
9771035

9781036
// Transpose extfrc_ from internal layout [ncol][nlev][extcnt]
9791037
// to output layout [ncol][extcnt][nlev]
9801038
// This aligns with expected field storage in the EAMxx infrastructure.
9811039
Kokkos::parallel_for("transpose_extfrc",
982-
Kokkos::MDRangePolicy<Kokkos::Rank<3>>({0,0,0}, {ncol, extcnt, nlev}),
1040+
Kokkos::MDRangePolicy<Kokkos::Rank<3>>({0,0,0}, {ncol, extcnt_, nlev}),
9831041
KOKKOS_LAMBDA(const int i, const int j, const int k) {
9841042
const int pcnst_idx = extfrc_pcnst_index[j];
9851043
const Real molar_mass_g_per_mol = molar_mass_g_per_mol_tmp[pcnst_idx]; // g/mol

components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.hpp

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <physics/mam/eamxx_mam_generic_process_interface.hpp>
55
#include <physics/mam/mam_coupling.hpp>
66
#include <share/util/eamxx_common_physics_functions.hpp>
7+
#include <share/field/field_utils.hpp>
78

89
#include "readfiles/tracer_reader_utils.hpp"
910
// For calling MAM4 processes
@@ -60,58 +61,11 @@ class MAMMicrophysics final : public MAMGenericInterface {
6061
// Finalize
6162
void finalize_impl(){/*Do nothing*/};
6263

63-
void process_diagnostic_tendencies(view_3d &qgcm_tendaa, view_3d &qqcwgcm_tendaa,
64-
const Kokkos::Array<Real, mam_coupling::gas_pcnst()> &adv_mass,
65-
const const_view_1d &pdel, const int ncol, const int nlev) {
66-
// HACK: these are placeholders until we establish a way of requesting diagnostic output
67-
// flag: write the full columns of mean tracer mixing ratios
68-
constexpr bool write_full_col_gas_spec = true;
69-
// flag: write the column-integrated tendencies
70-
constexpr bool write_coltend_gas_spec = true;
71-
const int gas_pcnst = mam_coupling::gas_pcnst();
72-
const int nq = mam4::microphysics::nqtendaa();
73-
const int nqqcw = mam4::microphysics::nqqcwtendaa();
74-
75-
if (write_full_col_gas_spec) {
76-
// TODO: write out qgcm_tendaa and qqcwgcm_tendaa...
77-
}
78-
79-
if (write_coltend_gas_spec) {
80-
using physconst = scream::physics::Constants<Real>;
81-
static constexpr Real gravity = physconst::gravit;
82-
static constexpr Real mw_dry_air = physconst::MWdry;
83-
// first calculate the tendencies
84-
view_2d q_coltendaa("diag_tends", gas_pcnst, nq);
85-
view_2d qqcw_coltendaa("diag_tends-cw", gas_pcnst, nqqcw);
86-
Kokkos::deep_copy(q_coltendaa, 0.0);
87-
Kokkos::deep_copy(qqcw_coltendaa, 0.0);
88-
89-
// TODO: can probably do this using vert_contract.hpp, though the messiness
90-
// of the weights could mean it's not worth it
91-
Kokkos::parallel_for("calc_diagnostic_tendencies",
92-
Kokkos::MDRangePolicy<Kokkos::Rank<3>>({0,0,0}, {nlev, gas_pcnst, nq}),
93-
KOKKOS_LAMBDA(const int k, const int spec, const int itend) {
94-
Real pdel_fac = pdel(k) / gravity;
95-
// const auto q_k = ekat::subview(qgcm_tendaa, k);
96-
q_coltendaa(spec, itend) = q_coltendaa(spec, itend)
97-
+ qgcm_tendaa(k, spec, itend) * pdel_fac * (adv_mass[spec] / mw_dry_air);
98-
});
99-
// NOTE: looping over the third dimension (nqqcw) may be pointless
100-
// here because nqqcw == 1 appears to be hard-coded
101-
Kokkos::parallel_for("calc_diagnostic_tendencies",
102-
Kokkos::MDRangePolicy<Kokkos::Rank<3>>({0,0,0}, {nlev, gas_pcnst, nqqcw}),
103-
KOKKOS_LAMBDA(const int k, const int spec, const int itend) {
104-
Real pdel_fac = pdel(k) / gravity;
105-
// const auto q_k = ekat::subview(qqcwgcm_tendaa, k);
106-
qqcw_coltendaa(spec, itend) = qqcw_coltendaa(spec, itend)
107-
+ qqcwgcm_tendaa(k, spec, itend) * pdel_fac * (adv_mass[spec] / mw_dry_air);
108-
});
109-
110-
// TODO: write q_coltendaa and qqcw_coltendaa out...
111-
}
112-
}
113-
11464
private:
65+
// number of species involved in gas phase chemistry (gases + aerosols)
66+
static constexpr int num_gas_spec_ = mam_coupling::gas_pcnst();
67+
// number of species with external forcing
68+
static constexpr int extcnt_ = mam4::gas_chemistry::extcnt;
11569
// The orbital year, used for zenith angle calculations:
11670
// If > 0, use constant orbital year for duration of simulation
11771
// If < 0, use year from timestamp for orbital parameters
@@ -211,6 +165,17 @@ class MAMMicrophysics final : public MAMGenericInterface {
211165
void init_temporary_views();
212166
int len_temporary_views_{0};
213167

168+
void set_vert_contraction_weights(view_2d wts, const Kokkos::Array<Real, num_gas_spec_> adv_mass,
169+
const const_view_1d pdel, const int nlev) {
170+
using physconst = scream::physics::Constants<Real>;
171+
static constexpr Real gravity = physconst::gravit;
172+
static constexpr Real mw_dry_air = physconst::MWdry;
173+
Kokkos::parallel_for("calc_diagnostic_tendencies",
174+
Kokkos::MDRangePolicy<Kokkos::Rank<2>>({0,0}, {nlev, num_gas_spec_}),
175+
KOKKOS_LAMBDA(const int k, const int spec) {
176+
wts(k, spec) = pdel(k) / gravity * adv_mass[spec] / mw_dry_air;
177+
});
178+
}
214179
}; // MAMMicrophysics
215180

216181
} // namespace scream

0 commit comments

Comments
 (0)