OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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.
40template<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
48template<unsigned int Dim>
50public:
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
82template<unsigned int Dim>
84public:
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
109template<unsigned int Dim>
111public:
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.
136template<class OP, unsigned int Dim>
138public:
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
191template<class OP>
192class SIndexExpLoop<OP,1U> {
193public:
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
213template<class OP>
214class SIndexExpLoop<OP,2U> {
215public:
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);
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
240template<class OP>
241class SIndexExpLoop<OP,3U> {
242public:
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
277template<unsigned Dim, class T>
278struct AssignActions { };
279
280template<unsigned Dim>
281struct 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
303template<unsigned Dim>
304struct 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.
333template<unsigned Dim, class RHS, class Op, bool IsExpr>
334void 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 ***************************************************************************/
const unsigned Dim
bool for_each(const BareFieldIterator< T, D > &p, SameFieldID s, C)
Definition: AssignDefs.h:30
FillGCIfNecessaryTag< D, T1 > FillGCIfNecessary(const BareField< T1, D > &bf)
Definition: AssignTags.h:126
void assign(SIndex< Dim > &a, RHS b, Op, const NDIndex< Dim > &domain, SIExprTag< IsExpr >)
PETE_Combiner< bool, OpAnd > PETE_AndCombiner
Definition: PETE.h:467
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
bool empty() const
void rewind(unsigned d)
Definition: BrickIterator.h:40
void step(unsigned d)
Definition: BrickIterator.h:39
bool done(unsigned d) const
Definition: BrickIterator.h:36
Definition: SIndex.h:64
container_t::iterator iterator_iv
Definition: SIndex.h:70
bool addIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:160
bool removeIndex(const SOffset< Dim > &)
Definition: SIndex.hpp:242
void clear()
Definition: SIndex.hpp:332
static void apply(SIndex< Dim > &, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
static void initialize(SIndex< Dim > &s)
static void apply(SIndex< Dim > &SI, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
static void initialize(SIndex< Dim > &)
static void apply(SIndex< Dim > &SI, typename SIndex< Dim >::iterator_iv &LSI, const SOffset< Dim > &SO, bool result)
static void initialize(SIndex< Dim > &)
static void evaluate(SIndex< Dim > &si, typename SIndex< Dim >::iterator_iv &lsi, NDIndex< Dim > &dom, RHS &Rhs)
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 evaluate(SIndex< 3U > &si, SIndex< 3U >::iterator_iv &lsi, NDIndex< 3U > &dom, RHS &Rhs)
static void fillgc(RHS &bb, const NDIndex< Dim > &)
static bool plugbase(RHS &bb, const NDIndex< Dim > &domain)
static bool plugbase(RHS &bb, const NDIndex< Dim > &)
static void fillgc(RHS &bb, const NDIndex< Dim > &)
static void abort(const char *=0)
Definition: IpplInfo.cpp:616