OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
BareField.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 "Field/BareField.h"
28 #include "Field/BrickExpression.h"
30 #include "Message/Communicate.h"
31 #include "Message/GlobalComm.h"
32 #include "Message/Tags.h"
33 #include "Utility/Inform.h"
34 #include "Utility/Unique.h"
35 #include "Utility/IpplInfo.h"
36 #include "Utility/IpplStats.h"
37 
38 #include <map>
39 #include <utility>
40 #include <cstdlib>
41 
42 
44 //
45 // Copy ctor.
46 //
47 
48 template< class T, unsigned Dim >
50 : Layout( a.Layout ), // Copy the layout.
51  Gc( a.Gc ), // Copy the number of guard cells.
52  compressible_m( a.compressible_m ),
53  pinned(false) //UL: for pinned memory allocation
54 {
55 
56 
57 
58  // We assume the guard cells are peachy so clear the dirty flag.
60 
61  // Reserve space for the pointers to the LFields.
62  Locals_ac.reserve( a.size_if() );
63  // Loop over the LFields of the other array, creating LFields as we go.
64  for ( const_iterator_if a_i = a.begin_if(); a_i != a.end_if(); ++a_i )
65  {
66  // Create an LField with copy ctor.
67  LField<T,Dim> *lf = new LField<T,Dim>( *((*a_i).second) );
68  // Insert in the local list, hinting that it should go at the end.
70  typename ac_id_larray::value_type((*a_i).first,lf) );
71  }
72  // Tell the layout we are here.
73  getLayout().checkin( *this , Gc );
74  //INCIPPLSTAT(incBareFields);
75 }
76 
77 
79 //
80 // Destructor
81 //
82 
83 template< class T, unsigned Dim >
85 
86 
87  // must check out from our layout
88  if (Layout != 0) {
89  Layout->checkout(*this);
90  }
91 }
92 
93 
95 // Initialize the field, if it was constructed from the default constructor.
96 // This should NOT be called if the field was constructed by providing
97 // a FieldLayout.
98 
99 template< class T, unsigned Dim >
100 void
102 
103 
104 
105  // if our Layout has been previously set, we just ignore this request
106  if (Layout == 0) {
107  Layout = &l;
108  setup();
109  }
110 }
111 
112 //UL: for pinned memory allocation
113 template< class T, unsigned Dim >
114 void
116 
117 
118 
119  // if our Layout has been previously set, we just ignore this request
120  if (Layout == 0) {
121  Layout = &l;
122  pinned = p;
123  setup();
124  }
125 }
126 
127 template< class T, unsigned Dim >
128 void
130  const GuardCellSizes<Dim>& gc) {
131 
132 
133 
134  // if our Layout has been previously set, we just ignore this request
135  if (Layout == 0) {
136  Layout = &l;
137  Gc = gc;
138  setup();
139  }
140 }
141 
142 
144 //
145 // Using the data that has been initialized by the ctors,
146 // complete the construction by allocating the LFields.
147 //
148 
149 template< class T, unsigned Dim >
150 void
152 {
153 
154 
155 
156  // Make sure this FieldLayout can handle the number of GuardCells
157  // which we have here
158  if ( ! getLayout().fitsGuardCells(Gc)) {
159  ERRORMSG("Cannot construct IPPL BareField:" << endl);
160  ERRORMSG(" One or more vnodes is too small for the guard cells." << endl);
161  ERRORMSG(" Guard cell sizes = " << Gc << endl);
162  ERRORMSG(" FieldLayout = " << getLayout() << endl);
163  Ippl::abort();
164  }
165 
166  // We assume the guard cells are peachy so clear the dirty flag.
167  clearDirtyFlag();
168 
169  // Reserve space for the pointers to the LFields.
170  Locals_ac.reserve( getLayout().size_iv() );
171 
172  // Loop over all the Vnodes, creating an LField in each.
173  for (typename Layout_t::iterator_iv v_i=getLayout().begin_iv();
174  v_i != getLayout().end_iv();
175  ++v_i)
176  {
177  // Get the owned and guarded sizes.
178  const NDIndex<Dim> &owned = (*v_i).second->getDomain();
179  NDIndex<Dim> guarded = AddGuardCells( owned , Gc );
180 
181  // Get the global vnode number (ID number, value from 0 to nvnodes-1):
182  int vnode = (*v_i).second->getVnode();
183 
184  // Construct the LField for this Vnode.
185  //UL: for pinned memory allocation
186  LField<T, Dim> *lf;
187  if (pinned)
188  lf = new LField<T,Dim>( owned, guarded, vnode, pinned );
189  else
190  lf = new LField<T,Dim>( owned, guarded, vnode );
191 
192  // Put it in the list.
193  Locals_ac.insert( end_if(),
194  typename ac_id_larray::value_type((*v_i).first,lf));
195  }
196  // Tell the layout we are here.
197  getLayout().checkin( *this , Gc );
198  //INCIPPLSTAT(incBareFields);
199 }
200 
202 
203 //
204 // Print a BareField out.
205 //
206 
207 template< class T, unsigned Dim>
208 void
209 BareField<T,Dim>::write(std::ostream& out)
210 {
211 
212 
213 
214  // Inform dbgmsg(">>>>>>>> BareField::write", INFORM_ALL_NODES);
215  // dbgmsg << "Printing values for field at address = " << &(*this) << endl;
216 
217  // on remote nodes, we must send the subnodes LField's to node 0
219  if (Ippl::myNode() != 0) {
220  for ( iterator_if local = begin_if(); local != end_if() ; ++local) {
221  // Cache some information about this local field.
222  LField<T,Dim>& l = *((*local).second);
223  NDIndex<Dim>& lo = (NDIndex<Dim>&) l.getOwned();
224  typename LField<T,Dim>::iterator rhs(l.begin());
225 
226  // Build and send a message containing the owned LocalField data
227  if (Ippl::myNode() != 0) {
228  Message *mess = new Message();
229  lo.putMessage(*mess); // send the local domain of the LField
230  rhs.putMessage(*mess); // send the data itself
231  // dbgmsg << "Sending domain " << lo << " to node 0" << endl;
232  Ippl::Comm->send(mess, 0, tag);
233  }
234  }
235  } else { // now, on node 0, receive the remaining LField's ...
236  // put all the LField's in a big, uncompressed LField
237  LField<T,Dim> data(getDomain(), getDomain());
238  data.Uncompress();
239 
240  // first put in our local ones
241  for ( iterator_if local = begin_if(); local != end_if() ; ++local) {
242  // Cache some information about this local field.
243  LField<T,Dim>& l = *((*local).second);
244  NDIndex<Dim>& lo = (NDIndex<Dim>&) l.getOwned();
245  typename LField<T,Dim>::iterator rhs(l.begin());
246 
247  // put the local LField in our big LField
248  // dbgmsg << " Copying local domain " << lo << " from Lfield at ";
249  // dbgmsg << &l << ":" << endl;
250  typename LField<T,Dim>::iterator putloc = data.begin(lo);
251  typename LField<T,Dim>::iterator getloc = l.begin(lo);
252  for ( ; getloc != l.end() ; ++putloc, ++getloc ) {
253  // dbgmsg << " from " << &(*getloc) << " to " << &(*putloc);
254  // dbgmsg << ": " << *putloc << " = " << *getloc << endl;
255  *putloc = *getloc;
256  }
257  }
258 
259  // we expect to receive one message from each remote vnode
260  int remaining = getLayout().size_rdv();
261 
262  // keep receiving messages until they're all here
263  for ( ; remaining > 0; --remaining) {
264  // Receive the generic message.
265  int any_node = COMM_ANY_NODE;
266  Message *mess = Ippl::Comm->receive_block(any_node, tag);
267 
268  // Extract the domain size and LField iterator from the message
269  NDIndex<Dim> lo;
270  T compressed_data;
271  typename LField<T,Dim>::iterator rhs(compressed_data);
272  lo.getMessage(*mess);
273  rhs.getMessage(*mess);
274  // dbgmsg << "Received domain " << lo << " from " << any_node << endl;
275 
276  // put the received LField in our big LField
277  typename LField<T,Dim>::iterator putloc = data.begin(lo);
278  for (unsigned elems=lo.size(); elems > 0; ++putloc, ++rhs, --elems)
279  *putloc = *rhs;
280 
281  // Free the memory in the message.
282  delete mess;
283  }
284 
285  // finally, we can print the big LField out
286  out << data;
287  }
288 }
289 
290 
292 
293 //
294 // Fill all the guard cells, including all the necessary communication.
295 //
296 
297 template< class T, unsigned Dim >
298 void BareField<T,Dim>::fillGuardCells(bool reallyFill) const
299 {
300 
301  // This operation is logically const because the physical cells
302  // of the BareField are unaffected, so cast away const here.
303  BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
304 
305  // Only fill if we are supposed to.
306  if (!reallyFill)
307  return;
308 
309  // Make ourselves clean.
310  ncf.clearDirtyFlag();
311 
312  // Only need to do work if we have non-zero GuardCellSizes
313  if (Gc == GuardCellSizes<Dim>())
314  return;
315 
316  // indicate we're doing another gc fill
317  //INCIPPLSTAT(incGuardCellFills);
318 
319  // iterators for looping through LField's of this BareField
320  iterator_if lf_i, lf_e = ncf.end_if();
321 
322 #ifdef IPPL_PRINTDEBUG
323  Inform msg("fillGuardCells", INFORM_ALL_NODES);
324 #endif
325 
326  // ----------------------------------------
327  // First the send loop.
328  // Loop over all the local nodes and
329  // send data to the remote ones they overlap.
330  int nprocs = Ippl::getNodes();
331  if (nprocs > 1) {
332 
333  // Build a map of the messages we expect to receive.
334  typedef std::multimap< NDIndex<Dim> , LField<T,Dim>* , std::less<NDIndex<Dim> > > ac_recv_type;
335  ac_recv_type recv_ac;
336  bool* recvmsg = new bool[nprocs];
337 
338 
339 
340  // set up messages to be sent
341  Message** mess = new Message*[nprocs];
342 #ifdef IPPL_PRINTDEBUG
343  int* ndomains = new int[nprocs];
344 #endif
345  int iproc;
346  for (iproc=0; iproc<nprocs; ++iproc) {
347  mess[iproc] = NULL;
348  recvmsg[iproc] = false;
349 #ifdef IPPL_PRINTDEBUG
350  ndomains[iproc] = 0;
351 #endif
352  }
353 
354  // now do main loop over LFields, packing overlaps into proper messages
355  for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i) {
356 
357  // Cache some information about this local array.
358  LField<T,Dim> &lf = *((*lf_i).second);
359  const NDIndex<Dim> &lf_domain = lf.getAllocated();
360  // Find the remote ones that touch this LField's guard cells
361  typename Layout_t::touch_range_dv
362  rrange(ncf.getLayout().touch_range_rdv(lf_domain));
363  typename Layout_t::touch_iterator_dv rv_i;
364  for (rv_i = rrange.first; rv_i != rrange.second; ++rv_i) {
365  // Save the intersection and the LField it is for.
366  NDIndex<Dim> sub = lf_domain.intersect( (*rv_i).first );
367  typedef typename ac_recv_type::value_type value_type;
368  recv_ac.insert(value_type(sub,&lf));
369  // note who will be sending this data
370  int rnode = (*rv_i).second->getNode();
371  recvmsg[rnode] = true;
372  }
373 
374 
375 
376  const NDIndex<Dim>& lo = lf.getOwned();
377 #ifdef IPPL_PRINTDEBUG
378  msg << "Finding send overlap regions for domain " << lo << endl;
379 #endif
380  // Loop over the remote domains which have guard cells
381  // that this local domain touches.
382  typename Layout_t::touch_range_dv
383  range( ncf.getLayout().touch_range_rdv(lo,ncf.getGC()) );
384  typename Layout_t::touch_iterator_dv remote_i;
385  for (remote_i = range.first; remote_i != range.second; ++remote_i) {
386  // Find the intersection.
387  NDIndex<Dim> intersection = lo.intersect( (*remote_i).first );
388  // Find out who owns this remote domain.
389  int rnode = (*remote_i).second->getNode();
390 #ifdef IPPL_PRINTDEBUG
391  msg << " Overlap domain = " << (*remote_i).first << endl;
392  msg << " Inters. domain = " << intersection;
393  msg << " --> node " << rnode << endl;
394 #endif
395  // Create an LField iterator for this intersection region,
396  // and try to compress it.
397  // storage for LField compression
398  T compressed_value;
399  LFI msgval = lf.begin(intersection, compressed_value);
400  msgval.TryCompress();
401 
402  // Put intersection domain and field data into message
403  if (!mess[rnode]) mess[rnode] = new Message;
404  PAssert(mess[rnode]);
405  mess[rnode]->put(intersection); // puts Dim items in Message
406  mess[rnode]->put(msgval); // puts 3 items in Message
407 #ifdef IPPL_PRINTDEBUG
408  ndomains[rnode]++;
409 #endif
410  }
411 
412  }
413 
414  int remaining = 0;
415  for (iproc=0; iproc<nprocs; ++iproc)
416  if (recvmsg[iproc]) ++remaining;
417  delete [] recvmsg;
418 
419 
420 
421  // Get message tag.
423 
424  // Send all the messages.
425  for (iproc=0; iproc<nprocs; ++iproc) {
426  if (mess[iproc]) {
427 #ifdef IPPL_PRINTDEBUG
428  msg << "fillGuardCells: Sending message to node " << iproc << endl
429  << " number of domains = " << ndomains[iproc] << endl
430  << " number of MsgItems = " << mess[iproc]->size() << endl;
431 #endif
432  Ippl::Comm->send(mess[iproc], iproc, tag);
433  }
434  }
435 
436  delete [] mess;
437 #ifdef IPPL_PRINTDEBUG
438  delete [] ndomains;
439 #endif
440 
441 
442  // ----------------------------------------
443  // Handle the local fills.
444  // Loop over all the local arrays.
445 
446  for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i)
447  {
448  // Cache some information about this LField.
449  LField<T,Dim> &lf = *(*lf_i).second;
450  const NDIndex<Dim>& la = lf.getAllocated();
451 
452  // Loop over all the other LFields to establish each LField's
453  // cache of overlaps.
454 
455  // This is an N*N operation, but the expectation is that this will
456  // pay off since we will reuse this cache quite often.
457 
458  if (!lf.OverlapCacheInitialized())
459  {
460  for (iterator_if rf_i = ncf.begin_if(); rf_i != ncf.end_if(); ++rf_i)
461  if ( rf_i != lf_i )
462  {
463  // Cache some info about this LField.
464  LField<T,Dim> &rf = *(*rf_i).second;
465  const NDIndex<Dim>& ro = rf.getOwned();
466 
467  // If the remote has info we want, then add it to our cache.
468  if ( la.touches(ro) )
469  lf.AddToOverlapCache(&rf);
470  }
471  }
472 
473  // We know at this point that the overlap cache is established.
474  // Use it.
475 
476  for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
477  rf_i != lf.EndOverlap(); ++rf_i)
478  {
479  LField<T, Dim> &rf = *(*rf_i);
480  const NDIndex<Dim>& ro = rf.getOwned();
481 
482  bool c1 = lf.IsCompressed();
483  bool c2 = rf.IsCompressed();
484  bool c3 = *rf.begin() == *lf.begin();
485 
486  // If these are compressed we might not have to do any work.
487  if ( !( c1 && c2 && c3 ) )
488  {
489 
490 
491  // Find the intersection.
492  NDIndex<Dim> intersection = la.intersect(ro);
493 
494  // Build an iterator for the rhs.
495  LFI rhs = rf.begin(intersection);
496 
497  // Could we compress that?
498  if ( !(c1 && rhs.CanCompress(*lf.begin())) )
499  {
500  // Make sure the left is not compressed.
501  lf.Uncompress();
502 
503  // Nope, we really have to copy.
504  LFI lhs = lf.begin(intersection);
505 #ifdef IPPL_PRINTDEBUG
506  msg << " Inters. domain=" << intersection << endl;
507 #endif
508  // And do the assignment.
509  BrickExpression<Dim,LFI,LFI,OpAssign>(lhs,rhs).apply();
510  }
511 
512 
513  }
514 #ifdef IPPL_PRINTDEBUG
515  else {
516  msg << " Both sides compressed and equal ... val = ";
517  msg << *rf.begin() << endl;
518  }
519 #endif
520  }
521  }
522 
523 
524  // ----------------------------------------
525  // Receive all the messages.
526 
527  while (remaining>0) {
528  // Receive the next message.
529  int any_node = COMM_ANY_NODE;
530 
531  Message* rmess = Ippl::Comm->receive_block(any_node,tag);
532  PAssert(rmess);
533  --remaining;
534 
535 
536  // Determine the number of domains being sent
537  int ndoms = rmess->size() / (Dim + 3);
538 #ifdef IPPL_PRINTDEBUG
539  msg << "fillGuardCells: Message received from node " << any_node
540  << ", number of domains = " << ndoms << endl;
541 #endif
542  for (int idom=0; idom<ndoms; ++idom) {
543  // Extract the intersection domain from the message.
544  NDIndex<Dim> intersection;
545  intersection.getMessage(*rmess);
546 
547  // Extract the rhs iterator from it.
548  T compressed_value;
549  LFI rhs(compressed_value);
550  rhs.getMessage(*rmess);
551 #ifdef IPPL_PRINTDEBUG
552  msg << "Received remote overlap region = " << intersection << endl;
553 #endif
554 
555  // Find the LField it is destined for.
556  typename ac_recv_type::iterator hit = recv_ac.find( intersection );
557  PAssert( hit != recv_ac.end() );
558  // Build the lhs brick iterator.
559  LField<T,Dim> &lf = *(*hit).second;
560  // Check and see if we really have to do this.
561 #ifdef IPPL_PRINTDEBUG
562  msg << " LHS compressed ? " << lf.IsCompressed();
563  msg << ", LHS value = " << *lf.begin() << endl;
564  msg << " RHS compressed ? " << rhs.IsCompressed();
565  msg << ", RHS value = " << *rhs << endl;
566  msg << " *rhs == *lf.begin() ? " << (*rhs == *lf.begin()) << endl;
567 #endif
568  if ( !(rhs.IsCompressed() && lf.IsCompressed() &&
569  (*rhs == *lf.begin())) )
570  {
571  // Yep. gotta do it.
572  lf.Uncompress();
573  LFI lhs = lf.begin(intersection);
574  // Do the assignment.
575 #ifdef IPPL_PRINTDEBUG
576  msg << " Doing copy." << endl;
577 #endif
578  BrickExpression<Dim,LFI,LFI,OpAssign>(lhs,rhs).apply();
579  }
580 
581  // Take that entry out of the receive list.
582  recv_ac.erase( hit );
583  }
584  delete rmess;
585  }
586 
587  }
588  else { // single-node case
589  // ----------------------------------------
590  // Handle the local fills.
591  // Loop over all the local arrays.
592 
593  for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i)
594  {
595  // Cache some information about this LField.
596  LField<T,Dim> &lf = *(*lf_i).second;
597  const NDIndex<Dim>& la = lf.getAllocated();
598 
599  // Loop over all the other LFields to establish each LField's
600  // cache of overlaps.
601 
602  // This is an N*N operation, but the expectation is that this will
603  // pay off since we will reuse this cache quite often.
604 
605  if (!lf.OverlapCacheInitialized())
606  {
607  for (iterator_if rf_i = ncf.begin_if(); rf_i != ncf.end_if(); ++rf_i)
608  if ( rf_i != lf_i )
609  {
610  // Cache some info about this LField.
611  LField<T,Dim> &rf = *(*rf_i).second;
612  const NDIndex<Dim>& ro = rf.getOwned();
613 
614  // If the remote has info we want, then add it to our cache.
615  if ( la.touches(ro) )
616  lf.AddToOverlapCache(&rf);
617  }
618  }
619 
620  // We know at this point that the overlap cache is established.
621  // Use it.
622 
623  for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
624  rf_i != lf.EndOverlap(); ++rf_i)
625  {
626  LField<T, Dim> &rf = *(*rf_i);
627  const NDIndex<Dim>& ro = rf.getOwned();
628 
629  bool c1 = lf.IsCompressed();
630  bool c2 = rf.IsCompressed();
631  bool c3 = *rf.begin() == *lf.begin();
632 
633  // If these are compressed we might not have to do any work.
634  if ( !( c1 && c2 && c3 ) )
635  {
636 
637 
638  // Find the intersection.
639  NDIndex<Dim> intersection = la.intersect(ro);
640 
641  // Build an iterator for the rhs.
642  LFI rhs = rf.begin(intersection);
643 
644  // Could we compress that?
645  if ( !(c1 && rhs.CanCompress(*lf.begin())) )
646  {
647  // Make sure the left is not compressed.
648  lf.Uncompress();
649 
650  // Nope, we really have to copy.
651  LFI lhs = lf.begin(intersection);
652 #ifdef IPPL_PRINTDEBUG
653  msg << " Inters. domain=" << intersection << endl;
654 #endif
655  // And do the assignment.
656  BrickExpression<Dim,LFI,LFI,OpAssign>(lhs,rhs).apply();
657  }
658 
659 
660  }
661 #ifdef IPPL_PRINTDEBUG
662  else {
663  msg << " Both sides compressed and equal ... val = ";
664  msg << *rf.begin() << endl;
665  }
666 #endif
667  }
668  }
669 
670  }
671  return;
672 }
673 
675 
676 //
677 // Fill guard cells with a constant value.
678 // This is typically used to zero out the guard cells before a scatter.
679 //
680 
681 template <class T, unsigned Dim>
682 void BareField<T,Dim>::setGuardCells(const T& val) const
683 {
684  // profiling macros
685 
686 
687 
688  // if there are no guard cells, we can just return
689  if (Gc == GuardCellSizes<Dim>())
690  return;
691 
692  // this member function is logically const, so cast away const-ness
693  BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
694 
695  // loop over our LFields and set guard cell values
696  iterator_if lf_i, lf_e = ncf.end_if();
697  for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i) {
698  // Get this LField
699  LField<T,Dim>& lf = *((*lf_i).second);
700 
701  // Quick test to see if we can avoid doing any work.
702  // If this LField is compressed and already contains
703  // the value that is being assigned to the guard cells,
704  // then we can just move on to the next LField.
705  if (lf.IsCompressed() && lf.getCompressedData() == val)
706  continue;
707 
708  // OK, we really have to fill the guard cells, so get
709  // the domains we will be working with.
710  const NDIndex<Dim>& adom = lf.getAllocated();
711  const NDIndex<Dim>& odom = lf.getOwned();
712  NDIndex<Dim> dom = odom; // initialize working domain to Owned
713 
714  // create a compressed LField with the same allocated domain
715  // containing the value to be assigned to the guard cells
716  LField<T,Dim> rf(odom,adom);
717  rf.Compress(val);
718 
719  // Uncompress LField to be filled and get some iterators
720  lf.Uncompress();
721  LFI lhs, rhs;
722 
723  // now loop over dimensions and fill guard cells along each
724  for (unsigned int idim = 0; idim < Dim; ++idim) {
725  // set working domain to left guards in this dimension
726  dom[idim] = Index(adom[idim].first(),
727  adom[idim].first() + Gc.left(idim) - 1);
728  if (!dom[idim].empty()) {
729  // Set iterators over working domain and do assignment
730  lhs = lf.begin(dom);
731  rhs = rf.begin(dom);
732  BrickExpression<Dim,LFI,LFI,OpAssign>(lhs,rhs).apply();
733  }
734 
735  // Set working domain to right guards in this dimension
736  dom[idim] = Index(adom[idim].last() - Gc.right(idim) + 1,
737  adom[idim].last());
738  if (!dom[idim].empty()) {
739  // Set iterators over working domain and do assignment
740  lhs = lf.begin(dom);
741  rhs = rf.begin(dom);
742  BrickExpression<Dim,LFI,LFI,OpAssign>(lhs,rhs).apply();
743  }
744 
745  // Adjust working domain along this direction
746  // in preparation for working on next dimension.
747  dom[idim] = adom[idim];
748  }
749  }
750 
751  // let's set the dirty flag, since we have modified guard cells.
752  ncf.setDirtyFlag();
753 
754  return;
755 }
756 
758 
759 //
760 // Accumulate guard cells into real cells, including necessary communication.
761 //
762 
763 template <class T, unsigned Dim>
765 {
766 
767  // Only need to do work if we have non-zero GuardCellSizes
768  if (Gc == GuardCellSizes<Dim>())
769  return;
770 
771  // iterators for looping through LField's of this BareField
772  iterator_if lf_i, lf_e = end_if();
773 
774 #ifdef IPPL_PRINTDEBUG
775  Inform msg("accumGuardCells", INFORM_ALL_NODES);
776 #endif
777 
778  // ----------------------------------------
779  // First the send loop.
780  // Loop over all the local nodes and
781  // send data to the remote ones they overlap.
782  int nprocs = Ippl::getNodes();
783  if (nprocs > 1) {
784 
785  // Build a map of the messages we expect to receive.
786  typedef std::multimap< NDIndex<Dim> , LField<T,Dim>* , std::less<NDIndex<Dim> > > ac_recv_type;
787  ac_recv_type recv_ac;
788  bool* recvmsg = new bool[nprocs];
789 
790 
791 
792  // set up messages to be sent
793  Message** mess = new Message*[nprocs];
794 #ifdef IPPL_PRINTDEBUG
795  int* ndomains = new int[nprocs];
796 #endif
797  int iproc;
798  for (iproc=0; iproc<nprocs; ++iproc) {
799  mess[iproc] = NULL;
800  recvmsg[iproc] = false;
801 #ifdef IPPL_PRINTDEBUG
802  ndomains[iproc] = 0;
803 #endif
804  }
805 
806  // now do main loop over LFields, packing overlaps into proper messages
807  for (lf_i = begin_if(); lf_i != lf_e; ++lf_i) {
808 
809  // Cache some information about this local array.
810  LField<T,Dim> &lf = *((*lf_i).second);
811  const NDIndex<Dim>& lo = lf.getOwned();
812  // Find the remote ones with guard cells touching this LField
813  typename Layout_t::touch_range_dv
814  rrange( getLayout().touch_range_rdv(lo,Gc) );
815  typename Layout_t::touch_iterator_dv rv_i;
816  for (rv_i = rrange.first; rv_i != rrange.second; ++rv_i) {
817  // Save the intersection and the LField it is for.
818  NDIndex<Dim> sub = lo.intersect( (*rv_i).first );
819  recv_ac.insert(typename ac_recv_type::value_type(sub,&lf));
820  // note who will be sending this data
821  int rnode = (*rv_i).second->getNode();
822  recvmsg[rnode] = true;
823  }
824 
825 
826 
827  const NDIndex<Dim> &lf_domain = lf.getAllocated();
828 #ifdef IPPL_PRINTDEBUG
829  msg << "Finding send overlap regions for domain " << lf_domain << endl;
830 #endif
831  // Loop over the remote domains that touch this local
832  // domain's guard cells
833  typename Layout_t::touch_range_dv
834  range(getLayout().touch_range_rdv(lf_domain));
835  typename Layout_t::touch_iterator_dv remote_i;
836  for (remote_i = range.first; remote_i != range.second; ++remote_i) {
837  // Find the intersection.
838  NDIndex<Dim> intersection = lf_domain.intersect( (*remote_i).first );
839  // Find out who owns this remote domain.
840  int rnode = (*remote_i).second->getNode();
841 #ifdef IPPL_PRINTDEBUG
842  msg << " Overlap domain = " << (*remote_i).first << endl;
843  msg << " Inters. domain = " << intersection;
844  msg << " --> node " << rnode << endl;
845 #endif
846  // Create an LField iterator for this intersection region,
847  // and try to compress it.
848  // storage for LField compression
849  T compressed_value;
850  LFI msgval = lf.begin(intersection, compressed_value);
851  msgval.TryCompress();
852 
853  // Put intersection domain and field data into message
854  if (!mess[rnode]) mess[rnode] = new Message;
855  PAssert(mess[rnode]);
856  mess[rnode]->put(intersection); // puts Dim items in Message
857  mess[rnode]->put(msgval); // puts 3 items in Message
858 #ifdef IPPL_PRINTDEBUG
859  ndomains[rnode]++;
860 #endif
861  }
862 
863  }
864 
865  int remaining = 0;
866  for (iproc=0; iproc<nprocs; ++iproc)
867  if (recvmsg[iproc]) ++remaining;
868  delete [] recvmsg;
869 
870 
871 
872  // Get message tag.
874 
875  // Send all the messages.
876  for (iproc=0; iproc<nprocs; ++iproc) {
877  if (mess[iproc]) {
878 #ifdef IPPL_PRINTDEBUG
879  msg << "accumGuardCells: Sending message to node " << iproc << endl
880  << " number of domains = " << ndomains[iproc] << endl
881  << " number of MsgItems = " << mess[iproc]->size() << endl;
882 #endif
883  Ippl::Comm->send(mess[iproc], iproc, tag);
884  }
885  }
886 
887  delete [] mess;
888 #ifdef IPPL_PRINTDEBUG
889  delete [] ndomains;
890 #endif
891 
892 
893  // ----------------------------------------
894  // Handle the local fills.
895  // Loop over all the local arrays.
896 
897  for (lf_i=begin_if(); lf_i != lf_e; ++lf_i)
898  {
899  // Cache some information about this LField.
900  LField<T,Dim> &lf = *(*lf_i).second;
901  const NDIndex<Dim>& la = lf.getAllocated();
902 
903  // Loop over all the other LFields to establish each LField's
904  // cache of overlaps.
905 
906  // This is an N*N operation, but the expectation is that this will
907  // pay off since we will reuse this cache quite often.
908 
909  if (!lf.OverlapCacheInitialized())
910  {
911  for (iterator_if rf_i = begin_if(); rf_i != end_if(); ++rf_i)
912  if ( rf_i != lf_i )
913  {
914  // Cache some info about this LField.
915  LField<T,Dim> &rf = *(*rf_i).second;
916  const NDIndex<Dim>& ro = rf.getOwned();
917 
918  // If the remote has info we want, then add it to our cache.
919  if ( la.touches(ro) )
920  lf.AddToOverlapCache(&rf);
921  }
922  }
923 
924  // We know at this point that the overlap cache is established.
925  // Use it.
926 
927  for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
928  rf_i != lf.EndOverlap(); ++rf_i)
929  {
930  LField<T, Dim> &rf = *(*rf_i);
931  const NDIndex<Dim>& ro = rf.getOwned();
932 
933 
934 
935  // Find the intersection.
936  NDIndex<Dim> intersection = la.intersect(ro);
937 
938  // Build iterator for lf guard cells
939  LFI lhs = lf.begin(intersection);
940 
941  // check if we can skip accumulation
942  if ( !lhs.CanCompress(T()) ) {
943 
944  // Make sure the right side is not compressed.
945  rf.Uncompress();
946 
947  // Build iterator for rf real cells
948  LFI rhs = rf.begin(intersection);
949 
950 #ifdef IPPL_PRINTDEBUG
951  msg << " Inters. domain=" << intersection << endl;
952 #endif
953  // And do the accumulation
955  }
956 
957  }
958  }
959 
960 
961  // ----------------------------------------
962  // Receive all the messages.
963 
964  while (remaining>0) {
965  // Receive the next message.
966  int any_node = COMM_ANY_NODE;
967 
968  Message* rmess = Ippl::Comm->receive_block(any_node,tag);
969  PAssert(rmess);
970  --remaining;
971 
972 
973  // Determine the number of domains being sent
974  int ndoms = rmess->size() / (Dim + 3);
975 #ifdef IPPL_PRINTDEBUG
976  msg << "accumGuardCells: Message received from node " << any_node
977  << ", number of domains = " << ndoms << endl;
978 #endif
979  for (int idom=0; idom<ndoms; ++idom) {
980  // Extract the intersection domain from the message.
981  NDIndex<Dim> intersection;
982  intersection.getMessage(*rmess);
983 
984  // Extract the rhs iterator from it.
985  T compressed_value;
986  LFI rhs(compressed_value);
987  rhs.getMessage(*rmess);
988 #ifdef IPPL_PRINTDEBUG
989  msg << "Received remote overlap region = " << intersection << endl;
990 #endif
991 
992  // Find the LField it is destined for.
993  typename ac_recv_type::iterator hit = recv_ac.find( intersection );
994  PAssert( hit != recv_ac.end() );
995 
996  // Build the lhs brick iterator.
997  LField<T,Dim> &lf = *(*hit).second;
998 
999  // Make sure LField is uncompressed
1000  lf.Uncompress();
1001  LFI lhs = lf.begin(intersection);
1002 
1003  // Do the accumulation
1005 
1006  // Take that entry out of the receive list.
1007  recv_ac.erase( hit );
1008  }
1009  delete rmess;
1010  }
1011 
1012  }
1013  else { // single-node case
1014  // ----------------------------------------
1015  // Handle the local fills.
1016  // Loop over all the local arrays.
1017 
1018  for (lf_i=begin_if(); lf_i != lf_e; ++lf_i)
1019  {
1020  // Cache some information about this LField.
1021  LField<T,Dim> &lf = *(*lf_i).second;
1022  const NDIndex<Dim>& la = lf.getAllocated();
1023 
1024  // Loop over all the other LFields to establish each LField's
1025  // cache of overlaps.
1026 
1027  // This is an N*N operation, but the expectation is that this will
1028  // pay off since we will reuse this cache quite often.
1029 
1030  if (!lf.OverlapCacheInitialized())
1031  {
1032  for (iterator_if rf_i = begin_if(); rf_i != end_if(); ++rf_i)
1033  if ( rf_i != lf_i )
1034  {
1035  // Cache some info about this LField.
1036  LField<T,Dim> &rf = *(*rf_i).second;
1037  const NDIndex<Dim>& ro = rf.getOwned();
1038 
1039  // If the remote has info we want, then add it to our cache.
1040  if ( la.touches(ro) )
1041  lf.AddToOverlapCache(&rf);
1042  }
1043  }
1044 
1045  // We know at this point that the overlap cache is established.
1046  // Use it.
1047 
1048  for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
1049  rf_i != lf.EndOverlap(); ++rf_i)
1050  {
1051  LField<T, Dim> &rf = *(*rf_i);
1052  const NDIndex<Dim>& ro = rf.getOwned();
1053 
1054 
1055 
1056  // Find the intersection.
1057  NDIndex<Dim> intersection = la.intersect(ro);
1058 
1059  // Build iterator for lf guard cells
1060  LFI lhs = lf.begin(intersection);
1061 
1062  // Check if we can skip accumulation
1063  if ( !lhs.CanCompress(T()) ) {
1064  // Make sure rf is not compressed.
1065  rf.Uncompress();
1066 
1067  // Build iterator for rf real cells
1068  LFI rhs = rf.begin(intersection);
1069 
1070 #ifdef IPPL_PRINTDEBUG
1071  msg << " Inters. domain=" << intersection << endl;
1072 #endif
1073  // And do the accumulation
1075  }
1076 
1077  }
1078  }
1079 
1080  }
1081 
1082  // since we just modified real cell values, set dirty flag if using
1083  // deferred guard cell fills
1084  setDirtyFlag();
1085  // fill guard cells now, unless we are deferring
1086  fillGuardCellsIfNotDirty();
1087  // try to compress the final result
1088  Compress();
1089 
1090  return;
1091 }
1092 
1094 
1095 // netCDF write operation for 1,2, and 3 Dimensionsal arrays
1096 // currently, only prints out doubles (RTTI would help....)
1097 // look here for more I/O capabilities
1098 
1099 template< class T, unsigned Dim >
1100 void BareField<T,Dim>::write(char* fname) const
1101 {
1102 
1103 
1104 
1105 #ifdef IPPL_NETCDF
1106 
1107  int ncid; // NetCDF file ID
1108  int varVID; // NetCDF variable ID's
1109 
1110  // Create the NetCDF file, overwrite if already exists:
1111  ncid = nccreate(fname, NC_CLOBBER);
1112  // Select no-fill mode, to avoid wasting time initializing values
1113  // into variables with no UNLIMITED dimension upon creation:
1114  int fillmode = ncsetfill(ncid,NC_NOFILL); //tjwdebug
1115  // Initialize metadata:
1116  // Dimensions:
1117 
1118  //tjw const NDIndex<Dim> &domain = Layout->get_Domain();
1119  const NDIndex<Dim> &domain = getDomain();
1120 
1121  // Variables:
1122  // Order them with x-direction last, so that IPPL's FORTRAN-ordered LField's
1123  // give the C interface of NetCDF what it expects (last dimension varying
1124  // fastest).
1125  int dimids[Dim];
1126  if ( Dim==1 )
1127  {
1128  dimids[0] = ncdimdef(ncid, "nx", domain[0].length());
1129  }
1130  else if ( Dim==2 )
1131  {
1132  dimids[1] = ncdimdef(ncid, "nx", domain[1].length());
1133  dimids[0] = ncdimdef(ncid, "ny", domain[0].length());
1134  }
1135  else if ( Dim==3 )
1136  {
1137  dimids[2] = ncdimdef(ncid, "nx", domain[0].length());
1138  dimids[1] = ncdimdef(ncid, "ny", domain[1].length());
1139  dimids[0] = ncdimdef(ncid, "nz", domain[2].length());
1140  }
1141  else if ( Dim>3 )
1142  {
1143  ERRORMSG("BareField: Can't write more than 3 dimensions." << endl);
1144  }
1145  varVID = ncvardef(ncid, fname, NC_DOUBLE, Dim, dimids);
1146  // End (metadata) definition mode and close file (par_io requires):
1147  int errRet = ncendef(ncid);
1148 
1149  // Loop over all the Vnodes, creating an LField in each.
1150  long startIndex[Dim];
1151  long countIndex[Dim];
1152  int rcode;
1153 
1154  for (const_iterator_if l_i = begin_if(); l_i != end_if(); ++l_i)
1155  {
1156  // find the offset within the global space
1157  LField<T,Dim> *ldf = (*l_i).second.get();
1158  const NDIndex<Dim> &Owned = ldf->getOwned();
1159 
1160  int size = 1;
1161  for(unsigned int i = 0 ; i < Dim ; i++ )
1162  {
1163  startIndex[Dim - i - 1] = Owned[i].first();
1164  countIndex[Dim - i - 1] = Owned[i].length();
1165  size *= countIndex[Dim - i - 1];
1166  }
1167  double* buffer = new double[size];
1168 
1169  int icount = 0;
1170  typename LField<T,Dim>::iterator lf_bi = ldf->begin();
1171  if ( Dim==1 )
1172  {
1173  int n0 = ldf->size(0);
1174  for (int i0=0; i0<n0; ++i0)
1175  buffer[icount++] = lf_bi.offset(i0);
1176  }
1177  else if ( Dim==2 )
1178  {
1179  int n0 = ldf->size(0);
1180  int n1 = ldf->size(1);
1181  for (int i1=0; i1<n1; ++i1)
1182  for (int i0=0; i0<n0; ++i0)
1183  buffer[icount++] = lf_bi.offset(i0,i1);
1184  }
1185  else if ( Dim==3 )
1186  {
1187  int n0 = ldf->size(0);
1188  int n1 = ldf->size(1);
1189  int n2 = ldf->size(2);
1190  for (int i2=0; i2<n2; ++i2)
1191  for (int i1=0; i1<n1; ++i1)
1192  for (int i0=0; i0<n0; ++i0)
1193  buffer[icount++] = lf_bi.offset(i0,i1,i2);
1194  }
1195  rcode = ncvarput(ncid, varVID, startIndex,countIndex, buffer);
1196  if ( rcode != 0)
1197  {
1198  ERRORMSG("BareField: ncvarput() error, rcode=" << rcode << endl);
1199  }
1200  delete [] buffer;
1201  }
1202  rcode = ncclose(ncid); // Everybody/master closes file.
1203 #else
1204  ERRORMSG("[Bare]Field::write(\"filename\") requires that you run 'conf' "
1205  << endl << " "
1206  << "with the NETCDF option when building libippl.a; you haven't."
1207  << endl);
1208 #endif
1209 }
1210 
1212 
1213 
1214 //
1215 // An output function which writes out the BareField
1216 // a vnode at a time and includes the border information
1217 //
1218 
1219 template< class T, unsigned Dim >
1220 void BareField<T,Dim>::writeb(char* fname) const
1221 {
1222 
1223 
1224  Inform outC(0, fname, Inform::OVERWRITE);
1225 
1226  int icount = 0;
1227  for (const_iterator_if l_i = begin_if(); l_i != end_if(); ++l_i)
1228  {
1229  // find the offset within the global space
1230  LField<T,Dim> *ldf = (*l_i).second.get();
1231  const NDIndex<Dim> &Owned = ldf->getOwned();
1232 
1233  outC << "vnode = " << icount++ << endl;
1234  typename LField<T,Dim>::iterator lf_bi = ldf->begin();
1235  if ( Dim==1 )
1236  {
1237  int n0 = ldf->size(0);
1238  int l0 = -Gc.left(0);
1239  int r0 = n0 + Gc.right(0);
1240  for (int i0=l0; i0<r0; ++i0)
1241  {
1242  outC << " [" << i0;
1243  outC << "]=" << lf_bi.offset(i0);
1244  }
1245  }
1246  else if ( Dim==2 )
1247  {
1248  int n0 = ldf->size(0);
1249  int n1 = ldf->size(1);
1250  int l0 = -Gc.left(0);
1251  int l1 = -Gc.left(1);
1252  int r0 = n0 + Gc.right(0);
1253  int r1 = n1 + Gc.right(1);
1254  for (int i1=l1; i1<r1; ++i1)
1255  {
1256  for (int i0=l0; i0<r0; ++i0)
1257  {
1258  outC << " [" << i0;
1259  outC << "][" << i1;
1260  outC << "]=" << lf_bi.offset(i0,i1);
1261  }
1262  outC << endl;
1263  }
1264  }
1265  else if ( Dim==3 )
1266  {
1267  int n0 = ldf->size(0);
1268  int n1 = ldf->size(1);
1269  int n2 = ldf->size(2);
1270  int l0 = -Gc.left(0);
1271  int l1 = -Gc.left(1);
1272  int l2 = -Gc.left(2);
1273  int r0 = n0 + Gc.right(0);
1274  int r1 = n1 + Gc.right(1);
1275  int r2 = n2 + Gc.right(2);
1276  for (int i2=l2; i2<r2; ++i2)
1277  {
1278  for (int i1=l1; i1<r1; ++i1)
1279  for (int i0=l0; i0<r0; ++i0)
1280  {
1281  outC << " [" << i0;
1282  outC << "][" << i1;
1283  outC << "][" << i2;
1284  outC << "]=" << lf_bi.offset(i0,i1,i2);
1285  }
1286  outC << endl;
1287  }
1288  }
1289  else
1290  {
1291  ERRORMSG(" can not write for larger than three dimensions " << endl);
1292  }
1293  outC << "------------------ " << endl;
1294  }
1295 }
1296 
1298 
1299 //
1300 // Tell a BareField to compress itself.
1301 // Just loop over all of the local fields and tell them to compress.
1302 //
1303 template<class T, unsigned Dim>
1305 {
1306 
1307 
1308 
1309  if (!compressible_m) return;
1310 
1311  // This operation is logically const, so cast away const here
1312  BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
1313  for (iterator_if lf_i = ncf.begin_if(); lf_i != ncf.end_if(); ++lf_i)
1314  (*lf_i).second->TryCompress(isDirty());
1315 }
1316 
1317 template<class T, unsigned Dim>
1319 {
1320 
1321 
1322 
1323  // This operation is logically const, so cast away const here
1324  BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
1325  for (iterator_if lf_i = ncf.begin_if(); lf_i != ncf.end_if(); ++lf_i)
1326  (*lf_i).second->Uncompress();
1327 }
1328 
1329 //
1330 // Look at all the local fields and calculate the
1331 // fraction of all the elements that are compressed.
1332 //
1333 template<class T, unsigned Dim>
1335 {
1336 
1337 
1338 
1339  // elements[0] = total elements
1340  // elements[1] = compressed elements
1341  double elements[2] = { 0.0, 0.0};
1342  // Loop over all of the local fields.
1343  for (const_iterator_if lf_i=begin_if(); lf_i != end_if(); ++lf_i)
1344  {
1345  // Get a reference to the current local field.
1346  LField<T,Dim> &lf = *(*lf_i).second;
1347  // Get the size of this one.
1348  double s = lf.getOwned().size();
1349  // Add that up.
1350  elements[0] += s;
1351  // If it is compressed...
1352  if ( lf.IsCompressed() )
1353  // Add that amount to the compressed total.
1354  elements[1] += s;
1355  }
1356  // Make some space to put the global sum of each of the above.
1357  double reduced_elements[2] = { 0.0, 0.0};
1358  // Do the global reduction.
1359  reduce(elements,elements+2,reduced_elements,OpAddAssign());
1360  // Return the fraction.
1361  return reduced_elements[1]/reduced_elements[0];
1362 }
1363 
1364 
1366 template<class T, unsigned Dim>
1368 {
1369 
1370 
1371 
1372  // Cast to the proper type of FieldLayout.
1373  Layout_t *newLayout = (Layout_t *)( userlist );
1374 
1375  // Build a new temporary field on the new layout.
1376  BareField<T,Dim> tempField( *newLayout, Gc );
1377 
1378  // Copy our data over to the new layout.
1379  tempField = *this;
1380 
1381  // Copy back the pointers to the new local fields.
1382  Locals_ac = tempField.Locals_ac;
1383 
1384  //INCIPPLSTAT(incRepartitions);
1385 }
1386 
1387 
1389 // Tell the subclass that the FieldLayout is being deleted, so
1390 // don't use it anymore
1391 template<class T, unsigned Dim>
1393 {
1394 
1395 
1396 
1397  // just set our layout pointer to NULL; if we try to do anything more
1398  // with this object, other than delete it, a core dump is likely
1399  if (Layout != 0 && Layout->get_Id() == userlist->getUserListID()) {
1400  // the ID refers to this layout, so get rid of it. It is possible
1401  // the ID refers to some other object, in which case we do not want
1402  // to cast away our Layout object.
1403  Layout = 0;
1404  } else {
1405  // for now, print a warning, until other types of FieldLayoutUser's
1406  // are set up to register with a FieldLayout ... but in general,
1407  // this is OK and this warning should be removed
1408  WARNMSG("BareField: notified of unknown UserList being deleted.");
1409  WARNMSG(endl);
1410  }
1411 }
1412 
1413 // a simple true-false template used to select which loop to implement
1414 // in the BareField::localElement body
1415 template<unsigned Dim, bool exists>
1417 #ifdef IPPL_PURIFY
1418  // Add explicit default/copy constructors and op= to avoid UMR's.
1419 public:
1420  LFieldDimTag() {}
1423  operator=(const LFieldDimTag<Dim,exists> &) { return *this; }
1424 #endif
1425 };
1426 
1427 // 1, 2, 3, and N Dimensional functions
1428 template <class T>
1429 inline
1430 T* PtrOffset(T* ptr, const NDIndex<1U>& pos, const NDIndex<1U>& alloc,
1432  T* newptr = ptr + pos[0].first() - alloc[0].first();
1433  return newptr;
1434 }
1435 
1436 template <class T>
1437 inline
1438 T* PtrOffset(T* ptr, const NDIndex<2U>& pos, const NDIndex<2U>& alloc,
1440  T* newptr = ptr + pos[0].first() - alloc[0].first() +
1441  alloc[0].length() * ( pos[1].first() - alloc[1].first() );
1442  return newptr;
1443 }
1444 
1445 template <class T>
1446 inline
1447 T* PtrOffset(T* ptr, const NDIndex<3U>& pos, const NDIndex<3U>& alloc,
1449  T* newptr = ptr + pos[0].first() - alloc[0].first() +
1450  alloc[0].length() * ( pos[1].first() - alloc[1].first() +
1451  alloc[1].length() * ( pos[2].first() - alloc[2].first() ) );
1452  return newptr;
1453 }
1454 
1455 template <class T, unsigned Dim>
1456 inline
1457 T* PtrOffset(T* ptr, const NDIndex<Dim>& pos, const NDIndex<Dim>& alloc,
1459  T* newptr = ptr;
1460  int n=1;
1461  for (unsigned int d=0; d<Dim; ++d) {
1462  newptr += n * (pos[d].first() - alloc[d].first());
1463  n *= alloc[d].length();
1464  }
1465  return newptr;
1466 }
1467 
1468 
1470 // Get a ref to a single element of the Field; if it is not local to our
1471 // processor, print an error and exit. This allows the user to provide
1472 // different index values on each node, instead of using the same element
1473 // and broadcasting to all nodes.
1474 template<class T, unsigned Dim>
1476 {
1477 
1478 
1479 
1480 
1481  // Instead of checking to see if the user has asked for one element,
1482  // we will just use the first element specified for each dimension.
1483 
1484  // Is this element here?
1485  // Try and find it in the local BareFields.
1486  const_iterator_if lf_i = begin_if();
1487  const_iterator_if lf_end = end_if();
1488  for ( ; lf_i != lf_end ; ++lf_i ) {
1489  LField<T,Dim>& lf(*(*lf_i).second);
1490  // End-point "contains" OK since "owned" is unit stride.
1491  // was before CK fix: if ( lf.getOwned().contains( Indexes ) ) {
1492  if ( lf.getAllocated().contains( Indexes ) ) {
1493  // Found it ... first uncompress, then get a pointer to the
1494  // requested element.
1495  lf.Uncompress();
1496  // return *(lf.begin(Indexes));
1497  // instead of building an iterator, just find the value
1498  NDIndex<Dim> alloc = lf.getAllocated();
1499  T* pdata = PtrOffset(lf.getP(), Indexes, alloc,
1501  return *pdata;
1502  }
1503  }
1504 
1505  // if we're here, we did not find it ... it must not be local
1506  ERRORMSG("BareField::localElement: attempt to access non-local index ");
1507  ERRORMSG(Indexes << " on node " << Ippl::myNode() << endl);
1508  ERRORMSG("Occurred in a BareField with layout = " << getLayout() << endl);
1509  ERRORMSG("Calling abort ..." << endl);
1510  Ippl::abort();
1511  return *((*((*(begin_if())).second)).begin());
1512 }
1513 
1514 
1516 //
1517 // Get a single value and return it in the given storage. Whichever
1518 // node owns the value must broadcast it to the other nodes.
1519 //
1521 template <class T, unsigned int Dim>
1522 void BareField<T,Dim>::getsingle(const NDIndex<Dim>& Indexes, T& r) const
1523 {
1524 
1525 
1526 
1527  // Instead of checking to see if the user has asked for one element,
1528  // we will just use the first element specified for each dimension.
1529 
1530  // Check to see if the point is in the boundary conditions.
1531  // Check for: The point is not in the owned domain, but it is in that
1532  // domain augmented with the boundary condition size.
1533  // If so, use a different algorithm.
1534  if ( (!Indexes.touches(Layout->getDomain())) &&
1535  Indexes.touches(AddGuardCells(Layout->getDomain(),Gc)) ) {
1536  getsingle_bc(Indexes,r);
1537  return;
1538  }
1539 
1540  // create a tag for send/receives if necessary
1542 
1543  // Is it here? Try and find it in the LFields
1544  const_iterator_if lf_end = end_if();
1545  for (const_iterator_if lf_i = begin_if(); lf_i != lf_end ; ++lf_i) {
1546  if ( (*lf_i).second->getOwned().contains( Indexes ) ) {
1547  // Found it.
1548  // Get a pointer to the requested element.
1549  LField<T,Dim>& lf( *(*lf_i).second );
1550  typename LField<T,Dim>::iterator lp = lf.begin(Indexes);
1551 
1552  // Get the requested data.
1553  r = *lp;
1554 
1555  // Broadcast it if we're running in parallel
1556  if (Ippl::getNodes() > 1) {
1557  Message *mess = new Message;
1558  ::putMessage(*mess, r);
1559  Ippl::Comm->broadcast_others(mess, tag);
1560  }
1561 
1562  return;
1563  }
1564  }
1565 
1566  // If we're here, we didn't find it: It is remote. Wait for a message.
1567  if (Ippl::getNodes() > 1) {
1568  int any_node = COMM_ANY_NODE;
1569  Message *mess = Ippl::Comm->receive_block(any_node,tag);
1570  ::getMessage(*mess, r);
1571  delete mess;
1572  }
1573  else {
1574  // we did not find it, and we only have one node, so this must be
1575  // an error.
1576  ERRORMSG("Illegal single-value index " << Indexes);
1577  ERRORMSG(" in BareField::getsingle()" << endl);
1578  }
1579 }
1580 
1582 
1583 //
1584 // Get a single value from the BareField when we know that the
1585 // value is in the boundary condition area.
1586 // We use a more robust but slower algorithm here because there could
1587 // be redundancy.
1588 //
1589 
1590 template<class T, unsigned D>
1591 void
1592 BareField<T,D>::getsingle_bc(const NDIndex<D>& Indexes, T& r) const
1593 {
1594  // We will look through everything to find who is the authority
1595  // for the data. We look through the locals to see if we have it,
1596  // and we look through the remotes to see if someone else has it.
1597  // The lowest numbered processor is the authority.
1598  int authority_proc = -1;
1599 
1600  // Look through all the locals to try and find it.
1601  // Loop over all the LFields.
1602  const_iterator_if lf_end = end_if();
1603  for (const_iterator_if lf_i = begin_if(); lf_i != lf_end ; ++lf_i) {
1604  // Is it in this LField?
1605  if ( (*lf_i).second->getAllocated().contains( Indexes ) ) {
1606  // Found it. As far as we know now, this is the authority proc.
1607  authority_proc = Ippl::myNode();
1608 
1609  // Get the requested data.
1610  LField<T,D>& lf( *(*lf_i).second );
1611  typename LField<T,D>::iterator lp = lf.begin(Indexes);
1612  r = *lp;
1613 
1614  // If we're not the only guy on the block, go on to find the remotes.
1615  if (Ippl::getNodes() > 1)
1616  break;
1617 
1618  // Otherwise, we're done.
1619  return;
1620  }
1621  }
1622 
1623  // Look through all the remotes to see who else has it.
1624  // Loop over all the remote LFields that touch Indexes.
1625  typename FieldLayout<D>::touch_range_dv range =
1626  Layout->touch_range_rdv(Indexes,Gc);
1627  for (typename FieldLayout<D>::touch_iterator_dv p=range.first;
1628  p!=range.second;++p)
1629  // See if anybody has a lower processor number.
1630  if ( authority_proc > (*p).second->getNode() )
1631  // Someone else is the authority.
1632  authority_proc = (*p).second->getNode();
1633 
1634  // create a tag for the broadcast.
1636 
1637  if ( authority_proc == Ippl::myNode() ) {
1638  // If we're the authority, broadcast.
1639  Message *mess = new Message;
1640  ::putMessage(*mess, r);
1641  Ippl::Comm->broadcast_others(mess, tag);
1642  }
1643  else {
1644  // If someone else is the authority, receive the message.
1645  Message *mess = Ippl::Comm->receive_block(authority_proc,tag);
1646  ::getMessage(*mess, r);
1647  delete mess;
1648  }
1649 
1650 }
1651 
1652 /***************************************************************************
1653  * $RCSfile: BareField.cpp,v $ $Author: adelmann $
1654  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
1655  * IPPL_VERSION_ID: $Id: BareField.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
1656  ***************************************************************************/
#define F_WRITE_TAG
Definition: Tags.h:45
static int getNodes()
Definition: IpplInfo.cpp:773
elements
Definition: IndexMap.cpp:141
std::pair< iterator, bool > insert(const value_type &x)
Definition: vmap.hpp:73
static void abort(const char *=0, int exitcode=(-1))
Definition: IpplInfo.cpp:696
Layout_t & getLayout() const
Definition: BareField.h:130
ac_id_larray::iterator iterator_if
Definition: BareField.h:91
void getsingle(const NDIndex< Dim > &, T &) const
Definition: BareField.hpp:1522
Definition: rbendmap.h:8
#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
T & offset(int i) const
void Compress() const
Definition: BareField.hpp:1304
virtual void Repartition(UserList *)
Definition: BareField.hpp:1367
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
ID_t getUserListID() const
Definition: UserList.cpp:54
bool OverlapCacheInitialized()
Definition: LField.h:180
Message & getMessage(Message &m)
Definition: NDIndex.h:147
ac_id_larray Locals_ac
Definition: BareField.h:332
OverlapIterator BeginOverlap()
Definition: LField.h:192
GuardCellSizes< Dim > Gc
Definition: BareField.h:344
const int COMM_ANY_NODE
Definition: Communicate.h:40
static int myNode()
Definition: IpplInfo.cpp:794
Definition: FFT.h:31
void Uncompress(bool fill_domain=true)
Definition: LField.h:166
void getsingle_bc(const NDIndex< Dim > &, T &) const
Definition: BareField.hpp:1592
void Uncompress() const
Definition: BareField.hpp:1318
void setGuardCells(const T &) const
Definition: BareField.hpp:682
unsigned size() const
NDIndex< Dim > AddGuardCells(const NDIndex< Dim > &idx, const GuardCellSizes< Dim > &g)
#define F_GUARD_CELLS_TAG
Definition: Tags.h:44
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
T & localElement(const NDIndex< Dim > &) const
Definition: BareField.hpp:1475
void reserve(size_type n)
Definition: vmap.h:143
const iterator & begin() const
Definition: LField.h:104
virtual void fillGuardCells(bool reallyFill=true) const
Definition: BareField.hpp:298
void setDirtyFlag()
Definition: BareField.h:116
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Definition: GlobalComm.hpp:55
iterator_if end_if()
Definition: BareField.h:100
Definition: Index.h:236
size_t size() const
Definition: Message.h:300
OverlapIterator EndOverlap()
Definition: LField.h:193
const iterator & end() const
Definition: LField.h:105
Message & getMessage(Message &m)
#define F_GETSINGLE_TAG
Definition: Tags.h:50
ac_id_vnodes::iterator iterator_iv
Definition: FieldLayout.h:73
bool touches(const NDIndex< Dim > &) const
virtual int broadcast_others(Message *, int, bool delmsg=true)
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:92
#define WARNMSG(msg)
Definition: IpplInfo.h:398
int size(unsigned d) const
Definition: BrickIterator.h:48
void setup()
Definition: BareField.hpp:151
bool IsCompressed() const
Definition: LField.h:128
std::pair< typename Unique::type, my_auto_ptr< LField< T, Dim > > > value_type
Definition: vmap.h:71
Definition: FFT.h:30
T * value_type(const SliceIterator< T > &)
void accumGuardCells()
Definition: BareField.hpp:764
ac_id_larray::const_iterator const_iterator_if
Definition: BareField.h:92
Message & put(const T &val)
Definition: Message.h:414
T * PtrOffset(T *ptr, const NDIndex< 1U > &pos, const NDIndex< 1U > &alloc, LFieldDimTag< 1U, true >)
Definition: BareField.hpp:1430
ac_id_larray::size_type size_if() const
Definition: BareField.h:103
void write(std::ostream &)
Definition: BareField.hpp:209
const GuardCellSizes< Dim > & getGC() const
Definition: BareField.h:145
void writeb(char *) const
Definition: BareField.hpp:1220
void getMessage(Message &m, T &t)
Definition: Message.h:580
void Compress()
Definition: LField.h:155
bool CanCompress(const T &) const
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
std::vector< LField< T, Dim > * >::iterator OverlapIterator
Definition: LField.h:190
#define PAssert(c)
Definition: PAssert.h:117
Message & putMessage(Message &m) const
Definition: NDIndex.h:139
std::string::iterator iterator
Definition: MSLang.h:16
const unsigned Dim
void putMessage(Message &m, const T &t)
Definition: Message.h:557
double CompressedFraction() const
Definition: BareField.hpp:1334
iterator_if begin_if()
Definition: BareField.h:99
Message * receive_block(int &node, int &tag)
Definition: Inform.h:41
virtual void notifyUserOfDelete(UserList *)
Definition: BareField.hpp:1392
T * getP()
Definition: LField.h:94
static Communicate * Comm
Definition: IpplInfo.h:93
T & getCompressedData()
Definition: LField.h:173
bool send(Message *, int node, int tag, bool delmsg=true)
int size(unsigned d) const
Definition: LField.h:91
std::pair< touch_iterator_dv, touch_iterator_dv > touch_range_dv
Definition: FieldLayout.h:77
void checkin(FieldLayoutUser &f, const GuardCellSizes< Dim > &gc=gc0())
void initialize(Layout_t &)
Definition: BareField.hpp:101
void AddToOverlapCache(LField< T, Dim > *newCacheItem)
Definition: LField.h:182
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
iterator end()
Definition: vmap.h:126
void clearDirtyFlag()
Definition: BareField.h:117
#define F_TAG_CYCLE
Definition: Tags.h:53