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