ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SurfaceModel.H
Go to the documentation of this file.
1 #ifndef ERF_SURFACEMODEL_H
2 #define ERF_SURFACEMODEL_H
3 
4 #include "AMReX_Geometry.H"
5 #include "AMReX_ParmParse.H"
6 #include "AMReX_FArrayBox.H"
7 #include "AMReX_IntVect.H"
8 #include "AMReX_MFIter.H"
9 #include "AMReX_MultiFab.H"
10 #include "AMReX_FillPatchUtil.H"
11 #include "AMReX_GpuLaunch.H"
12 
13 #include <ERF_DataStruct.H>
14 
15 enum SurfaceModelType { LAND = 0, URBAN = 1};
16 
18 
19 /**
20  * @brief Non-owning views of surface fluxes for one tile.
21  */
23  amrex::Array4<const amrex::Real> tau13;
24  amrex::Array4<const amrex::Real> tau23;
25  amrex::Array4<const amrex::Real> t_flux;
26  amrex::Array4<const amrex::Real> q_flux;
27 };
28 
29 /**
30  * @brief Interface between ERF and land-surface and urban models.
31  *
32  * SurfaceModel collects data and fluxes from the LSM and urban models,
33  * performs the land-urban weight averaging and exposes the resulting fields
34  * for use by ERF boundary-condition and physics components.
35  *
36  * Models may register data and mappings independently, without requiring a
37  * fixed ordering or one-to-one correspondence between their fields.
38  *
39  * Model-specific field names can also be registered under a common name for
40  * consumers such as RRTMGP and MOST.
41  *
42  * This class supports its own checkpoint state, ensuring the mappings are
43  * restored correctly on restart. This class also provides a surface plotfile
44  * for weight-averaged model data for the fields registered.
45  */
47 {
48 public:
49 
50  /**
51  * @brief Constructs a surface-model interface for the supplied AMR levels.
52  *
53  * @param nlevs Number of AMR levels initially available.
54  * @param ba Cell-centered box arrays for each level.
55  * @param geom Geometry for each level.
56  * @param dm Distribution mappings for each level.
57  * @param solverChoice ERF solver configuration.
58  * @param lmask_lev Land-mask data for each level.
59  */
60  explicit SurfaceModel (int nlevs,
61  const amrex::Vector<amrex::BoxArray> &ba,
62  const amrex::Vector<amrex::Geometry> &geom,
63  const amrex::Vector<amrex::DistributionMapping> &dm,
64  const SolverChoice &/*solverChoice*/,
65  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::iMultiFab>>>& /*lmask_lev*/)
66  : m_nlevs(nlevs), m_ba(ba), m_geom(geom), m_dmap(dm) {
67 
69  m_output_fields_registered = {false, false};
70 
71  // set initial fields for each model to none
72  lsm_fields = amrex::Vector<int>(5, -1);
73  urban_fields = amrex::Vector<int>(5, -1);
74  }
75 
76  /**
77  * @brief Initializes storage and boundary data for an AMR level.
78  *
79  * Existing coarser-level data are interpolated when a finer level is
80  * initialized.
81  *
82  * @param lev AMR level to initialize.
83  * @param ba Cell-centered box array for the level.
84  * @param geom Geometry for the level.
85  * @param dm Distribution mapping for the level.
86  * @param lmask_lev Land-mask data used by the level.
87  * @param domain_bcs_type Boundary conditions for interpolation.
88  * @param refRatio Refinement ratios between adjacent levels.
89  */
90  void initialize_for_level (int lev, const amrex::BoxArray &ba, const amrex::Geometry &geom, const amrex::DistributionMapping &dm, const amrex::Vector<std::unique_ptr<amrex::iMultiFab>>& lmask_lev, const amrex::Vector <amrex::BCRec> &domain_bcs_type, const amrex::Vector<amrex::IntVect> &refRatio)
91  {
92  if (lev >= m_nlevs) { resize_levels(lev+1); }
93 
94  m_ba[lev] = ba;
95  m_geom[lev] = geom;
96  m_dmap[lev] = dm;
97 
98  // Create a 2D ba, dm, & ghost cells
99  amrex::BoxList bl2d = ba.boxList();
100  for (auto& b : bl2d) {
101  b.setRange(2, 0);
102  }
103  m_ba2d[lev] = amrex::BoxArray(std::move(bl2d));
104 
105  amrex::RealBox dom2d = geom.ProbDomain();
106  dom2d.setHi(2, geom.CellSize(2));
107  m_geom2d[lev].define(makeSlab(m_geom[lev].Domain(), 2, 0), dom2d, geom.Coord(), geom.isPeriodic());
108 
109  m_lmask[lev] = lmask_lev[0].get();
110 
111  weighted_lsm_data_lev[lev].clear();
112  weighted_urban_data_lev[lev].clear();
113 
114  u_star[lev].reset();
115  t_star[lev].reset();
116  q_star[lev].reset();
117  t_surf[lev].reset();
118  wavg[lev].reset();
119  if (m_surface_outputs_requested[lev]) {
121  }
123 
124  // Recreate registered fields on the current level layout. This is also
125  // needed when an existing AMR level is remade with a new grid layout.
126  for (int field = 0; field < static_cast<int>(fields.size()); ++field) {
127  fields[field][lev].reset();
128  }
129  // Keep each map's consumer kind: a map active only for one output must not
130  // become persistent because a regrid happened while it was active
131  for (const auto& entry : fieldmap) {
132  if (entry.second.active) {
133  activate_field_map(entry.first, entry.second.persistent_consumer);
134  }
135  }
136  for (auto& entry : radiation_input_map) {
137  entry.second.weighted[lev].reset();
138  }
139 
140  // Cached radiation fields point into the registered storage above.
141  // Rebuild the cache when this level's fields have been replaced.
142  rad_fields[lev].clear();
143  rad_output_fields[lev].clear();
144 
145  // Interpolate the new finer level using coarse data
146  if (lev > 0) {
147  amrex::Real time_for_fp = zero; // This is not actually used
148  amrex::Vector<amrex::Real> ftime = {time_for_fp, time_for_fp};
149  amrex::Vector<amrex::Real> ctime = {time_for_fp, time_for_fp};
150  amrex::IntVect ng_od(0, 0, 0); // ng outside domain
151  amrex::Interpolater* mapper = &amrex::cell_cons_interp;
152  amrex::Vector<amrex::MultiFab*> fmf;
153  amrex::Vector<amrex::MultiFab*> cmf;
154  if (u_star[lev] != nullptr && u_star[lev-1] != nullptr) {
155  amrex::InterpFromCoarseLevel(*u_star[lev], u_star[lev-1]->nGrowVect(), ng_od,
156  *u_star[lev-1], 0, 0, 2,
157  m_geom[lev-1], m_geom[lev],
158  refRatio[lev-1], &amrex::cell_cons_interp,
159  domain_bcs_type, BCVars::cons_bc);
160  amrex::InterpFromCoarseLevel(*t_star[lev], t_star[lev-1]->nGrowVect(), ng_od,
161  *t_star[lev-1], 0, 0, 1,
162  m_geom[lev-1], m_geom[lev],
163  refRatio[lev-1], &amrex::cell_cons_interp,
164  domain_bcs_type, BCVars::cons_bc);
165  amrex::InterpFromCoarseLevel(*q_star[lev], q_star[lev-1]->nGrowVect(), ng_od,
166  *q_star[lev-1], 0, 0, 1,
167  m_geom[lev-1], m_geom[lev],
168  refRatio[lev-1], &amrex::cell_cons_interp,
169  domain_bcs_type, BCVars::cons_bc);
170  amrex::InterpFromCoarseLevel(*t_surf[lev], t_surf[lev-1]->nGrowVect(), ng_od,
171  *t_surf[lev-1], 0, 0, 1,
172  m_geom[lev-1], m_geom[lev],
173  refRatio[lev-1], &amrex::cell_cons_interp,
174  domain_bcs_type, BCVars::cons_bc);
175 
176  fmf = {u_star[lev ].get(), u_star[lev ].get()};
177  cmf = {u_star[lev-1].get(), u_star[lev-1].get()};
178  amrex::FillPatchTwoLevels(*u_star[lev].get(), u_star[lev]->nGrowVect(), ng_od,
179  time_for_fp, cmf, ctime, fmf, ftime,
180  0, 0, 2, m_geom[lev-1], m_geom[lev],
181  refRatio[lev-1], mapper, domain_bcs_type,
183  fmf = {t_star[lev ].get(), t_star[lev ].get()};
184  cmf = {t_star[lev-1].get(), t_star[lev-1].get()};
185  amrex::FillPatchTwoLevels(*t_star[lev].get(), t_star[lev]->nGrowVect(), ng_od,
186  time_for_fp, cmf, ctime, fmf, ftime,
187  0, 0, 1, m_geom[lev-1], m_geom[lev],
188  refRatio[lev-1], mapper, domain_bcs_type,
190  fmf = {q_star[lev ].get(), q_star[lev ].get()};
191  cmf = {q_star[lev-1].get(), q_star[lev-1].get()};
192  amrex::FillPatchTwoLevels(*q_star[lev].get(), q_star[lev]->nGrowVect(), ng_od,
193  time_for_fp, cmf, ctime, fmf, ftime,
194  0, 0, 1, m_geom[lev-1], m_geom[lev],
195  refRatio[lev-1], mapper, domain_bcs_type,
197  fmf = {t_surf[lev ].get(), t_surf[lev ].get()};
198  cmf = {t_surf[lev-1].get(), t_surf[lev-1].get()};
199  amrex::FillPatchTwoLevels(*t_surf[lev].get(), t_surf[lev]->nGrowVect(), ng_od,
200  time_for_fp, cmf, ctime, fmf, ftime,
201  0, 0, 1, m_geom[lev-1], m_geom[lev],
202  refRatio[lev-1], mapper, domain_bcs_type,
204  }
205 
206  for (int field = 0; field < static_cast<int>(fields.size()); ++field) {
207  if (fields[field][lev] == nullptr || fields[field][lev-1] == nullptr) { continue; }
208  amrex::IntVect ngv = fields[field][lev-1]->nGrowVect(); ngv[2] = 0;
209  amrex::InterpFromCoarseLevel(*fields[field][lev], ngv, ng_od,
210  *fields[field][lev-1], 0, 0, 1,
211  m_geom[lev-1], m_geom[lev],
212  refRatio[lev-1], &amrex::cell_cons_interp,
213  domain_bcs_type, BCVars::cons_bc);
214  fmf = {fields[field][lev ].get(), fields[field][lev ].get()};
215  cmf = {fields[field][lev-1].get(), fields[field][lev-1].get()};
216  amrex::FillPatchTwoLevels(*fields[field][lev].get(), ngv, ng_od,
217  time_for_fp, cmf, ctime, fmf, ftime,
218  0, 0, 1, m_geom[lev-1], m_geom[lev],
219  refRatio[lev-1], mapper, domain_bcs_type,
221  }
222  }
223  }
224 
225  /**
226  * @brief Removes an AMR level, and every level above it, from the surface model.
227  *
228  * Called when ERF destroys a level during regridding so that m_nlevs tracks the
229  * levels that actually exist. Otherwise the checkpoint and other level loops
230  * would still visit the destroyed levels and their stale provider pointers.
231  *
232  * @param lev AMR level being destroyed.
233  */
234  void clear_level (int lev)
235  {
236  if (lev < 0 || lev >= m_nlevs) { return; }
237  resize_levels(lev);
238  }
239 
240  /**
241  * @brief Registers model variables used in weighted averaging.
242  *
243  * @param lev AMR level associated with the data.
244  * @param model_data Pointers to the model variables.
245  * @param data_names Names corresponding to @p model_data.
246  * @param type Whether the data belong to the land or urban model.
247  */
248  void set_model_data (const int lev, const amrex::Vector<amrex::MultiFab*> model_data, const amrex::Vector<std::string>& data_names, SurfaceModelType type)
249  {
250  if (type == SurfaceModelType::LAND) {
251  lsm_data_lev[lev].resize(model_data.size());
252  weighted_lsm_data_lev[lev].clear();
253  weighted_lsm_data_lev[lev].resize(model_data.size());
254  if (lev == 0) {
255  // only set names on first level, since they are the same for all levels
256  m_lsm_names.resize(model_data.size());
257  AMREX_ALWAYS_ASSERT(data_names.size() == model_data.size());
258  for (int i = 0; i < static_cast<int>(data_names.size()); ++i) {
259  m_lsm_names[i] = data_names[i];
260  }
261  }
262 
263  for (int i = 0; i < static_cast<int>(lsm_data_lev[lev].size()); ++i) {
264  AMREX_ALWAYS_ASSERT(model_data[i]);
265  lsm_data_lev[lev][i] = model_data[i];
266  }
267  m_use_land = true;
269  for (auto& fields_at_level : rad_fields) { fields_at_level.clear(); }
270  for (auto& fields_at_level : rad_output_fields) { fields_at_level.clear(); }
271  for (auto& entry : radiation_input_map) {
272  if (lev < static_cast<int>(entry.second.weighted.size())) {
273  entry.second.weighted[lev].reset();
274  }
275  }
276  } else if (type == SurfaceModelType::URBAN) {
277  urban_data_lev[lev].resize(model_data.size());
278  weighted_urban_data_lev[lev].clear();
279  weighted_urban_data_lev[lev].resize(model_data.size());
280  if (lev == 0) {
281  // only set names on first level, since they are the same for all levels
282  m_urban_names.resize(model_data.size());
283  AMREX_ALWAYS_ASSERT(data_names.size() == model_data.size());
284  for (int i = 0; i < static_cast<int>(data_names.size()); ++i) {
285  m_urban_names[i] = data_names[i];
286  }
287  }
288  for (int i = 0; i < static_cast<int>(urban_data_lev[lev].size()); ++i) {
289  AMREX_ALWAYS_ASSERT(model_data[i]);
290  urban_data_lev[lev][i] = model_data[i];
291  }
292  m_use_urban = true;
294  for (auto& fields_at_level : rad_fields) { fields_at_level.clear(); }
295  for (auto& fields_at_level : rad_output_fields) { fields_at_level.clear(); }
296  for (auto& entry : radiation_input_map) {
297  if (lev < static_cast<int>(entry.second.weighted.size())) {
298  entry.second.weighted[lev].reset();
299  }
300  }
301  }
302  }
303 
304  /**
305  * @brief Registers model fluxes as additional weighted-average inputs.
306  *
307  * @param lev AMR level associated with the fluxes.
308  * @param model_fluxes Pointers to the model flux fields.
309  * @param flux_names Names corresponding to @p model_fluxes.
310  * @param type Whether the fluxes belong to the land or urban model.
311  */
312  void set_model_fluxes (const int lev, const amrex::Vector<amrex::MultiFab*> model_fluxes,
313  const amrex::Vector<std::string>& flux_names, SurfaceModelType type)
314  {
315  amrex::Vector<amrex::MultiFab*>* model_data = nullptr;
316  amrex::Vector<std::string>* model_names = nullptr;
317 
318  if (type == SurfaceModelType::LAND) {
319  model_data = &lsm_data_lev[lev];
320  model_names = &m_lsm_names;
321  } else if (type == SurfaceModelType::URBAN) {
322  model_data = &urban_data_lev[lev];
323  model_names = &m_urban_names;
324  }
325 
326  AMREX_ALWAYS_ASSERT(model_data != nullptr);
327  AMREX_ALWAYS_ASSERT(model_names != nullptr);
328  AMREX_ALWAYS_ASSERT(flux_names.size() == model_fluxes.size());
329 
330  const int data_size = static_cast<int>(model_data->size());
331  model_data->resize(data_size + static_cast<int>(model_fluxes.size()));
332  if (lev == 0) {
333  model_names->resize(data_size + static_cast<int>(model_fluxes.size()));
334  }
335 
336  for (int i = 0; i < static_cast<int>(model_fluxes.size()); ++i) {
337  AMREX_ALWAYS_ASSERT(model_fluxes[i]);
338  (*model_data)[data_size + i] = model_fluxes[i];
339  if (lev == 0) {
340  (*model_names)[data_size + i] = flux_names[i];
341  }
342  }
343  }
344 
345  /**
346  * @brief Selects the model fields that participate in weighted averaging.
347  *
348  * When using fluxes, the first five elements map to u-stress, v-stress,
349  * heat flux, vapor flux, and surface temperature. Otherwise, the first
350  * four elements map to ustar, tstar, qstar, and surface temperature. A
351  * field index of -1 skips that field.
352  *
353  * @param type Whether the fields belong to the land or urban model.
354  * @param field_indices Indices of the fields to average.
355  * @param use_fluxes Whether the selected fields are fluxes.
356  */
357  void set_model_fields (SurfaceModelType type, const amrex::Vector<int> &field_indices, const bool use_fluxes = true)
358  {
359  const int nfields = static_cast<int>(field_indices.size());
360  if (!use_fluxes) {
361  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(nfields >= 4, "Must have at least four fields to average (ustar, tstar, qstar, tsurf)");
362  } else {
363  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(nfields >= 5, "Must have at least five fields to average (u-stress, v-stress, hfx, qfx, tsurf)");
364  }
365 
366  // Latch the export mode off the first model that registers, then make sure every
367  // subsequent model agrees: either all of them supply fluxes, or all of them supply
368  // u*, t*, q* directly. Taking the mode from the caller rather than assuming the
369  // default is what makes the non-flux path reachable at all.
370  if (!m_export_fluxes_set) {
371  m_export_fluxes = use_fluxes;
372  m_export_fluxes_set = true;
373  }
375  "All registered surface models must export either fluxes or u*/t*/q*, not a mix");
376 
377  const int nregistered = (type == SurfaceModelType::LAND)
378  ? static_cast<int>(m_lsm_names.size())
379  : static_cast<int>(m_urban_names.size());
380  for (const int field : field_indices) {
382  field == -1 || (field >= 0 && field < nregistered),
383  "Model field index must be -1 or within the registered provider data range");
384  }
385 
386  if (type == SurfaceModelType::LAND) {
387  lsm_fields = amrex::Vector<int>(field_indices);
389  for (auto& fields_at_level : weighted_lsm_data_lev) {
390  fields_at_level.clear();
391  }
392  } else if (type == SurfaceModelType::URBAN) {
393  urban_fields = amrex::Vector<int>(field_indices);
395  for (auto& fields_at_level : weighted_urban_data_lev) {
396  fields_at_level.clear();
397  }
398  }
399  }
400 
401  /**
402  * @brief Applies land and urban weights into separate output fields.
403  *
404  * A null land or urban source is skipped, but both sources cannot be
405  * null. The source fields are not modified and the fields may use
406  * different underlying grids.
407  *
408  * @param lev AMR level whose weights are used.
409  * @param lsm_data Land-model source data to weight.
410  * @param lsm_weighted Destination for weighted land data.
411  * @param urban_data Urban-model source data to weight.
412  * @param urban_weighted Destination for weighted urban data.
413  */
414  void apply_weight_average (int lev, const amrex::MultiFab *lsm_data,
415  amrex::MultiFab *lsm_weighted,
416  const amrex::MultiFab *urban_data,
417  amrex::MultiFab *urban_weighted);
418 
419  /**
420  * @brief Computes land and urban weights and applies them to registered fields.
421  *
422  * @param lev AMR level to update.
423  * @param urban_frac Urban fraction used to compute the weights.
424  */
425  void calculate_weight_average (int lev, amrex::MultiFab* const urban_frac,
426  bool update_derived = true);
427 
428  /**
429  * @brief Returns whether the interface exports fluxes rather than MOST variables.
430  * @return True when weighted outputs are fluxes.
431  */
432  bool are_fluxes () { return m_export_fluxes; }
433 
434  /**
435  * @brief Enables and materializes the surface outputs consumed by ERF.
436  */
437  void request_surface_outputs (const bool persistent = true)
438  {
440  for (int lev = 0; lev < m_nlevs; ++lev) {
441  m_surface_outputs_requested[lev] = true;
443  }
444  }
445 
446  /**
447  * @brief Enables blended surface outputs needed by the SurfaceLayer.
448  */
450  {
452  for (int lev = 0; lev < m_nlevs; ++lev) {
454  m_surface_outputs_requested[lev] = true;
456  }
457  }
458  }
459 
460  /**
461  * @brief Marks the registered surface fields as filled by an actual model advance.
462  */
464 
465  /**
466  * @brief Returns whether the surface models have advanced at least once.
467  * @return False until the first advance, while the registered fields still hold their
468  * initial values rather than anything the models computed.
469  */
470  bool fields_are_valid () const { return m_fields_are_valid; }
471 
472  /**
473  * @brief Returns the weighted horizontal momentum output for a level.
474  * @param lev AMR level to query.
475  * @return Pointer to the weighted u-star or momentum-flux field.
476  */
477  amrex::MultiFab* get_ustar (const int& lev) {
478  return u_star[lev].get();
479  }
480 
481  /**
482  * @brief Returns the weighted thermal output for a level.
483  * @param lev AMR level to query.
484  * @return Pointer to the weighted t-star or heat-flux field.
485  */
486  amrex::MultiFab* get_tstar (const int& lev) {
487  return t_star[lev].get();
488  }
489 
490  /**
491  * @brief Returns the weighted moisture output for a level.
492  * @param lev AMR level to query.
493  * @return Pointer to the weighted q-star or vapor-flux field.
494  */
495  amrex::MultiFab* get_qstar (const int& lev) {
496  return q_star[lev].get();
497  }
498 
499  /**
500  * @brief Returns the weighted surface-temperature output for a level.
501  * @param lev AMR level to query.
502  * @return Pointer to the weighted surface-temperature field.
503  */
504  amrex::MultiFab* get_tsurf (const int& lev) {
505  return t_surf[lev].get();
506  }
507 
508  /**
509  * @brief Returns provider or blended surface-flux views for one tile.
510  * @param lev AMR level to query.
511  * @param mfi Tile whose flux arrays are requested.
512  * @return Read-only flux views selected for the level's provider mode.
513  */
514  SurfaceFluxView get_surface_flux_view (const int lev, const amrex::MFIter& mfi) const
515  {
517 
518  const SurfaceProviderMode mode = m_provider_mode[lev];
519  if (mode == SurfaceProviderMode::Both) {
520  AMREX_ALWAYS_ASSERT(u_star[lev] != nullptr);
521  AMREX_ALWAYS_ASSERT(t_star[lev] != nullptr);
522  AMREX_ALWAYS_ASSERT(q_star[lev] != nullptr);
523  return {u_star[lev]->const_array(mfi, 0),
524  u_star[lev]->const_array(mfi, 1),
525  t_star[lev]->const_array(mfi),
526  q_star[lev]->const_array(mfi)};
527  }
528 
529  const auto& provider_fields = (mode == SurfaceProviderMode::LandOnly)
531  const auto& provider_data = (mode == SurfaceProviderMode::LandOnly)
532  ? lsm_data_lev[lev] : urban_data_lev[lev];
533  auto get_provider_field = [&] (const int field) -> amrex::Array4<const amrex::Real> {
534  if (field >= static_cast<int>(provider_fields.size())) {
535  return {};
536  }
537  const int index = provider_fields[field];
538  if (index < 0 || index >= static_cast<int>(provider_data.size()) ||
539  provider_data[index] == nullptr) {
540  return {};
541  }
542  return provider_data[index]->const_array(mfi);
543  };
544 
545  return {get_provider_field(0), get_provider_field(1),
546  get_provider_field(2), get_provider_field(3)};
547  }
548 
549  /**
550  * @brief Returns weighted data for a selected model field.
551  * @param lev AMR level to query.
552  * @param type Provider type owning the field.
553  * @param field_idx Provider field index.
554  * @return Weighted field or the source field for a single provider, or nullptr if it has not been selected.
555  */
556  const amrex::MultiFab* get_weighted_model_data (const int lev,
557  SurfaceModelType type,
558  const int field_idx) const {
559  const SurfaceProviderMode mode = m_provider_mode[lev];
560  const bool single_provider =
563  if (single_provider) {
564  const auto& selected = (type == SurfaceModelType::LAND)
566  const int first_output_field = m_export_fluxes ? 5 : 4;
567  bool is_weighted_field = false;
568  for (int field = first_output_field;
569  field < static_cast<int>(selected.size()); ++field) {
570  if (selected[field] == field_idx) {
571  is_weighted_field = true;
572  break;
573  }
574  }
575  if (!is_weighted_field) {
576  return nullptr;
577  }
578 
579  const auto& source = (type == SurfaceModelType::LAND)
580  ? lsm_data_lev[lev] : urban_data_lev[lev];
581  if (field_idx < 0 || field_idx >= static_cast<int>(source.size())) {
582  return nullptr;
583  }
584  return source[field_idx];
585  }
586 
587  const auto& weighted = (type == SurfaceModelType::LAND)
589  if (field_idx < 0 || field_idx >= static_cast<int>(weighted.size())) {
590  return nullptr;
591  }
592  return weighted[field_idx].get();
593  }
594 
595  /**
596  * @brief Returns the land and urban weighting factors for a level.
597  * @param lev AMR level to query.
598  * @return Pointer to the weighting-factor field.
599  */
600  amrex::MultiFab* get_wavg_factors (const int &lev) {
602  return wavg[lev].get();
603  }
604 
605  /**
606  * @brief Activates all registered mapped fields for an output consumer.
607  */
608  void activate_all_field_maps (const bool persistent = true);
609 
610  /**
611  * @brief Writes registered surface-model fields to plotfile output.
612  * @param finest_lev Finest AMR level to write.
613  * @param time Simulation time associated with the output.
614  * @param plot_prefix Output plotfile prefix.
615  * @param level_steps Number of steps represented at each level.
616  * @param ref_ratio Refinement ratios between adjacent levels.
617  */
618  void write_output (const int &finest_lev, const amrex::Real &time, const std::string &plot_prefix, const amrex::Vector<int> &level_steps, const amrex::Vector<amrex::IntVect> &ref_ratio);
619 
620  /**
621  * @brief Registers a field map using land and urban field indices.
622  * @param name Common name used to retrieve the mapped field.
623  * @param lsm_urb_map Pair of land and urban field indices.
624  * @param fill_boundary Whether to fill mapped-field boundaries.
625  */
626  void register_field_map (std::string name, const std::pair<int, int> &lsm_urb_map, bool fill_boundary=false);
627 
628  /**
629  * @brief Registers a field map using per-level land and urban pointers.
630  * @param name Common name used to retrieve the mapped field.
631  * @param lsm_lev_mf Land-model fields, indexed by AMR level.
632  * @param urb_lev_mf Urban-model fields, indexed by AMR level.
633  * @param fill_boundary Whether to fill mapped-field boundaries.
634  */
635  void register_field_map (std::string name, amrex::Vector<amrex::MultiFab*> &lsm_lev_mf, amrex::Vector<amrex::MultiFab*> &urb_lev_mf, bool fill_boundary=false);
636 
637  /**
638  * @brief Updates a pointer-based field mapping for one level.
639  * @param name Common name of the mapped field.
640  * @param lev AMR level to update.
641  * @param lsm_mf Land-model field pointer, or nullptr.
642  * @param urban_mf Urban-model field pointer, or nullptr.
643  */
644  void set_field_map_pointers (const std::string& name, int lev,
645  amrex::MultiFab* lsm_mf, amrex::MultiFab* urban_mf);
646 
647  /**
648  * @brief Registers a canonical radiation input mapping.
649  * @param name Canonical radiation input name.
650  * @param lsm_urb_map Pair of land and urban model field indices.
651  */
652  void register_radiation_input (const std::string& name,
653  const std::pair<int, int>& lsm_urb_map);
654 
655  /**
656  * @brief Registers canonical radiation input mappings.
657  * @param input_map Canonical names mapped to land and urban indices.
658  */
660  const std::unordered_map<std::string, std::pair<int, int>>& input_map);
661 
662  /**
663  * @brief Registers a canonical radiation output mapping.
664  * @param name Canonical radiation output name.
665  * @param lsm_urb_map Pair of land and urban model field indices.
666  */
667  void register_radiation_output (const std::string& name,
668  const std::pair<int, int>& lsm_urb_map);
669 
670  /**
671  * @brief Registers canonical radiation output mappings.
672  * @param output_map Canonical names mapped to land and urban indices.
673  */
675  const std::unordered_map<std::string, std::pair<int, int>>& output_map);
676 
677  /**
678  * @brief Retrieves a registered field by its common name.
679  * @param name Registered field name.
680  * @param lev AMR level to query.
681  * @return Pointer to the registered field, or nullptr if it is unknown.
682  */
683  amrex::MultiFab* get_field (const std::string &name, int lev = 0) {
684  if (auto field = fieldmap.find(name); field != fieldmap.end()) {
686  return fields[field->second.mf_ind][lev].get();
687  } else {
688  return nullptr;
689  }
690  }
691 
692  /**
693  * @brief Returns fields registered under the RRTMGP radiation names.
694  *
695  * The resulting map is cached after the first call for reuse on subsequent timesteps.
696  * When an expected field is missing, it is marked nullptr for the RRTMGP implementation
697  * to apply its fallback values.
698  *
699  * @param lev AMR level to query.
700  * @return Radiation fields in the order expected by RRTMGP.
701  */
702  const amrex::Vector<const amrex::MultiFab*> get_radiation_fields (int lev = 0) {
703  // check if we need to build the radiation list (for first time step,)
704  if (rad_fields[lev].size() == 0) {
706  }
707  return rad_fields[lev];
708  }
709 
710  /**
711  * @brief Returns canonical radiation output destinations for one level.
712  * @param lev AMR level to query.
713  * @return One destination per canonical radiation output.
714  */
715  const amrex::Vector<amrex::MultiFab*> get_radiation_output_fields (int lev = 0);
716 
717  /**
718  * @brief Returns the destination of one canonical radiation output by name.
719  * @param lev AMR level to query.
720  * @param name Canonical radiation output name (aborts on an unknown name).
721  * @return The registered destination, or nullptr when none is registered.
722  */
723  amrex::MultiFab* get_radiation_output_field (int lev, const std::string& name);
724 
725  /**
726  * @brief Distributes updated canonical radiation outputs to other providers.
727  * @param lev AMR level to update.
728  */
729  void distribute_radiation_outputs (int lev);
730 
731  /**
732  * @brief Distributes one updated canonical radiation output to other providers.
733  * @param lev AMR level to update.
734  * @param output_index Index in the canonical radiation output list.
735  */
736  void distribute_radiation_output (int lev, int output_index);
737 
738  /**
739  * @brief Advances an input stream to the next line.
740  *
741  * taken from ERF_Checkpoint, reuse?
742  *
743  * @param is Input stream to advance.
744  */
745  static void GotoNextLine (std::istream& is);
746 
747  /**
748  * @brief Writes surface-model state to a checkpoint file.
749  * @param checkpointname Checkpoint file name.
750  */
751  void WriteCheckpoint (const std::string &checkpointname);
752 
753  /**
754  * @brief Restores surface-model state from a checkpoint file.
755  * @param checkpointname Checkpoint file name.
756  */
757  void ReadCheckpoint (const std::string &checkpointname);
758 
759  /**
760  * @brief Validates the layout contract for a canonical radiation output.
761  * @param lev AMR level associated with the destination.
762  * @param mf Radiation output destination to validate.
763  */
764  void validate_radiation_output_layout (int lev, const amrex::MultiFab* mf) const;
765 
766  /**
767  * @brief Computes simple land and urban weights from the urban fraction.
768  * @param lev AMR level to update.
769  * @param urban_frac Urban fraction used to compute the weights.
770  */
771  void calculate_simple_average (int lev, amrex::MultiFab* const urban_frac);
772 
773  /**
774  * @brief Builds the ordered radiation-field list for one AMR level.
775  * @param lev AMR level to update.
776  */
777  void build_radiation_fieldlist (int lev) {
778  amrex::Print() << " --- building radiation field list" << std::endl;
779 
780  // loop over fields and check against names of radiation variables
781  for (int li = 0; li < static_cast<int>(radnames.size()); ++li) {
782  amrex::Print() << " - Checking for radiation variable '" << radnames[li] << "'" << std::endl;
783 
784  amrex::MultiFab* mf = nullptr;
785  auto rad_it = radiation_input_map.find(radnames[li]);
786  if (rad_it != radiation_input_map.end()) {
787  const int land_idx = rad_it->second.map.first;
788  const int urban_idx = rad_it->second.map.second;
789  const SurfaceProviderMode mode = m_provider_mode[lev];
790  const bool use_land = mode == SurfaceProviderMode::LandOnly ||
792  const bool use_urban = mode == SurfaceProviderMode::UrbanOnly ||
794  const bool valid_land = use_land && land_idx >= 0 &&
795  lev < static_cast<int>(lsm_data_lev.size()) &&
796  land_idx < static_cast<int>(lsm_data_lev[lev].size()) &&
797  lsm_data_lev[lev][land_idx] != nullptr;
798  const bool valid_urban = use_urban && urban_idx >= 0 &&
799  lev < static_cast<int>(urban_data_lev.size()) &&
800  urban_idx < static_cast<int>(urban_data_lev[lev].size()) &&
801  urban_data_lev[lev][urban_idx] != nullptr;
802  if (valid_land && valid_urban) {
803  if (!rad_it->second.weighted[lev]) {
804  rad_it->second.weighted[lev] = std::make_unique<amrex::MultiFab>(
805  m_ba2d[lev], m_dmap[lev], 1, amrex::IntVect(1,1,0));
806  }
807  auto& weighted = *rad_it->second.weighted[lev];
808  const auto& land = *lsm_data_lev[lev][land_idx];
809  const auto& urban = *urban_data_lev[lev][urban_idx];
810  for (amrex::MFIter mfi(weighted); mfi.isValid(); ++mfi) {
811  const amrex::Box bx = mfi.tilebox();
812  const auto weights = wavg[lev]->const_array(mfi);
813  const auto land_arr = land.const_array(mfi);
814  const auto urban_arr = urban.const_array(mfi);
815  // LSM surface fields may be stored at k <= 0; use the top valid LSM
816  // plane, which matches k=0 when the LSM keeps those fields synchronized
817  // at the surface (such as SLM). Urban surface fields are stored at k=0.
818  const int land_k = land.box(mfi.index()).bigEnd(2);
819  const int urban_k = urban.box(mfi.index()).smallEnd(2);
820  auto output = weighted.array(mfi);
821  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
822  output(i,j,k) = land_arr(i,j,land_k) *
823  weights(i,j,0,SurfaceModelType::LAND) +
824  urban_arr(i,j,urban_k) *
825  weights(i,j,0,SurfaceModelType::URBAN);
826  });
827  }
828  weighted.FillBoundary(m_geom[lev].periodicity());
829  mf = rad_it->second.weighted[lev].get();
830  } else if (valid_land) {
831  mf = lsm_data_lev[lev][land_idx];
832  } else if (valid_urban) {
833  mf = urban_data_lev[lev][urban_idx];
834  }
835  }
836  if (mf) {
837  rad_fields[lev].push_back(mf);
838  } else {
839  amrex::Print() << " - WARNING: did not find radiation variable, setting to null to use default RRTMGP value!" << std::endl;
840  rad_fields[lev].push_back(nullptr);
841  }
842  }
844  static_cast<int>(rad_fields[lev].size()) == static_cast<int>(radnames.size()),
845  "Did not find all radiation fields");
846  }
847 
848  /**
849  * @brief Applies the current land and urban weights to selected model fields.
850  * @param lev AMR level to update.
851  * @param urban_frac Urban fraction used to compute the weights.
852  */
853  void weight_average_fields (int lev, amrex::MultiFab* const /*urban_frac*/);
854 
855  /**
856  * @brief Activates a mapped field and allocates its storage on all levels.
857  * @param name Common mapped field name.
858  */
859  void activate_field_map (const std::string& name, const bool persistent = true);
860 
861  /**
862  * @brief Disables and releases mapped fields used only by the last output.
863  */
865 
866  /**
867  * @brief Checks whether a model field participates in a registered mapping.
868  * @param lev AMR level to query.
869  * @param type Land or urban model owning the field.
870  * @param field_idx Index of the model field.
871  * @param mf Field pointer to test.
872  * @return True when the field is part of a registered mapping.
873  */
874  bool is_field_mapped (int lev, SurfaceModelType type, int field_idx,
875  const amrex::MultiFab* mf) const;
876 
877  /**
878  * @brief Writes a weighted copy of a model field.
879  * @param lev AMR level whose weights are used.
880  * @param source Model-owned source field.
881  * @param weighted SurfaceModel-owned destination field.
882  * @param type Provider type owning the source field.
883  */
884  void weight_model_field (int lev, const amrex::MultiFab* source,
885  amrex::MultiFab* weighted, SurfaceModelType type);
886 
887 private:
888 
889  /**
890  * @brief Sets the number of AMR levels and resizes all per-level storage to match.
891  *
892  * Shared by the constructor, initialize_for_level and clear_level so that every
893  * per-level member is grown and shrunk together. New levels start empty.
894  *
895  * @param nlevs New number of AMR levels.
896  */
897  void resize_levels (int nlevs)
898  {
899  m_nlevs = nlevs;
900 
901  u_star.resize(m_nlevs);
902  t_star.resize(m_nlevs);
903  q_star.resize(m_nlevs);
904  t_surf.resize(m_nlevs);
905 
906  wavg.resize(m_nlevs);
908 
909  m_dmap.resize(m_nlevs);
910  m_ba.resize(m_nlevs);
911  m_ba2d.resize(m_nlevs);
912  m_geom.resize(m_nlevs);
913  m_geom2d.resize(m_nlevs);
914  m_lmask.resize(m_nlevs);
915 
916  urban_frac_lev.resize(m_nlevs);
917  lsm_data_lev.resize(m_nlevs);
918  urban_data_lev.resize(m_nlevs);
921 
922  rad_fields.resize(m_nlevs);
923  rad_output_fields.resize(m_nlevs);
925  m_last_urban_frac.resize(m_nlevs, nullptr);
926 
927  for (auto& field_lev : fields) { field_lev.resize(m_nlevs); }
928  for (auto& entry : fieldmap) {
929  entry.second.lsm_ptr.resize(m_nlevs, nullptr);
930  entry.second.urb_ptr.resize(m_nlevs, nullptr);
931  }
932  for (auto& entry : radiation_input_map) { entry.second.weighted.resize(m_nlevs); }
933  }
934 
935  /**
936  * @brief Updates the provider mode after model data are registered.
937  * @param lev AMR level whose provider mode should be updated.
938  */
939  void update_provider_mode (const int lev)
940  {
941  const bool has_land = !lsm_data_lev[lev].empty();
942  const bool has_urban = !urban_data_lev[lev].empty();
943  if (has_land && has_urban) {
947  m_surface_outputs_requested[lev] = true;
949  }
950  } else if (has_land) {
952  wavg[lev].reset();
953  } else if (has_urban) {
955  wavg[lev].reset();
956  } else {
958  }
959  }
960 
961  /**
962  * @brief Creates weighting factors when an external caller requests them.
963  * @param lev AMR level whose weighting factors should be materialized.
964  */
965  void ensure_weight_factors (const int lev)
966  {
967  if (wavg[lev] != nullptr) { return; }
968 
969  const amrex::IntVect ng(1,1,0);
970  wavg[lev] = std::make_unique<amrex::MultiFab>(m_ba2d[lev], m_dmap[lev], 2, ng);
971  const SurfaceProviderMode mode = m_provider_mode[lev];
972  wavg[lev]->setVal(mode != SurfaceProviderMode::UrbanOnly ? 1.0 : 0.0,
973  SurfaceModelType::LAND, 1, 0);
974  wavg[lev]->setVal(mode == SurfaceProviderMode::UrbanOnly ? 1.0 : 0.0,
976  }
977 
978  /**
979  * @brief Allocates surface-output fields for one level.
980  * @param lev AMR level whose outputs should be materialized.
981  */
982  void ensure_surface_outputs (const int lev)
983  {
984  if (u_star[lev] != nullptr) { return; }
985 
986  const amrex::IntVect ng(1,1,0);
987  u_star[lev] = std::make_unique<amrex::MultiFab>(m_ba2d[lev], m_dmap[lev], 2, ng);
988  t_star[lev] = std::make_unique<amrex::MultiFab>(m_ba2d[lev], m_dmap[lev], 1, ng);
989  q_star[lev] = std::make_unique<amrex::MultiFab>(m_ba2d[lev], m_dmap[lev], 1, ng);
990  t_surf[lev] = std::make_unique<amrex::MultiFab>(m_ba2d[lev], m_dmap[lev], 1, ng);
991  u_star[lev]->setVal(0.0);
992  t_star[lev]->setVal(0.0);
993  q_star[lev]->setVal(0.0);
994  t_surf[lev]->setVal(300.0);
995  }
996 
997  /**
998  * @brief Releases surface outputs that have no persistent consumer.
999  */
1001  {
1002  if (m_surface_outputs_enabled) { return; }
1003  for (int lev = 0; lev < m_nlevs; ++lev) {
1006  continue;
1007  }
1008  m_surface_outputs_requested[lev] = false;
1009  u_star[lev].reset();
1010  t_star[lev].reset();
1011  q_star[lev].reset();
1012  t_surf[lev].reset();
1013  }
1014  }
1015 
1016  int m_nlevs;
1017 
1018  bool m_use_urban = false; // whether we have an urban model
1019  bool m_use_land = false; // whether we have a LSM
1020 
1021  bool m_export_fluxes = true;
1022  bool m_export_fluxes_set = false; // whether a model has registered and latched the mode above
1023  amrex::GpuArray<bool, 2> m_output_fields_registered{{false, false}};
1024 
1025  // Set once the surface models have actually integrated at least one step, so consumers can
1026  // tell registered-but-unfilled fields from real ones.
1027  bool m_fields_are_valid = false;
1028 
1029  // internal flag to indicate if the weight average has been calculated this time step
1030  bool m_weights_updated = false;
1031 
1032  amrex::Vector<SurfaceProviderMode> m_provider_mode;
1033 
1034  amrex::Vector<amrex::BoxArray> m_ba;
1035  amrex::Vector<amrex::BoxArray> m_ba2d;
1036  amrex::Vector<amrex::Geometry> m_geom;
1037  amrex::Vector<amrex::DistributionMapping> m_dmap;
1038 
1039  amrex::Vector<amrex::Geometry> m_geom2d;
1040  amrex::Vector<amrex::iMultiFab*> m_lmask;
1041 
1042  // Pointers to LSM and Urban model data
1043  amrex::Vector<amrex::MultiFab*> urban_frac_lev; // Urban fraction for each level [0-1.0]
1044  amrex::Vector<amrex::Vector<amrex::MultiFab*>> lsm_data_lev; // LSM data for each level
1045  amrex::Vector<amrex::Vector<amrex::MultiFab*>> urban_data_lev; // Urban data for each level
1046  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>> weighted_lsm_data_lev;
1047  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>> weighted_urban_data_lev;
1048 
1049  // Output weighted averages passed to MOST
1050  // These can either be the u*, t*, q* for MOST, or fluxes computed directly from the model
1051  amrex::Vector<std::unique_ptr<amrex::MultiFab>> u_star; // up to 2 components: X-stress, Y-stress
1052  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_star;
1053  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_star;
1054  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_surf;
1055 
1056  amrex::Vector<int> m_surface_outputs_requested;
1059  amrex::Vector<amrex::MultiFab*> m_last_urban_frac;
1060 
1061  // Current weight average factors for each level (2 components: land and urban)
1062  amrex::Vector<std::unique_ptr<amrex::MultiFab>> wavg;
1063 
1064  // Model variables to weight average
1065  // The flux interface uses u-stress, v-stress, heat flux, vapor flux, tsurf.
1066  // TODO: make this more flexible for different types of models
1067  amrex::Vector<int> lsm_fields;
1068  amrex::Vector<int> urban_fields;
1069 
1070  // These are the names to be consumed in RRTMGP, but the mapped LSM/Urban names can be different
1071  inline static const std::vector<std::string> radnames = {"tskin", "emiss", "albedo_vis", "albedo_nir", "albedo_vis_diff", "albedo_nir_diff"};
1072 
1073  /**
1074  * @brief Describes a registered land/urban field mapping.
1075  *
1076  * A Field associates the common name used by ERF consumers with either
1077  * model-specific field indices or per-level field pointers. The mapped
1078  * fields are stored in the SurfaceModel-owned field array and the source
1079  * pointers remain owned by their respective surface models.
1080  */
1081  struct Field {
1082  /// Land and urban model field indices, respectively.
1083  std::pair<int, int> map;
1084  /// Per-level land-model field pointers.
1085  amrex::Vector<amrex::MultiFab*> lsm_ptr;
1086  /// Per-level urban-model field pointers.
1087  amrex::Vector<amrex::MultiFab*> urb_ptr;
1088  /// Index of the mapped field in the SurfaceModel field array.
1089  int mf_ind;
1090  /// Whether boundaries are filled after mapping the field.
1092  /// Whether a consumer currently requires this mapped field.
1093  bool active = false;
1094  /// Whether the field must be updated on every timestep.
1095  bool persistent_consumer = false;
1096  };
1097  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>> fields; // NOTE: this is stored in inverse order: (field, nlev)
1098  std::unordered_map<std::string, Field> fieldmap;
1099 
1100  amrex::Vector<std::string> m_lsm_names;
1101  amrex::Vector<std::string> m_urban_names;
1102 
1103  amrex::Vector<amrex::Vector<const amrex::MultiFab*>> rad_fields; // pointers to radiation MFs at each level
1104  amrex::Vector<amrex::Vector<amrex::MultiFab*>> rad_output_fields;
1105 
1106  inline static const std::vector<std::string> rad_output_names = {
1107  "cos_zenith_angle", "sw_flux_dn", "sw_flux_dn_dir_vis",
1108  "sw_flux_dn_dir_nir", "sw_flux_dn_dif_vis", "sw_flux_dn_dif_nir",
1109  "lw_flux_dn"};
1110 
1112  std::pair<int, int> map;
1113  amrex::Vector<std::unique_ptr<amrex::MultiFab>> weighted;
1114  };
1115  std::unordered_map<std::string, RadiationField> radiation_input_map;
1116  std::unordered_map<std::string, RadiationField> radiation_output_map;
1117 
1118  // plotfile names for outputs
1119  inline static const std::vector<std::string> field_names = {
1120  "uflux",
1121  "vflux",
1122  "hfx",
1123  "qfx",
1124  "tskin",
1125  };
1126 };
1127 
1128 #endif
pp_for_pert_vels get("prob_type", prob_type)
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
ParallelFor(fab_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);})
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
std::string name
Definition: ERF_Plotfile2DCatalog.cpp:116
amrex::Real Real
Definition: ERF_ShocInterface.H:19
SurfaceProviderMode
Definition: ERF_SurfaceModel.H:17
SurfaceModelType
Definition: ERF_SurfaceModel.H:15
@ LAND
Definition: ERF_SurfaceModel.H:15
@ URBAN
Definition: ERF_SurfaceModel.H:15
Interface between ERF and land-surface and urban models.
Definition: ERF_SurfaceModel.H:47
amrex::MultiFab * get_tsurf(const int &lev)
Returns the weighted surface-temperature output for a level.
Definition: ERF_SurfaceModel.H:504
void clear_level(int lev)
Removes an AMR level, and every level above it, from the surface model.
Definition: ERF_SurfaceModel.H:234
amrex::Vector< amrex::MultiFab * > urban_frac_lev
Definition: ERF_SurfaceModel.H:1043
std::unordered_map< std::string, RadiationField > radiation_input_map
Definition: ERF_SurfaceModel.H:1115
void resize_levels(int nlevs)
Sets the number of AMR levels and resizes all per-level storage to match.
Definition: ERF_SurfaceModel.H:897
void apply_weight_average(int lev, const amrex::MultiFab *lsm_data, amrex::MultiFab *lsm_weighted, const amrex::MultiFab *urban_data, amrex::MultiFab *urban_weighted)
Applies land and urban weights into separate output fields.
Definition: ERF_SurfaceModel.cpp:12
std::unordered_map< std::string, RadiationField > radiation_output_map
Definition: ERF_SurfaceModel.H:1116
void register_radiation_output(const std::string &name, const std::pair< int, int > &lsm_urb_map)
Registers a canonical radiation output mapping.
Definition: ERF_SurfaceModel.cpp:340
amrex::Vector< std::string > m_lsm_names
Definition: ERF_SurfaceModel.H:1100
int m_nlevs
Definition: ERF_SurfaceModel.H:1016
amrex::MultiFab * get_radiation_output_field(int lev, const std::string &name)
Returns the destination of one canonical radiation output by name.
Definition: ERF_SurfaceModel.cpp:411
amrex::Vector< amrex::BoxArray > m_ba2d
Definition: ERF_SurfaceModel.H:1035
bool m_weights_updated
Definition: ERF_SurfaceModel.H:1030
void set_field_map_pointers(const std::string &name, int lev, amrex::MultiFab *lsm_mf, amrex::MultiFab *urban_mf)
Updates a pointer-based field mapping for one level.
Definition: ERF_SurfaceModel.cpp:619
bool is_field_mapped(int lev, SurfaceModelType type, int field_idx, const amrex::MultiFab *mf) const
Checks whether a model field participates in a registered mapping.
Definition: ERF_SurfaceModel.cpp:492
void write_output(const int &finest_lev, const amrex::Real &time, const std::string &plot_prefix, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &ref_ratio)
Writes registered surface-model fields to plotfile output.
Definition: ERF_SurfaceModel.cpp:758
amrex::Vector< amrex::Geometry > m_geom
Definition: ERF_SurfaceModel.H:1036
bool m_export_fluxes
Definition: ERF_SurfaceModel.H:1021
static const std::vector< std::string > rad_output_names
Definition: ERF_SurfaceModel.H:1106
void activate_field_map(const std::string &name, const bool persistent=true)
Activates a mapped field and allocates its storage on all levels.
Definition: ERF_SurfaceModel.cpp:637
amrex::Vector< amrex::Vector< amrex::MultiFab * > > rad_output_fields
Definition: ERF_SurfaceModel.H:1104
void weight_model_field(int lev, const amrex::MultiFab *source, amrex::MultiFab *weighted, SurfaceModelType type)
Writes a weighted copy of a model field.
Definition: ERF_SurfaceModel.cpp:43
amrex::Vector< amrex::MultiFab * > m_last_urban_frac
Definition: ERF_SurfaceModel.H:1059
void register_radiation_outputs(const std::unordered_map< std::string, std::pair< int, int >> &output_map)
Registers canonical radiation output mappings.
Definition: ERF_SurfaceModel.cpp:370
const amrex::Vector< const amrex::MultiFab * > get_radiation_fields(int lev=0)
Returns fields registered under the RRTMGP radiation names.
Definition: ERF_SurfaceModel.H:702
void distribute_radiation_outputs(int lev)
Distributes updated canonical radiation outputs to other providers.
Definition: ERF_SurfaceModel.cpp:439
amrex::MultiFab * get_ustar(const int &lev)
Returns the weighted horizontal momentum output for a level.
Definition: ERF_SurfaceModel.H:477
void register_field_map(std::string name, const std::pair< int, int > &lsm_urb_map, bool fill_boundary=false)
Registers a field map using land and urban field indices.
Definition: ERF_SurfaceModel.cpp:565
bool m_surface_layer_outputs_enabled
Definition: ERF_SurfaceModel.H:1058
amrex::MultiFab * get_tstar(const int &lev)
Returns the weighted thermal output for a level.
Definition: ERF_SurfaceModel.H:486
static void GotoNextLine(std::istream &is)
Advances an input stream to the next line.
Definition: ERF_SurfaceModel.cpp:824
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_star
Definition: ERF_SurfaceModel.H:1053
amrex::Vector< std::string > m_urban_names
Definition: ERF_SurfaceModel.H:1101
amrex::Vector< amrex::BoxArray > m_ba
Definition: ERF_SurfaceModel.H:1034
bool m_fields_are_valid
Definition: ERF_SurfaceModel.H:1027
amrex::Vector< int > lsm_fields
Definition: ERF_SurfaceModel.H:1067
void release_transient_surface_outputs()
Releases surface outputs that have no persistent consumer.
Definition: ERF_SurfaceModel.H:1000
std::unordered_map< std::string, Field > fieldmap
Definition: ERF_SurfaceModel.H:1098
void ensure_surface_outputs(const int lev)
Allocates surface-output fields for one level.
Definition: ERF_SurfaceModel.H:982
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
Definition: ERF_SurfaceModel.H:1054
void ReadCheckpoint(const std::string &checkpointname)
Restores surface-model state from a checkpoint file.
Definition: ERF_SurfaceModel.cpp:947
SurfaceFluxView get_surface_flux_view(const int lev, const amrex::MFIter &mfi) const
Returns provider or blended surface-flux views for one tile.
Definition: ERF_SurfaceModel.H:514
SurfaceModel(int nlevs, const amrex::Vector< amrex::BoxArray > &ba, const amrex::Vector< amrex::Geometry > &geom, const amrex::Vector< amrex::DistributionMapping > &dm, const SolverChoice &, amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab >>> &)
Constructs a surface-model interface for the supplied AMR levels.
Definition: ERF_SurfaceModel.H:60
amrex::Vector< SurfaceProviderMode > m_provider_mode
Definition: ERF_SurfaceModel.H:1032
bool m_use_urban
Definition: ERF_SurfaceModel.H:1018
void set_model_fields(SurfaceModelType type, const amrex::Vector< int > &field_indices, const bool use_fluxes=true)
Selects the model fields that participate in weighted averaging.
Definition: ERF_SurfaceModel.H:357
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > weighted_urban_data_lev
Definition: ERF_SurfaceModel.H:1047
void distribute_radiation_output(int lev, int output_index)
Distributes one updated canonical radiation output to other providers.
Definition: ERF_SurfaceModel.cpp:446
static const std::vector< std::string > radnames
Definition: ERF_SurfaceModel.H:1071
const amrex::Vector< amrex::MultiFab * > get_radiation_output_fields(int lev=0)
Returns canonical radiation output destinations for one level.
Definition: ERF_SurfaceModel.cpp:378
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > weighted_lsm_data_lev
Definition: ERF_SurfaceModel.H:1046
amrex::GpuArray< bool, 2 > m_output_fields_registered
Definition: ERF_SurfaceModel.H:1023
void calculate_simple_average(int lev, amrex::MultiFab *const urban_frac)
Computes simple land and urban weights from the urban fraction.
Definition: ERF_SurfaceModel.cpp:527
amrex::MultiFab * get_wavg_factors(const int &lev)
Returns the land and urban weighting factors for a level.
Definition: ERF_SurfaceModel.H:600
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
Definition: ERF_SurfaceModel.H:1051
const amrex::MultiFab * get_weighted_model_data(const int lev, SurfaceModelType type, const int field_idx) const
Returns weighted data for a selected model field.
Definition: ERF_SurfaceModel.H:556
void register_radiation_input(const std::string &name, const std::pair< int, int > &lsm_urb_map)
Registers a canonical radiation input mapping.
Definition: ERF_SurfaceModel.cpp:309
void validate_radiation_output_layout(int lev, const amrex::MultiFab *mf) const
Validates the layout contract for a canonical radiation output.
Definition: ERF_SurfaceModel.cpp:419
void calculate_weight_average(int lev, amrex::MultiFab *const urban_frac, bool update_derived=true)
Computes land and urban weights and applies them to registered fields.
Definition: ERF_SurfaceModel.cpp:71
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
Definition: ERF_SurfaceModel.H:1052
void build_radiation_fieldlist(int lev)
Builds the ordered radiation-field list for one AMR level.
Definition: ERF_SurfaceModel.H:777
void update_provider_mode(const int lev)
Updates the provider mode after model data are registered.
Definition: ERF_SurfaceModel.H:939
void register_radiation_inputs(const std::unordered_map< std::string, std::pair< int, int >> &input_map)
Registers canonical radiation input mappings.
Definition: ERF_SurfaceModel.cpp:332
void weight_average_fields(int lev, amrex::MultiFab *const)
Applies the current land and urban weights to selected model fields.
Definition: ERF_SurfaceModel.cpp:679
void set_model_data(const int lev, const amrex::Vector< amrex::MultiFab * > model_data, const amrex::Vector< std::string > &data_names, SurfaceModelType type)
Registers model variables used in weighted averaging.
Definition: ERF_SurfaceModel.H:248
static const std::vector< std::string > field_names
Definition: ERF_SurfaceModel.H:1119
amrex::Vector< amrex::Geometry > m_geom2d
Definition: ERF_SurfaceModel.H:1039
void mark_fields_valid()
Marks the registered surface fields as filled by an actual model advance.
Definition: ERF_SurfaceModel.H:463
amrex::Vector< int > urban_fields
Definition: ERF_SurfaceModel.H:1068
void ensure_weight_factors(const int lev)
Creates weighting factors when an external caller requests them.
Definition: ERF_SurfaceModel.H:965
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > fields
Definition: ERF_SurfaceModel.H:1097
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data_lev
Definition: ERF_SurfaceModel.H:1044
void activate_all_field_maps(const bool persistent=true)
Activates all registered mapped fields for an output consumer.
Definition: ERF_SurfaceModel.cpp:659
bool are_fluxes()
Returns whether the interface exports fluxes rather than MOST variables.
Definition: ERF_SurfaceModel.H:432
void WriteCheckpoint(const std::string &checkpointname)
Writes surface-model state to a checkpoint file.
Definition: ERF_SurfaceModel.cpp:830
amrex::Vector< int > m_surface_outputs_requested
Definition: ERF_SurfaceModel.H:1056
amrex::Vector< amrex::Vector< const amrex::MultiFab * > > rad_fields
Definition: ERF_SurfaceModel.H:1103
amrex::Vector< std::unique_ptr< amrex::MultiFab > > wavg
Definition: ERF_SurfaceModel.H:1062
bool fields_are_valid() const
Returns whether the surface models have advanced at least once.
Definition: ERF_SurfaceModel.H:470
void request_surface_outputs(const bool persistent=true)
Enables and materializes the surface outputs consumed by ERF.
Definition: ERF_SurfaceModel.H:437
amrex::Vector< amrex::iMultiFab * > m_lmask
Definition: ERF_SurfaceModel.H:1040
amrex::Vector< amrex::Vector< amrex::MultiFab * > > urban_data_lev
Definition: ERF_SurfaceModel.H:1045
amrex::MultiFab * get_qstar(const int &lev)
Returns the weighted moisture output for a level.
Definition: ERF_SurfaceModel.H:495
void set_model_fluxes(const int lev, const amrex::Vector< amrex::MultiFab * > model_fluxes, const amrex::Vector< std::string > &flux_names, SurfaceModelType type)
Registers model fluxes as additional weighted-average inputs.
Definition: ERF_SurfaceModel.H:312
bool m_export_fluxes_set
Definition: ERF_SurfaceModel.H:1022
amrex::MultiFab * get_field(const std::string &name, int lev=0)
Retrieves a registered field by its common name.
Definition: ERF_SurfaceModel.H:683
void initialize_for_level(int lev, const amrex::BoxArray &ba, const amrex::Geometry &geom, const amrex::DistributionMapping &dm, const amrex::Vector< std::unique_ptr< amrex::iMultiFab >> &lmask_lev, const amrex::Vector< amrex::BCRec > &domain_bcs_type, const amrex::Vector< amrex::IntVect > &refRatio)
Initializes storage and boundary data for an AMR level.
Definition: ERF_SurfaceModel.H:90
bool m_surface_outputs_enabled
Definition: ERF_SurfaceModel.H:1057
void deactivate_transient_field_maps()
Disables and releases mapped fields used only by the last output.
Definition: ERF_SurfaceModel.cpp:666
amrex::Vector< amrex::DistributionMapping > m_dmap
Definition: ERF_SurfaceModel.H:1037
bool m_use_land
Definition: ERF_SurfaceModel.H:1019
void request_surface_layer_outputs()
Enables blended surface outputs needed by the SurfaceLayer.
Definition: ERF_SurfaceModel.H:449
@ cons_bc
Definition: ERF_IndexDefines.H:110
@ ng
Definition: ERF_Morrison.H:51
Definition: ERF_DataStruct.H:715
Non-owning views of surface fluxes for one tile.
Definition: ERF_SurfaceModel.H:22
amrex::Array4< const amrex::Real > q_flux
Definition: ERF_SurfaceModel.H:26
amrex::Array4< const amrex::Real > tau23
Definition: ERF_SurfaceModel.H:24
amrex::Array4< const amrex::Real > tau13
Definition: ERF_SurfaceModel.H:23
amrex::Array4< const amrex::Real > t_flux
Definition: ERF_SurfaceModel.H:25
Describes a registered land/urban field mapping.
Definition: ERF_SurfaceModel.H:1081
bool fill_bound
Whether boundaries are filled after mapping the field.
Definition: ERF_SurfaceModel.H:1091
bool persistent_consumer
Whether the field must be updated on every timestep.
Definition: ERF_SurfaceModel.H:1095
amrex::Vector< amrex::MultiFab * > urb_ptr
Per-level urban-model field pointers.
Definition: ERF_SurfaceModel.H:1087
std::pair< int, int > map
Land and urban model field indices, respectively.
Definition: ERF_SurfaceModel.H:1083
int mf_ind
Index of the mapped field in the SurfaceModel field array.
Definition: ERF_SurfaceModel.H:1089
bool active
Whether a consumer currently requires this mapped field.
Definition: ERF_SurfaceModel.H:1093
amrex::Vector< amrex::MultiFab * > lsm_ptr
Per-level land-model field pointers.
Definition: ERF_SurfaceModel.H:1085
Definition: ERF_SurfaceModel.H:1111
std::pair< int, int > map
Definition: ERF_SurfaceModel.H:1112
amrex::Vector< std::unique_ptr< amrex::MultiFab > > weighted
Definition: ERF_SurfaceModel.H:1113