OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
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"
40 #include "Field/BrickExpression.h"
41 #include "Field/IndexedBareField.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 
49 #include "PETE/IpplExpressions.h"
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 
64 template<class T1, class T2, unsigned D1, unsigned D2>
65 inline 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 
163 template<class T1, class T2, unsigned D1, unsigned D2, class Container>
164 inline 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 
234 template<class T1, class T2, unsigned D1, unsigned D2, class Op>
235 inline 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);
347  bool c32 = OperatorTraits<Op>::IsAssign;
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;
356  typedef BrickExpression<D1,LFI,RFI,Op> Expr;
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 
382 template<class T1, class T2, unsigned D1, unsigned D2,
383  class Op, class Container>
384 inline 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;
403  typedef CompressedBrickIterator<T2,D1> RFI;
404 
405  // The type for the expression.
406  typedef BrickExpression<D1,LFI,RFI,Op> Expr;
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 
474 template<unsigned int D1, unsigned int D2>
476 {
477  static bool apply(const NDIndex<D1>&, const NDIndex<D2>&)
478  {
479  return false;
480  }
481 };
482 
483 template<unsigned int D1>
484 struct 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 
500 template<class T1, unsigned D1, class RHS, class Op>
501 void
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.
516  if ( AssignTouches<D1,D2>::apply(lhs.getDomain(),rhs.getDomain()))
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 
529  for_each(rhs.begin(), FillGCIfNecessary(lhs.getBareField()),
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  ***************************************************************************/
static int getNodes()
Definition: IpplInfo.cpp:773
Message & putMessage(Message &m, bool makecopy=true)
void PETE_apply(const OpPeriodic< T > &e, T &a, const T &b)
Definition: BCond.hpp:373
bool containsAllPoints(const NDIndex< Dim > &b) const
Layout_t & getLayout() const
Definition: BareField.h:130
Definition: Assign.h:47
ac_id_larray::iterator iterator_if
Definition: BareField.h:91
BareField< T, Dim > & getBareField()
#define INFORM_ALL_NODES
Definition: Inform.h:38
const NDIndex< Dim > & getOwned() const
Definition: LField.h:93
touch_range_dv touch_range_rdv(const NDIndex< Dim > &domain, const GuardCellSizes< Dim > &gc=gc0()) const
Definition: FieldLayout.h:780
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
const NDIndex< Dim > & getDomain() const
Message & getMessage(Message &m)
Definition: NDIndex.h:147
const int COMM_ANY_NODE
Definition: Communicate.h:40
Definition: FFT.h:31
void Uncompress(bool fill_domain=true)
Definition: LField.h:166
void assign(const BareField< T, Dim > &a, RHS b, OP op, ExprTag< true >)
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
const iterator & begin() const
Definition: LField.h:104
NDIndex< Dim > plugBase(const NDIndex< 1 > &i) const
Definition: NDIndex.h:118
iterator_if end_if()
Definition: BareField.h:100
CompressedBrickIterator< T, 1 > permute(NDIndex< Dim > &current, NDIndex< 1 > &permuted) const
size_t size() const
Definition: Message.h:300
void CalcIndexedReceive(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, Container &recv_ac, int &msgnum)
bool touches(const NDIndex< Dim > &) const
PETE_TBTree< OpLT, Index::PETE_Expr_t, PETE_Scalar< double > > lt(const Index &idx, double x)
Definition: IndexInlines.h:352
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:92
static bool apply(const NDIndex< D1 > &x, const NDIndex< D1 > &y)
bool IsCompressed() const
Definition: LField.h:128
Definition: FFT.h:30
T * value_type(const SliceIterator< T > &)
#define ASSIGNMSG(x)
Definition: Assign.h:28
void IndexedLocalAssign(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, Op &op)
FillGCIfNecessaryTag< D, T1 > FillGCIfNecessary(const BareField< T1, D > &bf)
Definition: AssignTags.h:146
#define F_GEN_ASSIGN_TAG
Definition: Tags.h:47
void IndexedReceive(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &, Op &op, Container &recv_ac, int msgnum, int tag)
bool contains(const NDIndex< Dim > &a) const
static bool apply(const NDIndex< D1 > &, const NDIndex< D2 > &)
void Compress()
Definition: LField.h:155
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
#define PAssert(c)
Definition: PAssert.h:117
Message & putMessage(Message &m) const
Definition: NDIndex.h:139
std::string::iterator iterator
Definition: MSLang.h:16
bool for_each(const BareFieldIterator< T, D > &p, SameFieldID s, C)
Definition: AssignDefs.h:30
iterator_if begin_if()
Definition: BareField.h:99
Message * receive_block(int &node, int &tag)
Definition: Inform.h:41
static Communicate * Comm
Definition: IpplInfo.h:93
void IndexedSend(IndexedBareField< T1, D1, D1 > &ilhs, IndexedBareField< T2, D2, D2 > &irhs, int tag)
bool send(Message *, int node, int tag, bool delmsg=true)
std::pair< touch_iterator_dv, touch_iterator_dv > touch_range_dv
Definition: FieldLayout.h:77
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define F_TAG_CYCLE
Definition: Tags.h:53