Proto  3.2
Proto_DisjointBoxLayout.H
Go to the documentation of this file.
1 #pragma once
2 #ifndef _PROTO_DISJOINT_BOX_LAYOUT_
3 #define _PROTO_DISJOINT_BOX_LAYOUT_
4 
5 #include "Proto_MayDay.H"
6 #include "Proto_Point.H"
7 #include "Proto_Box.H"
8 #include "Proto_ProblemDomain.H"
9 #include "Proto_BoxPartition.H"
10 #include "Proto_DataIterator.H"
11 #include "Proto_SPMD.H"
12 #include <cstdlib> //for size_t
13 #include <iostream>
14 #include <iomanip>
15 #include <stack>
16 #include <memory>
17 #include <array>
18 #include <unordered_map>
19 
20 namespace Proto
21 {
24  /// Disjoint Box Layout
25  /**
26  Layout of disjoint, logically rectangular regions of DIM-dimensional space.
27  This object is a simplified generalization of the DisjointBoxLayout class
28  used in Chombo, now specialized to use fixed box sizes.
29  */
31  {
32  template<typename P> friend class DataIndex;
33  template<typename P> friend class DataIterator;
34  friend class NeighborIterator;
35  friend std::ostream& operator<< (std::ostream& os, const DisjointBoxLayout& a_dbl);
36 
37  public:
38 
39  /// Default Constructor
41 
42  /// Constructor (Full Domain)
43  /**
44  Creates a DisjointBoxLayout by tiling an input ProblemDomain completely with boxes of
45  a predetermined size. If MPI is used, boxes will be distributed over available
46  processors using Morton ordering.
47  If <code>a_problemDomain.coarsenable(a_boxSize) != true</code> this results in an error.
48 
49  \param a_problemDomain A ProblemDomain
50  \param a_boxSize A set of box sizes
51  */
53  const ProblemDomain & a_problemDomain,
54  const Point & a_boxSize);
55 
56  //TODO: Either improve the interface or the documentation
57  /// Constructor (Partial Domain)
58  /**
59  Creates a DisjointBoxLayout by partially tiling an input ProblemDomain with boxes
60  according to a set of Points. Each element of a_coarsenedPatches represents a box
61  in the layout which has been coarsened by boxSize (resulting in a Box with a
62  single element). In parallel applications, <code>a_coarsenedPatches </code> should contain
63  the patches in the layout on ALL ranks, not just locally.
64 
65  \param a_problemDomain ProblemDomain containing the DBL.
66  \param a_coarsenedPatches An array of points corresponding to patches in the tiled layout
67  \param a_boxSize Possibly anisotropic size of each Box in the layout
68  */
69  inline DisjointBoxLayout(
70  const ProblemDomain & a_problemDomain,
71  const vector<Point> & a_coarsenedPatches,
72  const Point & a_boxSize);
73 
74  /// Constructor (Partial Domain - Simple)
75  /**
76  Creats a DisjointBoxLayout by partially covering an input ProblemDomain with all patches
77  in an input region. The sub-region must also be coarsenable by the box size, and must be
78  a contained within the problem domain.
79  Useful for quick debugging, but not practically useful for most real problems.
80 
81  \param a_problemDomain ProblemDomain containing the DBL.
82  \param a_region Sub-region of the domain which will be tiled in the layout.
83  \param a_boxSize Possibly anisotropic size of each Box in the layout.
84 
85  */
86  inline DisjointBoxLayout(
87  const ProblemDomain& a_problemDomain,
88  const Box& a_region,
89  const Point& a_boxSize);
90 
91  inline DisjointBoxLayout(
92  std::shared_ptr<BoxPartition> a_partition,
93  const Point& a_boxSize);
94 
95  /// Direct Define
96  /**
97  Creates a DisjointBoxLayout which is linked to an existing BoxPartition object.
98  This constructor is used internally and is not recommended for public use.
99  */
100  inline void define(
101  std::shared_ptr<BoxPartition> a_partition,
102  const Point& a_boxSize);
103 
104  /// Copy Constructor
105  /**
106  Copies share pointers to the internal structure hence this is relatively cheap.
107 
108  \param a_layout Another DisjointBoxLayout
109  */
110  inline DisjointBoxLayout(const DisjointBoxLayout& a_layout);
111 
112  /// Define (Full Domain)
113  /**
114  Construct a DisjointBoxLayout lazily or redefine an existing one.
115  */
116  inline void define(
117  const ProblemDomain & a_problemDomain,
118  const Point & a_boxSize);
119 
120  /// Define (Partial Domain)
121  /**
122  Construct a DisjointBoxLayout lazily or redefine an existing one.
123  */
124  inline void define(
125  const ProblemDomain & a_problemDomain,
126  const vector<PatchID> & a_patchIDs,
127  const Point & a_boxSize);
128 
129  /// Define (Partial Domaini - Simple)
130  /**
131  Construct a DisjointBoxLayout lazily or redefine an existing one.
132  */
133  inline void define(
134  const ProblemDomain & a_problemDomain,
135  const Box & a_region,
136  const Point & a_boxSize);
137 
138  /// Get Sorted Version of This
139  inline DisjointBoxLayout sorted() const;
140 
141  inline bool isSorted() const {return m_partition->isSorted(); }
142 
143  /// Load Balance
144  /**
145  Distribute the load of this layout over the range of processors whose
146  indices span <code>[a_startProc, a_endProc-1]</code>.
147  */
148  inline void loadBalance(unsigned int a_startProc, unsigned int a_endProc);
149 
150  /// Load Assign
151  /**
152  Manually assign the load of this layout using the syntax
153  <code> loadAssign(P0, N0, P1, N1, ..., Pk, Nk) </code>
154  where process Pi is assigned Ni boxes. The sum over all Ni should be
155  equal to the size of this layout.
156  */
157  template<typename... Args>
158  inline void loadAssign(Args... a_args);
159 
160  /// Load Assign
161  /**
162  Manually assign the load of this layout. The input is a vector of
163  <code>pair<int, unsigned int></code> where the first entry of each pair is a
164  process and the second is the number of boxes to be assigned to that process.
165  */
166  inline void loadAssign(std::vector<std::pair<int, unsigned int>>& a_assignment);
167 
168  /// Assignment
169  /**
170  Copies share pointers to the same internal structure
171  */
172  inline DisjointBoxLayout& operator=(const DisjointBoxLayout& a_input);
173 
174  /// Equality Operator
175  inline bool operator==(const DisjointBoxLayout& a_input) const;
176 
177  /** @name Access operators.
178  */
179 
180  /// Get All Boxes
181  /**
182  Get a copy of the patches in the layout. The output is a vector
183  of <code>pair<Point, int></code> where for each element
184  <code>item</code>, <code>item.first</code> contains a Point corresponding
185  to the Box <code>Box(item.first, item.first).refine(boxSize())</code>.
186  <code>item.second</code> contains the integer rank of the process which
187  handles the patch.
188 
189  Note that this function returns data for all patches on all parallel processes.
190  */
191  inline const std::vector<pair<Point, unsigned int>> boxes() const;
192 
193  /// Index Access
194  /**
195  Return the Box associated with a DataIndex.
196  Fails if the index is not compatible with *this.
198  \param a_index A DataIndex
199  */
200  inline Box operator[](const LevelIndex& a_index) const;
201 
202  /// Box Indexing
203  /**
204  Return the Box associated with a DataIndex. Identical to <code>operator[]</code>
205  Fails if the index is not compatible with *this.
206 
207  \param a_index A DataIndex
208  */
209  inline Box box(const LevelIndex& a_index) const;
210 
211  /// Point Indexing
212  /**
213  Return the Point version of the Box associated with a DataIndex.
214  Fails if the index is not compatible with *this.
215 
216  \param a_index A DataIndex
217  */
218  inline Point point(const LevelIndex& a_index) const;
219 
220  /// Get Process ID
221  /**
222  Get the process ID associated with a DataIndex.
223  Fails if the index is not compatible with *this.
224 
225  \param a_index A DataIndex
226  */
227  inline int procID(const LevelIndex& a_index) const; //consistent syntax
228  //inline int procid(const DataIndex& a_index) const;
229 
230  /// Patch Offset
231  /**
232  Returns the linear offset (in number of boxes) of the first patch on proc a_proc.
233  Used for serialization.
234 
235  \param a_proc An MPI rank
236  */
237  inline unsigned int offset(int a_proc) const;
239  /// This Patch Offset
240  /**
241  Returns the linear offset (in number of boxes) of the first patch on this proc.
242  Used for linearization.
243  */
244  inline unsigned int offset() const { return offset(Proto::procID()); }
245 
246  /// Get Index From Point
247  /**
248  Find the DataIndex associated with an input patch point.
249  This function is the inverse of DisjointBoxLayout::point(DataIndex).
250 
251  Input Points must be in <code>this->patchDomain()</code> or be a valid periodic
252  image thereof, otherwise this function will fail by assertion.
254  \param a_patchPoint A point representing a patch in the layout or a periodic image
255  */
256  inline LevelIndex index(Point& a_patchPoint) const;
257 
258  /// Size
259  /**
260  Return the number of Boxes contained in *this including those on other processors.
261  Deprecated: Use numBoxes() instead for improved in situe documentation.
262  */
263  inline unsigned int size() const;
264 
265  /// NumBoxes
266  /** Returns the number of Boxes contained in *this including those on other processors.
267  * This function is identical to the deprecated function size()
268  */
269  inline unsigned int numBoxes() const;
270 
271  /// Local Size
272  /**
273  Return the number of Boxes on this processor.
274  */
275  inline unsigned int localSize() const;
276 
277  /// Global Indexing
278  /**
279  Get the DataIndex associated with a global integer index.
280  Inputs are integers in <code>[0, this->size())</code>
281 
282  \param a_intIndex A valid integer index
283  */
284  inline LevelIndex index(unsigned int a_intIndex) const;
285 
286  /// Local Indexing
287  /**
288  Get the DataIndex associated with a local integer index.
289  Inputs are integers in <code>[0, this->localSize())</code>
290 
291  \param a_intIndex A valid integer index
292  */
293  inline LevelIndex localIndex(unsigned int a_myIndexInt) const;
294 
295  /// Get Box Size
296  /**
297  Return the constant size of all boxes in the layout.
298  */
299  inline Point boxSize() const{return m_boxSize;};
300 
301  /// Get Problem Domain
302  inline ProblemDomain domain() const {return m_problemDomain;};
304  /// Get Problem Domain in Patch Space
305  /**
306  Returns the problem domain box in patch-space.
307  */
308  inline ProblemDomain patchDomain() const {return domain().coarsen(boxSize()); }
309 
310  inline std::shared_ptr<BoxPartition> partition() {return m_partition; }
311  /// Find Index
312  /**
313  Given a patch Point, return the DataIndex of the associated Box if
314  it is in the layout including periodic images. If the Point does not
315  represent a patch in this layout, this function returns <code>this->end()</code>
316 
317  \param a_pt A patch Point.
318  */
319  inline LevelIndex find(const Point& a_pt) const;
320 
321  /// Find Tile Point
322  /**
323  Returns true if the tile a_pt (or a periodic image thereof) is contained in the layout
324  */
325  inline bool contains(const Point& a_pt) const;
326 
327  /// On Domain Boundary
328  /**
329  Returns true if <code>a_pt</code> corresponds to a patch that is adjacent to a
330  non-periodic domain boundary. If <code>a_pt</code> does not represent a valid patch
331  in this layout, this function fails by assertion.
332 
333  \param a_pt A valid patch Point.
334  */
335  inline bool onDomainBoundary(const Point& a_pt) const;
336 
337  inline bool isDomainBoundary(const LevelIndex& a_patch, const Point& a_dir) const;
338 
339  /// On Level Boundary
340  /**
341  Returns true if <code>a_pt</code> corresponds to a patch that is adjacent to a
342  non-periodic layout boundary (including domain boundaries). In other words, this function
343  returns false if and only if <code>a_pt</code> represents a patch that is completely
344  surrounded by other patches in the layout.
345  If <code>a_pt</code> does not represent a valid patch in this layout, this function
346  fails by assertion.
347 
348  \param a_pt A valid patch Point.
349  */
350  inline bool onLevelBoundary(const Point& a_pt) const;
351 
352  /// Iterator End
353  inline LevelIterator end() const;
354 
355  /// Get Iterator
356  inline LevelIterator begin() const;// {return DataIterator(*this).begin(); }
357 
358  /// Coarsenable Query
359  /**
360  Checks if the layout is coarsenable by a (possibly anisotropic) refinement ratio.
361  This property requires the ProblemDomain to be coarsenable as well as
362  boxSize() % a_refRatio == (0,0,....)
363 
364  \param a_refRatio Refinement ratios
365  */
366  inline bool coarsenable(const Point& a_refRatio) const;
368  /// Compatibility Query
369  /**
370  Checks if *this and another layout have the same patch configuration.
371  This is to say, both layouts have boxes in the same tile positions and on
372  the same processors, but the boxes themselves may be different sizes.
373  If true, objects built from these layouts can be processed together in the same
374  DataIterator loop.
375 
376  \param a_layout A DisjointBoxLayout
377  */
378  inline bool compatible(const DisjointBoxLayout& a_layout) const;
379 
380  /// Compatibility Query
381  /**
382  Checks if this layout can be iterated through using a DataIterator instance.
383 
384  \param a_layout A DataIterator
385  */
386  inline bool compatible(const LevelIterator& a_iter) const;
387 
388  /// Compatibility Query
389  /**
390  Checks if a DataIndex is associated with a compatible DataIterator.
391 
392  \param a_layout A DataIterator
393  */
394  inline bool compatible(const LevelIndex& a_iter) const;
395 
396  //TODO: Improve documentation
397  /// Simple Coarsen
398  /**
399  Coarsens the layout by an input (possibly anisotropic) refinement ratio.
400  coarsenable(a_refRatio) must be true or this function will result in an error.
401  The output of this function will always have the same size as the input and
402  will always be compatible in the DataIterator sense.
404  The coarsened layout has:
405  <code>crseLayout.domain().box() == fineLayout.problemDomain.box().coarsen(refRatio)</code>
406  <code>crseLayout[ii] == fineLayout[ii].coarsen(refRatio) </code> for each ii in [0, size())
407 
408  \param a_refRatio A refinement ratio
409  */
410  inline DisjointBoxLayout coarsen(const Point& a_refRatio) const;
411 
412  /// Coarsen
413  /**
414  Creates a new DisjointBoxLayout with a specified box size that has been coarsened by
415  a valid ratio. coarsenable(refRatio) must be true or this function will result in an error.
416  The output of this function will in general have a different size than the input and
417  is not guaranteed to be compatible in the DataIterator sense.
418 
419  \param a_refRatio A refinement ratio
420  \param a_boxSize Size of the output layout's boxes
421 
422  */
423  inline DisjointBoxLayout coarsen(const Point& a_refRatio, const Point& a_boxSize) const;
424 
425  //TODO: Do we implement a maximum box size?
426  /// Refine
427  /**
428  Refines the layout by an input (possibly anisotropic) refinement ratio.
429  Unline coarsen(...), this function should always be possible.
430  The output of this function will always have the same size as the input and
431  will always be compatible in the DataIterator sense.
432 
433  The refined layout has:
434  <code>fineLayout.domain().box() == crseLayout.problemDomain.box().refine(refRatio)</code>
435  <code>fineLayout[ii] == crseLayout[ii].refine(refRatio)</code> for each ii in [0, size())
436 
437  \param a_refRatio A refinement ratio
438  */
439  inline DisjointBoxLayout refine(const Point& a_refRatio) const;
440 
441  /// Get Bounding Box
442  /**
443  Returns the smallest Box containing all of the boxes in the layout.
444  Output is guaranteed to be coarsenable by boxSize().
445  */
446  inline Box boundingBox() const;
447 
448  /// Check Radial Symmetry
449  /**
450  @private
451  For debugging mesh refinement procedures
452  */
453  inline bool radialSymmetry(Point a_origin) const;
454 
455  /// Check Mirror Symmetry
456  /**
457  @private
458  For debugging mesh refinement procedures
459  */
460  inline bool mirrorSymmetry(Point a_origin, int a_coord) const;
461 
462  /// Print
463  inline void print(std::string a_name = "") const;
464 
465 #ifdef PROTO_ACCEL
466  // TODO: Used in Chombo4::LevelBoxData. Unclear if we still need this.
467  static protoStream_t getCurrentStream()
468  {
469  static protoStream_t currStream;
470  static bool init=false;
471  if(!init)
472  {
473  protoStreamCreate(&currStream);
474  init=true;
475  }
476  return currStream;
477  }
478 
479 #endif
480  private:
481 
484  std::shared_ptr<BoxPartition> m_partition;
485 };
486 
487 inline std::ostream& operator<< (std::ostream& os, const LevelIndex& a_dbl);
488 #include "implem/Proto_DisjointBoxLayoutImplem.H"
489 } //end namespace Proto
490 
491 #endif
bool contains(const Point &a_pt) const
Find Tile Point.
Definition: Proto_DisjointBoxLayout.H:279
friend std::ostream & operator<<(std::ostream &os, const DisjointBoxLayout &a_dbl)
Definition: Proto_DisjointBoxLayout.H:503
Definition: Proto_NeighborIterator.H:8
unsigned int size() const
Size.
Definition: Proto_DisjointBoxLayout.H:185
unsigned int offset() const
This Patch Offset.
Definition: Proto_DisjointBoxLayout.H:244
bool isDomainBoundary(const LevelIndex &a_patch, const Point &a_dir) const
Definition: Proto_DisjointBoxLayout.H:303
ProblemDomain patchDomain() const
Get Problem Domain in Patch Space.
Definition: Proto_DisjointBoxLayout.H:308
std::shared_ptr< BoxPartition > m_partition
Definition: Proto_DisjointBoxLayout.H:484
Distributed Data Iterator.
Definition: Proto_DataIndex.H:10
Box box(const LevelIndex &a_index) const
Box Indexing.
Definition: Proto_DisjointBoxLayout.H:220
Disjoint Box Layout.
Definition: Proto_DisjointBoxLayout.H:30
DisjointBoxLayout sorted() const
Get Sorted Version of This.
Definition: Proto_DisjointBoxLayout.H:108
bool onDomainBoundary(const Point &a_pt) const
On Domain Boundary.
Definition: Proto_DisjointBoxLayout.H:287
DataIterator< BoxPartition > LevelIterator
Definition: Proto_DisjointBoxLayout.H:23
void loadBalance(unsigned int a_startProc, unsigned int a_endProc)
Load Balance.
Definition: Proto_DisjointBoxLayout.H:116
bool operator==(const DisjointBoxLayout &a_input) const
Equality Operator.
Definition: Proto_DisjointBoxLayout.H:163
bool radialSymmetry(Point a_origin) const
Check Radial Symmetry.
Definition: Proto_DisjointBoxLayout.H:431
LevelIndex index(Point &a_patchPoint) const
Get Index From Point.
Definition: Proto_DisjointBoxLayout.H:238
void print(std::string a_name="") const
Print.
Definition: Proto_DisjointBoxLayout.H:470
unsigned int localSize() const
Local Size.
Definition: Proto_DisjointBoxLayout.H:197
An interval in DIM dimensional space.
Definition: Proto_Box.H:29
Box boundingBox() const
Get Bounding Box.
Definition: Proto_DisjointBoxLayout.H:413
int procID()
Get Local Process ID.
Definition: Proto_SPMD.H:39
Box operator[](const LevelIndex &a_index) const
Index Access.
Definition: Proto_DisjointBoxLayout.H:203
ProblemDomain domain() const
Get Problem Domain.
Definition: Proto_DisjointBoxLayout.H:302
int procID(const LevelIndex &a_index) const
Get Process ID.
Definition: Proto_DisjointBoxLayout.H:230
bool isSorted() const
Definition: Proto_DisjointBoxLayout.H:141
bool mirrorSymmetry(Point a_origin, int a_coord) const
Check Mirror Symmetry.
Definition: Proto_DisjointBoxLayout.H:449
LevelIterator begin() const
Get Iterator.
Definition: Proto_DisjointBoxLayout.H:341
Definition: Proto_Array.H:17
DisjointBoxLayout & operator=(const DisjointBoxLayout &a_input)
Assignment.
Definition: Proto_DisjointBoxLayout.H:152
DataIndex< BoxPartition > LevelIndex
Definition: Proto_DisjointBoxLayout.H:22
Point boxSize() const
Get Box Size.
Definition: Proto_DisjointBoxLayout.H:299
bool compatible(const DisjointBoxLayout &a_layout) const
Compatibility Query.
Definition: Proto_DisjointBoxLayout.H:355
const std::vector< pair< Point, unsigned int > > boxes() const
Get All Boxes.
Definition: Proto_DisjointBoxLayout.H:171
Integer Valued Vector.
Definition: Proto_Point.H:24
std::shared_ptr< BoxPartition > partition()
Definition: Proto_DisjointBoxLayout.H:310
ProblemDomain coarsen(Point a_refRatio) const
Coarsen (Anisotropic)
Definition: Proto_ProblemDomain.H:100
DisjointBoxLayout refine(const Point &a_refRatio) const
Refine.
Definition: Proto_DisjointBoxLayout.H:403
DisjointBoxLayout()
Default Constructor.
Definition: Proto_DisjointBoxLayout.H:6
LevelIterator end() const
Iterator End.
Definition: Proto_DisjointBoxLayout.H:334
LevelIndex localIndex(unsigned int a_myIndexInt) const
Local Indexing.
Definition: Proto_DisjointBoxLayout.H:253
ProblemDomain m_problemDomain
Definition: Proto_DisjointBoxLayout.H:482
bool onLevelBoundary(const Point &a_pt) const
On Level Boundary.
Definition: Proto_DisjointBoxLayout.H:318
unsigned int numBoxes() const
NumBoxes.
Definition: Proto_DisjointBoxLayout.H:191
LevelIndex find(const Point &a_pt) const
Find Index.
Definition: Proto_DisjointBoxLayout.H:263
void loadAssign(Args... a_args)
Load Assign.
Definition: Proto_DisjointBoxLayout.H:130
bool coarsenable(const Point &a_refRatio) const
Coarsenable Query.
Definition: Proto_DisjointBoxLayout.H:348
Point point(const LevelIndex &a_index) const
Point Indexing.
Definition: Proto_DisjointBoxLayout.H:212
void define(std::shared_ptr< BoxPartition > a_partition, const Point &a_boxSize)
Direct Define.
Definition: Proto_DisjointBoxLayout.H:40
Point m_boxSize
Definition: Proto_DisjointBoxLayout.H:483
#define protoStream_t
Definition: Proto_Macros.H:18
Represents a rectangular domain over which a problem can be defined, including periodic images...
Definition: Proto_ProblemDomain.H:22
DisjointBoxLayout coarsen(const Point &a_refRatio) const
Simple Coarsen.
Definition: Proto_DisjointBoxLayout.H:373