OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
AssignGeneralIBF.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
27//
28// This file contains the version of assign() that work with
29// general IndexedBareField = IndexedBareField expressions. It will perform
30// general communication to exchange data if the LHS and RHS layouts
31// do not match. It will also handle assignments between sliced fields,
32// permuted indices, etc.
33//
35
36// include files
37#include "Field/Assign.h"
38#include "Field/AssignDefs.h"
39#include "Field/BareField.h"
42#include "Field/LField.h"
43#include "Message/Communicate.h"
44#include "Message/Message.h"
45#include "Utility/PAssert.h"
46#include "Utility/IpplInfo.h"
47#include "Utility/IpplStats.h"
48
50
51#include <map>
52#include <vector>
53#include <functional>
54#include <utility>
55#include <iostream>
56#include <typeinfo>
57
59//
60// Send out messages needed to do an IBF = IBF assignment.
61//
63
64template<class T1, class T2, unsigned D1, unsigned D2>
65inline void
68 int tag)
69{
70
71
72
73 // debugging output macros. these are only enabled if DEBUG_ASSIGN is
74 // defined.
75 ASSIGNMSG(Inform msg("IndexedSend", INFORM_ALL_NODES));
76 ASSIGNMSG(msg << "Sending out messages for IBF[" << ilhs.getDomain());
77 ASSIGNMSG(msg << "] = IBF[" << irhs.getDomain() << "] ..." << endl);
78
79 // Get the BareField for the left and right hand sides.
80 BareField<T1,D1> &lhs = ilhs.getBareField();
81 BareField<T2,D2> &rhs = irhs.getBareField();
82 typename BareField<T2,D2>::iterator_if rf_i, rf_e = rhs.end_if();
83 T2 compressed_value;
84
85 // set up messages to be sent
86 int nprocs = Ippl::getNodes();
87 Message** mess = new Message*[nprocs];
88 int iproc;
89 for (iproc=0; iproc<nprocs; ++iproc)
90 mess[iproc] = 0;
91
92 // Loop over all the local nodes of the right hand side and
93 // send data to the remote ones they overlap on the left hand side.
94 for (rf_i = rhs.begin_if(); rf_i != rf_e; ++rf_i) {
95 // Cache some information about this local array.
96 LField<T2,D2> &rf = *((*rf_i).second);
97 const NDIndex<D2>& ro = rf.getOwned();
98
99 // Is this local field in the given right hand side domain?
100 if ( ro.touches( irhs.getDomain() ) ) {
101 // They touch, find the intersection.
102 NDIndex<D2> rt = irhs.getDomain().intersect( ro );
103
104 // Find the lhs domain where this is going to go.
105 NDIndex<D1> lt = ilhs.getDomain().plugBase( rt );
106
107 // Loop over the remote parts of lhs to find where to send stuff.
109 range(lhs.getLayout().touch_range_rdv(lt,lhs.getGuardCellSizes()));
110 typename FieldLayout<D1>::touch_iterator_dv remote_i;
111 for (remote_i = range.first; remote_i != range.second; ++remote_i) {
112 // Find the intersection.
113 NDIndex<D1> left_intersect = lt.intersect( (*remote_i).first );
114
115 // Find out who owns this remote domain
116 int rnode = (*remote_i).second->getNode();
117
118 // Forward substitute to get the domain in the rhs.
119 NDIndex<D2> right_intersect =
120 irhs.getDomain().plugBase(left_intersect);
121
122 // Build the iterator for the data.
123 typename LField<T2,D2>::iterator rhs_i =
124 rf.begin(right_intersect, compressed_value);
125
126 ASSIGNMSG(msg << "Sending IndexedField data from domain ");
127 ASSIGNMSG(msg << right_intersect << " to domain " << left_intersect);
128 ASSIGNMSG(msg << endl);
129
130 // Permute the loop order so that they agree.
132 rhs_i.permute(right_intersect,left_intersect);
133
134 // Try to compress it.
135 prhs_i.TryCompress();
136
137 // put data into proper message
138 if (!mess[rnode]) mess[rnode] = new Message;
139 PAssert(mess[rnode]);
140 left_intersect.putMessage(*mess[rnode]);
141 prhs_i.putMessage(*mess[rnode]);
142 } // loop over touching remote nodes
143 }
144 } // loop over LFields
145
146 // send all the messages
147 for (iproc=0; iproc<nprocs; ++iproc) {
148 if (mess[iproc])
149 Ippl::Comm->send(mess[iproc],iproc,tag);
150 }
151
152 delete [] mess;
153 return;
154}
155
156
158//
159// Calculate what messages we expect to receiving during an IBF = IBF assign.
160//
162
163template<class T1, class T2, unsigned D1, unsigned D2, class Container>
164inline void
167 Container& recv_ac, int& msgnum)
168{
169
170 // debugging output macros. these are only enabled if DEBUG_ASSIGN is
171 // defined.
172 ASSIGNMSG(Inform msg("CalcIndexedReceive", INFORM_ALL_NODES));
173 ASSIGNMSG(msg << "Computing receive messages for IBF[" << ilhs.getDomain());
174 ASSIGNMSG(msg << "] = IBF[" << irhs.getDomain() << "] ..." << endl);
175
176 // Get the BareField for the left and right hand sides.
177 BareField<T1,D1> &lhs = ilhs.getBareField();
178 BareField<T2,D2> &rhs = irhs.getBareField();
179 typename BareField<T1,D1>::iterator_if lf_i, lf_e = lhs.end_if();
180
181 int nprocs = Ippl::getNodes();
182 bool* recvmsg = new bool[nprocs];
183 int iproc;
184 for (iproc=0; iproc<nprocs; ++iproc)
185 recvmsg[iproc] = false;
186
187 // Loop over the locals.
188 for (lf_i = lhs.begin_if(); lf_i != lf_e; ++lf_i) {
189 // Cache some information about this LField.
190 LField<T1,D1> &lf = *((*lf_i).second);
191 const NDIndex<D1>& la = lf.getAllocated();
192 // Is this local field in the domain in question.
193 if ( la.touches( ilhs.getDomain() ) ) {
194 // They touch. Find the intersection.
195 NDIndex<D1> lt = ilhs.getDomain().intersect( la );
196 // Find the rhs domain this is coming from.
197 NDIndex<D2> rt = irhs.getDomain().plugBase( lt );
198 // Find the remote ones that that touch this.
200 range( rhs.getLayout().touch_range_rdv(rt) );
201 // Loop over them.
203 for (rv_i = range.first; rv_i != range.second; ++rv_i) {
204 // Save the intersection and the LField it is for.
205 NDIndex<D2> ri = rt.intersect((*rv_i).first);
206 NDIndex<D1> li = ilhs.getDomain().plugBase( ri );
207
208 ASSIGNMSG(msg << "Expecting IndexedField data from domain " << ri);
209 ASSIGNMSG(msg << " for domain " << li << endl);
210
211 typedef typename Container::value_type value_type;
212 recv_ac.insert(value_type(li,&lf));
213 // note who will be sending this data
214 int rnode = (*rv_i).second->getNode();
215 recvmsg[rnode] = true;
216 } // loop over remote nodes
217 }
218 } // loop over LFields
219
220 msgnum = 0;
221 for (iproc=0; iproc<nprocs; ++iproc)
222 if (recvmsg[iproc]) ++msgnum;
223 delete [] recvmsg;
224 return;
225}
226
227
229//
230// Assign between just the local blocks for an IBF = IBF assign.
231//
233
234template<class T1, class T2, unsigned D1, unsigned D2, class Op>
235inline void
238 Op& op)
239{
240
241 // debugging output macros. these are only enabled if DEBUG_ASSIGN is
242 // defined.
243 ASSIGNMSG(Inform msg("IndexedLocalAssign-IBF", INFORM_ALL_NODES));
244 ASSIGNMSG(msg << "Computing general local assignment to IBF[");
245 ASSIGNMSG(msg << ilhs.getDomain() << "] = IBF[");
246 ASSIGNMSG(msg << irhs.getDomain() << "] ..." << endl);
247
248 // Get the BareField for the left and right hand sides.
249 BareField<T1,D1> &lhs = ilhs.getBareField();
250 BareField<T2,D2> &rhs = irhs.getBareField();
251
252 // Loop over all the local Fields of the lhs and all the local
253 // fields in the rhs.
254 // This is an N*N operation, but the expectation is that there won't
255 // be TOO many Vnodes on a given processor.
256 for (typename BareField<T1,D1>::iterator_if lf_i=lhs.begin_if();
257 lf_i!=lhs.end_if(); ++lf_i)
258 {
259 // Cache some information about this LField.
260 LField<T1,D1> &lf = *(*lf_i).second;
261 const NDIndex<D1>& lo = lf.getOwned();
262 const NDIndex<D1>& la = lf.getAllocated();
263
264 // See if it touches the given domain.
265 if ( lo.touches( ilhs.getDomain() ) )
266 {
267 ASSIGNMSG(msg << "----------------" << endl);
268 ASSIGNMSG(msg << "Assigning to local LField with owned = " << lo);
269 ASSIGNMSG(msg << endl);
270
271 // Get the intersection.
272 NDIndex<D1> lt = ilhs.getDomain().intersect( lo );
273 ASSIGNMSG(msg << "Intersection lhs domain = " << lt << endl);
274
275 // Transform into right hand side space.
276 NDIndex<D2> rp = irhs.getDomain().plugBase( lt );
277 ASSIGNMSG(msg << "Plugbase domain = " << rp << endl);
278
279 // Loop over all the local lfields on the right.
280 for (typename BareField<T2,D2>::iterator_if rf_i = rhs.begin_if();
281 rf_i != rhs.end_if(); ++rf_i)
282 {
283 // Cache the domain for this local field.
284 LField<T2,D2> &rf = *(*rf_i).second;
285 const NDIndex<D2>& ra = rf.getAllocated();
286 const NDIndex<D2>& ro = rf.getOwned();
287
288 // Two cases:
289 // 1. rhs allocated contains lhs owned
290 // Then this is a stencil and we should fill from allocated.
291 // Assume that nobody else will fill the owned spot.
292 // 2. rhs allocated does not contain lhs owned.
293 // Then this is general communication and we
294 // should only fill from rhs owned.
295 // I can construct cases for which this gives wrong answers
296 // on += type operations. We'll be able to fix this much much
297 // easier with one sided communication.
298
299 // If this local field touches the domain, we have work to do.
300 // ra has unit stride so end-point "contains" is OK.
301 const NDIndex<D2> &rd = ( ra.contains(rp) ? ra : ro );
302 if ( rd.touches( rp ) )
303 {
304 // Get the intersection. We'll copy out of this.
305 NDIndex<D2> rhsDomain = rp.intersect(rd);
306
307 // Transform that back. We'll copy into this.
308 NDIndex<D1> lhsDomain = lt.plugBase(rhsDomain);
309
310 ASSIGNMSG(msg << "Found touching rhs field: assigning ");
311 ASSIGNMSG(msg << lhsDomain << " = " << rhsDomain << endl);
312
313 // Can we compress the left?
314 bool c1 = rf.IsCompressed();
315
316 // Not clear that lhs is unit stride, so call
317 // containsAllPoints...
318 bool c2 = lhsDomain.containsAllPoints(la);
320 bool c4 = lf.IsCompressed();
321 ASSIGNMSG(msg << "Checking for possible compressed-assign:");
322 ASSIGNMSG(msg << "\n rf.IsCompressed = " << c1);
323 ASSIGNMSG(msg << "\n lhs.contains(allocatd) = " << c2);
324 ASSIGNMSG(msg << "\n lf.IsCompressed = " << c4);
325 ASSIGNMSG(msg << "\n Doing assignment = " << c3);
326 ASSIGNMSG(msg << "\n Result = " << (c1&&c2&&(c3||c4)));
327 ASSIGNMSG(msg << endl);
328 if ( lhs.compressible() && c1 && c2 && ( c3 || c4 ) )
329 {
330 ASSIGNMSG(msg << "Can do compressed assign from rhs ");
331 ASSIGNMSG(msg << "to lhs." << endl);
332
333 // We can compress the left!
334 lf.Compress();
335
336 // Set the constant value.
337 PETE_apply(op, *lf.begin() , *rf.begin() );
338 ASSIGNMSG(msg << "After compress, " << *lf.begin());
339 ASSIGNMSG(msg << " = ");
340 ASSIGNMSG(msg << *rf.begin() << endl);
341 }
342 else
343 {
344 // Can't leave the left compressed.
345 // Only fill in the data if you have to.
346 bool c22 = lhsDomain.containsAllPoints(lo);
348 bool filldom = ((!c22) || (!c32));
349 ASSIGNMSG(msg << "Must uncompress, filldom = ");
350 ASSIGNMSG(msg << filldom << endl);
351 lf.Uncompress(filldom);
352
353 // Types for the assignment.
354 typedef typename LField<T1,D1>::iterator LFI;
355 typedef typename LField<T2,D1>::iterator RFI;
357
358 // Build iterators for the left and right hand sides.
359 RFI rhs_i =
360 rf.begin(rhsDomain).permute(rhsDomain,lhsDomain) ;
361 LFI lhs_i =
362 lf.begin(lhsDomain) ;
363
364 // And do the assignment.
365 ASSIGNMSG(msg << "Doing full loop assignment." << endl);
366 Expr(lhs_i,rhs_i,op).apply();
367 }
368 }
369 }
370 }
371 }
372}
373
374
376//
377// Receive in needed messages and assign them to our storage
378// for an IBF = IBF assign.
379//
381
382template<class T1, class T2, unsigned D1, unsigned D2,
383 class Op, class Container>
384inline void
387 Op& op,
388 Container& recv_ac, int msgnum,
389 int tag)
390{
391
392 // debugging output macros. these are only enabled if DEBUG_ASSIGN is
393 // defined.
394 ASSIGNMSG(Inform msg("IndexedReceive", INFORM_ALL_NODES));
395 ASSIGNMSG(msg << "Receiving messages for IBF[" << ilhs.getDomain());
396 ASSIGNMSG(msg << "] = IBF[" << irhs.getDomain() << "] ..." << endl);
397
398 // Get the BareField for the left hand side.
399 BareField<T1,D1> &lhs = ilhs.getBareField();
400
401 // Build iterators within local fields on the left and right hand side.
402 typedef typename LField<T1,D1>::iterator LFI;
404
405 // The type for the expression.
407
408 // Loop until we've received all the messages.
409 while (msgnum>0) {
410 // Receive the next message.
411 int any_node = COMM_ANY_NODE;
412 Message *mess = Ippl::Comm->receive_block(any_node,tag);
413 PAssert(mess != 0);
414 --msgnum;
415 // determine the number of domains being sent
416 int ndoms = mess->size() / (D1 + 3);
417 for (int idom=0; idom<ndoms; ++idom) {
418 // extract the next domain from the message
419 NDIndex<D1> domain;
420 domain.getMessage(*mess);
421 // Extract the rhs iterator from it.
422 T2 compressed_data;
423 RFI rhs_i(compressed_data);
424 rhs_i.getMessage(*mess);
425
426 ASSIGNMSG(msg << "Received IndexedField data for domain " << domain);
427 ASSIGNMSG(msg << endl);
428
429 // Find the LField it is destined for.
430 typename Container::iterator hit = recv_ac.find( domain );
431 PAssert( hit != recv_ac.end() );
432 LField<T1,D1> &lf = *(*hit).second;
433
434 // Can we compress the left?
435 bool c1 = rhs_i.IsCompressed();
436 bool c2 = domain.containsAllPoints( lf.getAllocated() );
438 bool c4 = lf.IsCompressed();
439 if ( lhs.compressible() && c1 && c2 && ( c3 || c4 ) ) {
440 // We can compress the left!
441 lf.Compress();
442 // Set the constant value.
443 PETE_apply(op, *lf.begin() , *rhs_i);
444 }
445 else {
446 // Can't leave the left compressed.
447 // Only fill in the data if you have to.
448 c2 = domain.containsAllPoints(lf.getOwned());
450 lf.Uncompress( !(c2&&c3) );
451 // Build iterators for the left and right hand sides.
452 LFI lhs_i = lf.begin(domain);
453 // And do the assignment.
454 Expr(lhs_i,rhs_i,op).apply();
455 }
456
457 // Take that entry out of the receive list.
458 recv_ac.erase( hit );
459 }
460 delete mess;
461 } // loop over messages to receive
462 return;
463}
464
465
467//
468// A simple utility struct used to do touching calculations between
469// domains of different dimensions. They only can possibly touch
470// if their dimensions are the same.
471//
473
474template<unsigned int D1, unsigned int D2>
476{
477 static bool apply(const NDIndex<D1>&, const NDIndex<D2>&)
478 {
479 return false;
480 }
481};
482
483template<unsigned int D1>
484struct AssignTouches< D1, D1 >
485{
486 static bool apply(const NDIndex<D1>& x,const NDIndex<D1>& y)
487 {
488 return x.touches(y);
489 }
490};
491
492
494//
495// Assign one IndexedBareField to another. This works even if the two
496// are on different layouts and are different dimensionalities.
497//
499
500template<class T1, unsigned D1, class RHS, class Op>
501void
503 RHS rhsp,
504 Op op, ExprTag<false>)
505{
506
507 typedef typename RHS::PETE_Return_t T2;
508 enum { D2=RHS::Dim_u };
509 IndexedBareField<T2,D2,D2> rhs ( rhsp.getBareField()[ rhsp.getDomain() ] );
510
511 // Make sure we aren't assigning into overlapping domains in the same array.
512 // First test to see if they are the same array.
513 if ( lhs.getBareField().get_Id() == rhs.getBareField().get_Id() )
514 {
515 // Now check to see if the domains overlap.
517 {
518 // They overlap. Scream and die.
519 ERRORMSG("Overlapping domains in indexed assignment!"<<endl);
520 PAssert(0);
521 }
522 }
523
524 // Get a unique tag for the messages here.
526
527 // Fill guard cells if necessary.
528
531
532 // ----------------------------------------
533 // Send all the data from the right hand side
534 // the the parts of the left hand side that need them.
535 if (Ippl::getNodes() > 1) {
536
537 IndexedSend(lhs,rhs,tag);
538
539 }
540
541 // ----------------------------------------
542 // Build a map of the messages we expect to receive.
543 std::multimap< NDIndex<D1> , LField<T1,D1>* , std::less< NDIndex<D1> > > recv_ac;
544 int msgnum = 0;
545 if (Ippl::getNodes() > 1) {
546
547 CalcIndexedReceive(lhs,rhs,recv_ac,msgnum);
548
549 }
550
551 // ----------------------------------------
552 // Handle the local fills.
553
554 IndexedLocalAssign(lhs,rhs,op);
555
556
557 // ----------------------------------------
558 // Receive all the messages.
559 if (Ippl::getNodes() > 1) {
560
561 IndexedReceive(lhs,rhs,op,recv_ac,msgnum,tag);
562
563 }
564
565 lhs.getBareField().setDirtyFlag();
566
567 // Update the guard cells.
568
569 lhs.getBareField().fillGuardCellsIfNotDirty();
570
571
572 // Compress the LHS.
573 lhs.getBareField().Compress();
574
575 //INCIPPLSTAT(incExpressions);
576 //INCIPPLSTAT(incIBFEqualsIBF);
577}
578
579/***************************************************************************
580 * $RCSfile: AssignGeneralIBF.cpp,v $ $Author: adelmann $
581 * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
582 * IPPL_VERSION_ID: $Id: AssignGeneralIBF.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
583 ***************************************************************************/
T * value_type(const SliceIterator< T > &)
const int COMM_ANY_NODE
Definition: Communicate.h:40
#define F_TAG_CYCLE
Definition: Tags.h:53
#define F_GEN_ASSIGN_TAG
Definition: Tags.h:47
#define ASSIGNMSG(x)
Definition: Assign.h:28
void IndexedReceive(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &, Op &op, Container &recv_ac, int msgnum, int tag)
void CalcIndexedReceive(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, Container &recv_ac, int &msgnum)
void IndexedSend(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, int tag)
void assign(IndexedBareField< T1, D1, D1 > lhs, RHS rhsp, Op op, ExprTag< false >)
void IndexedLocalAssign(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, Op &op)
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 PETE_apply(const OpPeriodic< T > &, T &a, const T &b)
Definition: BCond.hpp:353
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFORM_ALL_NODES
Definition: Inform.h:39
#define PAssert(c)
Definition: PAssert.h:102
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
std::string::iterator iterator
Definition: MSLang.h:16
bool lt(double x, double y)
CompressedBrickIterator< T, 1 > permute(NDIndex< Dim > &current, NDIndex< 1 > &permuted) const
Message & putMessage(Message &m, bool makecopy=true)
bool touches(const NDIndex< Dim > &) const
Message & putMessage(Message &m) const
Definition: NDIndex.h:130
bool contains(const NDIndex< Dim > &a) const
Message & getMessage(Message &m)
Definition: NDIndex.h:138
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
bool containsAllPoints(const NDIndex< Dim > &b) const
iterator_if begin_if()
Definition: BareField.h:100
ac_id_larray::iterator iterator_if
Definition: BareField.h:92
bool compressible() const
Definition: BareField.h:191
Layout_t & getLayout() const
Definition: BareField.h:131
iterator_if end_if()
Definition: BareField.h:101
const GuardCellSizes< Dim > & getGuardCellSizes() const
Definition: BareField.h:147
Definition: LField.h:58
void Compress()
Definition: LField.h:161
const NDIndex< Dim > & getOwned() const
Definition: LField.h:99
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:98
bool IsCompressed() const
Definition: LField.h:134
void Uncompress(bool fill_domain=true)
Definition: LField.h:172
const iterator & begin() const
Definition: LField.h:110
iterator begin() const
const NDIndex< Dim > & getDomain() const
BareField< T, Dim > & getBareField()
Definition: Assign.h:48
static bool apply(const NDIndex< D1 > &, const NDIndex< D2 > &)
static bool apply(const NDIndex< D1 > &x, const NDIndex< D1 > &y)
touch_range_dv touch_range_rdv(const NDIndex< Dim > &domain, const GuardCellSizes< Dim > &gc=gc0()) const
Definition: FieldLayout.h:780
std::pair< touch_iterator_dv, touch_iterator_dv > touch_range_dv
Definition: FieldLayout.h:77
bool send(Message *, int node, int tag, bool delmsg=true)
Message * receive_block(int &node, int &tag)
size_t size() const
Definition: Message.h:292
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
Definition: Inform.h:42
static int getNodes()
Definition: IpplInfo.cpp:670
static Communicate * Comm
Definition: IpplInfo.h:84