OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
SIndexAssign.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/SIndexAssign.h"
28 #include "Index/SIndex.h"
29 #include "Field/BrickIterator.h"
30 #include "Field/Field.h"
31 #include "Field/IndexedField.h"
32 #include "Field/Assign.h"
33 #include "Utility/IpplInfo.h"
34 
35 
36 
38 // a simple class to apply the assign function to one point of the
39 // assignment domain.
40 template<unsigned int Dim, class OP>
42 
43 
45 // a specialization of the simple class to apply the regular assign
46 // function to one point of the assignment domain.
47 
48 template<unsigned int Dim>
50 public:
51  // initially, the sparse index container must be cleared out
52  static void initialize(SIndex<Dim>& s) { s.clear(); }
53 
54  // S = exp means we cleared out all the points previously, so we know
55  // we do not need to worry about repeated points
56  static void apply(SIndex<Dim>& SI,
57  typename SIndex<Dim>::iterator_iv& LSI,
58  const SOffset<Dim>& SO,
59  bool result) {
60  if (result) {
61  // we can just add the index to the LSIndex's list here, for the
62  // following reasons:
63  // 1. We did a 'clear' before the expression started (when
64  // initialize was called), so all the LSIndex objects in this
65  // SIndex are separate, empty items, not references to other
66  // SIndex lists.
67  // 2. We know this point is unique, since we did a clear and then
68  // looped over completely different points in the expression
69  // evaluation.
70  // 3. We are sure this point belongs to this LSIndex, since we
71  // iterate over the vnodes of the SIndex.
72  (*LSI)->addIndex(SO);
73  }
74  }
75 };
76 
77 
79 // a specialization of the simple class to apply the bitwise AND assign
80 // function to one point of the assignment domain.
81 
82 template<unsigned int Dim>
84 public:
85  // since we do an intersection, we must keep the existing data
86  static void initialize(SIndex<Dim>&) { }
87 
88  // S &= expr means 'intersection' ... only keep the point if result is
89  // true, remove the point if result is false
90  static void apply(SIndex<Dim>& SI,
91  typename SIndex<Dim>::iterator_iv& LSI,
92  const SOffset<Dim>& SO,
93  bool result) {
94  if (!result && (*LSI)->hasIndex(SO)) {
95  // we must call removeIndex in SIndex (and not in LSIndex) here
96  // because we might need to make a copy of the LSIndex data
97  // first (copy-on-write). This will be slower than doing some
98  // form of direct assignment.
99  SI.removeIndex(LSI, SO);
100  }
101  }
102 };
103 
104 
106 // a specialization of the simple class to apply the bitwise OR assign
107 // function to one point of the assignment domain.
108 
109 template<unsigned int Dim>
111 public:
112  // since we do a union, we must keep the existing data
113  static void initialize(SIndex<Dim>&) { }
114 
115  // S |= expr means 'union' ... we add points as normal, but we did not
116  // clear out the points that were there previously
117  static void apply(SIndex<Dim>& SI,
118  typename SIndex<Dim>::iterator_iv& LSI,
119  const SOffset<Dim>& SO,
120  bool result) {
121 
122  if (result && ! (*LSI)->hasIndex(SO)) {
123  // we must call addIndex in SIndex (and not in LSIndex) here
124  // because we need to check if this point SO is already in the
125  // list of points. This will be slower than doing some form
126  // of direct assignment.
127  SI.addIndex(LSI, SO);
128  }
129  }
130 };
131 
132 
134 // a simple class to do different dimension-specific loops in an
135 // SIndex expression.
136 template<class OP, unsigned int Dim>
138 public:
139  // the general loop; this is done for 4D or higher dimensions
140  template<class RHS>
141  static void evaluate(SIndex<Dim>& si, typename SIndex<Dim>::iterator_iv& lsi,
142  NDIndex<Dim>& dom, RHS& Rhs) {
143 
144  int n0 = dom[0].length();
145  int n1 = dom[1].length();
146  int n2 = dom[2].length();
147  if (n0 > 0 && n1 > 0 && n2 > 0) {
148  BrickCounter<Dim> count(dom); // ada: changed from cdom to dom, cdom does not make sense!
149  ERRORMSG("changed from cdom to dom, cdom does not make sense! (SindexAssign.cpp)" << endl);
150 
151  unsigned d;
152  SOffset<Dim> so;
153  for (d=3; d < Dim; ++d)
154  so[d] = dom[d].first();
155  do {
156  Index::iterator x2 = dom[2].begin();
157  for (int i2=0; i2<n2; ++i2, ++x2) {
158  so[2] = *x2;
159  Index::iterator x1 = dom[1].begin();
160  for (int i1=0; i1<n1; ++i1, ++x1) {
161  so[1] = *x1;
162  Index::iterator x0 = dom[0].begin();
163  for (int i0=0; i0<n0; ++i0, ++x0) {
164  so[0] = *x0;
165  bool result = (for_each(Rhs, EvalFunctor_3(i0,i1,i2)) != false);
166  SIndexAssignTraits<3U,OP>::apply(si, lsi, so, result);
167  }
168  }
169  }
170 
171  for (d=3; d<Dim; ++d) {
172  count.step(d);
173  so[d] += dom[d].stride();
175  if ( ! count.done(d) )
176  break;
177  count.rewind(d);
178  so[d] = dom[d].first();
180  }
181 
182  } while (d<Dim);
183  }
184  }
185 };
186 
187 
189 //a specialization of SIndexAssignLoop for a 1D loop evaluation NOTE:
190 //dom must be within the local domain of the given LSIndex
191 template<class OP>
192 class SIndexExpLoop<OP,1U> {
193 public:
194  template<class RHS>
196  NDIndex<1U>& dom, RHS& Rhs) {
197 
198  int n0 = dom[0].length();
199  if (n0 > 0) {
200  Index::iterator x0 = dom[0].begin();
201  for (int i0 = 0; i0 < n0; ++i0, ++x0) {
202  bool result = (for_each(Rhs, EvalFunctor_1(i0)) != false);
203  SIndexAssignTraits<1U,OP>::apply(si, lsi, SOffset<1>(*x0), result);
204  }
205  }
206  }
207 };
208 
209 
211 // a specialization of SIndexAssignLoop for a 2D loop evaluation
212 // NOTE: dom must be within the local domain of the given LSIndex
213 template<class OP>
214 class SIndexExpLoop<OP,2U> {
215 public:
216  template<class RHS>
218  NDIndex<2U>& dom, RHS& Rhs) {
219 
220  int n0 = dom[0].length();
221  int n1 = dom[1].length();
222  if (n0 > 0 && n1 > 0) {
223  Index::iterator x1 = dom[1].begin();
224  for (int i1 = 0; i1 < n1; ++i1, ++x1) {
225  Index::iterator x0 = dom[0].begin();
226  for (int i0 = 0; i0 < n0; ++i0, ++x0) {
227  bool result = (for_each(Rhs, EvalFunctor_2(i0,i1)) != false);
228  SIndexAssignTraits<2U,OP>::apply(si, lsi, SOffset<2>(*x0, *x1),
229  result);
230  }
231  }
232  }
233  }
234 };
235 
236 
238 // a specialization of SIndexAssignLoop for a 3D loop evaluation
239 // NOTE: dom must be within the local domain of the given LSIndex
240 template<class OP>
241 class SIndexExpLoop<OP,3U> {
242 public:
243  template<class RHS>
245  NDIndex<3U>& dom, RHS& Rhs) {
246 
247  int n0 = dom[0].length();
248  int n1 = dom[1].length();
249  int n2 = dom[2].length();
250  if (n0 > 0 && n1 > 0 && n2 > 0) {
251  Index::iterator x2 = dom[2].begin();
252  for (int i2 = 0; i2 < n2; ++i2, ++x2) {
253  Index::iterator x1 = dom[1].begin();
254  for (int i1 = 0; i1 < n1; ++i1, ++x1) {
255  Index::iterator x0 = dom[0].begin();
256  for (int i0 = 0; i0 < n0; ++i0, ++x0) {
257  bool result = (for_each(Rhs, EvalFunctor_3(i0,i1,i2)) != false);
259  SOffset<3>(*x0, *x1, *x2),
260  result);
261  }
262  }
263  }
264  }
265  }
266 };
267 
268 
270 // The 'assign' function for SIndex objects must handle two situations,
271 // one where the RHS is a simple, full-field expression, and one where
272 // the RHS is a complex, indexed expression. The 'AssignActions'
273 // struct is specialized on the 'SiExprTag<bool>' class to perform
274 // different setup and cleaup operations for the RHS objects based on
275 // whether the expression is simple (bool=false) or indexed (bool=true).
276 
277 template<unsigned Dim, class T>
278 struct AssignActions { };
279 
280 template<unsigned Dim>
281 struct AssignActions<Dim, SIExprTag<true> > {
282  template<class RHS>
283  static void fillgc(RHS &bb, const NDIndex<Dim> &domain) {
284  // ask each field on the RHS to fill its guard cells, if necessary
285  //tjw3/3/99 for_each(bb, FillGCIfNecessary(domain), PETE_NullCombiner());
287  }
288 
289  template<class RHS>
290  static bool plugbase(RHS &bb, const NDIndex<Dim> &domain) {
291  // ask each RHS field to set itself up to iterate over the given locdomain.
292  // if any cannot, this will return false.
293  return for_each(bb, PlugBase<Dim>(domain), PETE_AndCombiner());
294  }
295 
296  template<class RHS>
297  static void nextLField(RHS &) {
298  // in this case, there is nothing to do, since PlugBase always ends
299  // up setting which LField to use
300  }
301 };
302 
303 template<unsigned Dim>
304 struct AssignActions<Dim, SIExprTag<false> > {
305  template<class RHS>
306  static void fillgc(RHS &bb, const NDIndex<Dim> &) {
307  // ask each field on the RHS to fill its guard cells, if necessary
308  // here, it cannot be a stencil, so not necessary
309  //tjw 3/3/99, add:
311  //tjw 3/3/99, add.
312  }
313 
314  template<class RHS>
315  static bool plugbase(RHS &bb, const NDIndex<Dim> &) {
316  // tell each RHS field to reset to the beginning of it's current LField
318  return true;
319  }
320 
321  template<class RHS>
322  static void nextLField(RHS &bb) {
323  // tell each RHS field to move on to the next LField
325  }
326 };
327 
328 
330 // assign values to an SIndex: evaluate the RHS at all the points in
331 // the given domain, find where it evaluates to true, and store the
332 // value of that index point.
333 template<unsigned Dim, class RHS, class Op, bool IsExpr>
334 void assign(SIndex<Dim>& a, RHS b, Op, const NDIndex<Dim> &domain,
335  SIExprTag<IsExpr> isexpr) {
336 
337 
338 
339 
340  // Inform dbgmsg("SIndex assign", INFORM_ALL_NODES);
341  // dbgmsg << "Computing on total domain = " << domain << endl;
342 
343  // unwrap the PETE expression object to get what we're computing with
344  typename RHS::Wrapped& bb = b.PETE_unwrap();
345 
346  // initialize the SIndex for this operation
348 
349  // Fill GC's, if necessary
350  AssignActions<Dim,SIExprTag<IsExpr> >::fillgc(bb, domain);
351 
352  // iterate through all the local vnodes in the FieldLayout used
353  // by the SIndex, and look at the points in these domains
354  typename SIndex<Dim>::iterator_iv la = a.begin_iv();
355  typename SIndex<Dim>::iterator_iv aend = a.end_iv();
356  for ( ; la != aend; ++la ) {
357  // check if we have any points in this LField to process
358  NDIndex<Dim> locdomain = domain.intersect((*la)->getDomain());
359  //dbgmsg << "Doing LField " << (*la)->getDomain() << " with intersection ";
360  //dbgmsg << locdomain << endl;
361 
362  // only proceed if we have any intersecting points
363  if (!locdomain.empty()) {
364  // First look and see if the arrays are sufficiently aligned to do
365  // this in one shot. We do this by trying to do a plugBase and
366  // seeing if it worked.
367  if (AssignActions<Dim,SIExprTag<IsExpr> >::plugbase(bb, locdomain)) {
368 
369  // check if the RHS is compressed and we can do a compressed assign
370  if (OperatorTraits<Op>::IsAssign && locdomain == (*la)->getDomain() &&
372  // why yes we can ... tell the SIndex to store the results for
373  // the entire vnode in one shot
374  bool result = (for_each(bb, EvalFunctor_0()) != false);
375  (*la)->Compress(result);
376 
377  //NDIndex<Dim>& dom = (NDIndex<Dim>&) ((*la)->getDomain());
378  //dbgmsg << "compressed in dom = " << dom << ", result = " << result;
379  //dbgmsg << endl;
380  } else {
381  // perform actions to find necessary points in the current Vnode
382  // of the SIndex, by looping over the domain and seeing where
383  // the RHS == true
384  SIndexExpLoop<Op,Dim>::evaluate(a, la, locdomain, bb);
385 
386  //NDIndex<Dim>& dom = (NDIndex<Dim>&) ((*la)->getDomain());
387  //dbgmsg << "uncompressed in dom = " << dom << endl;
388  }
389  } else {
390  ERRORMSG("All Fields in an expression must be aligned. ");
391  ERRORMSG("(Do you have enough guard cells?)" << endl);
392  ERRORMSG("This error occurred while evaluating an SIndex expression ");
393  ERRORMSG("for an LField with domain " << (*la)->getDomain() << endl);
394  Ippl::abort();
395  }
396  // } else {
397  // dbgmsg << " ... intersection is empty." << endl;
398  }
399 
400  // move the RHS Field's on to the next LField, if necessary
401  AssignActions<Dim,SIExprTag<IsExpr> >::nextLField(bb);
402  }
403 
404  // at the end, tell the SIndex we used this domain, so that should be
405  // its new bounding box
406  a.setDomain(domain);
407 }
408 
409 
410 /***************************************************************************
411  * $RCSfile: SIndexAssign.cpp,v $ $Author: adelmann $
412  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
413  * IPPL_VERSION_ID: $Id: SIndexAssign.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
414  ***************************************************************************/
static void abort(const char *=0, int exitcode=(-1))
Definition: IpplInfo.cpp:696
void setDomain(const NDIndex< Dim > &ndi)
Definition: SIndex.h:155
static bool plugbase(RHS &bb, const NDIndex< Dim > &domain)
void rewind(unsigned d)
Definition: BrickIterator.h:45
static void evaluate(SIndex< 3U > &si, SIndex< 3U >::iterator_iv &lsi, NDIndex< 3U > &dom, RHS &Rhs)
Definition: SIndex.h:28
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
static void evaluate(SIndex< 1U > &si, SIndex< 1U >::iterator_iv &lsi, NDIndex< 1U > &dom, RHS &Rhs)
static void evaluate(SIndex< 2U > &si, SIndex< 2U >::iterator_iv &lsi, NDIndex< 2U > &dom, RHS &Rhs)
static void initialize(SIndex< Dim > &)
static void fillgc(RHS &bb, const NDIndex< Dim > &domain)
void assign(const BareField< T, Dim > &a, RHS b, OP op, ExprTag< true >)
static void evaluate(SIndex< Dim > &si, typename SIndex< Dim >::iterator_iv &lsi, NDIndex< Dim > &dom, RHS &Rhs)
static void initialize(SIndex< Dim > &s)
static bool plugbase(RHS &bb, const NDIndex< Dim > &)
bool addIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:160
bool removeIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:243
iterator_iv begin_iv()
Definition: SIndex.h:246
bool empty() const
bool done(unsigned d) const
Definition: BrickIterator.h:41
container_t::iterator iterator_iv
Definition: SIndex.h:71
static void apply(SIndex< Dim > &SI, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
void step(unsigned d)
Definition: BrickIterator.h:44
void clear()
Definition: SIndex.hpp:334
iterator_iv end_iv()
Definition: SIndex.h:247
PETE_Combiner< bool, OpAnd > PETE_AndCombiner
Definition: PETE.h:529
FillGCIfNecessaryTag< D, T1 > FillGCIfNecessary(const BareField< T1, D > &bf)
Definition: AssignTags.h:146
static void apply(SIndex< Dim > &SI, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
static void initialize(SIndex< Dim > &)
static void apply(SIndex< Dim > &SI, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
const unsigned Dim
bool for_each(const BareFieldIterator< T, D > &p, SameFieldID s, C)
Definition: AssignDefs.h:30
static void fillgc(RHS &bb, const NDIndex< Dim > &)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42