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::Real &dt) 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 amrex::Real &elapsed_time, const amrex::Real &dt, const int &nstep) 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
 
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
 
- Public Member Functions inherited from NullSurf
 NullSurf ()
 
virtual ~NullSurf ()=default
 
virtual void Advance (const amrex::Real &)
 
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 ()
 

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_lsm_geom
 
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::Array< FabPtr, LsmData_NOAHMP::NumVarslsm_fab_data
 
amrex::Array< FabPtr, LsmFlux_NOAHMP::NumVarslsm_fab_flux
 
NoahmpIO_vector noahmpio_vect
 
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_input_tmp
 
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_output_tmp
 
int m_plot_int_1 = -1
 

Member Typedef Documentation

◆ FabPtr

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

Constructor & Destructor Documentation

◆ NOAHMP()

NOAHMP::NOAHMP ( )
inline
91 {}

◆ ~NOAHMP()

virtual NOAHMP::~NOAHMP ( )
virtualdefault

Member Function Documentation

◆ 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 amrex::Real elapsed_time,
const amrex::Real dt,
const int &  nstep 
)
overridevirtual

Reimplemented from NullSurf.

273 {
274  // Verify we need to take another LSM step. Use the class-level counter/dtbl
275  // (valid on land-free ranks) so every rank decides identically -- the
276  // FillBoundary at the end of this routine is collective.
277  Real NOAH_time = static_cast<Real>(m_itimestep-1) * m_dtbl;
278  if (elapsed_time < NOAH_time) { return; }
279 
280  // Advance the counter once per firing, in lockstep on every rank.
281  m_itimestep += 1;
282 
283  Box domain = m_geom.Domain();
284 
285  Print () << "Noah-MP driver started at time step: " << nstep+1 << std::endl;
286 
287  bool is_moist = (cons_in.nComp() > RhoQ1_comp);
288 
289  int klo = domain.smallEnd(2);
290 
291  // Loop over blocks to copy forcing data to Noahmp, drive the land model,
292  // and copy data back to ERF Multifabs.
293  int idb = 0;
294  for (MFIter mfi(cons_in); mfi.isValid(); ++mfi, ++idb) {
295 
296  Box bx = mfi.tilebox();
297  Box gbx = mfi.tilebox(IntVect(0,0,0),IntVect(1,1,0));
298 
299  // Check if tile is at the lower boundary in lower z direction
300  if (bx.smallEnd(2) != klo) { continue; }
301 
302  bx.makeSlab(2,klo);
303  gbx.makeSlab(2,klo);
304 
305  // For limiting when populating ghost cells
306  int i_lo = bx.smallEnd(0); int i_hi = bx.bigEnd(0);
307  int j_lo = bx.smallEnd(1); int j_hi = bx.bigEnd(1);
308 
309  NoahmpIO_type* noahmpio = &noahmpio_vect[idb];
310 
311  const Array4<const Real>& U_PHY = xvel_in.const_array(mfi);
312  const Array4<const Real>& V_PHY = yvel_in.const_array(mfi);
313  const Array4<const Real>& CONS = cons_in.const_array(mfi);
314 
315  // Into NOAH-MP
316  const Array4<const Real>& SWDOWN = lsm_fab_data[LsmData_NOAHMP::sw_flux_dn]->const_array(mfi);
317  const Array4<const Real>& GLW = lsm_fab_data[LsmData_NOAHMP::lw_flux_dn]->const_array(mfi);
318  const Array4<const Real>& COSZEN = lsm_fab_data[LsmData_NOAHMP::cos_zenith_angle]->const_array(mfi);
319 
320  // Out of NOAH-MP
321  Array4<Real> TSK = lsm_fab_data[LsmData_NOAHMP::t_sfc]->array(mfi);
322  Array4<Real> EMISS = lsm_fab_data[LsmData_NOAHMP::sfc_emis]->array(mfi);
323  Array4<Real> ALBSFCDIR_VIS = lsm_fab_data[LsmData_NOAHMP::sfc_alb_dir_vis]->array(mfi);
324  Array4<Real> ALBSFCDIR_NIR = lsm_fab_data[LsmData_NOAHMP::sfc_alb_dir_nir]->array(mfi);
325  Array4<Real> ALBSFCDIF_VIS = lsm_fab_data[LsmData_NOAHMP::sfc_alb_dif_vis]->array(mfi);
326  Array4<Real> ALBSFCDIF_NIR = lsm_fab_data[LsmData_NOAHMP::sfc_alb_dif_nir]->array(mfi);
327 
328  // NOTE: Need to expose stresses and get stresses from NOAHMP
329  Array4<Real> q_flux_arr = lsm_fab_flux[LsmFlux_NOAHMP::q_flux]->array(mfi);
330  Array4<Real> t_flux_arr = lsm_fab_flux[LsmFlux_NOAHMP::t_flux]->array(mfi);
331  Array4<Real> tau13_arr = lsm_fab_flux[LsmFlux_NOAHMP::tau13]->array(mfi);
332  Array4<Real> tau23_arr = lsm_fab_flux[LsmFlux_NOAHMP::tau23]->array(mfi);
333 
334  // Use The_Pinned_Arena() for host-accessible memory that can be used with GPU
335  Array4<Real> noah_input_arr = noahmp_input_tmp[idb]->array();
336  Array4<Real> noah_output_arr = noahmp_output_tmp[idb]->array();
337 
338  // Copy forcing data from ERF to Noahmp.
339  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
340  {
341  Real qv = (is_moist) ? CONS(i,j,k,RhoQ1_comp)/CONS(i,j,k,Rho_comp) : zero;
342  noah_input_arr(i,j,0,NoahmpInputComp::u_phy) = myhalf*(U_PHY(i,j,k)+U_PHY(i+1,j,k));
343  noah_input_arr(i,j,0,NoahmpInputComp::v_phy) = myhalf*(V_PHY(i,j,k)+V_PHY(i ,j+1,k));
344  noah_input_arr(i,j,0,NoahmpInputComp::t_phy) = getTgivenRandRTh(CONS(i,j,k,Rho_comp),CONS(i,j,k,RhoTheta_comp),qv);
345  noah_input_arr(i,j,0,NoahmpInputComp::qv_curr) = qv;
346  noah_input_arr(i,j,0,NoahmpInputComp::p8w) = getPgivenRTh(CONS(i,j,k,RhoTheta_comp),qv);
347  noah_input_arr(i,j,0,NoahmpInputComp::swdown) = SWDOWN(i,j,0);
348  noah_input_arr(i,j,0,NoahmpInputComp::glw) = GLW(i,j,0);
349  noah_input_arr(i,j,0,NoahmpInputComp::coszen) = COSZEN(i,j,0);
350  });
351 
352  // Synchronize to ensure GPU kernel is complete before host access
353  Gpu::streamSynchronize();
354 
355  // Now on the host, copy data to NoahmpIO arrays
356  LoopOnCpu(bx, [&] (int i, int j, int ) noexcept
357  {
358  noahmpio->U_PHY(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::u_phy);
359  noahmpio->V_PHY(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::v_phy);
360  noahmpio->T_PHY(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::t_phy);
361  noahmpio->QV_CURR(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::qv_curr);
362  noahmpio->P8W(i,1,j) = noah_input_arr(i,j,0,NoahmpInputComp::p8w);
363  noahmpio->SWDOWN(i,j) = noah_input_arr(i,j,0,NoahmpInputComp::swdown);
364  noahmpio->GLW(i,j) = noah_input_arr(i,j,0,NoahmpInputComp::glw);
365  noahmpio->COSZEN(i,j) = noah_input_arr(i,j,0,NoahmpInputComp::coszen);
366  });
367 
368  // Call the noahmpio driver code. This runs the land model forcing for
369  // each object in noahmpio_vect that represent a block in the domain.
370  // Mirror the authoritative counter into each block.
371  noahmpio->itimestep = m_itimestep;
372  noahmpio->DriverMain();
373 
374  // Copy results from NoahmpIO back to temporary arrays
375  LoopOnCpu(bx, [&] (int i, int j, int ) noexcept
376  {
377  noah_output_arr(i,j,0,NoahmpOutputComp::hfx) = noahmpio->HFX(i,j);
378  noah_output_arr(i,j,0,NoahmpOutputComp::lh) = noahmpio->LH(i,j);
379  noah_output_arr(i,j,0,NoahmpOutputComp::tau_ew) = noahmpio->TAU_EW(i,j);
380  noah_output_arr(i,j,0,NoahmpOutputComp::tau_ns) = noahmpio->TAU_NS(i,j);
381  noah_output_arr(i,j,0,NoahmpOutputComp::tsk) = noahmpio->TSK(i,j);
382  noah_output_arr(i,j,0,NoahmpOutputComp::emiss) = noahmpio->EMISS(i,j);
383  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdir_vis) = noahmpio->ALBSFCDIRXY(i,1,j);
384  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdir_nir) = noahmpio->ALBSFCDIRXY(i,2,j);
385  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdif_vis) = noahmpio->ALBSFCDIFXY(i,1,j);
386  noah_output_arr(i,j,0,NoahmpOutputComp::albsfcdif_nir) = noahmpio->ALBSFCDIFXY(i,2,j);
387  });
388 
389  // Copy forcing data from Noahmp to ERF
390  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
391  {
392  // Limit indices to the valid box. FillBoundary will pick these up below.
393  int ii = std::min(std::max(i,i_lo),i_hi);
394  int jj = std::min(std::max(j,j_lo),j_hi);
395 
396  // SurfaceLayer fluxes at CC.
397  // Noah-MP returns the -9999 fill value for cells it does NOT process
398  // (sea-ice / open-water points, which still have LANDMASK=1). Applying
399  // that as a flux gives -9999/(rho*Cp) ~ -7.6 K*m/s and crashes the
400  // lowest cell to ~200 K. Detect the fill and instead write the
401  // lsm_flux_undefined sentinel; the surface layer then falls back to
402  // the MOST flux for those cells (see ERF_SurfaceLayer.cpp).
403  // NOTE: tau13/tau23 are nodal in xz/yz; the 2D MFs have 1 ghost cell
404  // so the surface layer can average them.
405  Real hfx_lsm = noah_output_arr(ii,jj,0,NoahmpOutputComp::hfx);
406  if (hfx_lsm > Real(-9990.0)) {
407  t_flux_arr(i,j,k) = hfx_lsm/(CONS(ii,jj,k,Rho_comp)*Cp_d);
408  q_flux_arr(i,j,k) = noah_output_arr(ii,jj,0,NoahmpOutputComp::lh)/(CONS(ii,jj,k,Rho_comp)*L_v);
409  tau13_arr(i,j,k) = noah_output_arr(ii,jj,0,NoahmpOutputComp::tau_ew)/CONS(ii,jj,k,Rho_comp);
410  tau23_arr(i,j,k) = noah_output_arr(ii,jj,0,NoahmpOutputComp::tau_ns)/CONS(ii,jj,k,Rho_comp);
411  } else {
412  t_flux_arr(i,j,k) = lsm_flux_undefined;
413  q_flux_arr(i,j,k) = lsm_flux_undefined;
414  tau13_arr(i,j,k) = lsm_flux_undefined;
415  tau23_arr(i,j,k) = lsm_flux_undefined;
416  }
417 
418  // RRTMGP variables
419  TSK(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::tsk);
420  EMISS(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::emiss);
421  ALBSFCDIR_VIS(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::albsfcdir_vis);
422  ALBSFCDIR_NIR(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::albsfcdir_nir);
423  ALBSFCDIF_VIS(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::albsfcdif_vis);
424  ALBSFCDIF_NIR(i,j,0) = noah_output_arr(ii,jj,0,NoahmpOutputComp::albsfcdif_nir);
425  });
426  }
427 
428  // Fill the ghost cells
429  for (auto ivar = 0; ivar < LsmFlux_NOAHMP::NumVars; ++ivar) {
430  lsm_fab_flux[ivar]->FillBoundary(m_geom.periodicity());
431  }
432  Print () << "Noah-MP driver completed" << std::endl;
433 };
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:44
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real lsm_flux_undefined
Definition: ERF_Constants.H:35
constexpr amrex::Real L_v
Definition: ERF_Constants.H:48
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 Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
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);})
amrex::Real Real
Definition: ERF_ShocInterface.H:19
amrex::Array< FabPtr, LsmFlux_NOAHMP::NumVars > lsm_fab_flux
Definition: ERF_NOAHMP.H:289
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_output_tmp
Definition: ERF_NOAHMP.H:296
amrex::Vector< std::unique_ptr< amrex::FArrayBox > > noahmp_input_tmp
Definition: ERF_NOAHMP.H:295
NoahmpIO_vector noahmpio_vect
Definition: ERF_NOAHMP.H:292
int m_itimestep
Definition: ERF_NOAHMP.H:270
amrex::Array< FabPtr, LsmData_NOAHMP::NumVars > lsm_fab_data
Definition: ERF_NOAHMP.H:286
amrex::Real m_dtbl
Definition: ERF_NOAHMP.H:274
amrex::Geometry m_geom
Definition: ERF_NOAHMP.H:259
@ sw_flux_dn
Definition: ERF_NOAHMP.H:33
@ sfc_emis
Definition: ERF_NOAHMP.H:27
@ sfc_alb_dir_vis
Definition: ERF_NOAHMP.H:28
@ sfc_alb_dif_nir
Definition: ERF_NOAHMP.H:31
@ lw_flux_dn
Definition: ERF_NOAHMP.H:38
@ cos_zenith_angle
Definition: ERF_NOAHMP.H:32
@ t_sfc
Definition: ERF_NOAHMP.H:26
@ sfc_alb_dir_nir
Definition: ERF_NOAHMP.H:29
@ sfc_alb_dif_vis
Definition: ERF_NOAHMP.H:30
@ t_flux
Definition: ERF_NOAHMP.H:46
@ tau13
Definition: ERF_NOAHMP.H:48
@ q_flux
Definition: ERF_NOAHMP.H:47
@ NumVars
Definition: ERF_NOAHMP.H:50
@ tau23
Definition: ERF_NOAHMP.H:49
@ qv
Definition: ERF_Kessler.H:29
@ v_phy
Definition: ERF_NOAHMP.H:58
@ glw
Definition: ERF_NOAHMP.H:63
@ qv_curr
Definition: ERF_NOAHMP.H:60
@ u_phy
Definition: ERF_NOAHMP.H:57
@ coszen
Definition: ERF_NOAHMP.H:64
@ t_phy
Definition: ERF_NOAHMP.H:59
@ swdown
Definition: ERF_NOAHMP.H:62
@ p8w
Definition: ERF_NOAHMP.H:61
@ hfx
Definition: ERF_NOAHMP.H:71
@ tau_ns
Definition: ERF_NOAHMP.H:74
@ tau_ew
Definition: ERF_NOAHMP.H:73
@ tsk
Definition: ERF_NOAHMP.H:75
@ albsfcdir_vis
Definition: ERF_NOAHMP.H:77
@ albsfcdif_nir
Definition: ERF_NOAHMP.H:80
@ emiss
Definition: ERF_NOAHMP.H:76
@ albsfcdif_vis
Definition: ERF_NOAHMP.H:79
@ albsfcdir_nir
Definition: ERF_NOAHMP.H:78
@ lh
Definition: ERF_NOAHMP.H:72
Here is the call graph for this function:

◆ Define()

void NOAHMP::Define ( SolverChoice )
inlineoverridevirtual

Reimplemented from NullSurf.

99  {
100  // NOTE: We should parse constants from sc here if needed,
101  }

◆ Get_LSM_Step()

int NOAHMP::Get_LSM_Step ( ) const
inlineoverridevirtual

Reimplemented from NullSurf.

206  {
207  return m_itimestep;
208  }

◆ Init()

void NOAHMP::Init ( const int &  lev,
const amrex::MultiFab &  cons_in,
const amrex::Geometry &  geom,
const amrex::Real dt 
)
overridevirtual

Reimplemented from NullSurf.

23 {
24 
25  // Install Noah-MP's fatal-error handler once (thread-safe, runs on the first
26  // Init across all levels). Noah-MP carries no MPI/AMReX dependency of its own
27  // and instead calls NoahmpIO_fatal(); routing that through amrex::Abort makes a
28  // fatal error on any rank -- from either the C++ or the Fortran coupling side
29  // -- propagate to all ranks via MPI_Abort, rather than deadlocking peers in
30  // the next collective. See NoahmpFatal.H.
31  static const bool noahmp_fatal_installed = []() {
32  NoahmpIO_set_fatal_handler([](const char* msg){
33  amrex::Abort(msg ? msg : "Noah-MP fatal error");
34  });
35  return true;
36  }();
37  amrex::ignore_unused(noahmp_fatal_installed);
38 
39  m_dt = dt;
40  m_geom = geom;
41 
42  Box domain = geom.Domain();
43  khi_lsm = domain.smallEnd(2) - 1;
44 
54  LsmDataName = {"t_sfc" , "sfc_emis" ,
55  "sfc_alb_dir_vis" , "sfc_alb_dir_nir" ,
56  "sfc_alb_dif_vis" , "sfc_alb_dif_nir" ,
57  "cos_zenith_angle" , "sw_flux_dn" ,
58  "sw_flux_dn_dir_vis", "sw_flux_dn_dir_nir",
59  "sw_flux_dn_dif_vis", "sw_flux_dn_dif_nir",
60  "lw_flux_dn" };
61 
62 
67  LsmFluxName = {"t_flux" , "q_flux" ,
68  "tau13" , "tau23" };
69 
70  ParmParse pp("erf");
71  pp.query("plot_int_1" , m_plot_int_1);
72 
73  // NOTE: All boxes in ba extend from zlo to zhi, so this transform is valid.
74  // If that were to change, the dm and new ba are no longer valid and
75  // direct copying between lsm data/flux vars cannot be done in a parfor.
76 
77  // Set 2D box array for lsm data
78  IntVect ng(1,1,0);
79  BoxArray ba = cons_in.boxArray();
80  DistributionMapping dm = cons_in.DistributionMap();
81  BoxList bl_lsm = ba.boxList();
82  for (auto& b : bl_lsm) { b.setRange(2,0); }
83  BoxArray ba_lsm(std::move(bl_lsm));
84 
85  // Set up lsm geometry
86  const RealBox& dom_rb = m_geom.ProbDomain();
87  const Real* dom_dx = m_geom.CellSize();
88  RealBox lsm_rb = dom_rb;
89  Real lsm_dx[AMREX_SPACEDIM] = {AMREX_D_DECL(dom_dx[0],dom_dx[1],m_dz_lsm)};
90  Real lsm_z_hi = dom_rb.lo(2);
91  Real lsm_z_lo = lsm_z_hi - Real(m_nz_lsm)*lsm_dx[2];
92  lsm_rb.setHi(2,lsm_z_hi); lsm_rb.setLo(2,lsm_z_lo);
93  m_lsm_geom.define( ba_lsm.minimalBox(), lsm_rb, m_geom.Coord(), m_geom.isPeriodic() );
94 
95  // Create the data
96  for (auto ivar = 0; ivar < LsmData_NOAHMP::NumVars; ++ivar) {
97  // State vars are CC
98  lsm_fab_data[ivar] = std::make_shared<MultiFab>(ba_lsm, dm, 1, ng);
99 
100  // NOTE: Radiation steps first so we set values
101  // to reasonable initialization for coupling
102  Real val_to_set = zero;
103  if (ivar == LsmData_NOAHMP::t_sfc) {
104  val_to_set = Real(300.0);
105  } else if (ivar == LsmData_NOAHMP::sfc_emis) {
106  val_to_set = Real(0.9);
107  } else if ( (ivar>=LsmData_NOAHMP::sfc_alb_dir_vis) &&
109  val_to_set = Real(0.06);
110  } else {
111  val_to_set = zero;
112  }
113  lsm_fab_data[ivar]->setVal(val_to_set);
114  }
115 
116  // Create the fluxes
117  for (auto ivar = 0; ivar < LsmFlux_NOAHMP::NumVars; ++ivar) {
118  // NOTE: Fluxes are CC with ghost cells for averaging
119  lsm_fab_flux[ivar] = std::make_shared<MultiFab>(ba_lsm, dm, 1, IntVect(1,1,0));
120  lsm_fab_flux[ivar]->setVal(0.);
121  }
122 
123  Print() << "Noah-MP initialization started" << std::endl;
124 
125  // Size noahmpio_vect to the local blocks (boxes). A rank owning no boxes
126  // leaves it empty and relies on the class-level m_itimestep/m_dtbl instead.
127  if (cons_in.local_size() > 0) {
128  noahmpio_vect.resize(cons_in.local_size(), lev);
129  }
130 
131  // Allocate pinned buffer space for all the boxes
132  noahmp_input_tmp.resize(cons_in.local_size());
133  noahmp_output_tmp.resize(cons_in.local_size());
134 
135  int klo = domain.smallEnd(2);
136 
137  // Iterate over multifab and noahmpio object together. Multifabs is
138  // used to extract size of blocks and set bounds for noahmpio objects.
139  int idb = 0;
140  for (MFIter mfi(cons_in); mfi.isValid(); ++mfi, ++idb) {
141 
142  // Get bounds for the tile
143  Box bx = mfi.tilebox();
144 
145  // Check if tile is at the lower boundary in lower z direction
146  if (bx.smallEnd(2) != klo) { continue; }
147 
148  // Make a slab
149  bx.makeSlab(2,klo);
150 
151  // Allocate pinned buffers for each box
152  noahmp_input_tmp[idb] = std::make_unique<FArrayBox>(bx, NoahmpInputComp::NumComps , The_Pinned_Arena());
153  noahmp_output_tmp[idb] = std::make_unique<FArrayBox>(bx, NoahmpOutputComp::NumComps, The_Pinned_Arena());
154 
155  // Get reference to the noahmpio object
156  NoahmpIO_type* noahmpio = &noahmpio_vect[idb];
157 
158  // Pass idb context to noahmpio
159  noahmpio->blkid = idb;
160 
161  // Pass level context to noahmpio
162  noahmpio->level = lev;
163 
164  // Initialize scalar values
165  noahmpio->ScalarInitDefault();
166 
167  // Store the rank of process for noahmp
168  noahmpio->rank = ParallelDescriptor::MyProc();
169 
170  // Store parallel communicator for noahmp
171  noahmpio->comm = MPI_Comm_c2f(ParallelDescriptor::Communicator());
172 
173  // Read namelist.erf file. This file contains
174  // noahmpio specific parameters and is read by
175  // the Fortran side of the implementation.
176  noahmpio->ReadNamelist();
177 
178  // Read the headers from the NetCDF land file. This is also
179  // implemented on the Fortran side of things currently.
180  noahmpio->ReadLandHeader();
181 
182  // Extract tile bounds and set them to their corresponding
183  // noahmpio variables. At present we will set all the variables
184  // corresponding to domain, memory, and tile to the same bounds.
185  // This will be changed later if we want to do special memory
186  // management for expensive use cases.
187  noahmpio->xstart = bx.smallEnd(0);
188  noahmpio->xend = bx.bigEnd(0);
189  noahmpio->ystart = bx.smallEnd(1);
190  noahmpio->yend = bx.bigEnd(1);
191 
192  // Domain bounds
193  noahmpio->ids = noahmpio->xstart;
194  noahmpio->ide = noahmpio->xend;
195  noahmpio->jds = noahmpio->ystart;
196  noahmpio->jde = noahmpio->yend;
197  noahmpio->kds = 1;
198  noahmpio->kde = 2;
199 
200  // Tile bounds
201  noahmpio->its = noahmpio->xstart;
202  noahmpio->ite = noahmpio->xend;
203  noahmpio->jts = noahmpio->ystart;
204  noahmpio->jte = noahmpio->yend;
205  noahmpio->kts = 1;
206  noahmpio->kte = 2;
207 
208  // Memory bounds
209  noahmpio->ims = noahmpio->xstart;
210  noahmpio->ime = noahmpio->xend;
211  noahmpio->jms = noahmpio->ystart;
212  noahmpio->jme = noahmpio->yend;
213  noahmpio->kms = 1;
214  noahmpio->kme = 2;
215 
216  // This procedure allocates memory in Fortran for IO variables
217  // using bounds that are set above and read from namelist.erf
218  // and headers from the NetCDF land file
219  noahmpio->VarInitDefault();
220 
221  // This reads NoahmpTable.TBL file which is another input file
222  // we need to set some IO variables.
223  noahmpio->ReadTable();
224 
225  // Read and initialize data from the NetCDF land file.
226  noahmpio->ReadLandMain();
227 
228  // Compute additional initial values that were not supplied
229  // by the NetCDF land file.
230  noahmpio->InitMain();
231 
232  // Write initial plotfile for land with the tag 0
233  Print() << "Noah-MP writing lnd.nc file at lev: " << lev << std::endl;
234  noahmpio->WriteLand(0);
235  }
236 
237  // Broadcast DTBL and the initial substep counter to every rank so the firing
238  // decision in Advance_With_State is identical everywhere. Land-free ranks use
239  // sentinels that lose the max-reduction to any real value.
240  m_dtbl = noahmpio_vect.empty() ? std::numeric_limits<Real>::lowest()
241  : static_cast<Real>(noahmpio_vect[0].DTBL);
242  m_itimestep = noahmpio_vect.empty() ? std::numeric_limits<int>::lowest()
243  : noahmpio_vect[0].itimestep;
244  ParallelDescriptor::ReduceRealMax(m_dtbl);
245  ParallelDescriptor::ReduceIntMax(m_itimestep);
246 
247  // Guard against a degenerate decomposition in which no rank owns a land box.
250 
251  Print() << "Noah-MP initialization completed" << std::endl;
252 
253 };
ParmParse pp("prob")
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
int khi_lsm
Definition: ERF_NOAHMP.H:277
int m_plot_int_1
Definition: ERF_NOAHMP.H:299
amrex::Vector< std::string > LsmDataName
Definition: ERF_NOAHMP.H:253
amrex::Vector< int > LsmDataMap
Definition: ERF_NOAHMP.H:247
int m_lsm_data_size
Definition: ERF_NOAHMP.H:241
amrex::Geometry m_lsm_geom
Definition: ERF_NOAHMP.H:262
int m_nz_lsm
Definition: ERF_NOAHMP.H:280
int m_lsm_flux_size
Definition: ERF_NOAHMP.H:244
amrex::Vector< int > LsmFluxMap
Definition: ERF_NOAHMP.H:250
amrex::Vector< std::string > LsmFluxName
Definition: ERF_NOAHMP.H:256
amrex::Real m_dz_lsm
Definition: ERF_NOAHMP.H:283
amrex::Real m_dt
Definition: ERF_NOAHMP.H:265
@ sw_flux_dn_dif_nir
Definition: ERF_NOAHMP.H:37
@ sw_flux_dn_dir_vis
Definition: ERF_NOAHMP.H:34
@ sw_flux_dn_dir_nir
Definition: ERF_NOAHMP.H:35
@ NumVars
Definition: ERF_NOAHMP.H:39
@ sw_flux_dn_dif_vis
Definition: ERF_NOAHMP.H:36
@ ng
Definition: ERF_Morrison.H:48
@ NumComps
Definition: ERF_NOAHMP.H:65
@ NumComps
Definition: ERF_NOAHMP.H:81
Here is the call graph for this function:

◆ Lsm_Data_Ptr()

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

Reimplemented from NullSurf.

128  {
129  int lsmIdx = LsmDataMap[varIdx];
130  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_data_size && lsmIdx>=0);
131  return lsm_fab_data[lsmIdx].get();
132  }
Here is the call graph for this function:

◆ Lsm_Data_Size()

int NOAHMP::Lsm_Data_Size ( )
inlineoverridevirtual

Reimplemented from NullSurf.

149 { return NOAHMP::m_lsm_data_size; }

◆ Lsm_DataIndex()

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

Reimplemented from NullSurf.

167  {
168  int varIdx = -1;
169  std::string lc_varname = amrex::toLower(varname);
170  for (int idx(0); idx<LsmData_NOAHMP::NumVars; ++idx) {
171  if (lc_varname == amrex::toLower(LsmDataName[idx])) {
172  varIdx = idx;
173  }
174  }
175  return varIdx;
176  }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:287
Here is the call graph for this function:

◆ Lsm_DataName()

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

Reimplemented from NullSurf.

158  {
159  int lsmIdx = LsmDataMap[varIdx];
160  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_data_size && lsmIdx>=0);
161  return LsmDataName[lsmIdx];
162  }
Here is the call graph for this function:

◆ Lsm_Flux_Ptr()

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

Reimplemented from NullSurf.

137  {
138  int lsmIdx = LsmFluxMap[varIdx];
139  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_flux_size && lsmIdx>=0);
140  return lsm_fab_flux[lsmIdx].get();
141  }
Here is the call graph for this function:

◆ Lsm_Flux_Size()

int NOAHMP::Lsm_Flux_Size ( )
inlineoverridevirtual

Reimplemented from NullSurf.

153 { return NOAHMP::m_lsm_flux_size; }

◆ Lsm_FluxIndex()

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

Reimplemented from NullSurf.

190  {
191  int varIdx = -1;
192  std::string lc_varname = amrex::toLower(varname);
193  for (int idx(0); idx<LsmFlux_NOAHMP::NumVars; ++idx) {
194  if (lc_varname == amrex::toLower(LsmFluxName[idx])) {
195  varIdx = idx;
196  }
197  }
198  return varIdx;
199  }
Here is the call graph for this function:

◆ Lsm_FluxName()

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

Reimplemented from NullSurf.

181  {
182  int lsmIdx = LsmFluxMap[varIdx];
183  AMREX_ALWAYS_ASSERT(lsmIdx < NOAHMP::m_lsm_flux_size && lsmIdx>=0);
184  return LsmFluxName[lsmIdx];
185  }
Here is the call graph for this function:

◆ Lsm_Geom()

amrex::Geometry NOAHMP::Lsm_Geom ( )
inlineoverridevirtual

Reimplemented from NullSurf.

145 { return m_lsm_geom; }

◆ Plot_Landfile()

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

Reimplemented from NullSurf.

257 {
258  for (NoahmpIO_type &noahmpio : noahmpio_vect) {
259  noahmpio.WriteLand(nstep);
260  }
261 }

◆ Read_Lsm_Restart()

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

Reimplemented from NullSurf.

233  {
234  for (NoahmpIO_type& noahmpio : noahmpio_vect) {
235  noahmpio.ReadRestart(dir);
236  }
237  }

◆ Set_LSM_Step()

void NOAHMP::Set_LSM_Step ( int  step)
inlineoverridevirtual

Reimplemented from NullSurf.

212  {
213  m_itimestep = step;
214  for (auto& noahmpio : noahmpio_vect) {
215  noahmpio.itimestep = step;
216  }
217  }

◆ Write_Lsm_Restart()

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

Reimplemented from NullSurf.

225  {
226  for (const NoahmpIO_type& noahmpio : noahmpio_vect) {
227  const_cast<NoahmpIO_type&>(noahmpio).WriteRestart(dir);
228  }
229  }

Member Data Documentation

◆ khi_lsm

int NOAHMP::khi_lsm
private

◆ lsm_fab_data

amrex::Array<FabPtr, LsmData_NOAHMP::NumVars> 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().

◆ 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_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_itimestep

int NOAHMP::m_itimestep = 0
private

Referenced by Get_LSM_Step(), and Set_LSM_Step().

◆ m_lsm_data_size

int NOAHMP::m_lsm_data_size = LsmData_NOAHMP::NumVars
private

Referenced by Lsm_Data_Size().

◆ 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_nz_lsm

int NOAHMP::m_nz_lsm = 1
private

◆ m_plot_int_1

int NOAHMP::m_plot_int_1 = -1
private

◆ 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

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