Skip to content

Commit 63caa55

Browse files
authored
Merge branch 'bartgol/eamxx/cosp-fixes' (PR #6933)
In COSP, fix a bug related to timestamp handling, and do some upgrades/cleanup. [non-BFB] only for cosp outputs
2 parents f2a7b4f + f8074b6 commit 63caa55

File tree

4 files changed

+138
-111
lines changed

4 files changed

+138
-111
lines changed

components/eamxx/src/physics/cosp/cosp_functions.hpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ namespace scream {
3131
};
3232
inline void main(
3333
const Int ncol, const Int nsubcol, const Int nlay, const Int ntau, const Int nctp, const Int ncth, const Real emsfc_lw,
34-
view_1d<const Real>& sunlit , view_1d<const Real>& skt,
35-
view_2d<const Real>& T_mid , view_2d<const Real>& p_mid , view_2d<const Real>& p_int,
36-
view_2d<const Real>& z_mid , view_2d<const Real>& qv , view_2d<const Real>& qc , view_2d<const Real>& qi,
37-
view_2d<const Real>& cldfrac,
38-
view_2d<const Real>& reff_qc, view_2d<const Real>& reff_qi,
39-
view_2d<const Real>& dtau067, view_2d<const Real>& dtau105,
40-
view_1d<Real>& isccp_cldtot , view_3d<Real>& isccp_ctptau, view_3d<Real>& modis_ctptau, view_3d<Real>& misr_cthtau) {
34+
const view_1d<const Real>& sunlit , const view_1d<const Real>& skt,
35+
const view_2d<const Real>& T_mid , const view_2d<const Real>& p_mid ,
36+
const view_2d<const Real>& p_int, const view_2d<const Real>& z_mid,
37+
const view_2d<const Real>& qv , const view_2d<const Real>& qc,
38+
const view_2d<const Real>& qi, const view_2d<const Real>& cldfrac,
39+
const view_2d<const Real>& reff_qc, const view_2d<const Real>& reff_qi,
40+
const view_2d<const Real>& dtau067, const view_2d<const Real>& dtau105,
41+
const view_1d<Real>& isccp_cldtot , const view_3d<Real>& isccp_ctptau,
42+
const view_3d<Real>& modis_ctptau, const view_3d<Real>& misr_cthtau) {
4143

4244
// Make host copies and permute data as needed
4345
lview_host_2d

components/eamxx/src/physics/cosp/eamxx_cosp.cpp

Lines changed: 122 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "eamxx_cosp.hpp"
22
#include "cosp_functions.hpp"
33
#include "share/property_checks/field_within_interval_check.hpp"
4+
#include "physics/share/physics_constants.hpp"
45

56
#include "ekat/ekat_assert.hpp"
67
#include "ekat/util/ekat_units.hpp"
@@ -93,6 +94,12 @@ void Cosp::set_grids(const std::shared_ptr<const GridsManager> grids_manager)
9394
add_field<Computed>("modis_ctptau", scalar4d_ctptau, percent, grid_name, 1);
9495
add_field<Computed>("misr_cthtau", scalar4d_cthtau, percent, grid_name, 1);
9596
add_field<Computed>("cosp_sunlit", scalar2d, nondim, grid_name);
97+
98+
// We can allocate these now
99+
m_z_mid = Field(FieldIdentifier("z_mid",scalar3d_mid,m,grid_name));
100+
m_z_int = Field(FieldIdentifier("z_int",scalar3d_int,m,grid_name));
101+
m_z_mid.allocate_view();
102+
m_z_int.allocate_view();
96103
}
97104

98105
// =========================================================================================
@@ -131,106 +138,127 @@ void Cosp::run_impl (const double dt)
131138
// Make sure cosp frequency is multiple of rad frequency?
132139

133140
// Compare frequency in steps with current timestep
134-
auto ts = timestamp();
135-
auto update_cosp = cosp_do(cosp_freq_in_steps, ts.get_num_steps());
136-
137-
// Get fields from field manager; note that we get host views because this
138-
// interface serves primarily as a wrapper to a c++ to f90 bridge for the COSP
139-
// all then need to be copied to layoutLeft views to permute the indices for
140-
// F90.
141-
//
142-
// Need to make sure device data is synced to host?
143-
get_field_in("qv").sync_to_host();
144-
get_field_in("qc").sync_to_host();
145-
get_field_in("qi").sync_to_host();
146-
get_field_in("sunlit").sync_to_host();
147-
get_field_in("surf_radiative_T").sync_to_host();
148-
get_field_in("T_mid").sync_to_host();
149-
get_field_in("p_mid").sync_to_host();
150-
get_field_in("p_int").sync_to_host();
151-
get_field_in("cldfrac_rad").sync_to_host();
152-
get_field_in("eff_radius_qc").sync_to_host();
153-
get_field_in("eff_radius_qi").sync_to_host();
154-
get_field_in("dtau067").sync_to_host();
155-
get_field_in("dtau105").sync_to_host();
156-
get_field_in("phis").sync_to_host();
157-
get_field_in("pseudo_density").sync_to_host();
158-
159-
auto qv = get_field_in("qv").get_view<const Real**, Host>();
160-
auto qc = get_field_in("qc").get_view<const Real**, Host>();
161-
auto qi = get_field_in("qi").get_view<const Real**, Host>();
162-
auto sunlit = get_field_in("sunlit").get_view<const Real*, Host>();
163-
auto skt = get_field_in("surf_radiative_T").get_view<const Real*, Host>();
164-
auto T_mid = get_field_in("T_mid").get_view<const Real**, Host>();
165-
auto p_mid = get_field_in("p_mid").get_view<const Real**, Host>();
166-
auto p_int = get_field_in("p_int").get_view<const Real**, Host>();
167-
auto phis = get_field_in("phis").get_view<const Real*, Host>();
168-
auto pseudo_density = get_field_in("pseudo_density").get_view<const Real**, Host>();
169-
auto cldfrac = get_field_in("cldfrac_rad").get_view<const Real**, Host>();
170-
auto reff_qc = get_field_in("eff_radius_qc").get_view<const Real**, Host>();
171-
auto reff_qi = get_field_in("eff_radius_qi").get_view<const Real**, Host>();
172-
auto dtau067 = get_field_in("dtau067").get_view<const Real**, Host>();
173-
auto dtau105 = get_field_in("dtau105").get_view<const Real**, Host>();
174-
auto isccp_cldtot = get_field_out("isccp_cldtot").get_view<Real*, Host>();
175-
auto isccp_ctptau = get_field_out("isccp_ctptau").get_view<Real***, Host>();
176-
auto modis_ctptau = get_field_out("modis_ctptau").get_view<Real***, Host>();
177-
auto misr_cthtau = get_field_out("misr_cthtau").get_view<Real***, Host>();
178-
auto cosp_sunlit = get_field_out("cosp_sunlit").get_view<Real*, Host>(); // Copy of sunlit flag with COSP frequency for proper averaging
179-
180-
// Compute heights
181-
const auto z_mid = CospFunc::view_2d<Real>("z_mid", m_num_cols, m_num_levs);
182-
const auto z_int = CospFunc::view_2d<Real>("z_int", m_num_cols, m_num_levs+1);
183-
const auto dz = z_mid; // reuse tmp memory for dz
184-
const auto ncol = m_num_cols;
185-
const auto nlev = m_num_levs;
186-
// calculate_z_int contains a team-level parallel_scan, which requires a special policy
187-
// TODO: do this on device?
188-
const auto scan_policy = ekat::ExeSpaceUtils<KTH::ExeSpace>::get_thread_range_parallel_scan_team_policy(ncol, nlev);
189-
Kokkos::parallel_for(scan_policy, KOKKOS_LAMBDA (const KTH::MemberType& team) {
190-
const int i = team.league_rank();
191-
const auto dz_s = ekat::subview(dz, i);
192-
const auto p_mid_s = ekat::subview(p_mid, i);
193-
const auto T_mid_s = ekat::subview(T_mid, i);
194-
const auto qv_s = ekat::subview(qv, i);
195-
const auto z_int_s = ekat::subview(z_int, i);
196-
const auto z_mid_s = ekat::subview(z_mid, i);
197-
const Real z_surf = phis(i) / 9.81;
198-
const auto pseudo_density_s = ekat::subview(pseudo_density, i);
199-
PF::calculate_dz(team, pseudo_density_s, p_mid_s, T_mid_s, qv_s, dz_s);
200-
team.team_barrier();
201-
PF::calculate_z_int(team,nlev,dz_s,z_surf,z_int_s);
202-
team.team_barrier();
203-
PF::calculate_z_mid(team,nlev,z_int_s,z_mid_s);
204-
team.team_barrier();
205-
});
141+
// NOTE: timestamp() returns the time RIGHT BEFORE the call to run
142+
auto end_of_step = timestamp()+dt;
143+
auto update_cosp = cosp_do(cosp_freq_in_steps, end_of_step.get_num_steps());
206144

207145
// Call COSP wrapper routines
208146
if (update_cosp) {
147+
// Get fields from field manager; note that we get host views because this
148+
// interface serves primarily as a wrapper to a c++ to f90 bridge for the COSP
149+
// all then need to be copied to layoutLeft views to permute the indices for
150+
// F90.
151+
152+
// Ensure host data of input fields is up to date
153+
get_field_in("qv").sync_to_host();
154+
get_field_in("qc").sync_to_host();
155+
get_field_in("qi").sync_to_host();
156+
get_field_in("sunlit").sync_to_host();
157+
get_field_in("surf_radiative_T").sync_to_host();
158+
get_field_in("T_mid").sync_to_host();
159+
get_field_in("p_int").sync_to_host();
160+
get_field_in("cldfrac_rad").sync_to_host();
161+
get_field_in("eff_radius_qc").sync_to_host();
162+
get_field_in("eff_radius_qi").sync_to_host();
163+
get_field_in("dtau067").sync_to_host();
164+
get_field_in("dtau105").sync_to_host();
165+
166+
// Compute z_mid
167+
const auto T_mid_d = get_field_in("T_mid").get_view<const Real**>();
168+
const auto qv_d = get_field_in("qv").get_view<const Real**>();
169+
const auto p_mid_d = get_field_in("p_mid").get_view<const Real**>();
170+
const auto phis_d = get_field_in("phis").get_view<const Real*>();
171+
const auto pseudo_density_d = get_field_in("pseudo_density").get_view<const Real**>();
172+
const auto z_mid_d = m_z_mid.get_view<Real**>();
173+
const auto z_int_d = m_z_int.get_view<Real**>();
174+
const auto ncol = m_num_cols;
175+
const auto nlev = m_num_levs;
176+
177+
using KT = KokkosTypes<DefaultDevice>;
178+
using ExeSpace = typename KT::ExeSpace;
179+
using ESU = ekat::ExeSpaceUtils<ExeSpace>;
180+
using PF = scream::PhysicsFunctions<DefaultDevice>;
181+
182+
const auto scan_policy = ESU::get_thread_range_parallel_scan_team_policy(ncol, nlev);
183+
const auto g = physics::Constants<Real>::gravit;
184+
Kokkos::parallel_for(scan_policy, KOKKOS_LAMBDA (const KT::MemberType& team) {
185+
const int i = team.league_rank();
186+
const auto p_mid_s = ekat::subview(p_mid_d, i);
187+
const auto T_mid_s = ekat::subview(T_mid_d, i);
188+
const auto qv_s = ekat::subview(qv_d, i);
189+
const auto z_int_s = ekat::subview(z_int_d, i);
190+
const auto z_mid_s = ekat::subview(z_mid_d, i);
191+
const Real z_surf = phis_d(i) / g;
192+
const auto pseudo_density_s = ekat::subview(pseudo_density_d, i);
193+
194+
// 1. Compute dz (recycle z_mid_s as a temporary)
195+
const auto dz_s = z_mid_s; //
196+
PF::calculate_dz(team, pseudo_density_s, p_mid_s, T_mid_s, qv_s, dz_s);
197+
team.team_barrier();
198+
199+
// 2. Compute z_int (vertical scan)
200+
PF::calculate_z_int(team,nlev,dz_s,z_surf,z_int_s);
201+
team.team_barrier();
202+
203+
// 3. Compute z_mid (int->mid interpolation)
204+
PF::calculate_z_mid(team,nlev,z_int_s,z_mid_s);
205+
team.team_barrier();
206+
});
207+
Kokkos::fence();
208+
209+
m_z_mid.sync_to_host();
210+
const auto z_mid_h = m_z_mid.get_view<const Real**,Host>();
211+
const auto T_mid_h = get_field_in("T_mid").get_view<const Real**, Host>();
212+
const auto qv_h = get_field_in("qv").get_view<const Real**, Host>();
213+
const auto p_mid_h = get_field_in("p_mid").get_view<const Real**,Host>();
214+
const auto qc_h = get_field_in("qc").get_view<const Real**, Host>();
215+
const auto qi_h = get_field_in("qi").get_view<const Real**, Host>();
216+
const auto sunlit_h = get_field_in("sunlit").get_view<const Real*, Host>();
217+
const auto skt_h = get_field_in("surf_radiative_T").get_view<const Real*, Host>();
218+
const auto p_int_h = get_field_in("p_int").get_view<const Real**, Host>();
219+
const auto cldfrac_h = get_field_in("cldfrac_rad").get_view<const Real**, Host>();
220+
const auto reff_qc_h = get_field_in("eff_radius_qc").get_view<const Real**, Host>();
221+
const auto reff_qi_h = get_field_in("eff_radius_qi").get_view<const Real**, Host>();
222+
const auto dtau067_h = get_field_in("dtau067").get_view<const Real**, Host>();
223+
const auto dtau105_h = get_field_in("dtau105").get_view<const Real**, Host>();
224+
225+
auto isccp_cldtot_h = get_field_out("isccp_cldtot").get_view<Real*, Host>();
226+
auto isccp_ctptau_h = get_field_out("isccp_ctptau").get_view<Real***, Host>();
227+
auto modis_ctptau_h = get_field_out("modis_ctptau").get_view<Real***, Host>();
228+
auto misr_cthtau_h = get_field_out("misr_cthtau").get_view<Real***, Host>();
229+
auto cosp_sunlit_h = get_field_out("cosp_sunlit").get_view<Real*, Host>(); // Copy of sunlit flag with COSP frequency for proper averaging
230+
209231
Real emsfc_lw = 0.99;
210-
Kokkos::deep_copy(cosp_sunlit, sunlit);
211-
CospFunc::view_2d<const Real> z_mid_c = z_mid; // Need a const version of z_mid for call to CospFunc::main
232+
Kokkos::deep_copy(cosp_sunlit_h, sunlit_h);
212233
CospFunc::main(
213-
m_num_cols, m_num_subcols, m_num_levs, m_num_tau, m_num_ctp, m_num_cth,
214-
emsfc_lw, sunlit, skt, T_mid, p_mid, p_int, z_mid_c, qv, qc, qi,
215-
cldfrac, reff_qc, reff_qi, dtau067, dtau105,
216-
isccp_cldtot, isccp_ctptau, modis_ctptau, misr_cthtau
234+
m_num_cols, m_num_subcols, m_num_levs, m_num_tau, m_num_ctp, m_num_cth, emsfc_lw,
235+
sunlit_h, skt_h, T_mid_h, p_mid_h, p_int_h, z_mid_h, qv_h, qc_h, qi_h,
236+
cldfrac_h, reff_qc_h, reff_qi_h, dtau067_h, dtau105_h,
237+
isccp_cldtot_h, isccp_ctptau_h, modis_ctptau_h, misr_cthtau_h
217238
);
218239
// Remask night values to ZERO since our I/O does not know how to handle masked/missing values
219240
// in temporal averages; this is all host data, so we can just use host loops like its the 1980s
220241
for (int i = 0; i < m_num_cols; i++) {
221-
if (sunlit(i) == 0) {
222-
isccp_cldtot(i) = 0;
223-
for (int j = 0; j < m_num_tau; j++) {
224-
for (int k = 0; k < m_num_ctp; k++) {
225-
isccp_ctptau(i,j,k) = 0;
226-
modis_ctptau(i,j,k) = 0;
227-
}
228-
for (int k = 0; k < m_num_cth; k++) {
229-
misr_cthtau (i,j,k) = 0;
230-
}
231-
}
242+
if (sunlit_h(i) == 0) {
243+
isccp_cldtot_h(i) = 0;
244+
for (int j = 0; j < m_num_tau; j++) {
245+
for (int k = 0; k < m_num_ctp; k++) {
246+
isccp_ctptau_h(i,j,k) = 0;
247+
modis_ctptau_h(i,j,k) = 0;
248+
}
249+
for (int k = 0; k < m_num_cth; k++) {
250+
misr_cthtau_h (i,j,k) = 0;
251+
}
232252
}
253+
}
233254
}
255+
256+
// Make sure dev data is up to date
257+
get_field_out("isccp_cldtot").sync_to_dev();
258+
get_field_out("isccp_ctptau").sync_to_dev();
259+
get_field_out("modis_ctptau").sync_to_dev();
260+
get_field_out("misr_cthtau").sync_to_dev();
261+
get_field_out("cosp_sunlit").sync_to_dev();
234262
} else {
235263
// If not updating COSP statistics, set these to ZERO; this essentially weights
236264
// the ISCCP cloud properties by the sunlit mask. What will be output for time-averages
@@ -241,17 +269,12 @@ void Cosp::run_impl (const double dt)
241269
// avg(X) = sum(M * X) / sum(M) = (sum(M * X)/N) / (sum(M)/N) = avg(M * X) / avg(M)
242270
//
243271
// TODO: mask this when/if the AD ever supports masked averages
244-
Kokkos::deep_copy(isccp_cldtot, 0.0);
245-
Kokkos::deep_copy(isccp_ctptau, 0.0);
246-
Kokkos::deep_copy(modis_ctptau, 0.0);
247-
Kokkos::deep_copy(misr_cthtau, 0.0);
248-
Kokkos::deep_copy(cosp_sunlit, 0.0);
272+
get_field_out("isccp_cldtot").deep_copy(0);
273+
get_field_out("isccp_ctptau").deep_copy(0);
274+
get_field_out("modis_ctptau").deep_copy(0);
275+
get_field_out("misr_cthtau").deep_copy(0);
276+
get_field_out("cosp_sunlit").deep_copy(0);
249277
}
250-
get_field_out("isccp_cldtot").sync_to_dev();
251-
get_field_out("isccp_ctptau").sync_to_dev();
252-
get_field_out("modis_ctptau").sync_to_dev();
253-
get_field_out("misr_cthtau").sync_to_dev();
254-
get_field_out("cosp_sunlit").sync_to_dev();
255278
}
256279

257280
// =========================================================================================
@@ -260,6 +283,5 @@ void Cosp::finalize_impl()
260283
// Finalize COSP wrappers
261284
CospFunc::finalize();
262285
}
263-
// =========================================================================================
264286

265287
} // namespace scream

components/eamxx/src/physics/cosp/eamxx_cosp.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ class Cosp : public AtmosphereProcess
2020
{
2121

2222
public:
23-
using PF = scream::PhysicsFunctions<HostDevice>;
24-
using KT = KokkosTypes<DefaultDevice>;
25-
using KTH = KokkosTypes<HostDevice>;
26-
2723
// Constructors
2824
Cosp (const ekat::Comm& comm, const ekat::ParameterList& params);
2925

@@ -75,6 +71,9 @@ class Cosp : public AtmosphereProcess
7571

7672
std::shared_ptr<const AbstractGrid> m_grid;
7773

74+
// TODO: use atm buffer instead
75+
Field m_z_mid;
76+
Field m_z_int;
7877
}; // class Cosp
7978

8079
} // namespace scream

components/eamxx/tests/single-process/cosp/input.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ time_stepping:
1010

1111
atmosphere_processes:
1212
atm_procs_list: [cosp]
13+
cosp:
14+
cosp_frequency: ${NUM_STEPS}
15+
cosp_frequency_units: steps
16+
1317

1418
grids_manager:
1519
Type: Mesh Free

0 commit comments

Comments
 (0)