OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
SIndex.hpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  * This program was prepared by PSI.
7  * All rights in the program are reserved by PSI.
8  * Neither PSI nor the author(s)
9  * makes any warranty, express or implied, or assumes any liability or
10  * responsibility for the use of this software
11  *
12  * Visit www.amas.web.psi for more details
13  *
14  ***************************************************************************/
15 
16 // -*- C++ -*-
17 /***************************************************************************
18  *
19  * The IPPL Framework
20  *
21  *
22  * Visit http://people.web.psi.ch/adelmann/ for more details
23  *
24  ***************************************************************************/
25 
26 // include files
27 #include "Index/SIndex.h"
28 #include "Index/IndexedSIndex.h"
30 #include "Utility/PAssert.h"
31 
32 
33 
34 
36 // default constructor: this requires the user to call 'initialize'
37 // before any other actions are carried out with this SIndex
38 template<unsigned int Dim>
39 SIndex<Dim>::SIndex() : Layout(0) {
40 
41 }
42 
43 
45 // constructor: requires a FieldLayout, and optionally an offset amount
46 template<unsigned int Dim>
48 
49 
50 
51  setup();
52 }
53 
54 
56 // copy constructor
57 template<unsigned int Dim>
59  : Layout(si.Layout), Offset(si.Offset), IndexList(si.IndexList),
60  BoundingBox(si.BoundingBox)
61 {
62 
63 
64 
65  // check in as a user of this Layout
66  Layout->checkin(*this);
67 }
68 
69 
71 // a special constructor, taking another SIndex and an Offset. This
72 // version is almost like a copy constructor, except that the given Offset
73 // is added to our own offset.
74 template<unsigned int Dim>
76  : Layout(si.Layout), Offset(si.Offset), IndexList(si.IndexList),
77  BoundingBox(si.BoundingBox)
78 {
79 
80 
81 
82  // add in the extra offset amount
83  Offset += so;
84 
85  // check in as a user of this Layout
86  Layout->checkin(*this);
87 }
88 
89 
91 // a special constructor, taking another SIndex and an int * offset. This
92 // version is almost like a copy constructor, except that the given Offset
93 // is added to our own offset.
94 template<unsigned int Dim>
95 SIndex<Dim>::SIndex(const SIndex<Dim>& si, const int *so)
96  : Layout(si.Layout), Offset(si.Offset), IndexList(si.IndexList),
97  BoundingBox(si.BoundingBox)
98 {
99 
100 
101 
102  // add in the extra offset amount
103  Offset += so;
104 
105  // check in as a user of this Layout
106  Layout->checkin(*this);
107 }
108 
109 
111 // destructor: frees memory used to store indices, and check out from Layout
112 template<unsigned int Dim>
114 
115  if (Layout != 0)
116  Layout->checkout(*this);
117 }
118 
119 
121 // initialize the object, if we were constructed with the default
122 // constructor
123 template<unsigned int Dim>
125 
126 
127 
128  Layout = &fl;
129  setup();
130 }
131 
132 
134 // set up our internal data structures from the constructor. Assumes
135 // the Layout and Offset have been set.
136 template<unsigned int Dim>
138 
139 
140  // check in as a user of the FieldLayout
141  Layout->checkin(*this);
142 
143  // get the number of vnodes, and make sure we have storage for them
144  IndexList.reserve(Layout->size_iv());
145 
146  // create new LSIndex objects for the local vnodes
147  typename FieldLayout<Dim>::iterator_iv locvn = Layout->begin_iv();
148  for ( ; locvn != Layout->end_iv(); ++locvn)
149  IndexList.push_back(std::make_shared<LSIndex<Dim>>((*locvn).second.get()));
150 
151  // save our bounding box information
152  BoundingBox = Layout->getDomain();
153 }
154 
155 
157 // add a new index point, specified as an Offset or as a single-point NDIndex.
158 // return success (this can fail if the point is outsize the field's domain)
159 template<unsigned int Dim>
161 
162 
163 
164  // right now, this is straightforward: try to add to each LSIndex in
165  // succession until one actually works
166  for (iterator_iv curr = begin_iv(); curr != end_iv(); ++curr) {
167  if (addIndex(curr, so)) {
168  return true;
169  }
170  }
171 
172  // if we're here, we could not find a vnode to take this point
173  return false;
174 }
175 
176 
178 // add a new index point, specified as an Offset or as a single-point NDIndex.
179 // This version specifically tells which LField to use.
180 // return success (this can fail if the point is outsize the field's domain)
181 template<unsigned int Dim>
183  const SOffset<Dim>& so) {
184 
185 
186 
187  // if the point is in the LField's region, add it
188  if ((*curr)->contains(so) && ! (*curr)->hasIndex(so)) {
189  (*curr)->addIndex(so);
190  return true;
191  }
192 
193  // if we're here, the point was outside the given LField's domain
194  return false;
195 }
196 
197 
199 // same as above, but taking an NDIndex. One point is added to our lists
200 // for each point in the NDIndex region (e.g., if a 2x3 NDIndex is given,
201 // 6 points in total will be added to this SIndex).
202 template<unsigned int Dim>
203 void SIndex<Dim>::addIndex(const NDIndex<Dim>& constndi) {
204 
205 
206 
207  // cast away const; we are not modifying the NDIndex, so this should be ok
208  NDIndex<Dim>& ndi((NDIndex<Dim> &)constndi);
209 
210  // calculate the total number of points, and counters for looping
211  unsigned int d, totalnum = ndi.size();
212  Index::iterator counter[Dim];
213  for (d=0; d < Dim; ++d)
214  counter[d] = ndi[d].begin();
215 
216  while (totalnum-- > 0) {
217  // create an SOffset obj and add it to our lists
218  SOffset<Dim> newpoint;
219  for (d=0; d < Dim; ++d)
220  newpoint[d] = *(counter[d]);
221  addIndex(newpoint);
222 
223  // increment the index iterators
224  unsigned int chkdim = 0;
225  while(chkdim < Dim) {
226  ++(counter[chkdim]);
227  if (counter[chkdim] == ndi[chkdim].end()) {
228  counter[chkdim] = ndi[chkdim].begin();
229  chkdim++;
230  } else {
231  break;
232  }
233  }
234  }
235 }
236 
237 
239 // add a new index point, specified as an Offset or as a single-point NDIndex.
240 // return success (this can fail if the point is outsize the field's domain)
241 template<unsigned int Dim>
243 
244 
245 
246  // right now, this is straightforward: try to add to each LSIndex in
247  // succession until one actually works
248  for (iterator_iv curr = begin_iv(); curr != end_iv(); ++curr)
249  if (removeIndex(curr, so))
250  return true;
251 
252  // if we're here, we could not find a vnode to take this point
253  return false;
254 }
255 
256 
258 // add a new index point, specified as an Offset or as a single-point NDIndex.
259 // This version specifically tells which LField to use.
260 // return success (this can fail if the point is outsize the field's domain)
261 template<unsigned int Dim>
263  const SOffset<Dim>& so) {
264 
265 
266  if ((*curr)->hasIndex(so)) {
267  (*curr)->removeIndex(so);
268  return true;
269  }
270  return false;
271 }
272 
273 
275 // same as above, but taking an NDIndex. One point is added to our lists
276 // for each point in the NDIndex region (e.g., if a 2x3 NDIndex is given,
277 // 6 points in total will be added to this SIndex).
278 template<unsigned int Dim>
279 void SIndex<Dim>::removeIndex(const NDIndex<Dim>& constndi) {
280 
281 
282 
283  // cast away const; we are not modifying the NDIndex, so this should be ok
284  NDIndex<Dim>& ndi((NDIndex<Dim> &)constndi);
285 
286  // calculate the total number of points, and counters for looping
287  unsigned int d, totalnum = ndi.size();
288  Index::iterator counter[Dim];
289  for (d=0; d < Dim; ++d)
290  counter[d] = ndi[d].begin();
291 
292  while (totalnum-- > 0) {
293  // create an SOffset obj and add it to our lists
294  SOffset<Dim> newpoint;
295  for (d=0; d < Dim; ++d)
296  newpoint[d] = *(counter[d]);
297  removeIndex(newpoint);
298 
299  // increment the index iterators
300  unsigned int chkdim = 0;
301  while(chkdim < Dim) {
302  ++(counter[chkdim]);
303  if (counter[chkdim] == ndi[chkdim].end()) {
304  counter[chkdim] = ndi[chkdim].begin();
305  chkdim++;
306  } else {
307  break;
308  }
309  }
310  }
311 }
312 
313 
315 // reserve storage space equal to the given fraction of the size of
316 // each vnode. if fraction=1.0, reserve storage for the entire vnode.
317 template<unsigned int Dim>
318 void SIndex<Dim>::reserve(double fraction) {
319  for (iterator_iv a = begin_iv(); a != end_iv(); ++a) {
320  typename LSIndex<Dim>::size_type newcapacity = (*a)->getDomain().size();
321  if (fraction < 0.9999 && fraction > 0.0)
322  newcapacity = static_cast<typename LSIndex<Dim>::size_type>(fraction *
323  static_cast<double>(newcapacity));
324  (*a)->reserve(newcapacity);
325  }
326 }
327 
328 
330 // clear out the existing indices
331 template<unsigned int Dim>
333 
334 
335  // tell all LSIndex objects to remove their points
336  for (iterator_iv a = begin_iv(); a != end_iv(); ++a) {
337  (*a)->clear();
338  }
339 }
340 
341 
343 // return whether the given point is contained here
344 template<unsigned int Dim>
345 bool SIndex<Dim>::hasIndex(const SOffset<Dim>& so) const {
346 
347 
348 
349  for (const_iterator_iv a = begin_iv(); a != end_iv(); ++a)
350  if ((*a)->hasIndex(so))
351  return true;
352  return false;
353 }
354 
355 
357 // assignment operator
358 // NOTE: this right now only works properly when the layout's match
359 template<unsigned int Dim>
361 
362 
363 
364  if (&si != this) {
365  // copy the offset and layout, checking ourselves in if necessary
366  Offset = si.Offset;
367  if (Layout == 0 || Layout != si.Layout) {
368  if (Layout != 0)
369  Layout->checkout(*this);
370  Layout = si.Layout;
371  Layout->checkin(*this);
372  }
373 
374  // copy the list of index objects, replacing our current contents
375  IndexList = si.IndexList;
376 
377  // copy the bounding box
378  BoundingBox = si.BoundingBox;
379  }
380 
381  return *this;
382 }
383 
384 
386 // assignment operator from a single SOffset. This will leave this SIndex
387 // with just the one point.
388 template<unsigned int Dim>
390 
391 
392 
393  // put in the single point
394  clear();
395  addIndex(so);
396 
397  // set our bounding box to just this point
398  toNDIndex(so, BoundingBox);
399 
400  return *this;
401 }
402 
403 
405 // assignment operator from an NDIndex. All the points in the index space
406 // will be added.
407 template<unsigned int Dim>
409 
410 
411 
412  // put in all the points from the NDIndex
413  clear();
414  addIndex(ndi);
415 
416  // set our bounding box to this NDIndex domain
417  BoundingBox = ndi;
418 
419  return *this;
420 }
421 
422 
424 // intersection operator, with another SIndex object.
425 // NOTE: this right now only works properly when the layout's match
426 template<unsigned int Dim>
428 
429 
430 
431  if (&si != this) {
432  // for all our own points, only keep those which are in the other one
433  SIndex<Dim> newval(*Layout);
434  const_iterator_iv a = begin_iv();
435  const_iterator_iv ea = end_iv();
436  iterator_iv na = newval.begin_iv();
437  for ( ; a != ea; ++a, ++na) {
438  typename LSIndex<Dim>::const_iterator ls_i = (*a)->begin();
439  typename LSIndex<Dim>::const_iterator ls_e = (*a)->end();
440  for ( ; ls_i != ls_e ; ++ls_i) {
441  if (si.hasIndex(*ls_i))
442  newval.addIndex(na, *ls_i);
443  }
444  }
445 
446  // copy over the points to here
447  *this = newval;
448 
449  // the bounding box of the intersection will be the intersection
450  // of the two original bounding boxes
451  BoundingBox = BoundingBox.intersect(si.BoundingBox);
452  }
453 
454  return *this;
455 }
456 
457 
459 // intersection operator, with another SOffset object.
460 template<unsigned int Dim>
462 
463 
464 
465  bool found = hasIndex(so);
466  clear();
467  if (found)
468  addIndex(so);
469  toNDIndex(so, BoundingBox);
470 
471  return *this;
472 }
473 
474 
476 // intersection operator, with the points in an NDIndex
477 template<unsigned int Dim>
479 
480 
481 
482  // for all our own points, only keep those which are in the other one
483  SIndex<Dim> newval(*Layout);
484  const_iterator_iv a = begin_iv();
485  const_iterator_iv ea = end_iv();
486  iterator_iv na = newval.begin_iv();
487  for ( ; a != ea; ++a, ++na) {
488  typename LSIndex<Dim>::const_iterator ls_i = (*a)->begin();
489  typename LSIndex<Dim>::const_iterator ls_e = (*a)->end();
490  for ( ; ls_i != ls_e ; ++ls_i) {
491  if ((*ls_i).inside(ndi))
492  newval.addIndex(na, *ls_i);
493  }
494  }
495 
496  // the bounding box of the intersection will be the intersection
497  // of the two original bounding boxes
498  BoundingBox = BoundingBox.intersect(ndi);
499 
500  // copy over the points to here
501  *this = newval;
502  return *this;
503 }
504 
505 
507 // union operator, with another SIndex or SOffset object. This will
508 // append the point if it is not already present.
509 // NOTE: this right now only works properly when the layout's match.
510 template<unsigned int Dim>
512 
513 
514 
515  if (&si != this) {
517  const_iterator_iv ea = si.end_iv();
518  iterator_iv na = begin_iv();
519  for ( ; a != ea; ++a, ++na) {
520  typename LSIndex<Dim>::const_iterator ls_i = (*a)->begin();
521  typename LSIndex<Dim>::const_iterator ls_e = (*a)->end();
522  for ( ; ls_i != ls_e ; ++ls_i)
523  addIndex(na, *ls_i);
524  }
525 
526  // just reset the bounding box to the original full domain
527  BoundingBox = Layout->getDomain();
528  }
529 
530  return *this;
531 }
532 
533 
535 // union operator, with another SIndex or SOffset object. This will
536 // append the point if it is not already present.
537 template<unsigned int Dim>
539 
540 
541 
542  addIndex(so);
543 
544  // just reset the bounding box to the original full domain
545  BoundingBox = Layout->getDomain();
546 
547  return *this;
548 }
549 
550 
552 // union operator, with an NDIndex object. This just needs to add the
553 // points in the NDIndex object
554 template<unsigned int Dim>
556 
557 
558 
559  addIndex(ndi);
560 
561  // just reset the bounding box to the original full domain
562  BoundingBox = Layout->getDomain();
563 
564  return *this;
565 }
566 
567 
569 // () operators which make a copy of this SIndex with an extra offset.
570 // These are functionally identical to the operator+, but provide a
571 // nicer syntax. That is, si(1,1) means si + SOffset<Dim>(1,1)
572 template<unsigned int Dim>
574 
575 
576 
577  CTAssert(Dim==1);
578  return SIndex(*this, SOffset<Dim>(i0));
579 }
580 
581 template<unsigned int Dim>
583 
584 
585  CTAssert(Dim==2);
586  return SIndex(*this, SOffset<Dim>(i0,i1));
587 }
588 
589 template<unsigned int Dim>
590 SIndex<Dim> SIndex<Dim>::operator()(int i0, int i1, int i2) {
591 
592 
593 
594  CTAssert(Dim==3);
595  return SIndex(*this, SOffset<Dim>(i0,i1,i2));
596 }
597 
598 template<unsigned int Dim>
599 SIndex<Dim> SIndex<Dim>::operator()(int i0, int i1, int i2, int i3) {
600 
601 
602 
603  CTAssert(Dim==4);
604  return SIndex(*this, SOffset<Dim>(i0,i1,i2,i3));
605 }
606 
607 template<unsigned int Dim>
608 SIndex<Dim> SIndex<Dim>::operator()(int i0, int i1, int i2, int i3, int i4) {
609 
610 
611 
612  CTAssert(Dim==5);
613  return SIndex(*this, SOffset<Dim>(i0,i1,i2,i3,i4));
614 }
615 
616 template<unsigned int Dim>
617 SIndex<Dim> SIndex<Dim>::operator()(int i0, int i1, int i2, int i3, int i4,
618  int i5) {
619 
620 
621 
622  CTAssert(Dim==6);
623  return SIndex(*this, SOffset<Dim>(i0,i1,i2,i3,i4,i5));
624 }
625 
626 template<unsigned int Dim>
628 
629 
630 
631  return SIndex(*this, so);
632 }
633 
634 template<unsigned int Dim>
636 
637 
638 
639  return SIndex(*this, SOffset<Dim>(so));
640 }
641 
642 
644 // operator[], which is used with Index or NDIndex objects to further
645 // subset the data. This will only work if the dimension of the Index
646 // arguments + Brackets is <= Dim. Otherwise, too many dimensions worth
647 // of Index objects are being applied
648 template<unsigned int Dim>
650 
651 
652 
653  CTAssert(Dim >= 1);
654  NDIndex<Dim> dom;
655  dom[0] = i;
656  return IndexedSIndex<Dim,1>(*this, dom);
657 }
658 
659 
660 
662 // convert from the given SOffset value to an NDIndex, with offset added
663 template<unsigned int Dim>
665 
666 
667 
668  for (unsigned int d=0; d < Dim; ++d) {
669  int m = val[d] + Offset[d];
670  NDI[d] = Index(m, m);
671  }
672 }
673 
674 
676 // return the total size, which is the sum of the individual sizes
677 template<unsigned int Dim>
679 
680 
681 
682  size_type_iv retval = 0;
683  for (const_iterator_iv a = begin_iv(); a != end_iv(); ++a)
684  retval += (*a)->size();
685 
686  return retval;
687 }
688 
689 
691 // change to using a new layout.
692 // NOTE: this needs to be fixed to properly redistribute points to
693 // their proper nodes.
694 template<unsigned int Dim>
696 
697 
698 
699  // create a new, empty SIndex
700  SIndex<Dim> newindx(fl, Offset);
701 
702  // NOTE: PUT CODE TO REDISTRIBUTE POINTS PROPERLY HERE
703 
704 
705  // copy over this new SIndex to ourselves
706  *this = newindx;
707 }
708 
709 
711 // Repartition onto a new layout
712 template<unsigned int Dim>
714 
715 
716 
717  if (Layout != 0 && userlist->getUserListID() == Layout->get_Id()) {
718  // it is indeed our layout which is being repartitioned. The easiest
719  // way to do this is to just use the setFieldLayout with our current
720  // layout, but which we now know is partitioned differently.
721  setFieldLayout(*Layout);
722  }
723 }
724 
725 
727 // Tell this object that an object is being deleted
728 template<unsigned int Dim>
730 
731 
732 
733  if (Layout != 0 && userlist->getUserListID() == Layout->get_Id())
734  Layout = 0;
735 }
736 
737 
739 // write contents to given ostream
740 template<unsigned int Dim>
741 std::ostream& operator<<(std::ostream& o, const SIndex<Dim>& si) {
742 
743 
744 
745  o << "vnodes = " << si.size_iv();
746  o << ", offset = " << si.getOffset();
747  o << ", bounding box = " << si.getDomain();
748  o << ", points in each LField (w/offset):" << std::endl;
749  for (typename SIndex<Dim>::const_iterator_iv a=si.begin_iv(); a!=si.end_iv(); ++a) {
750  o << " In LField w/domain=" << (*a)->getDomain() << ":" << std::endl;
751  o << " compressed = " << (*a)->IsCompressed() << std::endl;
752  unsigned int lsize = (*a)->size();
753  for (unsigned int i=0; i < lsize; ++i)
754  o << " " << (*a)->getIndex(i) + si.getOffset() << std::endl;
755  }
756 
757  return o;
758 }
759 
760 
762 // print out debugging info
763 template<unsigned int Dim>
765 
766 
767  o << *this << endl;
768 }
769 
770 
771 /***************************************************************************
772  * $RCSfile: SIndex.cpp,v $ $Author: adelmann $
773  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
774  * IPPL_VERSION_ID: $Id: SIndex.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
775  ***************************************************************************/
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
const unsigned Dim
std::ostream & operator<<(std::ostream &o, const SIndex< Dim > &si)
Definition: SIndex.hpp:741
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define CTAssert(c)
Definition: PAssert.h:35
Definition: Offset.h:66
unsigned size() const
iterator_iv end_iv()
Definition: FieldLayout.h:716
ac_id_vnodes::iterator iterator_iv
Definition: FieldLayout.h:73
Definition: Index.h:237
container_t::const_iterator const_iterator
Definition: LSIndex.h:38
container_t::size_type size_type
Definition: LSIndex.h:39
Definition: SIndex.h:64
container_t::iterator iterator_iv
Definition: SIndex.h:70
virtual ~SIndex()
Definition: SIndex.hpp:113
size_type_iv size_iv() const
Definition: SIndex.h:249
SIndex()
Definition: SIndex.hpp:39
bool addIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:160
void initialize(FieldLayout< Dim > &)
Definition: SIndex.hpp:124
iterator_iv end_iv()
Definition: SIndex.h:246
SIndex< Dim > & operator=(const PETE_Expr< T1 > &rhs)
Definition: SIndex.h:98
container_t::size_type size_type_iv
Definition: SIndex.h:72
FieldLayout< Dim > * Layout
Definition: SIndex.h:276
size_type_iv size() const
Definition: SIndex.hpp:678
bool removeIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:242
container_t IndexList
Definition: SIndex.h:283
void printDebug(Inform &) const
Definition: SIndex.hpp:764
void setup()
Definition: SIndex.hpp:137
SOffset< Dim > & getOffset()
Definition: SIndex.h:143
const NDIndex< Dim > & getDomain() const
Definition: SIndex.h:153
bool hasIndex(const SOffset< Dim > &) const
Definition: SIndex.hpp:345
virtual void notifyUserOfDelete(UserList *)
Definition: SIndex.hpp:729
container_t::const_iterator const_iterator_iv
Definition: SIndex.h:71
IndexedSIndex< Dim, 1 > operator[](const Index &)
Definition: SIndex.hpp:649
virtual void Repartition(UserList *)
Definition: SIndex.hpp:713
SOffset< Dim > Offset
Definition: SIndex.h:280
SIndex< Dim > operator()(int)
Definition: SIndex.hpp:573
iterator_iv begin_iv()
Definition: SIndex.h:245
void clear()
Definition: SIndex.hpp:332
SIndex< Dim > & operator&=(const SIndex< Dim > &)
Definition: SIndex.hpp:427
NDIndex< Dim > BoundingBox
Definition: SIndex.h:288
void setFieldLayout(FieldLayout< Dim > &)
Definition: SIndex.hpp:695
void toNDIndex(const SOffset< Dim > &, NDIndex< Dim > &)
Definition: SIndex.hpp:664
void reserve(double=1.0)
Definition: SIndex.hpp:318
SIndex< Dim > & operator|=(const SIndex< Dim > &)
Definition: SIndex.hpp:511
Definition: Inform.h:42
ID_t getUserListID() const
Definition: UserList.cpp:54