ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
NOAHMP Class Reference

#include <ERF_NOAHMP.H>

Inheritance diagram for NOAHMP:
Collaboration diagram for NOAHMP:

Public Member Functions

 NOAHMP ()
 
virtual ~NOAHMP ()=default
 
void Define (SolverChoice &) override
 
void Init (const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Geometry &geom0, amrex::Vector< amrex::BCRec > &domain_bcs_type, amrex::IntVect &refRatio, const amrex::Real &dt, amrex::Vector< amrex::Vector< std::string >> &nc_init_file) override
 
void Advance_With_State (const int &lev, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, amrex::MultiFab *hfx3_out, amrex::MultiFab *qfx3_out, const SurfacePrecipAccumulationSources &precip_sources, const amrex::Real &elapsed_time, const amrex::Real &dt, const int &nstep, const bool updated_lev0) override
 
void Plot_Landfile (const int &nstep) override
 
amrex::MultiFab * Lsm_Data_Ptr (const int &varIdx) override
 
amrex::MultiFab * Lsm_Flux_Ptr (const int &varIdx) override
 
amrex::Geometry Lsm_Geom () override
 
int Lsm_Data_Size () override
 
int Lsm_Flux_Size () override
 
std::string Lsm_DataName (const int &varIdx) override
 
int Lsm_DataIndex (std::string varname) override
 
std::string Lsm_FluxName (const int &varIdx) override
 
int Lsm_FluxIndex (std::string varname) override
 
void Lsm_Set_Lev0_Data_Ptr (const int &varIdx, amrex::MultiFab *lev0_data_ptr) override
 
void Lsm_Set_Lev0_Flux_Ptr (const int &varIdx, amrex::MultiFab *lev0_flux_ptr) override
 
bool Get_Update_Status () override
 
int Get_LSM_Step () const override
 
void Set_LSM_Step (int step) override
 
void Write_Lsm_Restart (const std::string &dir) const override
 
void Read_Lsm_Restart (const std::string &dir) override
 
void interp_from_lev0 (const int &lev, amrex::MultiFab &cons_in, const int &nstep)
 
bool time_to_fire (const amrex::Real &elapsed_time)
 
void stage_forcing (const amrex::MFIter &mfi, const erf_noahmp::NoahmpBlockViews &blk, const amrex::Box &bx, const int &klo, const int &lev, const bool is_moist, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const erf_noahmp::PrecipSlots &precip, amrex::Vector< erf_noahmp::ClampedPrecipCell > &clamped_cells, amrex::Vector< erf_noahmp::InvariantPrecipCell > &invariant_cells)
 
void read_results (const amrex::MFIter &mfi, const erf_noahmp::NoahmpBlockViews &blk, const amrex::Box &bx, const amrex::Box &gbx, amrex::MultiFab &cons_in)
 
erf_noahmp::PrecipSlots collect_precip_sources (const SurfacePrecipAccumulationSources &precip_sources)
 
void prepare_precip_snapshots (const int &lev, const erf_noahmp::PrecipSlots &precip)
 
void advance_precip_snapshots (const int &lev, const erf_noahmp::PrecipSlots &precip)
 
void report_precip_diagnostics (const int &lev, const amrex::Vector< erf_noahmp::ClampedPrecipCell > &clamped_cells, const amrex::Vector< erf_noahmp::InvariantPrecipCell > &invariant_cells)
 
int soil_data_idx (int g, int k) const
 
void m_ensure_nsoil_resolved ()
 
- Public Member Functions inherited from NullSurf
 NullSurf ()
 
virtual ~NullSurf ()=default
 
virtual void Advance (const double &)
 
virtual void Update_Micro_Vars (amrex::MultiFab &)
 
virtual void Update_State_Vars (amrex::MultiFab &)
 
virtual void Copy_State_to_Micro (const amrex::MultiFab &)
 
virtual void Copy_Micro_to_State (amrex::MultiFab &)
 
virtual std::unordered_map< std::string, std::string > & Lsm_WRFInputNames ()
 

Static Public Member Functions

static std::string m_precip_snapshot_name (const std::string &dir, int l, int s)
 

Public Attributes

bool m_nsoil_resolved = false
 

Private Types

using FabPtr = std::shared_ptr< amrex::MultiFab >
 

Private Attributes

int m_lsm_data_size = LsmData_NOAHMP::NumVars
 
int m_lsm_flux_size = LsmFlux_NOAHMP::NumVars
 
amrex::Vector< int > LsmDataMap
 
amrex::Vector< int > LsmFluxMap
 
amrex::Vector< std::string > LsmDataName
 
amrex::Vector< std::string > LsmFluxName
 
amrex::Geometry m_geom
 
amrex::Geometry m_geom0
 
amrex::Geometry m_lsm_geom
 
amrex::IntVect m_refRatio
 
amrex::Vector< amrex::BCRec > m_domain_bcs_type
 
amrex::Real m_dt
 
int m_itimestep = 0
 
amrex::Real m_dtbl = std::numeric_limits<amrex::Real>::max()
 
int khi_lsm
 
int m_nz_lsm = 1
 
amrex::Real m_dz_lsm = one
 
amrex::Vector< FabPtrlsm_fab_data
 
amrex::Array< FabPtr, LsmFlux_NOAHMP::NumVarslsm_fab_flux
 
amrex::Vector< amrex::MultiFab * > lsm_lev0_data
 
amrex::Array< amrex::MultiFab *, LsmFlux_NOAHMP::NumVarslsm_lev0_flux
 
int m_nsoil = 4
 
NoahmpIO_vector noahmpio_vect
 
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_input_tmp
 
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_output_tmp
 
amrex::Vector< amrex::Array< std::unique_ptr< amrex::MultiFab >, NoahmpPrecipSlot::NumSlots > > m_precip_accum_prev
 
amrex::Array< std::unique_ptr< amrex::MultiFab >, NoahmpPrecipSlot::NumSlotsm_precip_accum_restored
 
int m_lev = 0
 
int m_plot_int_1 = -1
 
bool m_updated = false
 
bool m_has_nc_file = false
 

Member Typedef Documentation

◆ FabPtr

using NOAHMP::FabPtr = std::shared_ptr<amrex::MultiFab>
private

Constructor & Destructor Documentation

◆ NOAHMP()

NOAHMP::NOAHMP ( )
inline
62 {}

◆ ~NOAHMP()

virtual NOAHMP::~NOAHMP ( )
virtualdefault

Member Function Documentation

◆ advance_precip_snapshots()

void NOAHMP::advance_precip_snapshots ( const int &  lev,
const erf_noahmp::PrecipSlots precip 
)
68 {
69  if (!precip.have_any) { return; }
70  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
71  if (precip.has[s]) {
72  MultiFab::Copy(*m_precip_accum_prev[lev][s], *precip.accum[s], 0, 0, 1, 0);
73  }
74  }
75 }
amrex::Vector< amrex::Array< std::unique_ptr< amrex::MultiFab >, NoahmpPrecipSlot::NumSlots > > m_precip_accum_prev
Definition: ERF_NOAHMP.H:391
@ NumSlots
Definition: ERF_NOAHMP_Fields.H:146
bool have_any
Definition: ERF_NOAHMP.H:37
bool has[NoahmpPrecipSlot::NumSlots]
Definition: ERF_NOAHMP.H:36
const amrex::MultiFab * accum[NoahmpPrecipSlot::NumSlots]
Definition: ERF_NOAHMP.H:34

◆ Advance_With_State()

void NOAHMP::Advance_With_State ( const int &  lev,
amrex::MultiFab &  cons_in,
amrex::MultiFab &  xvel_in,
amrex::MultiFab &  yvel_in,
amrex::MultiFab *  hfx3_out,
amrex::MultiFab *  qfx3_out,
const SurfacePrecipAccumulationSources precip_sources,
const amrex::Real elapsed_time,
const amrex::Real dt,
const int &  nstep,
const bool  updated_lev0 
)
overridevirtual

Reimplemented from NullSurf.

353 {
354  amrex::ignore_unused(dt);
355 
356  if (!m_has_nc_file) {
357  // Skip interpolation if lev 0 was just updated: Noah runs post-step, so
358  // the fluxes & data still hold lsm_undefined values.
359  if (!updated_lev0) {
360  interp_from_lev0(lev, cons_in, nstep);
361  } else {
362  m_updated = false;
363  }
364  } else {
365  // Gate on the subcycling schedule (identical on every rank).
366  if (!time_to_fire(elapsed_time)) { return; }
367 
368  Box domain = m_geom.Domain();
369 
370  Print () << "Noah-MP driver at level " << lev << " started at time step: " << nstep+1 << std::endl;
371 
372  bool is_moist = (cons_in.nComp() > RhoQ1_comp);
373 
374  int klo = domain.smallEnd(2);
375 
376  // Collect the typed precip slots, then seed the per-level previous-accumulation
377  // snapshots the delta kernel differences against (ERF_NOAHMP_Precip.cpp).
378  const erf_noahmp::PrecipSlots precip = collect_precip_sources(precip_sources);
379  prepare_precip_snapshots(lev, precip);
380 
381  // Cells the guards touched this call; reported after the box loop.
382  Vector<erf_noahmp::ClampedPrecipCell> clamped_cells;
383  Vector<erf_noahmp::InvariantPrecipCell> invariant_cells;
384 
385  // Loop over blocks: ERF -> Noahmp, drive the land model, Noahmp -> ERF.
386  int idb = 0;
387  for (MFIter mfi(cons_in); mfi.isValid(); ++mfi, ++idb) {
388 
389  Box bx = mfi.tilebox();
390  Box gbx = mfi.tilebox(IntVect(0,0,0),IntVect(1,1,0));
391 
392  // Only tiles at the lower z boundary
393  if (bx.smallEnd(2) != klo) { continue; }
394 
395  bx.makeSlab(2,klo);
396  gbx.makeSlab(2,klo);
397 
398  // The NoahmpIO block and its pinned staging buffers for this box,
399  // all co-indexed by idb, bundled into one handle.
400  const erf_noahmp::NoahmpBlockViews blk {
401  &noahmpio_vect[idb],
402  noahmp_input_tmp[idb]->array(),
403  noahmp_output_tmp[idb]->array()
404  };
405 
406  // (1-3) ERF forcing -> pinned input -> NoahmpIO arrays.
407  stage_forcing(mfi, blk, bx, klo, lev, is_moist,
408  cons_in, xvel_in, yvel_in,
409  precip, clamped_cells, invariant_cells);
410 
411  // (4) Drive Noah-MP. Mirror the authoritative counter into the block first.
412  blk.io->itimestep = m_itimestep;
413  blk.io->DriverMain();
414 
415  // (5-6) NoahmpIO results -> pinned output -> ERF coupling fields.
416  read_results(mfi, blk, bx, gbx, cons_in);
417  }
418 
419  // Advance the snapshots now that this call's RAINBL/SR have been consumed.
420  advance_precip_snapshots(lev, precip);
421 
422  // Report any cells the guards clamped / rescaled (never silent).
423  report_precip_diagnostics(lev, clamped_cells, invariant_cells);
424 
425  for (auto ivar = 0; ivar < LsmFlux_NOAHMP::NumVars; ++ivar) {
426  lsm_fab_flux[ivar]->FillBoundary(m_geom.periodicity());
427  }
428  Print () << "Noah-MP driver at level " << lev << " completed" << std::endl;
429  }
430 }
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
amrex::Array< FabPtr, LsmFlux_NOAHMP::NumVars > lsm_fab_flux
Definition: ERF_NOAHMP.H:369
bool m_updated
Definition: ERF_NOAHMP.H:404
void read_results(const amrex::MFIter &mfi, const erf_noahmp::NoahmpBlockViews &blk, const amrex::Box &bx, const amrex::Box &gbx, amrex::MultiFab &cons_in)
Definition: ERF_NOAHMP_Advance.cpp:207
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_output_tmp
Definition: ERF_NOAHMP.H:386
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_input_tmp
Definition: ERF_NOAHMP.H:385
NoahmpIO_vector noahmpio_vect
Definition: ERF_NOAHMP.H:382
erf_noahmp::PrecipSlots collect_precip_sources(const SurfacePrecipAccumulationSources &precip_sources)
Definition: ERF_NOAHMP_Precip.cpp:20
void report_precip_diagnostics(const int &lev, const amrex::Vector< erf_noahmp::ClampedPrecipCell > &clamped_cells, const amrex::Vector< erf_noahmp::InvariantPrecipCell > &invariant_cells)
Definition: ERF_NOAHMP_Precip.cpp:80
int m_itimestep
Definition: ERF_NOAHMP.H:349
void stage_forcing(const amrex::MFIter &mfi, const erf_noahmp::NoahmpBlockViews &blk, const amrex::Box &bx, const int &klo, const int &lev, const bool is_moist, amrex::MultiFab &cons_in, amrex::MultiFab &xvel_in, amrex::MultiFab &yvel_in, const erf_noahmp::PrecipSlots &precip, amrex::Vector< erf_noahmp::ClampedPrecipCell > &clamped_cells, amrex::Vector< erf_noahmp::InvariantPrecipCell > &invariant_cells)
Definition: ERF_NOAHMP_Advance.cpp:76
void prepare_precip_snapshots(const int &lev, const erf_noahmp::PrecipSlots &precip)
Definition: ERF_NOAHMP_Precip.cpp:38
bool m_has_nc_file
Definition: ERF_NOAHMP.H:407
void interp_from_lev0(const int &lev, amrex::MultiFab &cons_in, const int &nstep)
Definition: ERF_NOAHMP_Advance.cpp:24
void advance_precip_snapshots(const int &lev, const erf_noahmp::PrecipSlots &precip)
Definition: ERF_NOAHMP_Precip.cpp:66
amrex::Geometry m_geom
Definition: ERF_NOAHMP.H:330
bool time_to_fire(const amrex::Real &elapsed_time)
Definition: ERF_NOAHMP_Advance.cpp:59
@ NumVars
Definition: ERF_NOAHMP_Fields.H:133
Definition: ERF_NOAHMP.H:49
Definition: ERF_NOAHMP.H:33

◆ collect_precip_sources()

erf_noahmp::PrecipSlots NOAHMP::collect_precip_sources ( const SurfacePrecipAccumulationSources precip_sources)
21 {
24  precip_sources.total, precip_sources.rain, precip_sources.snow,
25  precip_sources.graupel, precip_sources.hail };
26  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
27  p.accum[s] = slot_src[s].accum;
28  p.factor[s] = slot_src[s].native_to_kg_m2;
29  p.has[s] = (slot_src[s].accum != nullptr);
30  }
31  p.have_any = surface_precip_has_any_source(precip_sources);
32  return p;
33 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool surface_precip_has_any_source(const SurfacePrecipAccumulationSources &src) noexcept
Definition: ERF_SurfacePrecipitation.H:48
@ p
Definition: ERF_WSM6.H:189
Definition: ERF_SurfacePrecipitation.H:15
const amrex::MultiFab * accum
Definition: ERF_SurfacePrecipitation.H:16
amrex::Real native_to_kg_m2
Definition: ERF_SurfacePrecipitation.H:17
SurfacePrecipAccumulationSource rain
Definition: ERF_SurfacePrecipitation.H:23
SurfacePrecipAccumulationSource snow
Definition: ERF_SurfacePrecipitation.H:24
SurfacePrecipAccumulationSource hail
Definition: ERF_SurfacePrecipitation.H:26
SurfacePrecipAccumulationSource total
Definition: ERF_SurfacePrecipitation.H:22
SurfacePrecipAccumulationSource graupel
Definition: ERF_SurfacePrecipitation.H:25
Here is the call graph for this function:

◆ Define()

void NOAHMP::Define ( SolverChoice )
inlineoverridevirtual

Reimplemented from NullSurf.

70  {
71  // NOTE: We should parse constants from sc here if needed,
72  }

◆ Get_LSM_Step()

int NOAHMP::Get_LSM_Step ( ) const
inlineoverridevirtual

Reimplemented from NullSurf.

200  {
201  return m_itimestep;
202  }

◆ Get_Update_Status()

bool NOAHMP::Get_Update_Status ( )
inlineoverridevirtual

Reimplemented from NullSurf.

194 { return m_updated; }

◆ Init()

void NOAHMP::Init ( const int &  lev,
const amrex::MultiFab &  cons_in,
const amrex::Geometry &  geom,
const amrex::Geometry &  geom0,
amrex::Vector< amrex::BCRec > &  domain_bcs_type,
amrex::IntVect &  refRatio,
const amrex::Real dt,
amrex::Vector< amrex::Vector< std::string >> &  nc_init_file 
)
overridevirtual

Reimplemented from NullSurf.

31 {
32  // Install Noah-MP's fatal-error handler once: route NoahmpIO_fatal() through
33  // amrex::Abort so a fatal error propagates via MPI_Abort. See NoahmpFatal.H.
34  static const bool noahmp_fatal_installed = []() {
35  NoahmpIO_set_fatal_handler([](const char* msg){
36  amrex::Abort(msg ? msg : "Noah-MP fatal error");
37  });
38  return true;
39  }();
40  amrex::ignore_unused(noahmp_fatal_installed);
41 
42  m_lev = lev;
43  m_dt = dt;
44  m_geom = geom;
45  m_geom0 = geom0;
46  m_domain_bcs_type = domain_bcs_type;
47  m_refRatio = refRatio;
48 
49  Box domain = geom.Domain();
50  khi_lsm = domain.smallEnd(2) - 1;
51 
52  // Resolve NSOIL from erf.lsm_nsoil before building the collective LSM fabs (same
53  // value the parent used via Lsm_Data_Size()); namelist NSOIL asserted below.
55 
56  // The fixed 2D fields are identity-mapped; their names mirror the enum order.
59  for (int i(0); i < LsmData_NOAHMP::NumVars; ++i) { LsmDataMap[i] = i; }
60  {
61  // Names from the same registry as the enum, so they cannot drift.
62  const std::vector<std::string> fixed_names = {
64  };
65  AMREX_ALWAYS_ASSERT(int(fixed_names.size()) == LsmData_NOAHMP::NumVars);
66  for (int i(0); i < LsmData_NOAHMP::NumVars; ++i) { LsmDataName[i] = fixed_names[i]; }
67  }
68  // Per-layer soil profile: 3 groups of m_nsoil, layer index 1-based (WRF SMOIS_k).
69  {
70  const char* group[3] = {"smois", "sh2o", "tslb"};
71  for (int g(0); g < 3; ++g) {
72  for (int k(0); k < m_nsoil; ++k) {
73  int idx = soil_data_idx(g,k);
74  LsmDataMap[idx] = idx;
75  LsmDataName[idx] = std::string(group[g]) + "_" + std::to_string(k+1);
76  }
77  }
78  }
79 
84  LsmFluxName = {"t_flux" , "q_flux" ,
85  "tau13" , "tau23" };
86 
87  ParmParse pp("erf");
88  pp.query("plot_int_1" , m_plot_int_1);
89 
90  // NOTE: relies on all boxes in ba spanning zlo..zhi; otherwise dm/ba no longer
91  // line up and lsm data/flux vars can't be copied directly in a parfor.
92 
93  // Set 2D box array for lsm data
94  IntVect ng(1,1,0);
95  BoxArray ba = cons_in.boxArray();
96  DistributionMapping dm = cons_in.DistributionMap();
97  BoxList bl_lsm = ba.boxList();
98  for (auto& b : bl_lsm) { b.setRange(2,0); }
99  BoxArray ba_lsm(std::move(bl_lsm));
100 
101  // Set up lsm geometry
102  const RealBox& dom_rb = m_geom.ProbDomain();
103  const Real* dom_dx = m_geom.CellSize();
104  RealBox lsm_rb = dom_rb;
105  Real lsm_dx[AMREX_SPACEDIM] = {AMREX_D_DECL(dom_dx[0],dom_dx[1],m_dz_lsm)};
106  Real lsm_z_hi = dom_rb.lo(2);
107  Real lsm_z_lo = lsm_z_hi - Real(m_nz_lsm)*lsm_dx[2];
108  lsm_rb.setHi(2,lsm_z_hi); lsm_rb.setLo(2,lsm_z_lo);
109  m_lsm_geom.define( ba_lsm.minimalBox(), lsm_rb, m_geom.Coord(), m_geom.isPeriodic() );
110 
111  // Create the data (CC), runtime-sized (fixed 2D fields + 3*m_nsoil) so soil scales
112  // with NSOIL. lsm_lev0_data pointers are populated later by the parent.
114  lsm_lev0_data.resize(m_lsm_data_size, nullptr);
115  for (auto ivar = 0; ivar < m_lsm_data_size; ++ivar) {
116  lsm_fab_data[ivar] = std::make_shared<MultiFab>(ba_lsm, dm, 1, ng);
117  lsm_fab_data[ivar]->setVal(lsm_undefined);
118  }
119 
120  // Create the fluxes (CC with ghost cells for averaging)
121  for (auto ivar = 0; ivar < LsmFlux_NOAHMP::NumVars; ++ivar) {
122  lsm_fab_flux[ivar] = std::make_shared<MultiFab>(ba_lsm, dm, 1, IntVect(1,1,0));
123  lsm_fab_flux[ivar]->setVal(lsm_undefined);
124  }
125 
126  m_has_nc_file = (!nc_init_file[lev].empty());
127  if (m_has_nc_file) {
128  Print() << "Noah-MP initialization started" << std::endl;
129 
130  // Size noahmpio_vect to the local boxes. A rank owning no boxes leaves it
131  // empty and relies on the class-level m_itimestep/m_dtbl instead.
132  if (cons_in.local_size() > 0) {
133  noahmpio_vect.resize(cons_in.local_size(), lev);
134  }
135 
136  // Pinned buffer space for all the boxes
137  noahmp_input_tmp.resize(cons_in.local_size());
138  noahmp_output_tmp.resize(cons_in.local_size());
139 
140  int klo = domain.smallEnd(2);
141 
142  // Iterate over the multifab and noahmpio objects together, using the
143  // multifab to set the per-box bounds on each noahmpio object.
144  int idb = 0;
145  for (MFIter mfi(cons_in); mfi.isValid(); ++mfi, ++idb) {
146 
147  Box bx = mfi.tilebox();
148 
149  // Only tiles at the lower z boundary
150  if (bx.smallEnd(2) != klo) { continue; }
151 
152  bx.makeSlab(2,klo);
153 
154  // Pinned buffers per box; output carries the 2D outputs + 3 soil groups.
155  noahmp_input_tmp[idb] = std::make_unique<FArrayBox>(bx, NoahmpInputComp::NumComps , The_Pinned_Arena());
156  noahmp_output_tmp[idb] = std::make_unique<FArrayBox>(bx, NoahmpOutputComp::NumComps + 3*m_nsoil, The_Pinned_Arena());
157 
158  NoahmpIO_type* noahmpio = &noahmpio_vect[idb];
159 
160  noahmpio->blkid = idb;
161  noahmpio->level = lev;
162  noahmpio->ScalarInitDefault();
163  noahmpio->rank = ParallelDescriptor::MyProc();
164  noahmpio->comm = MPI_Comm_c2f(ParallelDescriptor::Communicator());
165 
166  // namelist.erf holds noahmpio-specific parameters, read Fortran-side.
167  noahmpio->ReadNamelist();
168 
169  // Assert namelist NSOIL matches erf.lsm_nsoil (used to size the fabs) so a
170  // mismatch fails loudly rather than truncating the soil diagnostics.
171  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(noahmpio->nsoil == m_nsoil,
172  "namelist.erf NSOIL does not match erf.lsm_nsoil (default 4); "
173  "set erf.lsm_nsoil to the Noah-MP soil-layer count");
174 
175  // NetCDF land-file headers (also Fortran-side)
176  noahmpio->ReadLandHeader();
177 
178  // Set domain/memory/tile bounds from the tile. All three are set to the
179  // same bounds for now; may change for special memory management later.
180  noahmpio->xstart = bx.smallEnd(0);
181  noahmpio->xend = bx.bigEnd(0);
182  noahmpio->ystart = bx.smallEnd(1);
183  noahmpio->yend = bx.bigEnd(1);
184 
185  // Domain bounds
186  noahmpio->ids = noahmpio->xstart;
187  noahmpio->ide = noahmpio->xend;
188  noahmpio->jds = noahmpio->ystart;
189  noahmpio->jde = noahmpio->yend;
190  noahmpio->kds = 1;
191  noahmpio->kde = 2;
192 
193  // Tile bounds
194  noahmpio->its = noahmpio->xstart;
195  noahmpio->ite = noahmpio->xend;
196  noahmpio->jts = noahmpio->ystart;
197  noahmpio->jte = noahmpio->yend;
198  noahmpio->kts = 1;
199  noahmpio->kte = 2;
200 
201  // Memory bounds
202  noahmpio->ims = noahmpio->xstart;
203  noahmpio->ime = noahmpio->xend;
204  noahmpio->jms = noahmpio->ystart;
205  noahmpio->jme = noahmpio->yend;
206  noahmpio->kms = 1;
207  noahmpio->kme = 2;
208 
209  // Allocate Fortran IO memory from the bounds above + namelist/header info
210  noahmpio->VarInitDefault();
211 
212  // NoahmpTable.TBL input
213  noahmpio->ReadTable();
214 
215  // Read/initialize from the NetCDF land file
216  noahmpio->ReadLandMain();
217 
218  // Compute initial values not supplied by the land file
219  noahmpio->InitMain();
220 
221  // Initial land plotfile (tag 0)
222  Print() << "Noah-MP writing lnd.nc file at lev: " << lev << std::endl;
223  noahmpio->WriteLand(0);
224  }
225 
226  // Broadcast DTBL and the initial substep counter so the firing decision is
227  // identical on every rank. Land-free ranks use max-reduction-losing sentinels.
228  m_dtbl = noahmpio_vect.empty() ? std::numeric_limits<Real>::lowest()
229  : static_cast<Real>(noahmpio_vect[0].DTBL);
230  m_itimestep = noahmpio_vect.empty() ? std::numeric_limits<int>::lowest()
231  : noahmpio_vect[0].itimestep;
232  ParallelDescriptor::ReduceRealMax(m_dtbl);
233  ParallelDescriptor::ReduceIntMax(m_itimestep);
234 
235  // Guard against a decomposition in which no rank owns a land box.
238 
239  Print() << "Noah-MP initialization completed" << std::endl;
240  } // has nc_init_file
241 
242 };
constexpr amrex::Real lsm_undefined
Definition: ERF_Constants.H:35
ParmParse pp("prob")
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:287
#define NOAHMP_LSMDATA_FIELDS(X)
Definition: ERF_NOAHMP_Fields.H:19
#define NOAHMP_QUOTE(comp)
Definition: ERF_NOAHMP_Fields.H:110
amrex::Real Real
Definition: ERF_ShocInterface.H:19
int khi_lsm
Definition: ERF_NOAHMP.H:356
amrex::Vector< amrex::BCRec > m_domain_bcs_type
Definition: ERF_NOAHMP.H:342
int m_plot_int_1
Definition: ERF_NOAHMP.H:401
amrex::Vector< std::string > LsmDataName
Definition: ERF_NOAHMP.H:324
amrex::Vector< int > LsmDataMap
Definition: ERF_NOAHMP.H:318
int soil_data_idx(int g, int k) const
Definition: ERF_NOAHMP.H:285
int m_nsoil
Definition: ERF_NOAHMP.H:379
amrex::IntVect m_refRatio
Definition: ERF_NOAHMP.H:339
amrex::Vector< FabPtr > lsm_fab_data
Definition: ERF_NOAHMP.H:366
int m_lsm_data_size
Definition: ERF_NOAHMP.H:312
int m_lev
Definition: ERF_NOAHMP.H:398
amrex::Geometry m_lsm_geom
Definition: ERF_NOAHMP.H:336
amrex::Geometry m_geom0
Definition: ERF_NOAHMP.H:333
int m_nz_lsm
Definition: ERF_NOAHMP.H:359
amrex::Vector< amrex::MultiFab * > lsm_lev0_data
Definition: ERF_NOAHMP.H:372
int m_lsm_flux_size
Definition: ERF_NOAHMP.H:315
amrex::Real m_dtbl
Definition: ERF_NOAHMP.H:353
amrex::Vector< int > LsmFluxMap
Definition: ERF_NOAHMP.H:321
void m_ensure_nsoil_resolved()
Definition: ERF_NOAHMP.H:292
amrex::Vector< std::string > LsmFluxName
Definition: ERF_NOAHMP.H:327
amrex::Real m_dz_lsm
Definition: ERF_NOAHMP.H:362
amrex::Real m_dt
Definition: ERF_NOAHMP.H:345
@ NumVars
Definition: ERF_NOAHMP_Fields.H:120
@ t_flux
Definition: ERF_NOAHMP_Fields.H:129
@ tau13
Definition: ERF_NOAHMP_Fields.H:131
@ q_flux
Definition: ERF_NOAHMP_Fields.H:130
@ tau23
Definition: ERF_NOAHMP_Fields.H:132
@ ng
Definition: ERF_Morrison.H:49
@ NumComps
Definition: ERF_NOAHMP_Fields.H:160
@ NumComps
Definition: ERF_NOAHMP_Fields.H:176
real(c_double), parameter g
Definition: ERF_module_model_constants.F90:19
Here is the call graph for this function:

◆ interp_from_lev0()

void NOAHMP::interp_from_lev0 ( const int &  lev,
amrex::MultiFab &  cons_in,
const int &  nstep 
)
27 {
28  amrex::ignore_unused(cons_in);
29 
30  Print () << "Noah-MP interpolation at level " << lev << " started at time step: " << nstep+1 << std::endl;
31  m_updated = true;
32  for (int ivar(0); ivar<m_lsm_data_size; ++ivar) {
33  InterpFromCoarseLevel(*lsm_fab_data[ivar], lsm_fab_data[ivar]->nGrowVect(),
34  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
35  *lsm_lev0_data[ivar], 0, 0, 1,
36  m_geom0, m_geom,
37  m_refRatio, &cell_cons_interp,
39  }
40 
41  // SurfaceLayer filled the noah flux where lsm_undefined existed, so the
42  // coarse-grid flux is complete and safe to interpolate.
43  for (int ivar(0); ivar<LsmFlux_NOAHMP::NumVars; ++ivar) {
44  InterpFromCoarseLevel(*lsm_fab_flux[ivar], lsm_fab_flux[ivar]->nGrowVect(),
45  IntVect(0,0,0), // do NOT fill ghost cells outside the domain
46  *lsm_lev0_flux[ivar], 0, 0, 1,
47  m_geom0, m_geom,
48  m_refRatio, &cell_cons_interp,
50  }
51  Print () << "Noah-MP interpolation at level " << lev << " completed" << std::endl;
52 }
amrex::Array< amrex::MultiFab *, LsmFlux_NOAHMP::NumVars > lsm_lev0_flux
Definition: ERF_NOAHMP.H:375
@ cons_bc
Definition: ERF_IndexDefines.H:86

◆ Lsm_Data_Ptr()

amrex::MultiFab* NOAHMP::Lsm_Data_Ptr ( const int &  varIdx)
inlineoverridevirtual

Reimplemented from NullSurf.

105  {
106  int lsmIdx = LsmDataMap[varIdx];
107  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_data_size && lsmIdx>=0);
108  return lsm_fab_data[lsmIdx].get();
109  }
Here is the call graph for this function:

◆ Lsm_Data_Size()

int NOAHMP::Lsm_Data_Size ( )
inlineoverridevirtual

Reimplemented from NullSurf.

Here is the call graph for this function:

◆ Lsm_DataIndex()

int NOAHMP::Lsm_DataIndex ( std::string  varname)
inlineoverridevirtual

Reimplemented from NullSurf.

145  {
146  int varIdx = -1;
147  std::string lc_varname = amrex::toLower(varname);
148  for (int idx(0); idx<m_lsm_data_size; ++idx) {
149  if (lc_varname == amrex::toLower(LsmDataName[idx])) {
150  varIdx = idx;
151  }
152  }
153  return varIdx;
154  }
Here is the call graph for this function:

◆ Lsm_DataName()

std::string NOAHMP::Lsm_DataName ( const int &  varIdx)
inlineoverridevirtual

Reimplemented from NullSurf.

136  {
137  int lsmIdx = LsmDataMap[varIdx];
138  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_data_size && lsmIdx>=0);
139  return LsmDataName[lsmIdx];
140  }
Here is the call graph for this function:

◆ Lsm_Flux_Ptr()

amrex::MultiFab* NOAHMP::Lsm_Flux_Ptr ( const int &  varIdx)
inlineoverridevirtual

Reimplemented from NullSurf.

114  {
115  int lsmIdx = LsmFluxMap[varIdx];
116  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_flux_size && lsmIdx>=0);
117  return lsm_fab_flux[lsmIdx].get();
118  }
Here is the call graph for this function:

◆ Lsm_Flux_Size()

int NOAHMP::Lsm_Flux_Size ( )
inlineoverridevirtual

Reimplemented from NullSurf.

131 { return NOAHMP::m_lsm_flux_size; }

◆ Lsm_FluxIndex()

int NOAHMP::Lsm_FluxIndex ( std::string  varname)
inlineoverridevirtual

Reimplemented from NullSurf.

168  {
169  int varIdx = -1;
170  std::string lc_varname = amrex::toLower(varname);
171  for (int idx(0); idx<LsmFlux_NOAHMP::NumVars; ++idx) {
172  if (lc_varname == amrex::toLower(LsmFluxName[idx])) {
173  varIdx = idx;
174  }
175  }
176  return varIdx;
177  }
Here is the call graph for this function:

◆ Lsm_FluxName()

std::string NOAHMP::Lsm_FluxName ( const int &  varIdx)
inlineoverridevirtual

Reimplemented from NullSurf.

159  {
160  int lsmIdx = LsmFluxMap[varIdx];
161  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_flux_size && lsmIdx>=0);
162  return LsmFluxName[lsmIdx];
163  }
Here is the call graph for this function:

◆ Lsm_Geom()

amrex::Geometry NOAHMP::Lsm_Geom ( )
inlineoverridevirtual

Reimplemented from NullSurf.

122 { return m_lsm_geom; }

◆ Lsm_Set_Lev0_Data_Ptr()

void NOAHMP::Lsm_Set_Lev0_Data_Ptr ( const int &  varIdx,
amrex::MultiFab *  lev0_data_ptr 
)
inlineoverridevirtual

Reimplemented from NullSurf.

182  {
183  lsm_lev0_data[varIdx] = lev0_data_ptr;
184  }

◆ Lsm_Set_Lev0_Flux_Ptr()

void NOAHMP::Lsm_Set_Lev0_Flux_Ptr ( const int &  varIdx,
amrex::MultiFab *  lev0_flux_ptr 
)
inlineoverridevirtual

Reimplemented from NullSurf.

189  {
190  lsm_lev0_flux[varIdx] = lev0_flux_ptr;
191  }

◆ m_ensure_nsoil_resolved()

void NOAHMP::m_ensure_nsoil_resolved ( )
inline
292  {
293  if (m_nsoil_resolved) { return; }
294  amrex::ParmParse pp_nsoil("erf");
295  pp_nsoil.query("lsm_nsoil", m_nsoil);
296  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_nsoil >= 1, "erf.lsm_nsoil must be >= 1");
298  m_nsoil_resolved = true;
299  }
bool m_nsoil_resolved
Definition: ERF_NOAHMP.H:291

Referenced by Lsm_Data_Size().

Here is the caller graph for this function:

◆ m_precip_snapshot_name()

static std::string NOAHMP::m_precip_snapshot_name ( const std::string &  dir,
int  l,
int  s 
)
inlinestatic
303  {
304  return dir + "/precip_accum_prev_Level_" + std::to_string(l)
305  + "_slot_" + std::to_string(s);
306  }

◆ Plot_Landfile()

void NOAHMP::Plot_Landfile ( const int &  nstep)
overridevirtual

Reimplemented from NullSurf.

21 {
22  for (NoahmpIO_type &noahmpio : noahmpio_vect) {
23  noahmpio.WriteLand(nstep);
24  }
25 }

◆ prepare_precip_snapshots()

void NOAHMP::prepare_precip_snapshots ( const int &  lev,
const erf_noahmp::PrecipSlots precip 
)
40 {
41  if (!precip.have_any) { return; }
42 
43  if (int(m_precip_accum_prev.size()) <= lev) { m_precip_accum_prev.resize(lev+1); }
44  auto& prev = m_precip_accum_prev[lev];
45  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
46  if (precip.has[s] && prev[s] == nullptr) {
47  // Zero ghost cells + setVal(0) so no cell is uninitialized (garbage prev
48  // -> ~1e25 deltas -> Noah-MP water-balance abort); only the slab is read.
49  prev[s] = std::make_unique<MultiFab>(
50  precip.accum[s]->boxArray(), precip.accum[s]->DistributionMap(), 1, 0);
51  prev[s]->setVal(0.0);
52  if (m_precip_accum_restored[s]) {
53  // Restart: ParallelCopy handles a changed decomposition; consume once.
54  prev[s]->ParallelCopy(*m_precip_accum_restored[s], 0, 0, 1);
55  m_precip_accum_restored[s].reset();
56  } else {
57  MultiFab::Copy(*prev[s], *precip.accum[s], 0, 0, 1, 0);
58  }
59  }
60  }
61 }
amrex::Array< std::unique_ptr< amrex::MultiFab >, NoahmpPrecipSlot::NumSlots > m_precip_accum_restored
Definition: ERF_NOAHMP.H:395

◆ Read_Lsm_Restart()

void NOAHMP::Read_Lsm_Restart ( const std::string &  dir)
overridevirtual

Reimplemented from NullSurf.

50 {
51  for (NoahmpIO_type& noahmpio : noahmpio_vect) {
52  noahmpio.ReadRestart(dir);
53  }
54 
55  // Read saved precip snapshots into a staging store; the first Advance copies them
56  // into the live snapshots. Legacy checkpoints lack the files -> Advance cold-seeds.
57  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
58  const std::string name = m_precip_snapshot_name(dir, m_lev, s);
59  if (amrex::FileExists(name + "_H")) {
60  auto mf = std::make_unique<amrex::MultiFab>();
61  amrex::VisMF::Read(*mf, name);
62  m_precip_accum_restored[s] = std::move(mf);
63  }
64  }
65 }
std::string name
Definition: ERF_Plotfile2DCatalog.cpp:97
static std::string m_precip_snapshot_name(const std::string &dir, int l, int s)
Definition: ERF_NOAHMP.H:303

◆ read_results()

void NOAHMP::read_results ( const amrex::MFIter &  mfi,
const erf_noahmp::NoahmpBlockViews blk,
const amrex::Box &  bx,
const amrex::Box &  gbx,
amrex::MultiFab &  cons_in 
)
212 {
213  NoahmpIO_type* noahmpio = blk.io;
214 
215  // For limiting when populating ghost cells
216  int i_lo = bx.smallEnd(0); int i_hi = bx.bigEnd(0);
217  int j_lo = bx.smallEnd(1); int j_hi = bx.bigEnd(1);
218 
219  const Array4<const Real>& CONS = cons_in.const_array(mfi);
220 
221  // Mechanical result destinations (RRTMGP coupling + return-term diagnostics),
222  // bound from NOAHMP_RESULT_FIELDS to stay in sync with the scatter below.
223 #define NOAHMP_BIND_RESULT(alias,lsm,out) Array4<Real> alias = lsm_fab_data[LsmData_NOAHMP::lsm]->array(mfi);
225 #undef NOAHMP_BIND_RESULT
226  // Sentinels (this core does not compute them; always lsm_undefined below).
227  Array4<Real> SMSTAV_o = lsm_fab_data[LsmData_NOAHMP::smstav]->array(mfi);
228  Array4<Real> SMSTOT_o = lsm_fab_data[LsmData_NOAHMP::smstot]->array(mfi);
229 
230  // Per-layer soil output fabs (3 groups x m_nsoil) in a device-visible vector so
231  // the scatter loops over any NSOIL. Layout: g in {0:smois,1:sh2o,2:tslb}, k in [0,nsoil).
232  const int nsoil = m_nsoil;
233  const int n_soil_fld = 3*nsoil;
234  Gpu::DeviceVector<Array4<Real>> soil_arr_d(n_soil_fld);
235  {
236  Vector<Array4<Real>> soil_arr_h(n_soil_fld);
237  for (int g(0); g < 3; ++g) {
238  for (int k(0); k < nsoil; ++k) {
239  soil_arr_h[g*nsoil+k] = lsm_fab_data[soil_data_idx(g,k)]->array(mfi);
240  }
241  }
242  Gpu::copyAsync(Gpu::hostToDevice, soil_arr_h.begin(), soil_arr_h.end(), soil_arr_d.begin());
243  Gpu::streamSynchronize();
244  }
245  Array4<Real>* soil_arr = soil_arr_d.data();
246  const int soil_out_base = NoahmpOutputComp::NumComps; // soil outputs start here
247 
248  // SurfaceLayer flux destinations
249  Array4<Real> q_flux_arr = lsm_fab_flux[LsmFlux_NOAHMP::q_flux]->array(mfi);
250  Array4<Real> t_flux_arr = lsm_fab_flux[LsmFlux_NOAHMP::t_flux]->array(mfi);
251  Array4<Real> tau13_arr = lsm_fab_flux[LsmFlux_NOAHMP::tau13]->array(mfi);
252  Array4<Real> tau23_arr = lsm_fab_flux[LsmFlux_NOAHMP::tau23]->array(mfi);
253 
254  Array4<Real> noah_output_arr = blk.output;
255 
256  // (5) Copy NoahmpIO results into the pinned output buffer; banded albedos and
257  // the soil profile are read explicitly. SMSTAV/SMSTOT are emitted lsm_undefined.
258  LoopOnCpu(bx, [&] (int i, int j, int ) noexcept
259  {
260 #define NOAHMP_READ_OUT_2D(comp,member) noah_output_arr(i,j,0,NoahmpOutputComp::comp) = noahmpio->member(i,j);
262 #undef NOAHMP_READ_OUT_2D
263  // Banded radiation reads (VIS=1, NIR=2)
264  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdir_vis) = noahmpio->ALBSFCDIRXY(i,1,j);
265  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdir_nir) = noahmpio->ALBSFCDIRXY(i,2,j);
266  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdif_vis) = noahmpio->ALBSFCDIFXY(i,1,j);
267  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdif_nir) = noahmpio->ALBSFCDIFXY(i,2,j);
268  // Soil profile, one 2D component per layer (Fortran layer index is 1-based).
269  for (int k(0); k < nsoil; ++k) {
270  noah_output_arr(i,j,0,soil_out_base + 0*nsoil + k) = noahmpio->SMOIS(i,k+1,j);
271  noah_output_arr(i,j,0,soil_out_base + 1*nsoil + k) = noahmpio->SH2O (i,k+1,j);
272  noah_output_arr(i,j,0,soil_out_base + 2*nsoil + k) = noahmpio->TSLB (i,k+1,j);
273  }
274  });
275 
276  // (6) Copy Noahmp results to ERF (device; from pinned buffer): per-field math
277  // (flux ÷rho, -9999 fill guard, sentinels, soil loop), deliberately not table-driven.
278  ParallelFor(gbx, [=,Cp_d_d=Cp_d,L_v_d=L_v,lsm_undefined_d=lsm_undefined]
279  AMREX_GPU_DEVICE (int i, int j, int k) noexcept
280  {
281  // Limit indices to the valid box. FillBoundary will pick these up below.
282  int ii = std::min(std::max(i,i_lo),i_hi);
283  int jj = std::min(std::max(j,j_lo),j_hi);
284 
285  // Noah-MP returns -9999 for cells it does not process (sea-ice/open-water);
286  // HFX is Noah-MP's processed-cell gate; it is not a statement that
287  // every physical output is valid. tau13/tau23 are nodal in xz/yz;
288  // the 2D MFs carry 1 ghost cell for averaging.
289  const Real hfx_lsm = noah_output_arr(ii,jj,0,NoahmpOutputComp::hfx);
290  const noahmp_result_policy::CellPolicy cell_policy(hfx_lsm);
291  // Noah-MP returns HFX,LH [W/m2] and TAU [N/m2] (rho included); divide by
292  // rho for the kinematic MOST form ERF stores. Exner factor on t_flux is
293  // omitted to match WRF (<~1% error near surface, ~6-7% at p~800 hPa).
294  const Real rho_l = CONS(ii,jj,k,Rho_comp);
295  const auto fluxes = cell_policy.select_fluxes(
296  noah_output_arr(ii,jj,0,NoahmpOutputComp::lh),
297  noah_output_arr(ii,jj,0,NoahmpOutputComp::tau_ew),
298  noah_output_arr(ii,jj,0,NoahmpOutputComp::tau_ns),
299  rho_l, Cp_d_d, L_v_d, lsm_undefined_d);
300  t_flux_arr(i,j,k) = fluxes.temperature;
301  q_flux_arr(i,j,k) = fluxes.mixing_ratio;
302  tau13_arr(i,j,k) = fluxes.tau_ew;
303  tau23_arr(i,j,k) = fluxes.tau_ns;
304 
305  // Processed cells retain field-specific validity checks. Unprocessed
306  // cells invalidate the complete provider result set.
307  if (cell_policy.processed) {
308 #define NOAHMP_COPY_RESULT(alias,lsm,out) \
309  { \
310  const Real value = noah_output_arr(ii,jj,0,NoahmpOutputComp::out); \
311  alias(i,j,0) = cell_policy.select( \
312  value, lsm_undefined_d, NoahmpOutputComp::out); \
313  }
315 #undef NOAHMP_COPY_RESULT
316  // Not computed by this core -> sentinel, not a misleading 0.
317  SMSTAV_o(i,j,0) = lsm_undefined_d;
318  SMSTOT_o(i,j,0) = lsm_undefined_d;
319  for (int s(0); s < n_soil_fld; ++s) {
320  const Real value = noah_output_arr(ii,jj,0,soil_out_base + s);
321  soil_arr[s](i,j,0) = cell_policy.select(value, lsm_undefined_d, -1);
322  }
323  } else {
324 #define NOAHMP_UNDEF_RESULT(alias,lsm,out) alias(i,j,0) = lsm_undefined_d;
326 #undef NOAHMP_UNDEF_RESULT
327  SMSTAV_o(i,j,0) = lsm_undefined_d;
328  SMSTOT_o(i,j,0) = lsm_undefined_d;
329  for (int s(0); s < n_soil_fld; ++s) {
330  soil_arr[s](i,j,0) = lsm_undefined_d;
331  }
332  }
333  });
334  // The scatter kernel reads soil_arr_d; sync before it is destroyed.
335  Gpu::streamSynchronize();
336 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real L_v
Definition: ERF_Constants.H:59
Real value
Definition: ERF_HurricaneDiagnostics.cpp:30
#define Rho_comp
Definition: ERF_IndexDefines.H:36
ParallelFor(grown_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
#define NOAHMP_READ_OUT_2D(comp, member)
#define NOAHMP_COPY_RESULT(alias, lsm, out)
#define NOAHMP_UNDEF_RESULT(alias, lsm, out)
#define NOAHMP_BIND_RESULT(alias, lsm, out)
#define NOAHMP_RESULT_FIELDS(X)
Definition: ERF_NOAHMP_Fields.H:85
#define NOAHMP_OUTPUT_2D_FIELDS(X)
Definition: ERF_NOAHMP_Fields.H:80
@ albsfcdir_vis
Definition: ERF_NOAHMP_Fields.H:168
@ albsfcdif_nir
Definition: ERF_NOAHMP_Fields.H:171
@ albsfcdif_vis
Definition: ERF_NOAHMP_Fields.H:170
@ albsfcdir_nir
Definition: ERF_NOAHMP_Fields.H:169
NoahmpIO_type * io
Definition: ERF_NOAHMP.H:50
amrex::Array4< amrex::Real > output
Definition: ERF_NOAHMP.H:52
Definition: ERF_NOAHMP_ResultPolicy.H:59
Here is the call graph for this function:

◆ report_precip_diagnostics()

void NOAHMP::report_precip_diagnostics ( const int &  lev,
const amrex::Vector< erf_noahmp::ClampedPrecipCell > &  clamped_cells,
const amrex::Vector< erf_noahmp::InvariantPrecipCell > &  invariant_cells 
)
83 {
84  if (!clamped_cells.empty()) {
85  const int nshow = amrex::min(int(clamped_cells.size()), 50);
86  amrex::AllPrint aprint;
87  aprint << "WARNING: NOAHMP precip guard (level " << lev << "): clamped "
88  << clamped_cells.size() << " non-physical interval-precip cell(s) (> "
89  << lsm_max_precip_interval << " mm):\n";
90  for (int c(0); c < nshow; ++c) {
91  aprint << " (i,j)=(" << clamped_cells[c].i << "," << clamped_cells[c].j
92  << ") raw=" << clamped_cells[c].raw_mm << " mm\n";
93  }
94  if (int(clamped_cells.size()) > nshow) {
95  aprint << " ... and " << (int(clamped_cells.size()) - nshow) << " more\n";
96  }
97  }
98 
99  if (!invariant_cells.empty()) {
100  const int nshow = amrex::min(int(invariant_cells.size()), 50);
101  amrex::AllPrint aprint;
102  aprint << "WARNING: NOAHMP precip invariant (level " << lev << "): rescaled frozen "
103  << "components in " << invariant_cells.size() << " cell(s) where "
104  << "MP_SNOW+MP_GRAUP exceeded MP_RAINNC:\n";
105  for (int c(0); c < nshow; ++c) {
106  aprint << " (i,j)=(" << invariant_cells[c].i << "," << invariant_cells[c].j
107  << ") frozen=" << invariant_cells[c].froz_mm
108  << " mm > total=" << invariant_cells[c].total_mm << " mm\n";
109  }
110  if (int(invariant_cells.size()) > nshow) {
111  aprint << " ... and " << (int(invariant_cells.size()) - nshow) << " more\n";
112  }
113  }
114 }
constexpr amrex::Real lsm_max_precip_interval
Definition: ERF_Constants.H:40

◆ Set_LSM_Step()

void NOAHMP::Set_LSM_Step ( int  step)
inlineoverridevirtual

Reimplemented from NullSurf.

206  {
207  m_itimestep = step;
208  for (auto& noahmpio : noahmpio_vect) {
209  noahmpio.itimestep = step;
210  }
211  }

◆ soil_data_idx()

int NOAHMP::soil_data_idx ( int  g,
int  k 
) const
inline
285  {
286  return LsmData_NOAHMP::NumVars + g*m_nsoil + k;
287  }

◆ stage_forcing()

void NOAHMP::stage_forcing ( const amrex::MFIter &  mfi,
const erf_noahmp::NoahmpBlockViews blk,
const amrex::Box &  bx,
const int &  klo,
const int &  lev,
const bool  is_moist,
amrex::MultiFab &  cons_in,
amrex::MultiFab &  xvel_in,
amrex::MultiFab &  yvel_in,
const erf_noahmp::PrecipSlots precip,
amrex::Vector< erf_noahmp::ClampedPrecipCell > &  clamped_cells,
amrex::Vector< erf_noahmp::InvariantPrecipCell > &  invariant_cells 
)
88 {
89  NoahmpIO_type* noahmpio = blk.io;
90 
91  const Array4<const Real>& U_PHY = xvel_in.const_array(mfi);
92  const Array4<const Real>& V_PHY = yvel_in.const_array(mfi);
93  const Array4<const Real>& CONS = cons_in.const_array(mfi);
94 
95  // Forcing pulled from the coupling data fields
96  const Array4<const Real>& SWDOWN = lsm_fab_data[LsmData_NOAHMP::sw_flux_dn]->const_array(mfi);
97  const Array4<const Real>& GLW = lsm_fab_data[LsmData_NOAHMP::lw_flux_dn]->const_array(mfi);
98  const Array4<const Real>& COSZEN = lsm_fab_data[LsmData_NOAHMP::cos_zenith_angle]->const_array(mfi);
99 
100  // Pinned (host-accessible, GPU-usable) staging buffer
101  Array4<Real> noah_input_arr = blk.input;
102 
103  // Per-slot precip views (current + previous snapshot) and their native->kg/m^2
104  // factors. Read only inside the device kernel; absent slots guarded by slot_present.
105  const bool hp = precip.have_any;
106  GpuArray<Array4<const Real>, NoahmpPrecipSlot::NumSlots> accum_now, accum_prv;
107  GpuArray<Real, NoahmpPrecipSlot::NumSlots> accum_fac;
108  GpuArray<int, NoahmpPrecipSlot::NumSlots> slot_present;
109  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
110  slot_present[s] = (hp && precip.has[s]) ? 1 : 0;
111  accum_fac[s] = precip.factor[s];
112  if (slot_present[s]) {
113  accum_now[s] = precip.accum[s]->const_array(mfi);
114  accum_prv[s] = m_precip_accum_prev[lev][s]->const_array(mfi);
115  }
116  }
117  const int kklo = klo;
118 
119  // (1) Stage ERF forcing into the pinned buffer (device).
120  ParallelFor(bx, [=,zero_d=zero] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
121  {
122  Real qv = (is_moist) ? CONS(i,j,k,RhoQ1_comp)/CONS(i,j,k,Rho_comp) : zero_d;
123  noah_input_arr(i,j,0,NoahmpInputComp::u_phy) = myhalf*(U_PHY(i,j,k)+U_PHY(i+1,j,k));
124  noah_input_arr(i,j,0,NoahmpInputComp::v_phy) = myhalf*(V_PHY(i,j,k)+V_PHY(i ,j+1,k));
125  noah_input_arr(i,j,0,NoahmpInputComp::t_phy) = getTgivenRandRTh(CONS(i,j,k,Rho_comp),CONS(i,j,k,RhoTheta_comp),qv);
126  noah_input_arr(i,j,0,NoahmpInputComp::qv_curr) = qv;
127  noah_input_arr(i,j,0,NoahmpInputComp::p8w) = getPgivenRTh(CONS(i,j,k,RhoTheta_comp),qv);
128  noah_input_arr(i,j,0,NoahmpInputComp::swdown) = SWDOWN(i,j,0);
129  noah_input_arr(i,j,0,NoahmpInputComp::glw) = GLW(i,j,0);
130  noah_input_arr(i,j,0,NoahmpInputComp::coszen) = COSZEN(i,j,0);
131 
132  // RAW water-equivalent interval precip [mm]: per slot d = max(0, (now-prev)
133  // * native_to_kg_m2). Host applies the guard and derives SR / MP_RAINNC.
134  Real drain = zero_d, dsnow = zero_d, dgraup = zero_d;
135  if (hp) {
137  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
138  dd[s] = slot_present[s]
139  ? amrex::max(zero_d, (accum_now[s](i,j,kklo) - accum_prv[s](i,j,kklo)) * accum_fac[s])
140  : zero_d;
141  }
142  // Hail is folded into MP_GRAUP (no ERF scheme fills the hail slot
143  // today); to feed it separately, stage dd[hail] into MP_HAIL instead.
144  dsnow = dd[NoahmpPrecipSlot::snow];
146  const Real dfroz = dsnow + dgraup;
147  // Total: scheme's `total` slot, else rain + frozen.
148  drain = slot_present[NoahmpPrecipSlot::total]
150  : (dd[NoahmpPrecipSlot::rain] + dfroz);
151  }
152  noah_input_arr(i,j,0,NoahmpInputComp::rainbl) = drain;
153  noah_input_arr(i,j,0,NoahmpInputComp::mp_snow) = dsnow;
154  noah_input_arr(i,j,0,NoahmpInputComp::mp_graup) = dgraup;
155  });
156 
157  // (2) Wait for the kernel before host access.
158  Gpu::streamSynchronize();
159 
160  // (3) Copy pinned staged data to NoahmpIO on the host (3D members take the k/j
161  // transpose (i,1,j), 2D take (i,j)); precip is derived below.
162  LoopOnCpu(bx, [&,zero_d=zero,one_d=one,lsm_max_precip_interval_d=lsm_max_precip_interval]
163  (int i, int j, int ) noexcept
164  {
165 #define NOAHMP_STAGE_IN_3D(comp,member) noahmpio->member(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::comp);
166 #define NOAHMP_STAGE_IN_2D(comp,member) noahmpio->member(i,j) = noah_input_arr(i,j,0,NoahmpInputComp::comp);
169 #undef NOAHMP_STAGE_IN_3D
170 #undef NOAHMP_STAGE_IN_2D
171  // Guard the RAW total, then derive SR / MP_RAINNC. Clamped cells are
172  // reported after the box loop (never silent).
173  Real dsnow_h = noah_input_arr(i,j,0,NoahmpInputComp::mp_snow);
174  Real dgraup_h = noah_input_arr(i,j,0,NoahmpInputComp::mp_graup);
175  Real drain_h = noah_input_arr(i,j,0,NoahmpInputComp::rainbl);
176  if (drain_h > lsm_max_precip_interval_d) {
177  clamped_cells.push_back(erf_noahmp::ClampedPrecipCell{i, j, drain_h});
178  drain_h = lsm_max_precip_interval_d;
179  }
180  // Frozen/total invariant: MP_SNOW+MP_GRAUP are subsets of MP_RAINNC; if
181  // their sum exceeds it, rescale the frozen components down and record the cell.
182  Real dfroz_h = dsnow_h + dgraup_h;
183  const Real inv_tol = Real(1.0e-6) * (one_d + drain_h);
184  if (dfroz_h > drain_h + inv_tol) {
185  invariant_cells.push_back(erf_noahmp::InvariantPrecipCell{i, j, dfroz_h, drain_h});
186  if (dfroz_h > zero_d) {
187  const Real scale = drain_h / dfroz_h; // <= 1
188  dsnow_h *= scale;
189  dgraup_h *= scale;
190  dfroz_h = dsnow_h + dgraup_h; // == drain_h (to round-off)
191  }
192  }
193  noahmpio->RAINBL(i,j) = drain_h; // [mm]
194  noahmpio->SR(i,j) = (drain_h > zero_d) ? amrex::min(one_d, dfroz_h/drain_h) : zero_d; // [-]
195  noahmpio->MP_RAINNC(i,j) = drain_h; // [mm]
196  noahmpio->MP_SNOW(i,j) = dsnow_h; // [mm]
197  noahmpio->MP_GRAUP(i,j) = dgraup_h; // [mm] (includes folded hail)
198  // 0 = "no hail" (a real value, not a sentinel; lsm_undefined would corrupt opt_snf=4)
199  noahmpio->MP_HAIL(i,j) = zero_d; // [mm]
200  });
201 }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define NOAHMP_STAGE_IN_2D(comp, member)
#define NOAHMP_STAGE_IN_3D(comp, member)
#define NOAHMP_INPUT_2D_FIELDS(X)
Definition: ERF_NOAHMP_Fields.H:48
#define NOAHMP_INPUT_3D_FIELDS(X)
Definition: ERF_NOAHMP_Fields.H:40
@ qv
Definition: ERF_Kessler.H:30
@ rainbl
Definition: ERF_NOAHMP_Fields.H:155
@ mp_graup
Definition: ERF_NOAHMP_Fields.H:159
@ mp_snow
Definition: ERF_NOAHMP_Fields.H:158
@ graupel
Definition: ERF_NOAHMP_Fields.H:144
@ rain
Definition: ERF_NOAHMP_Fields.H:142
@ total
Definition: ERF_NOAHMP_Fields.H:141
@ hail
Definition: ERF_NOAHMP_Fields.H:145
@ snow
Definition: ERF_NOAHMP_Fields.H:143
Definition: ERF_NOAHMP.H:41
Definition: ERF_NOAHMP.H:45
amrex::Array4< amrex::Real > input
Definition: ERF_NOAHMP.H:51
amrex::Real factor[NoahmpPrecipSlot::NumSlots]
Definition: ERF_NOAHMP.H:35
Here is the call graph for this function:

◆ time_to_fire()

bool NOAHMP::time_to_fire ( const amrex::Real elapsed_time)
60 {
61  Real NOAH_time = static_cast<Real>(m_itimestep-1) * m_dtbl;
62  if (elapsed_time < NOAH_time) {
63  m_updated = false;
64  return false;
65  }
66 
67  m_updated = true;
68  m_itimestep += 1; // advance once per firing, in lockstep on every rank
69  return true;
70 }

◆ Write_Lsm_Restart()

void NOAHMP::Write_Lsm_Restart ( const std::string &  dir) const
overridevirtual

Reimplemented from NullSurf.

31 {
32  for (const NoahmpIO_type& noahmpio : noahmpio_vect) {
33  const_cast<NoahmpIO_type&>(noahmpio).WriteRestart(dir);
34  }
35 
36  // Also save the precip snapshots so the next land call after restart differences
37  // against the same baseline (no precip dropped or double-counted).
38  if (m_lev < int(m_precip_accum_prev.size())) {
39  for (int s(0); s < NoahmpPrecipSlot::NumSlots; ++s) {
40  if (m_precip_accum_prev[m_lev][s]) {
41  amrex::VisMF::Write(*m_precip_accum_prev[m_lev][s],
42  m_precip_snapshot_name(dir, m_lev, s));
43  }
44  }
45  }
46 }

Member Data Documentation

◆ khi_lsm

int NOAHMP::khi_lsm
private

◆ lsm_fab_data

amrex::Vector<FabPtr> NOAHMP::lsm_fab_data
private

Referenced by Lsm_Data_Ptr().

◆ lsm_fab_flux

amrex::Array<FabPtr, LsmFlux_NOAHMP::NumVars> NOAHMP::lsm_fab_flux
private

Referenced by Lsm_Flux_Ptr().

◆ lsm_lev0_data

amrex::Vector<amrex::MultiFab*> NOAHMP::lsm_lev0_data
private

Referenced by Lsm_Set_Lev0_Data_Ptr().

◆ lsm_lev0_flux

amrex::Array<amrex::MultiFab*, LsmFlux_NOAHMP::NumVars> NOAHMP::lsm_lev0_flux
private

Referenced by Lsm_Set_Lev0_Flux_Ptr().

◆ LsmDataMap

amrex::Vector<int> NOAHMP::LsmDataMap
private

Referenced by Lsm_Data_Ptr(), and Lsm_DataName().

◆ LsmDataName

amrex::Vector<std::string> NOAHMP::LsmDataName
private

Referenced by Lsm_DataIndex(), and Lsm_DataName().

◆ LsmFluxMap

amrex::Vector<int> NOAHMP::LsmFluxMap
private

Referenced by Lsm_Flux_Ptr(), and Lsm_FluxName().

◆ LsmFluxName

amrex::Vector<std::string> NOAHMP::LsmFluxName
private

Referenced by Lsm_FluxIndex(), and Lsm_FluxName().

◆ m_domain_bcs_type

amrex::Vector<amrex::BCRec> NOAHMP::m_domain_bcs_type
private

◆ m_dt

amrex::Real NOAHMP::m_dt
private

◆ m_dtbl

amrex::Real NOAHMP::m_dtbl = std::numeric_limits<amrex::Real>::max()
private

◆ m_dz_lsm

amrex::Real NOAHMP::m_dz_lsm = one
private

◆ m_geom

amrex::Geometry NOAHMP::m_geom
private

◆ m_geom0

amrex::Geometry NOAHMP::m_geom0
private

◆ m_has_nc_file

bool NOAHMP::m_has_nc_file = false
private

◆ m_itimestep

int NOAHMP::m_itimestep = 0
private

Referenced by Get_LSM_Step(), and Set_LSM_Step().

◆ m_lev

int NOAHMP::m_lev = 0
private

◆ m_lsm_data_size

int NOAHMP::m_lsm_data_size = LsmData_NOAHMP::NumVars
private

◆ m_lsm_flux_size

int NOAHMP::m_lsm_flux_size = LsmFlux_NOAHMP::NumVars
private

Referenced by Lsm_Flux_Size().

◆ m_lsm_geom

amrex::Geometry NOAHMP::m_lsm_geom
private

Referenced by Lsm_Geom().

◆ m_nsoil

int NOAHMP::m_nsoil = 4
private

◆ m_nsoil_resolved

bool NOAHMP::m_nsoil_resolved = false

Referenced by m_ensure_nsoil_resolved().

◆ m_nz_lsm

int NOAHMP::m_nz_lsm = 1
private

◆ m_plot_int_1

int NOAHMP::m_plot_int_1 = -1
private

◆ m_precip_accum_prev

amrex::Vector<amrex::Array<std::unique_ptr<amrex::MultiFab>, NoahmpPrecipSlot::NumSlots> > NOAHMP::m_precip_accum_prev
private

◆ m_precip_accum_restored

amrex::Array<std::unique_ptr<amrex::MultiFab>, NoahmpPrecipSlot::NumSlots> NOAHMP::m_precip_accum_restored
private

◆ m_refRatio

amrex::IntVect NOAHMP::m_refRatio
private

◆ m_updated

bool NOAHMP::m_updated = false
private

Referenced by Get_Update_Status().

◆ noahmp_input_tmp

amrex::Vector<std::unique_ptr<amrex::FArrayBox> > NOAHMP::noahmp_input_tmp
private

◆ noahmp_output_tmp

amrex::Vector<std::unique_ptr<amrex::FArrayBox> > NOAHMP::noahmp_output_tmp
private

◆ noahmpio_vect

NoahmpIO_vector NOAHMP::noahmpio_vect
private

Referenced by Set_LSM_Step().


The documentation for this class was generated from the following files: