Skip to content

Commit 86f5520

Browse files
committed
EAMxx: Move the unit conversion of O3 from wet mm rto dry vmr. Add a namelist parameter in RRTMGP so that one can decide whether to use prog ozone from the chemistry model or not.
1 parent ce40315 commit 86f5520

File tree

5 files changed

+54
-29
lines changed

5 files changed

+54
-29
lines changed

components/eamxx/cime_config/namelist_defaults_eamxx.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@ be lost if SCREAM_HACK_XML is not enabled.
307307
<mam4_do_rename type="logical" doc="Switch to enable aerosol microphysics rename process">true</mam4_do_rename>
308308
<!-- LINOZ parameters -->
309309
<mam4_compute_linoz type="logical" doc="turn on/off linoz computation">true</mam4_compute_linoz>
310-
<mam4_use_ozone_linoz_in_rrtmgp type="logical" doc="Use OZONE (o3_volume_mix_ratio) computed by MAM4 in the radiation model.">false</mam4_use_ozone_linoz_in_rrtmgp>
311310
<mam4_o3_tau type="real" doc="Linoz tau parameter">172800.0</mam4_o3_tau>
312311
<mam4_o3_sfc type="real" doc="Linoz surface parameter">3.0E-008</mam4_o3_sfc>
313312
<mam4_o3_lbl type="integer" doc="Linoz lbl parameter">4</mam4_o3_lbl>
@@ -558,6 +557,8 @@ be lost if SCREAM_HACK_XML is not enabled.
558557
</do_subcol_sampling>
559558
<pool_size_multiplier type="real">1.0</pool_size_multiplier>
560559
<force_run_after_restart type="logical" doc="Force rad to run on first step after restart, regardless of rad frequency">false</force_run_after_restart>
560+
<prognostic_ozone type="logical" doc="Use OZONE computed by a chemistry model, e.g, mam4xx.">false</prognostic_ozone>
561+
561562
</rrtmgp>
562563

563564
<mac_aero_mic inherit="atm_proc_group">

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

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ MAMMicrophysics::MAMMicrophysics(const ekat::Comm &comm,
3636

3737
// LINOZ namelist parameters
3838
config_.linoz.compute = m_params.get<bool>("mam4_compute_linoz", true);
39-
m_use_ozone_linoz_in_rrtmgp =m_params.get<bool>("mam4_use_ozone_linoz_in_rrtmgp",false);
39+
4040
if (config_.linoz.compute) {
4141
config_.linoz.o3_lbl = m_params.get<int>("mam4_o3_lbl");
4242
config_.linoz.o3_tau = m_params.get<double>("mam4_o3_tau");
@@ -380,11 +380,6 @@ void MAMMicrophysics::set_grids(
380380
index_season_lai_);
381381
}
382382

383-
if (config_.linoz.compute and m_use_ozone_linoz_in_rrtmgp) {
384-
// dry O3 vmr [mol/mol]
385-
add_field<Computed>("o3_volume_mix_ratio", scalar3d_mid, mol / mol, grid_name);
386-
}
387-
388383
} // set_grids
389384

390385
// ================================================================
@@ -562,12 +557,7 @@ void MAMMicrophysics::initialize_impl(const RunType run_type) {
562557
scream::mam_coupling::create_linoz_chlorine_reader(
563558
linoz_chlorine_file, ts, chlorine_loading_ymd, chlorine_values_,
564559
chlorine_time_secs_);
565-
} else{
566-
EKAT_REQUIRE_MSG(
567-
!m_use_ozone_linoz_in_rrtmgp,
568-
"Error! mam4_compute_linoz is false. "
569-
"Linoz will no compute o3_volume_mix_ratio. \n");
570-
} // LINOZ
560+
}
571561

572562
init_temporary_views();
573563
// FIXME : why are we only using nlev_ instead of ncol_xnlev?
@@ -1058,19 +1048,6 @@ void MAMMicrophysics::run_impl(const double dt) {
10581048
// postprocess output
10591049
post_process(wet_aero_, dry_aero_, dry_atm_);
10601050
Kokkos::fence();
1061-
if (config_.linoz.compute and m_use_ozone_linoz_in_rrtmgp) {
1062-
// 0 corresponds to O3
1063-
constexpr int O3_idx=0;
1064-
constexpr Real O3_gas_mol_weights = mam4::gas_chemistry::adv_mass[O3_idx];
1065-
auto dry_o3_vmr = get_field_out("o3_volume_mix_ratio").get_view<Real**>();
1066-
Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const ThreadTeam& team) {
1067-
const int icol = team.league_rank();
1068-
Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev), [&] (const int& k) {
1069-
dry_o3_vmr(icol,k) = PF::calculate_vmr_from_mmr(O3_gas_mol_weights,
1070-
dry_atm.qv(icol,k),dry_aero.gas_mmr[O3_idx](icol,k));
1071-
});
1072-
});
1073-
}
10741051

10751052
} // MAMMicrophysics::run_impl
10761053

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ class MAMMicrophysics final : public MAMGenericInterface {
158158
void init_temporary_views();
159159
int len_temporary_views_{0};
160160

161-
// if linoz is turn on, mam4 will update o3 in rrtmgp
162-
bool m_use_ozone_linoz_in_rrtmgp;
163161

164162
}; // MAMMicrophysics
165163

components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ RRTMGPRadiation (const ekat::Comm& comm, const ekat::ParameterList& params)
8282

8383
// Determine rad timestep, specified as number of atm steps
8484
m_rad_freq_in_steps = m_params.get<Int>("rad_frequency", 1);
85+
// use ozone computed by a chemistry model, e.g., mam4xx
86+
m_prognostic_ozone =m_params.get<bool>("prognostic_ozone",false);
87+
8588
}
8689

8790
void RRTMGPRadiation::set_grids(const std::shared_ptr<const GridsManager> grids_manager) {
@@ -383,6 +386,9 @@ void RRTMGPRadiation::init_buffers(const ATMBufferManager &buffer_manager)
383386
mem += m_buffer.d_tint.size();
384387
m_buffer.d_dz = decltype(m_buffer.d_dz)(mem, m_col_chunk_size, m_nlay);
385388
mem += m_buffer.d_dz.size();
389+
//
390+
m_buffer.o3_prog = decltype(m_buffer.o3_prog)(mem, m_col_chunk_size, m_nlay);
391+
mem += m_buffer.o3_prog.size();
386392
// 3d arrays
387393
m_buffer.sw_flux_up_k = decltype(m_buffer.sw_flux_up_k)(mem, m_col_chunk_size, m_nlay+1);
388394
mem += m_buffer.sw_flux_up_k.size();
@@ -549,6 +555,19 @@ void RRTMGPRadiation::initialize_impl(const RunType run_type) {
549555

550556
m_force_run_on_next_step = run_type==RunType::Initial or
551557
m_params.get("force_run_after_restart",false);
558+
559+
// If m_prognostic_ozone is true, we should not use O3 as it is currently employed in RRTMGP.
560+
if (m_prognostic_ozone)
561+
{
562+
for (int igas = 0; igas < m_ngas; igas++) {
563+
auto name = m_gas_names[igas];
564+
EKAT_REQUIRE_MSG(
565+
m_gas_names[igas] !="o3",
566+
"Error! m_prognostic_ozone is set to true,"
567+
"remove o3 from list of active gases.. \n");
568+
}
569+
}
570+
552571
}
553572

554573
// =========================================================================================
@@ -955,6 +974,28 @@ void RRTMGPRadiation::run_impl (const double dt) {
955974
m_gas_concs_k.set_vmr(name, tmp2d_k);
956975
}
957976

977+
if (m_prognostic_ozone)
978+
{
979+
auto o3_dry_vmr = m_buffer.o3_prog;
980+
// get O3 from FM, here we assume that O3 is wet_mmr
981+
auto o3_wet_mmr = get_field_out("O3").get_view<Real**>();
982+
const Real O3_molecular_weigth= PC::get_gas_mol_weight("o3");
983+
const auto policy = ekat::ExeSpaceUtils<ExeSpace>::get_default_team_policy(ncol, m_nlay);
984+
const int nlev_local = m_nlay;
985+
Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) {
986+
const int icol = team.league_rank();
987+
Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev_local), [&] (const int& k) {
988+
// from wet to dry
989+
const Real o3_dry_mmr = PF::calculate_drymmr_from_wetmmr(o3_wet_mmr(icol,k),d_qv(icol,k));
990+
// Question: Do I need to use qv_dry?
991+
// from mmr to vmr
992+
o3_dry_vmr(icol,k) = PF::calculate_vmr_from_mmr(O3_molecular_weigth,
993+
d_qv(icol,k),o3_dry_mmr);
994+
});
995+
});
996+
m_gas_concs_k.set_vmr("o3", o3_dry_vmr);
997+
}
998+
958999
// Set layer cloud fraction.
9591000
//
9601001
// If not doing subcolumn sampling for mcica, we want to make sure we use grid-mean

components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class RRTMGPRadiation : public AtmosphereProcess {
133133
// Structure for storing local variables initialized using the ATMBufferManager
134134
struct Buffer {
135135
static constexpr int num_1d_ncol = 8;
136-
static constexpr int num_2d_nlay = 16;
136+
static constexpr int num_2d_nlay = 17;
137137
static constexpr int num_2d_nlay_p1 = 23;
138138
static constexpr int num_2d_nswbands = 2;
139139
static constexpr int num_3d_nlev_nswbands = 4;
@@ -171,6 +171,10 @@ class RRTMGPRadiation : public AtmosphereProcess {
171171
ureal2dk sw_heating_k;
172172
ureal2dk lw_heating_k;
173173

174+
// ozone prog
175+
ureal2dk o3_prog;
176+
177+
174178
// 2d size (ncol, nlay+1)
175179
ureal2dk d_tint;
176180
ureal2dk p_lev_k;
@@ -240,6 +244,10 @@ class RRTMGPRadiation : public AtmosphereProcess {
240244
Buffer m_buffer;
241245

242246
bool m_force_run_on_next_step = false;
247+
// use a ozone prognostic variable computed by chemistry
248+
bool m_prognostic_ozone = false;
249+
250+
243251
}; // class RRTMGPRadiation
244252

245253
} // namespace scream

0 commit comments

Comments
 (0)