Proto  3.2
Proto_Box.H
Go to the documentation of this file.
1 #pragma once
2 #ifndef _PROTO_BOX_
3 #define _PROTO_BOX_
4 
5 #include <cstdlib> //for size_t
6 #include <iostream> //pretty printing
7 #include <sstream> //pretty printing
8 #include <cmath>
9 
10 #include "Proto_MayDay.H"
11 #include "Proto_Face.H"
12 #include "Proto_Point.H"
13 #include "Proto_Centering.H"
14 
15 namespace Proto
16 {
17 
18  // forward declarations
19  class BoxIterator;
20 #ifdef PR_HDF5
21  class HDF5Handler;
22 #endif
23  /// An interval in DIM dimensional space.
24  /**
25  A Box is a region in \f$ \mathbb{Z}^{DIM} \f$ specified by two corner Point objects, <code> high </code> and <code> low </code> INCLUSIVELY.
26  Equivalently, a Box is a collection of \f$DIM\f$ linear intervals in \f$\mathbb{Z}^{DIM}\f$
27  \f$[low[i] ,high[i]] : i \in [0,DIM)\f$. Boxes are written using the notation <code> [low, high] </code>.
28  */
29  class Box
30  {
31 #ifdef PR_HDF5
32  friend class Proto::HDF5Handler;
33 #endif
34  public:
35  typedef BoxIterator iterator; //Box::iterator aliases to BoxIterator
36 
37  ///////////////////////////////////////////////////////////////////////////////////////////
38  /** @name Constructors */
39  ///@{
40 
41  /// Default Constructor
42  /**
43  Builds the empty Box <code>[(-1,-1,...,-1), (0,0,...,0)]</code>
44  */
45  inline Box();
46 
47  //useful for bc evaluation
48  Box faceBox(int a_idir, const Side::LoHiSide a_side) const
49  {
50  Box retval = adjCellSide(a_idir, 1, a_side);
51  if(a_side == Side::Lo)
52  {
53  retval = retval.shift(Point::Basis(a_idir, 1));
54  }
55  return retval;
56  }
57 
58  /// Two-Point Constructor
59  /**
60  Builds the non-trivial Box <code>[low, high]</code>
61 
62  \param a_low low corner
63  \param a_high high corner
64  */
65  inline Box(const Point& a_low, const Point& a_high);
66 
67  /// Primitive Two-Point Constructor
68  /**
69  Used for building a Box on platforms where plain-old-data is more convenient
70 
71  \param a_low C-Array representing this.low()
72  \param a_high C-Array representing this.high()
73  */
74  inline Box (const int* a_low, const int* a_high) { define(a_low, a_high); }
75 
76  /// Size Constructor
77  /**
78  Builds the non-trivial Box <code>[(0,...,0), a_sizes - (1,...,1)]</code>.
79  This is the box with its low corner at the origin and <code>a_sizes[dir]</code>
80  Points in direction <code>dir</code>.
81 
82  \param a_sizes sizes
83  */
84  inline Box(const Point& a_sizes);
85 
86  /// Copy Constructor
88  inline Box(const Box& a_box);
89 
90  /// Primitive Two-Point Lazy Constructor
91  /**
92  Weak construct this Box if necessary
93 
94  \param a_lo C-Array representing this.low()
95  \param a_hi C-Array representing this.high()
96  */
97  inline void define(const int* a_lo, const int* a_hi);
98  ///@}
99 
100  ///////////////////////////////////////////////////////////////////////////////////////////////
101  /** @name Static Functions */
102  ///@{
103  /// Build Cube Box
104  /**
105  Creates the Box <code>[Point::Zeros(), Point::Ones(a_size-1)]</code>,
106  a cube in \f$\bf{Z}^{DIM}\f$ of side length a_size
107 
108  \param a_size side length
109  */
110  inline static Box Cube(int a_size);
111 
112  /// Build Kernel Box
113  /**
114  Creates a Box of size <code> 2*a_radius + 1</code> on all sides with (0,...,0) at the center.
115  Useful for iterating through boundary cells, defining symmetric Stencils, etc.
116 
117  \param a_radius the number of "rings" of cells around the center cell.
118 
119  Example:
120  @code
121  //DIM=2
122  using namespace Proto;
123  auto K0 = Box::Kernel(1);
124  K0.print(); // [(-1,-1), (1, 1)]
125  auto K1 = Box::Kernel(2);
126  K1.print(); // [(-2, -2), (2, 2)]
127  @endcode
128  */
129  inline static Box Kernel(int a_radius);
130 
131  /// Stencil Index
132  /**
133  @private
134  Returns the linear index of <code>a_pt</code> inside the <code>Box</code> defined by <code>[a_low, a_high].
135  \nEquivalent to <code>Box::index</code> but does not require a <code>Box</code> instance.
136 
137  \param a_pt A Point
138  \param a_low The low Point of a Box
139  \param a_high The high Point of a Box
140  */
142  inline static unsigned int sindex(Point a_pt, Point a_low, Point a_high);
143 
144  /// Stencil Offset
145  /**
146  @private
147  Used internally by <code>Stencil</code>, not recommended for public use.
148 
149  \param a_pt A Point
150  \param a_low The low Point of a Box
151  \param a_high The high Point of a Box
152  */
153  // TODO: Doesn't appear to be used anywhere -CLG
154  //ACCEL_DECORATION
155  //inline static unsigned int soffset(const Point& a_pt, const Point& a_low, const Point& a_high);
156  ///@}
157 
158  ///////////////////////////////////////////////////////////////////////////////////////////////
159  /** @name Accessors And Queries */
160  ///@{
161 
162  /// Access Low Corner
163  /**
164  This function returns by value; a Box cannot be altered through the output of <code>low()</code>.
165  */
167  inline Point low() const {return m_low;}
168 
169  /// Access High Corner
170  /**
171  This function returns by value; a Box cannot be altered through the output of <code>high()</code>.
172  */
174  inline Point high() const {return m_high;}
175 
176  //TODO: needs renaming
177  //useful for bc evaluation
178  inline Point boundary(const Side::LoHiSide a_side) const;
179 
180  /// Edge Size
181  /**
182  Returns the "edge length" of this Box on a given axis
183 
184  /param a_dim direction axis in <code>[0,DIM)</code>
185 
186  Example:
187  @code
188  //DIM=2
189  using namespace Proto;
190  Box B(Point::Zeros(), Point({1,3}));
191  B.print(); //prints [(0,0),(1,3)]
192  std::cout << B.size(0) << std::endl; //prints 2
193  std::cout << B.size(1) << std::endl; //prints 4
194  @endcode
195  */
197  inline std::size_t size(unsigned int a_dim) const;
198 
199  /// Volumetric Size
200  /**
201  Returns the "volume" (in number of points) of this box.
202 
203  Example:
204  @code
205  //DIM=2
206  using namespace Proto;
207  Box B(Point::Zeros(), Point({1,3}));
208  B.print(); //prints [(0,0),(1,3)]
209  std::cout << B.size() << std::endl; //prints 8 (=2*4)
210  @endcode
211  */
213  inline std::size_t size() const;
214 
215  /// All Sizes
216  /**
217  Returns all sizes at once in the form of a Point.
218  */
220  inline Point sizes() const;
221 
222  /// Contains Point Query
223  /**
224  Checks if a_pt is inside of *this.
225  Note that <code>this->low() </code> and <code> this->high() </code> are both considered inside *this
226 
227  Example:
228  @code
229  //DIM=2
230  using namespace Proto;
231  Box B(Point::Zeros(), Point({1,3}));
232  std::cout << B.contains(Point({0,0})) << std::endl; //prints true
233  std::cout << B.contains(Point({1,1})) << std::endl; //prints true
234  std::cout << B.contains(Point({1,3})) << std::endl; //prints true
235  std::cout << B.contains(Point({1,4})) << std::endl; //prints false
236  @endcode
237  */
239  inline bool containsPoint(const Point& a_pt) const;
240 
241  /// Contains Box Query
242  /**
243  Check if Box a_rhs is a subset of *this. Returns true even if a_rhs is not a proper subset.
244  Equivalent to <code> this->contains(a_rhs.low()) && this->contains(a_rhs.high() </code>
245 
246  Example:
247  @code
248  //DIM=2
249  using namespace Proto;
250  Box B0(Point({0,0}),Point({3,3}));
251  Box B1(Point({1,1}),Point({2,2}));
252  Box B2(Point({1,1}),Point({4,4}));
253  Box B2(Point({-1,-1}),Point({2,2}));
254  std::cout << B0.contains(B0) << std::endl; //prints true
255  std::cout << B0.contains(B1) << std::endl; //prints true
256  std::cout << B0.contains(B2) << std::endl; //prints false
257  std::cout << B0.contains(B3) << std::endl; //prints false
258  @endcode
259  */
261  inline bool containsBox(const Box& a_rhs) const;
262 
263  /// Point on Boundry Query
264  /**
265  Check of <code>a_p</code> is part of the boundary of this Box.
266 
267  \param a_p A Point
268  */
269  inline bool onBoundary(const Point& a_p) const;
270 
271  /** Returns the direction of the region adjacent to this which contains a point.
272  * Point::Zeros() is returned if a_point is contained inside of this */
273  inline Point whichBoundaryContains(const Point& a_point) const;
274 
275  /// Empty Query
276  /**
277  Check if *this contains no Points
278  */
280  inline bool empty() const {return (m_size < 1);}
281 
282  /// Point to Linear Index
283  /**
284  Returns a linear index in <code>[0,this->size())</code> associated with <code>a_pt</code>.
285  Fails by assertion if <code>a_pt</code> is not inside <code>*this</code>.
286  Indices start at <code>this->low()</code> which has an index of 0. Indices increase
287  fastest in dimension 0 and slowest in dimension <code>DIM-1</code>. <code>this->high()</code>
288  has an index of <code>this->size()-1</code> as is consistent with the < operator of <code>Point</code>.
289 
290  \param a_pt a Point inside *this
291  */
293  inline unsigned int index(const Point& a_pt) const;
294 
295  /// Access Point by Index
296  /**
297  Return a Point associated with <code> a_index </code>.
298  This is the inverse of the <code>index(Point)</code> function.
299 
300  \param a_index an index in <code>[0,this->size())</code>
301  */
303  inline Point operator[](unsigned int a_index) const;
304 
305 
307  inline Point operator()(unsigned int a_idx, unsigned int a_idy, unsigned a_idz) const;
308  ///@}
309 
310 
311 
312  ///////////////////////////////////////////////////////////////////////////////////////////////
313  /** @name Operators */
314  ///@{
315 
316  /// Intersection Operator
317  /**
318  Returns a new Box which is the intersection of <code>*this</code> and <code>*a_rightBox</code>.
319 
320  \param a_rightBox Another Box
321 
322  Example:
323  @code
324  //DIM=2
325  using namespace Proto;
326  Box B0 = Box::Cube(3);
327  Box B1 = Box::Cube(3).shift(Point::Ones());
328  Box B2 = B0 & B1;
329  B0.print(); //prints [(0,0),(2,2)]
330  B1.print(); //prints [(1,1),(3,3)]
331  B2.print(); //prints [(1,1),(2,2)]
332  @endcode
333  */
334  inline Box operator&(const Box& a_rightBox) const;
335 
336 
337  /// In Place Intersection
338  /**
339  Performs intersection on *this with <code>a_rhs</code>
340 
341  \param a_rhs Another Box
342  */
343  inline void operator&=(const Box& a_rhs);
344 
345  inline Box operator+(const Box& box) const;
346  inline void operator+=(const Box& box);
347  /// Add Point Operator
348  /**
349  Returns a new Box which has been grown such that it contains a_pt.
350  if <code>this->contains(a_pt)</code> this function returns *this.
351 
352  \param a_pt Point to be added
353 
354  Example:
355  @code
356  //DIM=2
357  using namespace Proto;
358  auto B0 = Box::Cube(3);
359  B0.print(); //[(0,0), (2,2)]
360  Point p(-1,3);
361  auto B1 = B0 & p;
362  B1.print(); //[(-1,0), (2,3)]
363  @endcode
364  */
365  inline Box operator&(const Point& a_pt) const;
366 
367  /// In Place Add Point Operator
368  /**
369  Alters <code>*this</code> so that it now includes <code>a_pt</code>.
370  If <code>this->contains(a_pt)</code>, this function does nothing.
371 
372  \param a_pt A Point
373  */
374  inline void operator&=(const Point& a_pt);
375 
376 
377 
378  /// Equality Operator
379  /**
380  Two Boxes are considered equal if they have identical (==) low() and high()
381 
382  \param a_rhsBox A Box to test equality with
383  */
384  inline bool operator==(const Box& a_rhsBox) const;
385 
386  /// Inequality Operator
387  inline bool operator!=(const Box& a_rhsBox) const;
388 
389  /// Less Than Operator
390  /**
391  Establishes an ordering for Boxes. This ordering is defined by comparing
392  the low corner Point and then the high corner Point of the two Boxes.
393 
394  \param a_rhsBox A Box.
395  */
396  inline bool operator<(const Box& a_rhsBox) const;
397 
398  /// Modulus Operator
399  /**
400  Convenience operator for <code>Box::mod</code>.
401  Returns the periodic image of <code>a_pt</code> contained in <code>*this</code>
402 
403  \param a_pt A Point to mod by
404  */
406  inline Point operator%(const Point& a_pt) const;
407 
408  /// Modulus Function
409  /**
410  Returns the periodic image of a_pt that is inside *this.
411 
412  \param a_pt Point divisor
413 
414  Example:
415  @code
416  //DIM = 2;
417  using namespace Proto;
418  Box B = Box::Cube(3); // [(0,0), (2,2)]
419  std::cout << B.mod(Point({3,3})) << std::endl; //prints (0,0)
420  std::cout << B.mod(Point({-1,-1})) << std::endl; //prints (2,2)
421  @endcode
422  */
424  inline Point mod(const Point& a_pt) const;
425 
426  ///@}
427 
428  ///////////////////////////////////////////////////////////////////////////////////////////////
429  /** @name Transformations */
430  ///@{
431 
432  /// Shift Transformation
433  /**
434  Creates a new Box shifted in <code>a_direction</code> by <code>a_offset</code>
435  units relative to <code>*this</code>.
436 
437  \param a_direction an int in /f$[0,DIM)/f$ specifying a direction
438  \param a_offset number of points to offset. Use a negative value for a negative offset.
439 
440  Example:
441  @code
442  //DIM=2
443  using namespace Proto;
444  Box B1 = Box::Cube(2);
445  Box B2 = B1.shift(0,1);
446  Box B3 = B1.shift(1,-1);
447  B1.print(); //prints [(0,0), (1,1)]
448  B2.print(); //prints [(1,0), (2,1)]
449  B3.print(); //prints [(0,-1), (1,0)]
450  @endcode
451  */
452  inline Box shift(int a_direction, int a_offset) const;
453 
454  /// Point Shift Transformation
455  /**
456  Creates a new Box shifted by <code>a_pt</code> relative to <code>*this</code>.
457  New Box is: <code>[low() + a_pt, high() + a_pt]</code>
458  \param a_pt shift offset
459 
460  Example:
461  @code
462  //DIM=2
463  using namespace Proto;
464  Box B1(Point::Zeros(),Point::Ones());
465  Box B2 = B1.shift(Point({2,-3}));
466  B1.print(); //prints [(0,0), (1,1)]
467  B2.print(); //prints [(2,-3), (3,-2)]
468  @endcode
469  */
470  inline Box shift(const Point& a_pt) const;
471 
472  /// Shift To Origin
473  /**
474  Creates a new Box shifted such that <code>this->low() == (0,...,0)</code>.
475  Equivalent to <code>this->shift(this->low())</code>.
476  */
477  inline Box toOrigin() const;
478 
479  /// Isotropic Grow Operation
480  /**
481  Returns a new Box which is larger in every direction by a_numpoints units.
482  If a_numpoints is negative, the box will shrink.
483  \param a_numpoints number of points to grow by in each direction
484 
485  Example:
486  @code
487  //DIM=2
488  using namespace Proto;
489  Box B0(Point::Zeros(),Point::Ones());
490  Box B1 = B0.grow(3);
491  Box B2 = B1.grow(-2);
492  B0.print(); //prints [(0, 0), (1, 1)]
493  B1.print(); //prints [(-3,-3), (4, 4)]
494  B2.print(); //prints [(-1,-1), (2, 2)]
495  @endcode
496  */
497  inline Box grow(int a_numpoints) const;
498 
499  /// Anisotropic Grow Operation
500  /**
501  Returns the reshaped Box: [low() - a_pt, high() + a_pt]
502  To grow a box only upwards / downwards, see <code>Box::extrude</code>.
503 
504  \param a_pt growth offset
505 
506  Example:
507  @code
508  //DIM=2
509  using namespace Proto;
510  Box B0(Point::Zeros(),Point::Ones()*3);
511  Box B1 = B0.grow(Point({-1,1})); //shrink in dimension 0, grow in dimension 1
512  B0.print(); //prints [(0, 0), (3, 3)]
513  B1.print(); //prints [(1, -1), (2, 4)]
514  @endcode
515  */
516  inline Box grow(const Point& a_pt) const;
517 
518  /// Anisotropic Grow (Int Version)
519  /**
520  Returns grow(Point::Basis(a_dir, a_dist))
521  Useful in places where plain-old-data inputs are preferable.
522  To grow a grow a box only upwards / downwards, see <code>Box::extrude</code>.
523 
524  \param a_dir A direction in [0,DIM)
525  \param a_dist Distance to grow
526  */
527  inline Box grow(int a_dir, int a_dist) const;
528 
529  /// One-Sided Grow
530  /**
531  Grows the box along coordinate <code>a_dir</code> a distance <code> a_dist </code>
532  on side <code>a_side</code> only. This function is equivalent to
533  <code>extrude(Point::Basis(a_dir, sign(a_side)*a_dist)) </code>.
534 
535  \param a_dir A direction in [0, DIM)
536  \param a_side Either Side::Lo or Side::Hi
537  \param a_dist How far to grow
538  */
539  inline Box grow(int a_dir, Side::LoHiSide a_side, int a_dist) const;
540 
541  /// Apply Centering
542  /**
543  * Create a new Box that is grown in such a way as to accomodate the extra points needed
544  * by a domain with the specified centering. If a_ctr=PR_CELL this function is a null-op.
545  */
546  inline Box grow(Centering a_ctr) const;
547 
548  /// Extrude
549  /**
550  AKA directional grow. Returns a new Box with the <code> a_dir </code> direction extruded a distance <code> a_dist </code).
551 
552  \param a_dir Direction to extrude in.
553  \param a_dist (Optional) Distance to extrude (default: 1)
554 
555  Example:
556  @code
557  //DIM=3
558  using namespace Proto;
559  Box B0 = Box::Cube(4).shift(Point::Ones());
560  Box B1 = B0.extrude(Point::Ones(), 2);
561  Box B2 = B0.extrude(Point::Basis(0,-1),3);
562  Box B3 = B0.extrued(Point(-1, 1, 0);
563  B0.print(); //prints [(1, 1, 1), (4, 4, 4)]
564  B1.print(); //prints [(1, 1, 1), (6, 6, 6)]
565  B2.print(); //prints [(-2, 1, 1), (4, 4, 4)]
566  B3.print(); //prints [(0, 1, 1), (4, 5, 4)]
567  @endcode
568  */
569  inline Box extrude(const Point& a_dir, int a_dist = 1) const;
570 
571  //TODO: Better to use grow(dir, side, dist) in my opinion -CLG
572  /// Extrude (Primitive Version)
573  /**
574  AKA directional grow. Returns a new Box with the <code> a_dir </code> direction extruded a distance <code> a_dist </code).
575  By default, the extrusion is upwards. If <code>a_upper</code> is false, extrudes downwards.
576 
577  \param a_dir Axis to extrude along
578  \param a_dist (Optional) Distance to extrude (default: 1)
579  \param a_upper (Optional) Extrude upwards? (default: true)
580 
581  Example:
582  @code
583  //DIM=2
584  using namespace Proto;
585  Box B0 = Box::Cube(4).shift(Point::Ones());
586  Box B1 = B0.extrude(2,3,false);
587  Box B2 = B0.extrude(2,3,true);
588  B0.print(); //prints [(1, 1, 1), (4, 4, 4)]
589  B1.print(); //prints [(1, 1, -2), (4, 4, 4)]
590  B2.print(); //prints [(1, 1, 1), (4, 4, 7)]
591  @endcode
592  */
593  inline Box extrude(int a_dir, int a_dist = 1, bool a_upper = true) const;
594 
595  /// Grow High Side
596  /**
597  Equivalent to <code>grow(a_dir, Side::Hi, a_dist)</code>
598 
599  \param a_dir Coordinate axis to grow along
600  \param a_dist Distance to grow
601  */
602  inline Box growHi(int a_dir, int a_dist) const;
603 
604  /// Grow Low Side
605  /**
606  Equivalent to <code>grow(a_dir, Side::Lo, a_dist)</code>
607 
608  \param a_dir Coordinate axis to grow along
609  \param a_dist Distance to grow
610  */
611  inline Box growLo(int idir, int igrow) const;
612 
613  /// Isotropic Coarsen Operation
614  /**
615  Returns a new Box coarsened by a factor of <code>a_numpoints</code>. Fails if user tries to
616  coarsen using a non-positive ratio.
617  If the limits of <code>*this</code> are not multiples of the coarsening ratio
618  (e.g. if <code>this-> coarsenable() != true</code>) the resulting Box is not guaranteed to
619  be a subset of <code>*this</code>. In this situation, use <code>Box::taperCoarsen</code>
620 
621  \param a_ratio Coarsening ratio
622 
623  Example:
624  @code
625  //DIM=2
626  using namespace Proto;
627  Box B0 = Box::Cube(4);
628  Box B1 = B0.coarsen(2);
629  B0.print(); //prints [(0, 0), (3, 3)]
630  B1.print(); //prints [(0, 0), (1, 1)]
631  Box B2 = Box::Cube(3).shift(Point::Ones(2));
632  Box B3 = B2.coarsen(2);
633  B2.print(); //prints [(2, 2), (4, 4)]
634  B3.print(); //prints [(1, 1), (2, 2)]
635  @endcode
636  */
637  inline Box coarsen(unsigned int a_ratio) const;
638 
639  /// Anisotropic Coarsen Operation
640  /**
641  Returns a new Box coarsened in each direction according to <code>a_pt</code>.
642  Fails if user tries to coarsen using a non-positive ratio.
643  (*this).coarsen(a_pt).refine(a_pt) will always contain *this.
644 
645  \param a_pt Coarsening ratios
646 
647  Example:
648  @code
649  //DIM=2
650  using namespace Proto;
651  Box B0 = Box::Cube(4);
652  //coarsen in only the 1 direction
653  Box B1 = B0.coarsen(Point({1,2}));
654  B1.print(); //prints [(0,0),(3,1)]
655  @endcode
656  */
657  inline Box coarsen(const Point& a_pt) const;
658 
659  /// (Isotropic) Coarsenable Query
660  /**
661  Returns true if *this will coarsen normally by a given ratio.
662 
663  \param a_ratio Coarsening ratio
664  */
665  inline bool coarsenable(const int& a_ratio) const;
666 
667  /// (Anisotropic) Coarsenable Query
668  /**
669  Returns true if *this will coarsen normally by a given ratio.
670 
671  \param a_ratio Coarsening ratio
672  */
673  inline bool coarsenable(const Point& a_ratio) const;
674 
675  /// Tapered Coarsen
676  /**
677  This function is identical to Box::coarsen when Box::coarsenable() is true.
678  For non-coarsenable Boxes, the new Box's limits are rounded such that the result
679  Is always a subset of *this. Specifically, the lower limits are always rounded UP.
680  This function is used heavily in the automatic computation of domains and ranges
681  for pointwise and Stencil operators, but generally has limited use otherwise.
682 
683  \param a_ref Coarsening ratio
684  */
685  inline Box taperCoarsen(const Point& a_ref) const;
686 
687  /// Anisotropic Refine Operation
688  /**
689  Returns a new Box refined in each direction according to a_pt.
690  \param a_pt Refinement ratios
691 
692  Example:
693  @code
694  //DIM=2
695  using namespace Proto;
696  Box B0 = Box::Cube(2);
697  Box B1 = B0.refine(Point({1,2}));
698  B0.print(); //prints [(0, 0), (1, 1)]
699  B1.print(); //prints [(0, 0), (1, 3)]
700  @endcode
701  */
702  inline Box refine(const Point& a_pt) const;
703 
704  /// Isotropic Refine Operation
705  /**
706  Returns a new Box refined in all directions by a_numpoints.
707 
708  \param a_ratio Refinement ratio
709 
710  Example:
711  @code
712  //DIM=2
713  using namespace Proto;
714  Box B0 = Box::Cube(2);
715  Box B1 = B0.refine(2);
716  B0.print(); //prints [(0, 0), (1, 1)]
717  B1.print(); //prints [(0, 0), (3, 3)]
718 
719  Box B2 = Box::Cube(2).shift(Point::Ones());
720  Box B3 = B2.refine(2);
721  B2.print(); //prints [(1, 1), (2, 2)]
722  B3.print(); //prints [(2, 2), (5, 5)]
723  @endcode
724  */
725  inline Box refine(unsigned int a_ratio) const;
726 
727  /// Edge
728  /**
729  Returns the subset on the boundary of *this in a given direction with specified thickness.
730  Very handy for adjacency and boundary based computations. This function is slightly more general
731  than <code>face(...)</code> in that it can return regions of all codimensionalities (faces, edges, corners, etc.)
732  The returned <code>Box</code> is always a subset of <code>*this</code>
733 
734  \param a_dir Direction of desired edge with respect to the cell center of *this
735  \param a_dist Thickness of the output (default: 1)
736 
737  Examples:
738  @code
739  //DIM = 2
740  using namespace Proto;
741  auto B0 = Box::Cube(4).shift(Point::Ones()); //[(1,1), (4,4)]
742  auto B1 = B0.edge(Point::Basis(0)); //[(4,1), (4,4)]
743  auto B2 = B0.edge(Point::Ones(), 2); //[(3,3), (4,4)]
744  auto B3 = B0.edge(Point::Basis(1,-1), 2); //[(1,1), (4,2)]
745  @endcode
746  */
747  inline Box edge(const Point& a_dir, int a_dist) const;
748 
749  /// Edge (Anisotropic)
750  /**
751  Returns an edge box that is allowed to be anisotropic
752 
753  Example
754  @code
755  //DIM=2
756  using namespace Proto;
757  auto B0 = Box::Cube(4).shift(Point::Ones()); //[(1,1), (4,4)]
758  // get the 1 x 2 Box in the (-x, +y) direction corner of B0
759  auto B1 = B0.edge(Point(-1,2)); //[(1,3), (1,4)]
760  @endcode
761  */
762  inline Box edge(const Point& a_dir) const;
763  inline Box edge(int a_dir, Side::LoHiSide a_side, int a_dist) const;
764  /// Face
765  /**
766  Returns the face (e.g. region of codimension 1) of this box in a specified direction.
767  The output box is always contained in *this.
768  For adjacent faces, use <code>adjacent(...)</code>.
769  If <code>a_dist >= size(a_dir) </code>, the rturned box = *this.
770 
771  \param a_dir Coordinate direction in [0, DIM)
772  \param a_side Side::Lo or Side::Hi
773  \param a_dist (Optional) Thickness of the output. (default: 1)
774 
775  Examples:
776  @code
777  //DIM = 2
778  using namespace Proto;
779  auto B0 = Box::Cube(4).shift(Point::Ones()); //[(1,1), (4,4)]
780  auto B1 = B0.face(0, Side::Hi); //[(4,1), (4,4)]
781  auto B2 = B0.face(1, Side::Lo, 2); //[(1,1), (4,2)]
782  auto B3 = B0.face(0, Side::Lo, 5); //[(1,1), (4,4)]
783  @endcode
784  */
785  inline Box face(int a_dir, Side::LoHiSide a_side, int a_dist = 1) const;
786 
787  inline Box face(Point a_dir, int a_dist = 1) const;
788 
789  //TODO: redundant with face, unused
790  //Box faceBox(int a_idir, const Side::LoHiSide a_side) const;
791 
792  //TODO: Redundant with face
793  /// Flatten
794  /**
795  Returns a copy of *this with dimension a_dir flattened to a thickness of 1.
796  Useful for creating Boxes of dimensionality less than DIM (e.g. a plane in 3D).
797 
798  \param a_dir Direction to flatten
799  \param a_upper Flatten upwards?
800 
801  Example:
802  @code
803  //DIM=3
804  using namespace Proto;
805  Box B0 = Box::Cube(4).shift(Point::Ones());
806  Box B1 = B0.flatten(2);
807  Box B2 = B0.flatten(2,true);
808  B0.print(); //prints [(1, 1, 1), (4, 4, 4)]
809  B1.print(); //prints [(1, 1, 1), (4, 4, 1)]
810  B2.print(); //prints [(1, 1, 4), (4, 4, 4)]
811  @endcode
812  */
813  inline Box flatten(const int a_dir, bool a_upper = false) const;
814  /// Adjacent Cells
815  /**
816  Returns a box adjacent to *this in a given direction with a thickness
817  a_dist in the normal direction. If there are multiple non-zero entries
818  in a_dir, a_dist will be applied to the thickness in all of those directions
819 
820  \param a_dir "Normal" direction of the desired adjacent cell
821  \param a_dist (Optional) "thickness" of the desired adjacent cell (default: this->size(a_dir))
822 
823  Examples:
824  @code
825  //DIM = 2;
826  Box B0 = Box::Cube(8); // [(0,0) , (7,7)]
827  B0.adjacent((1,0) , 2); // [(8,0) , (9,7)]
828  B0.adjacent((0,-1), 2); // [(0,-2), (7,-1)]
829  B0.adjacent((-1,1), 2); // [(-2,8), (-1,9)]
830  B0.adjacent((1,0)); // [(8,0) , (15,7)], 8 x 8 cube directly adjacent in (1, 0) direction
831  @endcode
832  */
833  inline Box adjacent(const Point& a_dir, int a_dist) const;
834 
835  /// Adjacent Cells (Anisotropic)
836  /**
837  Overload of adjacent which allows for anisotropic outputs.
838 
839  Example:
840  @code
841  //DIM = 2;
842  using namespace Proto;
843  Box B0 = Box::Cube(8); // [(0,0) , (7,7)]
844  // Get the 1 x 2 Box adjacent to B0 in the (+x, -y) direction
845  B0.adjacent(Point(1,-2)); // [(8,-2) , (8,-1)]
846  @endcode
847  */
848  inline Box adjacent(const Point& a_dir) const;
849 
850  /// Adjacent Cells (Side)
851  /**
852  Overload of adjacent that uses a Side input.
853 
854  \param a_dir Coordinate direction (0 for x direction, etc.)
855  \param a_side Low or high side
856  \param a_dist (optional) "thickness" of the desired adjacent cell (default: this->size(a_dir))
857 
858  Examples:
859  @code
860  //DIM = 2;
861  Box B0 = Box::Cube(8); // [(0,0) , (7,7)]
862  B0.adjacent((0, Side::Hi, 2); // [(8, 0), (9, 7)]
863  B0.adjacent((0, Side::Lo, 2); // [(0,-2), (7,-1)]
864  B0.adjacent((0, Side::Hi); // [(8, 0), (15,7)]
865  @endcode
866  */
867  inline Box adjacent(int a_dir, Side::LoHiSide a_side, int a_dist) const;
868 
869  //TODO: Redundant
870  inline Box adjCellLo(int a_dir, int a_dist) const;
871 
872  //TODO: Redundant
873  inline Box adjCellHi(int a_dir, int a_dist) const;
874 
875  //TODO: Redundant
876  inline Box adjCellSide(int a_idir, int a_length, Side::LoHiSide a_sd) const
877  {
878  Box retval = adjCellHi(a_idir, a_length);
879  if(a_sd == Side::Lo)
880  {
881  retval = adjCellLo(a_idir, a_length);
882  }
883  return retval;
884  }
885 
886  ///@}
887 
888  ///////////////////////////////////////////////////////////////////////////////////////////////
889  /** @name Utility */
890  ///@{
891 
892  /// Iterator Begin
893  /**
894  See documentation for Proto::BoxIterator for a basic usage example.
895  */
896  inline BoxIterator begin() const;
897 
898  /// Iterator End
899  /**
900  See documentation for Proto::BoxIterator for a basic usage example.
901  */
902  inline BoxIterator end() const;
903 
904  /// Iterator Reverse Begin
905  /**
906  See documentation for Proto::BoxIterator for a basic usage example.
907  */
908  inline BoxIterator rbegin() const;
909 
910  /// Iterator Reverse End
911  /**
912  See documentation for Proto::BoxIterator for a basic usage example.
913  */
914  inline BoxIterator rend() const;
915 
916  /// Linear Size
917  /**
918  Computes the number of bytes needed to store *this in linear buffer.
919  */
920  inline size_t linearSize() const;
921 
922  /// Read From Buffer
923  /**
924  Reads data into *this from a buffer
925  */
926  inline void linearIn(const char* a_buf);
927 
928  /// Write To Buffer
929  /**
930  Writes the data in *this to a buffer
931  */
932  inline void linearOut(char* a_buf) const;
933 
934  /// Print
935  /**
936  Prints *this using the format <code>[low, high]</code>
937  */
938  inline void print() const;
939 
940  inline std::string str() const;
941  ///@}
942 
943  //private: // these should be treated as private. Some wise guy needs access.
944 
945  inline void recomputeSize(); ///< Used to reevaluate the size of the box when it is changed.
946 
947  Point m_low; ///< Point object containing the lower bounds of the Box.
948  Point m_high; ///< Point object containing the upper bounds of the Box.
949  int m_size; ///< "Volume" of the box.
950 
951  }; //end class Box
952 
953  /// OStream Operator
954  inline std::ostream& operator<<(std::ostream& a_os, const Box& a_box)
955  {
956  //a_os << "[" << a_box.low() << "," << a_box.high() << "]";
957  a_os << a_box.str();
958  return a_os;
959  }
960 
961  /// OStream Operator
962  inline std::istream& operator>>(std::istream& a_is, Box& a_box)
963  {
964 
965  Point low, high;
966  char dum1, dum2, dum3;
967  a_is >> dum1 >> low >> dum2 >> high >> dum3;
968  a_box = Box(low, high);
969  return a_is;
970  }
971 
972  /// Iterator for Boxes
973  /**
974  Iteration class which conforms to most of the syntax of std Iterator implementations.
975 
976  Example:
977  @code
978  Box box = Box::Cube(8);
979  // STL style iteration
980  for (auto biter = box.begin(); biter != box.end(); ++biter)
981  {
982  (*biter).print(); //prints all the points in box
983  }
984  // Alternate style
985  for (auto biter = box.begin(); biter.ok(); ++biter)
986  {
987  (*biter).print(); //prints all the points in box
988  }
989  @endcode
990  */
992  {
993  public:
994  /// Default Constructor
995  inline BoxIterator(){};
996 
997  /// Index Constructor
998  inline BoxIterator(const Box& a_box, int a_pos = 0);
999 
1000  /// Point Constructor
1001  inline BoxIterator(const Box& a_box, const Point& a_pos);
1002 
1003  /// Reset Iterator
1004  inline void begin() { m_pos = 0; }
1005 
1006  /// Continue Iteration Query
1007  inline bool ok() const;
1008 
1009  /// Equality Operator
1010  /**
1011  Returns true for two iterators with identical iteration index and Box.
1012  The Box instances need not be the same.
1013  */
1014  inline bool operator==(const BoxIterator& a_iter) const;
1015 
1016  /// Inequality Operator
1017  inline bool operator!=(const BoxIterator& a_iter) const { return !((*this) == a_iter); }
1018 
1019  /// Dereference Iterator
1020  /**
1021  Returns a Point
1022  */
1023  inline Point operator*() const { return m_box[m_pos]; };
1024 
1025  /// Get Index
1026  /**
1027  Returns the current index of the point *(*this).
1028  */
1029  inline int operator()() const { return m_pos; };
1030 
1031  /// Prefix Increment Iterator
1032  inline BoxIterator& operator++();
1033 
1034  /// Prefix Decrement Iterator
1035  inline BoxIterator& operator--();
1036 
1037  /// Postfix Increment Iterator
1038  inline BoxIterator operator++(int);
1039 
1040  /// Postfix Decrement Iterator
1041  inline BoxIterator operator--(int);
1042 
1043  private:
1045  int m_pos;
1046  }; //end class BoxIterator
1047 
1048 } //end namespace Proto
1049 #endif //end include guard
static Box Cube(int a_size)
Box(const int *a_low, const int *a_high)
Primitive Two-Point Constructor.
Definition: Proto_Box.H:74
bool operator!=(const BoxIterator &a_iter) const
Inequality Operator.
Definition: Proto_Box.H:1017
BoxIterator iterator
Definition: Proto_Box.H:35
ACCEL_DECORATION Point high() const
Access High Corner.
Definition: Proto_Box.H:174
Box toOrigin() const
Shift To Origin.
Box faceBox(int a_idir, const Side::LoHiSide a_side) const
Definition: Proto_Box.H:48
BoxIterator()
Default Constructor.
Definition: Proto_Box.H:995
Iterator for Boxes.
Definition: Proto_Box.H:991
LoHiSide
Side Enum.
Definition: Proto_Face.H:23
BoxIterator rend() const
Iterator Reverse End.
Box adjacent(const Point &a_dir, int a_dist) const
Adjacent Cells.
void operator &=(const Box &a_rhs)
In Place Intersection.
bool operator!=(const Box &a_rhsBox) const
Inequality Operator.
void define(const int *a_lo, const int *a_hi)
Primitive Two-Point Lazy Constructor.
std::istream & operator>>(std::istream &a_is, Box &a_box)
OStream Operator.
Definition: Proto_Box.H:962
int operator()() const
Get Index.
Definition: Proto_Box.H:1029
Low side; normal is in negative coordinate direction.
Definition: Proto_Face.H:26
ACCEL_DECORATION Point mod(const Point &a_pt) const
Modulus Function.
ACCEL_DECORATION Point operator[](unsigned int a_index) const
Access Point by Index.
Box flatten(const int a_dir, bool a_upper=false) const
Flatten.
Box adjCellLo(int a_dir, int a_dist) const
ACCEL_DECORATION unsigned int index(const Point &a_pt) const
Point to Linear Index.
ACCEL_DECORATION Point operator%(const Point &a_pt) const
Modulus Operator.
ACCEL_DECORATION bool containsPoint(const Point &a_pt) const
Contains Point Query.
Box extrude(const Point &a_dir, int a_dist=1) const
Extrude.
Point whichBoundaryContains(const Point &a_point) const
Point m_low
Point object containing the lower bounds of the Box.
Definition: Proto_Box.H:947
static ACCEL_DECORATION Point Basis(int a_dir, int a_scale=1)
Get Basis.
Box refine(const Point &a_pt) const
Anisotropic Refine Operation.
std::string str() const
void linearOut(char *a_buf) const
Write To Buffer.
An interval in DIM dimensional space.
Definition: Proto_Box.H:29
Box face(int a_dir, Side::LoHiSide a_side, int a_dist=1) const
Face.
ACCEL_DECORATION Point operator()(unsigned int a_idx, unsigned int a_idy, unsigned a_idz) const
Box adjCellSide(int a_idir, int a_length, Side::LoHiSide a_sd) const
Definition: Proto_Box.H:876
int m_size
"Volume" of the box.
Definition: Proto_Box.H:949
Box shift(int a_direction, int a_offset) const
Shift Transformation.
static ACCEL_DECORATION unsigned int sindex(Point a_pt, Point a_low, Point a_high)
Stencil Index.
Box edge(const Point &a_dir, int a_dist) const
Edge.
Point operator*() const
Dereference Iterator.
Definition: Proto_Box.H:1023
bool onBoundary(const Point &a_p) const
Point on Boundry Query.
Box growHi(int a_dir, int a_dist) const
Grow High Side.
Box grow(int a_numpoints) const
Isotropic Grow Operation.
size_t linearSize() const
Linear Size.
Box growLo(int idir, int igrow) const
Grow Low Side.
#define ACCEL_DECORATION
Definition: Proto_Accel.H:12
Box adjCellHi(int a_dir, int a_dist) const
ACCEL_DECORATION bool empty() const
Empty Query.
Definition: Proto_Box.H:280
ACCEL_DECORATION Point low() const
Access Low Corner.
Definition: Proto_Box.H:167
int m_pos
Definition: Proto_Box.H:1045
ACCEL_DECORATION std::size_t size() const
Volumetric Size.
Box m_box
Definition: Proto_Box.H:1044
Definition: Proto_Array.H:17
ACCEL_DECORATION Point sizes() const
All Sizes.
bool operator==(const Box &a_rhsBox) const
Equality Operator.
static Box Kernel(int a_radius)
Build Kernel Box.
std::ostream & operator<<(std::ostream &stream, const Array< T, N > &arr)
Ostream operator.
Box operator &(const Box &a_rightBox) const
Intersection Operator.
Point m_high
Point object containing the upper bounds of the Box.
Definition: Proto_Box.H:948
Integer Valued Vector.
Definition: Proto_Point.H:24
void print() const
Print.
BoxIterator begin() const
Iterator Begin.
Box taperCoarsen(const Point &a_ref) const
Tapered Coarsen.
BoxIterator end() const
Iterator End.
Box()
Default Constructor.
Box coarsen(unsigned int a_ratio) const
Isotropic Coarsen Operation.
void begin()
Reset Iterator.
Definition: Proto_Box.H:1004
bool operator<(const Box &a_rhsBox) const
Less Than Operator.
void linearIn(const char *a_buf)
Read From Buffer.
Point boundary(const Side::LoHiSide a_side) const
bool coarsenable(const int &a_ratio) const
(Isotropic) Coarsenable Query
Box operator+(const Box &box) const
void operator+=(const Box &box)
BoxIterator rbegin() const
Iterator Reverse Begin.
void recomputeSize()
Used to reevaluate the size of the box when it is changed.
Centering
Definition: Proto_Centering.H:7
ACCEL_DECORATION bool containsBox(const Box &a_rhs) const
Contains Box Query.