OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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"
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 <cstdlib>
40
41
43//
44// Copy ctor.
45//
46
47template< class T, unsigned Dim >
49: Layout( a.Layout ), // Copy the layout.
50 Gc( a.Gc ), // Copy the number of guard cells.
51 compressible_m( a.compressible_m ),
52 pinned(false) //UL: for pinned memory allocation
53{
54
55
56
57 // We assume the guard cells are peachy so clear the dirty flag.
59
60 // Reserve space for the pointers to the LFields.
61 Locals_ac.reserve( a.size_if() );
62 // Loop over the LFields of the other array, creating LFields as we go.
63 for ( const_iterator_if a_i = a.begin_if(); a_i != a.end_if(); ++a_i )
64 {
65 // Create an LField with copy ctor.
66 LField<T,Dim> *lf = new LField<T,Dim>( *((*a_i).second) );
67 // Insert in the local list, hinting that it should go at the end.
69 typename ac_id_larray::value_type((*a_i).first,lf) );
70 }
71 // Tell the layout we are here.
72 getLayout().checkin( *this , Gc );
73 //INCIPPLSTAT(incBareFields);
74}
75
76
78//
79// Destructor
80//
81
82template< class T, unsigned Dim >
84
86 // must check out from our layout
87 if (Layout != 0) {
88 Layout->checkout(*this);
89 }
90}
91
92
94// Initialize the field, if it was constructed from the default constructor.
95// This should NOT be called if the field was constructed by providing
96// a FieldLayout.
97
98template< class T, unsigned Dim >
99void
101
102
103
104 // if our Layout has been previously set, we just ignore this request
105 if (Layout == 0) {
106 Layout = &l;
107 setup();
108 }
109}
111//UL: for pinned memory allocation
112template< class T, unsigned Dim >
113void
115
116
117
118 // if our Layout has been previously set, we just ignore this request
119 if (Layout == 0) {
120 Layout = &l;
121 pinned = p;
122 setup();
123 }
124}
125
126template< class T, unsigned Dim >
127void
129 const GuardCellSizes<Dim>& gc) {
130
131
132
133 // if our Layout has been previously set, we just ignore this request
134 if (Layout == 0) {
135 Layout = &l;
136 Gc = gc;
137 setup();
138 }
139}
140
141
143//
144// Using the data that has been initialized by the ctors,
145// complete the construction by allocating the LFields.
146//
147
148template< class T, unsigned Dim >
149void
151{
152
153
154
155 // Make sure this FieldLayout can handle the number of GuardCells
156 // which we have here
157 if ( ! getLayout().fitsGuardCells(Gc)) {
158 ERRORMSG("Cannot construct IPPL BareField:" << endl);
159 ERRORMSG(" One or more vnodes is too small for the guard cells." << endl);
160 ERRORMSG(" Guard cell sizes = " << Gc << endl);
161 ERRORMSG(" FieldLayout = " << getLayout() << endl);
162 Ippl::abort();
163 }
164
165 // We assume the guard cells are peachy so clear the dirty flag.
166 clearDirtyFlag();
167
168 // Reserve space for the pointers to the LFields.
169 Locals_ac.reserve( getLayout().size_iv() );
170
171 // Loop over all the Vnodes, creating an LField in each.
172 for (typename Layout_t::iterator_iv v_i=getLayout().begin_iv();
173 v_i != getLayout().end_iv();
174 ++v_i)
175 {
176 // Get the owned and guarded sizes.
177 const NDIndex<Dim> &owned = (*v_i).second->getDomain();
178 NDIndex<Dim> guarded = AddGuardCells( owned , Gc );
179
180 // Get the global vnode number (ID number, value from 0 to nvnodes-1):
181 int vnode = (*v_i).second->getVnode();
182
183 // Construct the LField for this Vnode.
184 //UL: for pinned memory allocation
185 LField<T, Dim> *lf;
186 if (pinned)
187 lf = new LField<T,Dim>( owned, guarded, vnode, pinned );
188 else
189 lf = new LField<T,Dim>( owned, guarded, vnode );
190
191 // Put it in the list.
192 Locals_ac.insert( end_if(),
193 typename ac_id_larray::value_type((*v_i).first,lf));
194 }
195 // Tell the layout we are here.
196 getLayout().checkin( *this , Gc );
197 //INCIPPLSTAT(incBareFields);
199
201
203// Print a BareField out.
204//
205
206template< class T, unsigned Dim>
207void
208BareField<T,Dim>::write(std::ostream& out)
209{
210
211
212
213 // Inform dbgmsg(">>>>>>>> BareField::write", INFORM_ALL_NODES);
214 // dbgmsg << "Printing values for field at address = " << &(*this) << endl;
215
216 // on remote nodes, we must send the subnodes LField's to node 0
218 if (Ippl::myNode() != 0) {
219 for ( iterator_if local = begin_if(); local != end_if() ; ++local) {
220 // Cache some information about this local field.
221 LField<T,Dim>& l = *((*local).second);
224
225 // Build and send a message containing the owned LocalField data
226 if (Ippl::myNode() != 0) {
227 Message *mess = new Message();
228 lo.putMessage(*mess); // send the local domain of the LField
229 rhs.putMessage(*mess); // send the data itself
230 // dbgmsg << "Sending domain " << lo << " to node 0" << endl;
231 Ippl::Comm->send(mess, 0, tag);
232 }
233 }
234 } else { // now, on node 0, receive the remaining LField's ...
235 // put all the LField's in a big, uncompressed LField
236 LField<T,Dim> data(getDomain(), getDomain());
237 data.Uncompress();
238
239 // first put in our local ones
240 for ( iterator_if local = begin_if(); local != end_if() ; ++local) {
241 // Cache some information about this local field.
242 LField<T,Dim>& l = *((*local).second);
244 typename LField<T,Dim>::iterator rhs(l.begin());
245
246 // put the local LField in our big LField
247 // dbgmsg << " Copying local domain " << lo << " from Lfield at ";
248 // dbgmsg << &l << ":" << endl;
249 typename LField<T,Dim>::iterator putloc = data.begin(lo);
250 typename LField<T,Dim>::iterator getloc = l.begin(lo);
251 for ( ; getloc != l.end() ; ++putloc, ++getloc ) {
252 // dbgmsg << " from " << &(*getloc) << " to " << &(*putloc);
253 // dbgmsg << ": " << *putloc << " = " << *getloc << endl;
254 *putloc = *getloc;
255 }
256 }
257
258 // we expect to receive one message from each remote vnode
259 int remaining = getLayout().size_rdv();
260
261 // keep receiving messages until they're all here
262 for ( ; remaining > 0; --remaining) {
263 // Receive the generic message.
264 int any_node = COMM_ANY_NODE;
265 Message *mess = Ippl::Comm->receive_block(any_node, tag);
266
267 // Extract the domain size and LField iterator from the message
268 NDIndex<Dim> lo;
269 T compressed_data;
270 typename LField<T,Dim>::iterator rhs(compressed_data);
271 lo.getMessage(*mess);
272 rhs.getMessage(*mess);
273 // dbgmsg << "Received domain " << lo << " from " << any_node << endl;
274
275 // put the received LField in our big LField
276 typename LField<T,Dim>::iterator putloc = data.begin(lo);
277 for (unsigned elems=lo.size(); elems > 0; ++putloc, ++rhs, --elems)
278 *putloc = *rhs;
279
280 // Free the memory in the message.
281 delete mess;
282 }
283
284 // finally, we can print the big LField out
285 out << data;
286 }
287}
288
289
291
292//
293// Fill all the guard cells, including all the necessary communication.
294//
295
296template< class T, unsigned Dim >
297void BareField<T,Dim>::fillGuardCells(bool reallyFill) const
298{
299
300 // This operation is logically const because the physical cells
301 // of the BareField are unaffected, so cast away const here.
302 BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
303
304 // Only fill if we are supposed to.
305 if (!reallyFill)
306 return;
307
308 // Make ourselves clean.
310
311 // Only need to do work if we have non-zero GuardCellSizes
312 if (Gc == GuardCellSizes<Dim>())
313 return;
314
315 // indicate we're doing another gc fill
316 //INCIPPLSTAT(incGuardCellFills);
317
318 // iterators for looping through LField's of this BareField
319 iterator_if lf_i, lf_e = ncf.end_if();
320
321 // ----------------------------------------
322 // First the send loop.
323 // Loop over all the local nodes and
324 // send data to the remote ones they overlap.
325 int nprocs = Ippl::getNodes();
326 if (nprocs > 1) {
327
328 // Build a map of the messages we expect to receive.
329 typedef std::multimap< NDIndex<Dim> , LField<T,Dim>* , std::less<NDIndex<Dim> > > ac_recv_type;
330 ac_recv_type recv_ac;
331 bool* recvmsg = new bool[nprocs];
332
333
334
335 // set up messages to be sent
336 Message** mess = new Message*[nprocs];
337 int iproc;
338 for (iproc=0; iproc<nprocs; ++iproc) {
339 mess[iproc] = NULL;
340 recvmsg[iproc] = false;
341 }
342
343 // now do main loop over LFields, packing overlaps into proper messages
344 for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i) {
345
346 // Cache some information about this local array.
347 LField<T,Dim> &lf = *((*lf_i).second);
348 const NDIndex<Dim> &lf_domain = lf.getAllocated();
349 // Find the remote ones that touch this LField's guard cells
351 rrange(ncf.getLayout().touch_range_rdv(lf_domain));
352 typename Layout_t::touch_iterator_dv rv_i;
353 for (rv_i = rrange.first; rv_i != rrange.second; ++rv_i) {
354 // Save the intersection and the LField it is for.
355 NDIndex<Dim> sub = lf_domain.intersect( (*rv_i).first );
356 typedef typename ac_recv_type::value_type value_type;
357 recv_ac.insert(value_type(sub,&lf));
358 // note who will be sending this data
359 int rnode = (*rv_i).second->getNode();
360 recvmsg[rnode] = true;
361 }
362
363
364
365 const NDIndex<Dim>& lo = lf.getOwned();
366 // Loop over the remote domains which have guard cells
367 // that this local domain touches.
368 typename Layout_t::touch_range_dv
369 range( ncf.getLayout().touch_range_rdv(lo,ncf.getGC()) );
370 typename Layout_t::touch_iterator_dv remote_i;
371 for (remote_i = range.first; remote_i != range.second; ++remote_i) {
372 // Find the intersection.
373 NDIndex<Dim> intersection = lo.intersect( (*remote_i).first );
374 // Find out who owns this remote domain.
375 int rnode = (*remote_i).second->getNode();
376 // Create an LField iterator for this intersection region,
377 // and try to compress it.
378 // storage for LField compression
379 T compressed_value;
380 LFI msgval = lf.begin(intersection, compressed_value);
381 msgval.TryCompress();
382
383 // Put intersection domain and field data into message
384 if (!mess[rnode]) mess[rnode] = new Message;
385 PAssert(mess[rnode]);
386 mess[rnode]->put(intersection); // puts Dim items in Message
387 mess[rnode]->put(msgval); // puts 3 items in Message
388 }
389
390 }
391
392 int remaining = 0;
393 for (iproc=0; iproc<nprocs; ++iproc)
394 if (recvmsg[iproc]) ++remaining;
395 delete [] recvmsg;
396
397
398
399 // Get message tag.
401
402 // Send all the messages.
403 for (iproc=0; iproc<nprocs; ++iproc) {
404 if (mess[iproc]) {
405 Ippl::Comm->send(mess[iproc], iproc, tag);
406 }
407 }
408
409 delete [] mess;
410
411 // ----------------------------------------
412 // Handle the local fills.
413 // Loop over all the local arrays.
414
415 for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i)
416 {
417 // Cache some information about this LField.
418 LField<T,Dim> &lf = *(*lf_i).second;
419 const NDIndex<Dim>& la = lf.getAllocated();
420
421 // Loop over all the other LFields to establish each LField's
422 // cache of overlaps.
423
424 // This is an N*N operation, but the expectation is that this will
425 // pay off since we will reuse this cache quite often.
426
427 if (!lf.OverlapCacheInitialized())
428 {
429 for (iterator_if rf_i = ncf.begin_if(); rf_i != ncf.end_if(); ++rf_i)
430 if ( rf_i != lf_i )
431 {
432 // Cache some info about this LField.
433 LField<T,Dim> &rf = *(*rf_i).second;
434 const NDIndex<Dim>& ro = rf.getOwned();
435
436 // If the remote has info we want, then add it to our cache.
437 if ( la.touches(ro) )
438 lf.AddToOverlapCache(&rf);
439 }
440 }
441
442 // We know at this point that the overlap cache is established.
443 // Use it.
444
445 for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
446 rf_i != lf.EndOverlap(); ++rf_i)
447 {
448 LField<T, Dim> &rf = *(*rf_i);
449 const NDIndex<Dim>& ro = rf.getOwned();
450
451 bool c1 = lf.IsCompressed();
452 bool c2 = rf.IsCompressed();
453 bool c3 = *rf.begin() == *lf.begin();
454
455 // If these are compressed we might not have to do any work.
456 if ( !( c1 && c2 && c3 ) )
457 {
458
459
460 // Find the intersection.
461 NDIndex<Dim> intersection = la.intersect(ro);
462
463 // Build an iterator for the rhs.
464 LFI rhs = rf.begin(intersection);
465
466 // Could we compress that?
467 if ( !(c1 && rhs.CanCompress(*lf.begin())) )
468 {
469 // Make sure the left is not compressed.
470 lf.Uncompress();
471
472 // Nope, we really have to copy.
473 LFI lhs = lf.begin(intersection);
474 // And do the assignment.
476 }
477
478
479 }
480 }
481 }
482
483
484 // ----------------------------------------
485 // Receive all the messages.
486
487 while (remaining>0) {
488 // Receive the next message.
489 int any_node = COMM_ANY_NODE;
490
491 Message* rmess = Ippl::Comm->receive_block(any_node,tag);
492 PAssert(rmess);
493 --remaining;
494
495
496 // Determine the number of domains being sent
497 int ndoms = rmess->size() / (Dim + 3);
498 for (int idom=0; idom<ndoms; ++idom) {
499 // Extract the intersection domain from the message.
500 NDIndex<Dim> intersection;
501 intersection.getMessage(*rmess);
502
503 // Extract the rhs iterator from it.
504 T compressed_value;
505 LFI rhs(compressed_value);
506 rhs.getMessage(*rmess);
507
508 // Find the LField it is destined for.
509 typename ac_recv_type::iterator hit = recv_ac.find( intersection );
510 PAssert( hit != recv_ac.end() );
511 // Build the lhs brick iterator.
512 LField<T,Dim> &lf = *(*hit).second;
513 // Check and see if we really have to do this.
514 if ( !(rhs.IsCompressed() && lf.IsCompressed() &&
515 (*rhs == *lf.begin())) )
516 {
517 // Yep. gotta do it.
518 lf.Uncompress();
519 LFI lhs = lf.begin(intersection);
520 // Do the assignment.
522 }
523
524 // Take that entry out of the receive list.
525 recv_ac.erase( hit );
526 }
527 delete rmess;
528 }
529
530 }
531 else { // single-node case
532 // ----------------------------------------
533 // Handle the local fills.
534 // Loop over all the local arrays.
535
536 for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i)
537 {
538 // Cache some information about this LField.
539 LField<T,Dim> &lf = *(*lf_i).second;
540 const NDIndex<Dim>& la = lf.getAllocated();
541
542 // Loop over all the other LFields to establish each LField's
543 // cache of overlaps.
544
545 // This is an N*N operation, but the expectation is that this will
546 // pay off since we will reuse this cache quite often.
547
548 if (!lf.OverlapCacheInitialized())
549 {
550 for (iterator_if rf_i = ncf.begin_if(); rf_i != ncf.end_if(); ++rf_i)
551 if ( rf_i != lf_i )
552 {
553 // Cache some info about this LField.
554 LField<T,Dim> &rf = *(*rf_i).second;
555 const NDIndex<Dim>& ro = rf.getOwned();
556
557 // If the remote has info we want, then add it to our cache.
558 if ( la.touches(ro) )
559 lf.AddToOverlapCache(&rf);
560 }
561 }
562
563 // We know at this point that the overlap cache is established.
564 // Use it.
565
566 for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
567 rf_i != lf.EndOverlap(); ++rf_i)
568 {
569 LField<T, Dim> &rf = *(*rf_i);
570 const NDIndex<Dim>& ro = rf.getOwned();
571
572 bool c1 = lf.IsCompressed();
573 bool c2 = rf.IsCompressed();
574 bool c3 = *rf.begin() == *lf.begin();
575
576 // If these are compressed we might not have to do any work.
577 if ( !( c1 && c2 && c3 ) )
578 {
579
580
581 // Find the intersection.
582 NDIndex<Dim> intersection = la.intersect(ro);
583
584 // Build an iterator for the rhs.
585 LFI rhs = rf.begin(intersection);
586
587 // Could we compress that?
588 if ( !(c1 && rhs.CanCompress(*lf.begin())) )
589 {
590 // Make sure the left is not compressed.
591 lf.Uncompress();
592
593 // Nope, we really have to copy.
594 LFI lhs = lf.begin(intersection);
595 // And do the assignment.
597 }
598
599
600 }
601 }
602 }
603
604 }
605 return;
606}
607
609
610//
611// Fill guard cells with a constant value.
612// This is typically used to zero out the guard cells before a scatter.
613//
614
615template <class T, unsigned Dim>
616void BareField<T,Dim>::setGuardCells(const T& val) const
617{
618 // profiling macros
619
620
621
622 // if there are no guard cells, we can just return
623 if (Gc == GuardCellSizes<Dim>())
624 return;
625
626 // this member function is logically const, so cast away const-ness
627 BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
628
629 // loop over our LFields and set guard cell values
630 iterator_if lf_i, lf_e = ncf.end_if();
631 for (lf_i = ncf.begin_if(); lf_i != lf_e; ++lf_i) {
632 // Get this LField
633 LField<T,Dim>& lf = *((*lf_i).second);
634
635 // Quick test to see if we can avoid doing any work.
636 // If this LField is compressed and already contains
637 // the value that is being assigned to the guard cells,
638 // then we can just move on to the next LField.
639 if (lf.IsCompressed() && lf.getCompressedData() == val)
640 continue;
641
642 // OK, we really have to fill the guard cells, so get
643 // the domains we will be working with.
644 const NDIndex<Dim>& adom = lf.getAllocated();
645 const NDIndex<Dim>& odom = lf.getOwned();
646 NDIndex<Dim> dom = odom; // initialize working domain to Owned
647
648 // create a compressed LField with the same allocated domain
649 // containing the value to be assigned to the guard cells
650 LField<T,Dim> rf(odom,adom);
651 rf.Compress(val);
652
653 // Uncompress LField to be filled and get some iterators
654 lf.Uncompress();
655 LFI lhs, rhs;
656
657 // now loop over dimensions and fill guard cells along each
658 for (unsigned int idim = 0; idim < Dim; ++idim) {
659 // set working domain to left guards in this dimension
660 dom[idim] = Index(adom[idim].first(),
661 adom[idim].first() + Gc.left(idim) - 1);
662 if (!dom[idim].empty()) {
663 // Set iterators over working domain and do assignment
664 lhs = lf.begin(dom);
665 rhs = rf.begin(dom);
667 }
668
669 // Set working domain to right guards in this dimension
670 dom[idim] = Index(adom[idim].last() - Gc.right(idim) + 1,
671 adom[idim].last());
672 if (!dom[idim].empty()) {
673 // Set iterators over working domain and do assignment
674 lhs = lf.begin(dom);
675 rhs = rf.begin(dom);
677 }
678
679 // Adjust working domain along this direction
680 // in preparation for working on next dimension.
681 dom[idim] = adom[idim];
682 }
683 }
684
685 // let's set the dirty flag, since we have modified guard cells.
686 ncf.setDirtyFlag();
687
688 return;
689}
690
692
693//
694// Accumulate guard cells into real cells, including necessary communication.
695//
696
697template <class T, unsigned Dim>
699{
700
701 // Only need to do work if we have non-zero GuardCellSizes
702 if (Gc == GuardCellSizes<Dim>())
703 return;
704
705 // iterators for looping through LField's of this BareField
706 iterator_if lf_i, lf_e = end_if();
707
708 // ----------------------------------------
709 // First the send loop.
710 // Loop over all the local nodes and
711 // send data to the remote ones they overlap.
712 int nprocs = Ippl::getNodes();
713 if (nprocs > 1) {
714
715 // Build a map of the messages we expect to receive.
716 typedef std::multimap< NDIndex<Dim> , LField<T,Dim>* , std::less<NDIndex<Dim> > > ac_recv_type;
717 ac_recv_type recv_ac;
718 bool* recvmsg = new bool[nprocs];
719
720
721
722 // set up messages to be sent
723 Message** mess = new Message*[nprocs];
724 int iproc;
725 for (iproc=0; iproc<nprocs; ++iproc) {
726 mess[iproc] = NULL;
727 recvmsg[iproc] = false;
728 }
729
730 // now do main loop over LFields, packing overlaps into proper messages
731 for (lf_i = begin_if(); lf_i != lf_e; ++lf_i) {
732
733 // Cache some information about this local array.
734 LField<T,Dim> &lf = *((*lf_i).second);
735 const NDIndex<Dim>& lo = lf.getOwned();
736 // Find the remote ones with guard cells touching this LField
738 rrange( getLayout().touch_range_rdv(lo,Gc) );
739 typename Layout_t::touch_iterator_dv rv_i;
740 for (rv_i = rrange.first; rv_i != rrange.second; ++rv_i) {
741 // Save the intersection and the LField it is for.
742 NDIndex<Dim> sub = lo.intersect( (*rv_i).first );
743 recv_ac.insert(typename ac_recv_type::value_type(sub,&lf));
744 // note who will be sending this data
745 int rnode = (*rv_i).second->getNode();
746 recvmsg[rnode] = true;
747 }
748
749
750
751 const NDIndex<Dim> &lf_domain = lf.getAllocated();
752 // Loop over the remote domains that touch this local
753 // domain's guard cells
755 range(getLayout().touch_range_rdv(lf_domain));
756 typename Layout_t::touch_iterator_dv remote_i;
757 for (remote_i = range.first; remote_i != range.second; ++remote_i) {
758 // Find the intersection.
759 NDIndex<Dim> intersection = lf_domain.intersect( (*remote_i).first );
760 // Find out who owns this remote domain.
761 int rnode = (*remote_i).second->getNode();
762 // Create an LField iterator for this intersection region,
763 // and try to compress it.
764 // storage for LField compression
765 T compressed_value;
766 LFI msgval = lf.begin(intersection, compressed_value);
767 msgval.TryCompress();
768
769 // Put intersection domain and field data into message
770 if (!mess[rnode]) mess[rnode] = new Message;
771 PAssert(mess[rnode]);
772 mess[rnode]->put(intersection); // puts Dim items in Message
773 mess[rnode]->put(msgval); // puts 3 items in Message
774 }
775
776 }
777
778 int remaining = 0;
779 for (iproc=0; iproc<nprocs; ++iproc)
780 if (recvmsg[iproc]) ++remaining;
781 delete [] recvmsg;
782
783
784
785 // Get message tag.
787
788 // Send all the messages.
789 for (iproc=0; iproc<nprocs; ++iproc) {
790 if (mess[iproc]) {
791 Ippl::Comm->send(mess[iproc], iproc, tag);
792 }
793 }
794
795 delete [] mess;
796
797 // ----------------------------------------
798 // Handle the local fills.
799 // Loop over all the local arrays.
800
801 for (lf_i=begin_if(); lf_i != lf_e; ++lf_i)
802 {
803 // Cache some information about this LField.
804 LField<T,Dim> &lf = *(*lf_i).second;
805 const NDIndex<Dim>& la = lf.getAllocated();
806
807 // Loop over all the other LFields to establish each LField's
808 // cache of overlaps.
809
810 // This is an N*N operation, but the expectation is that this will
811 // pay off since we will reuse this cache quite often.
812
813 if (!lf.OverlapCacheInitialized())
814 {
815 for (iterator_if rf_i = begin_if(); rf_i != end_if(); ++rf_i)
816 if ( rf_i != lf_i )
817 {
818 // Cache some info about this LField.
819 LField<T,Dim> &rf = *(*rf_i).second;
820 const NDIndex<Dim>& ro = rf.getOwned();
821
822 // If the remote has info we want, then add it to our cache.
823 if ( la.touches(ro) )
824 lf.AddToOverlapCache(&rf);
825 }
826 }
827
828 // We know at this point that the overlap cache is established.
829 // Use it.
830
831 for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
832 rf_i != lf.EndOverlap(); ++rf_i)
833 {
834 LField<T, Dim> &rf = *(*rf_i);
835 const NDIndex<Dim>& ro = rf.getOwned();
836
837
838
839 // Find the intersection.
840 NDIndex<Dim> intersection = la.intersect(ro);
841
842 // Build iterator for lf guard cells
843 LFI lhs = lf.begin(intersection);
844
845 // check if we can skip accumulation
846 if ( !lhs.CanCompress(T()) ) {
847
848 // Make sure the right side is not compressed.
849 rf.Uncompress();
850
851 // Build iterator for rf real cells
852 LFI rhs = rf.begin(intersection);
853
854 // And do the accumulation
856 }
857
858 }
859 }
860
861
862 // ----------------------------------------
863 // Receive all the messages.
864
865 while (remaining>0) {
866 // Receive the next message.
867 int any_node = COMM_ANY_NODE;
868
869 Message* rmess = Ippl::Comm->receive_block(any_node,tag);
870 PAssert(rmess);
871 --remaining;
872
873
874 // Determine the number of domains being sent
875 int ndoms = rmess->size() / (Dim + 3);
876 for (int idom=0; idom<ndoms; ++idom) {
877 // Extract the intersection domain from the message.
878 NDIndex<Dim> intersection;
879 intersection.getMessage(*rmess);
880
881 // Extract the rhs iterator from it.
882 T compressed_value;
883 LFI rhs(compressed_value);
884 rhs.getMessage(*rmess);
885
886 // Find the LField it is destined for.
887 typename ac_recv_type::iterator hit = recv_ac.find( intersection );
888 PAssert( hit != recv_ac.end() );
889
890 // Build the lhs brick iterator.
891 LField<T,Dim> &lf = *(*hit).second;
892
893 // Make sure LField is uncompressed
894 lf.Uncompress();
895 LFI lhs = lf.begin(intersection);
896
897 // Do the accumulation
899
900 // Take that entry out of the receive list.
901 recv_ac.erase( hit );
902 }
903 delete rmess;
904 }
905
906 }
907 else { // single-node case
908 // ----------------------------------------
909 // Handle the local fills.
910 // Loop over all the local arrays.
911
912 for (lf_i=begin_if(); lf_i != lf_e; ++lf_i)
913 {
914 // Cache some information about this LField.
915 LField<T,Dim> &lf = *(*lf_i).second;
916 const NDIndex<Dim>& la = lf.getAllocated();
917
918 // Loop over all the other LFields to establish each LField's
919 // cache of overlaps.
920
921 // This is an N*N operation, but the expectation is that this will
922 // pay off since we will reuse this cache quite often.
923
924 if (!lf.OverlapCacheInitialized())
925 {
926 for (iterator_if rf_i = begin_if(); rf_i != end_if(); ++rf_i)
927 if ( rf_i != lf_i )
928 {
929 // Cache some info about this LField.
930 LField<T,Dim> &rf = *(*rf_i).second;
931 const NDIndex<Dim>& ro = rf.getOwned();
932
933 // If the remote has info we want, then add it to our cache.
934 if ( la.touches(ro) )
935 lf.AddToOverlapCache(&rf);
936 }
937 }
938
939 // We know at this point that the overlap cache is established.
940 // Use it.
941
942 for (typename LField<T,Dim>::OverlapIterator rf_i = lf.BeginOverlap();
943 rf_i != lf.EndOverlap(); ++rf_i)
944 {
945 LField<T, Dim> &rf = *(*rf_i);
946 const NDIndex<Dim>& ro = rf.getOwned();
947
948
949
950 // Find the intersection.
951 NDIndex<Dim> intersection = la.intersect(ro);
952
953 // Build iterator for lf guard cells
954 LFI lhs = lf.begin(intersection);
955
956 // Check if we can skip accumulation
957 if ( !lhs.CanCompress(T()) ) {
958 // Make sure rf is not compressed.
959 rf.Uncompress();
960
961 // Build iterator for rf real cells
962 LFI rhs = rf.begin(intersection);
963
964 // And do the accumulation
966 }
967
968 }
969 }
970
971 }
972
973 // since we just modified real cell values, set dirty flag if using
974 // deferred guard cell fills
975 setDirtyFlag();
976 // fill guard cells now, unless we are deferring
977 fillGuardCellsIfNotDirty();
978 // try to compress the final result
979 Compress();
980
981 return;
982}
983
985
986//
987// Tell a BareField to compress itself.
988// Just loop over all of the local fields and tell them to compress.
989//
990template<class T, unsigned Dim>
992{
993
994
995
996 if (!compressible_m) return;
997
998 // This operation is logically const, so cast away const here
999 BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
1000 for (iterator_if lf_i = ncf.begin_if(); lf_i != ncf.end_if(); ++lf_i)
1001 (*lf_i).second->TryCompress(isDirty());
1002}
1003
1004template<class T, unsigned Dim>
1006{
1007
1008
1009
1010 // This operation is logically const, so cast away const here
1011 BareField<T,Dim>& ncf = const_cast<BareField<T,Dim>&>(*this);
1012 for (iterator_if lf_i = ncf.begin_if(); lf_i != ncf.end_if(); ++lf_i)
1013 (*lf_i).second->Uncompress();
1014}
1015
1016//
1017// Look at all the local fields and calculate the
1018// fraction of all the elements that are compressed.
1019//
1020template<class T, unsigned Dim>
1022{
1023
1024
1025
1026 // elements[0] = total elements
1027 // elements[1] = compressed elements
1028 double elements[2] = { 0.0, 0.0};
1029 // Loop over all of the local fields.
1030 for (const_iterator_if lf_i=begin_if(); lf_i != end_if(); ++lf_i)
1031 {
1032 // Get a reference to the current local field.
1033 LField<T,Dim> &lf = *(*lf_i).second;
1034 // Get the size of this one.
1035 double s = lf.getOwned().size();
1036 // Add that up.
1037 elements[0] += s;
1038 // If it is compressed...
1039 if ( lf.IsCompressed() )
1040 // Add that amount to the compressed total.
1041 elements[1] += s;
1042 }
1043 // Make some space to put the global sum of each of the above.
1044 double reduced_elements[2] = { 0.0, 0.0};
1045 // Do the global reduction.
1046 reduce(elements,elements+2,reduced_elements,OpAddAssign());
1047 // Return the fraction.
1048 return reduced_elements[1]/reduced_elements[0];
1049}
1050
1051
1053template<class T, unsigned Dim>
1055{
1056
1057
1058
1059 // Cast to the proper type of FieldLayout.
1060 Layout_t *newLayout = (Layout_t *)( userlist );
1061
1062 // Build a new temporary field on the new layout.
1063 BareField<T,Dim> tempField( *newLayout, Gc );
1064
1065 // Copy our data over to the new layout.
1066 tempField = *this;
1067
1068 // Copy back the pointers to the new local fields.
1069 Locals_ac = tempField.Locals_ac;
1070
1071 //INCIPPLSTAT(incRepartitions);
1072}
1073
1074
1076// Tell the subclass that the FieldLayout is being deleted, so
1077// don't use it anymore
1078template<class T, unsigned Dim>
1080{
1081
1082
1083
1084 // just set our layout pointer to NULL; if we try to do anything more
1085 // with this object, other than delete it, a core dump is likely
1086 if (Layout != 0 && Layout->get_Id() == userlist->getUserListID()) {
1087 // the ID refers to this layout, so get rid of it. It is possible
1088 // the ID refers to some other object, in which case we do not want
1089 // to cast away our Layout object.
1090 Layout = 0;
1091 } else {
1092 // for now, print a warning, until other types of FieldLayoutUser's
1093 // are set up to register with a FieldLayout ... but in general,
1094 // this is OK and this warning should be removed
1095 WARNMSG("BareField: notified of unknown UserList being deleted.");
1096 WARNMSG(endl);
1097 }
1098}
1099
1100// a simple true-false template used to select which loop to implement
1101// in the BareField::localElement body
1102template<unsigned Dim, bool exists>
1104};
1105
1106// 1, 2, 3, and N Dimensional functions
1107template <class T>
1108inline
1109T* PtrOffset(T* ptr, const NDIndex<1U>& pos, const NDIndex<1U>& alloc,
1111 T* newptr = ptr + pos[0].first() - alloc[0].first();
1112 return newptr;
1113}
1114
1115template <class T>
1116inline
1117T* PtrOffset(T* ptr, const NDIndex<2U>& pos, const NDIndex<2U>& alloc,
1119 T* newptr = ptr + pos[0].first() - alloc[0].first() +
1120 alloc[0].length() * ( pos[1].first() - alloc[1].first() );
1121 return newptr;
1122}
1123
1124template <class T>
1125inline
1126T* PtrOffset(T* ptr, const NDIndex<3U>& pos, const NDIndex<3U>& alloc,
1128 T* newptr = ptr + pos[0].first() - alloc[0].first() +
1129 alloc[0].length() * ( pos[1].first() - alloc[1].first() +
1130 alloc[1].length() * ( pos[2].first() - alloc[2].first() ) );
1131 return newptr;
1132}
1133
1134template <class T, unsigned Dim>
1135inline
1136T* PtrOffset(T* ptr, const NDIndex<Dim>& pos, const NDIndex<Dim>& alloc,
1138 T* newptr = ptr;
1139 int n=1;
1140 for (unsigned int d=0; d<Dim; ++d) {
1141 newptr += n * (pos[d].first() - alloc[d].first());
1142 n *= alloc[d].length();
1143 }
1144 return newptr;
1145}
1146
1147
1149// Get a ref to a single element of the Field; if it is not local to our
1150// processor, print an error and exit. This allows the user to provide
1151// different index values on each node, instead of using the same element
1152// and broadcasting to all nodes.
1153template<class T, unsigned Dim>
1155{
1156
1157
1158
1159
1160 // Instead of checking to see if the user has asked for one element,
1161 // we will just use the first element specified for each dimension.
1162
1163 // Is this element here?
1164 // Try and find it in the local BareFields.
1165 const_iterator_if lf_i = begin_if();
1166 const_iterator_if lf_end = end_if();
1167 for ( ; lf_i != lf_end ; ++lf_i ) {
1168 LField<T,Dim>& lf(*(*lf_i).second);
1169 // End-point "contains" OK since "owned" is unit stride.
1170 // was before CK fix: if ( lf.getOwned().contains( Indexes ) ) {
1171 if ( lf.getAllocated().contains( Indexes ) ) {
1172 // Found it ... first uncompress, then get a pointer to the
1173 // requested element.
1174 lf.Uncompress();
1175 // return *(lf.begin(Indexes));
1176 // instead of building an iterator, just find the value
1177 NDIndex<Dim> alloc = lf.getAllocated();
1178 T* pdata = PtrOffset(lf.getP(), Indexes, alloc,
1179 LFieldDimTag<Dim,(Dim<=3)>());
1180 return *pdata;
1181 }
1182 }
1183
1184 // if we're here, we did not find it ... it must not be local
1185 ERRORMSG("BareField::localElement: attempt to access non-local index ");
1186 ERRORMSG(Indexes << " on node " << Ippl::myNode() << endl);
1187 ERRORMSG("Occurred in a BareField with layout = " << getLayout() << endl);
1188 ERRORMSG("Calling abort ..." << endl);
1189 Ippl::abort();
1190 return *((*((*(begin_if())).second)).begin());
1191}
1192
1193
1195//
1196// Get a single value and return it in the given storage. Whichever
1197// node owns the value must broadcast it to the other nodes.
1198//
1200template <class T, unsigned int Dim>
1201void BareField<T,Dim>::getsingle(const NDIndex<Dim>& Indexes, T& r) const
1202{
1203
1204
1205
1206 // Instead of checking to see if the user has asked for one element,
1207 // we will just use the first element specified for each dimension.
1208
1209 // Check to see if the point is in the boundary conditions.
1210 // Check for: The point is not in the owned domain, but it is in that
1211 // domain augmented with the boundary condition size.
1212 // If so, use a different algorithm.
1213 if ( (!Indexes.touches(Layout->getDomain())) &&
1214 Indexes.touches(AddGuardCells(Layout->getDomain(),Gc)) ) {
1215 getsingle_bc(Indexes,r);
1216 return;
1217 }
1218
1219 // create a tag for send/receives if necessary
1221
1222 // Is it here? Try and find it in the LFields
1223 const_iterator_if lf_end = end_if();
1224 for (const_iterator_if lf_i = begin_if(); lf_i != lf_end ; ++lf_i) {
1225 if ( (*lf_i).second->getOwned().contains( Indexes ) ) {
1226 // Found it.
1227 // Get a pointer to the requested element.
1228 LField<T,Dim>& lf( *(*lf_i).second );
1229 typename LField<T,Dim>::iterator lp = lf.begin(Indexes);
1230
1231 // Get the requested data.
1232 r = *lp;
1233
1234 // Broadcast it if we're running in parallel
1235 if (Ippl::getNodes() > 1) {
1236 Message *mess = new Message;
1237 ::putMessage(*mess, r);
1238 Ippl::Comm->broadcast_others(mess, tag);
1239 }
1240
1241 return;
1242 }
1243 }
1244
1245 // If we're here, we didn't find it: It is remote. Wait for a message.
1246 if (Ippl::getNodes() > 1) {
1247 int any_node = COMM_ANY_NODE;
1248 Message *mess = Ippl::Comm->receive_block(any_node,tag);
1249 ::getMessage(*mess, r);
1250 delete mess;
1251 }
1252 else {
1253 // we did not find it, and we only have one node, so this must be
1254 // an error.
1255 ERRORMSG("Illegal single-value index " << Indexes);
1256 ERRORMSG(" in BareField::getsingle()" << endl);
1257 }
1258}
1259
1261
1262//
1263// Get a single value from the BareField when we know that the
1264// value is in the boundary condition area.
1265// We use a more robust but slower algorithm here because there could
1266// be redundancy.
1267//
1268
1269template<class T, unsigned D>
1270void
1272{
1273 // We will look through everything to find who is the authority
1274 // for the data. We look through the locals to see if we have it,
1275 // and we look through the remotes to see if someone else has it.
1276 // The lowest numbered processor is the authority.
1277 int authority_proc = -1;
1278
1279 // Look through all the locals to try and find it.
1280 // Loop over all the LFields.
1281 const_iterator_if lf_end = end_if();
1282 for (const_iterator_if lf_i = begin_if(); lf_i != lf_end ; ++lf_i) {
1283 // Is it in this LField?
1284 if ( (*lf_i).second->getAllocated().contains( Indexes ) ) {
1285 // Found it. As far as we know now, this is the authority proc.
1286 authority_proc = Ippl::myNode();
1287
1288 // Get the requested data.
1289 LField<T,D>& lf( *(*lf_i).second );
1290 typename LField<T,D>::iterator lp = lf.begin(Indexes);
1291 r = *lp;
1292
1293 // If we're not the only guy on the block, go on to find the remotes.
1294 if (Ippl::getNodes() > 1)
1295 break;
1296
1297 // Otherwise, we're done.
1298 return;
1299 }
1300 }
1301
1302 // Look through all the remotes to see who else has it.
1303 // Loop over all the remote LFields that touch Indexes.
1304 typename FieldLayout<D>::touch_range_dv range =
1305 Layout->touch_range_rdv(Indexes,Gc);
1306 for (typename FieldLayout<D>::touch_iterator_dv p=range.first;
1307 p!=range.second;++p)
1308 // See if anybody has a lower processor number.
1309 if ( authority_proc > (*p).second->getNode() )
1310 // Someone else is the authority.
1311 authority_proc = (*p).second->getNode();
1312
1313 // create a tag for the broadcast.
1315
1316 if ( authority_proc == Ippl::myNode() ) {
1317 // If we're the authority, broadcast.
1318 Message *mess = new Message;
1319 ::putMessage(*mess, r);
1320 Ippl::Comm->broadcast_others(mess, tag);
1321 }
1322 else {
1323 // If someone else is the authority, receive the message.
1324 Message *mess = Ippl::Comm->receive_block(authority_proc,tag);
1325 ::getMessage(*mess, r);
1326 delete mess;
1327 }
1328
1329}
1330
1331/***************************************************************************
1332 * $RCSfile: BareField.cpp,v $ $Author: adelmann $
1333 * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
1334 * IPPL_VERSION_ID: $Id: BareField.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
1335 ***************************************************************************/
T * value_type(const SliceIterator< T > &)
elements
Definition: IndexMap.cpp:163
const unsigned Dim
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Definition: GlobalComm.hpp:55
void putMessage(Message &m, const T &t)
Definition: Message.h:549
void getMessage(Message &m, T &t)
Definition: Message.h:572
const int COMM_ANY_NODE
Definition: Communicate.h:40
#define F_GETSINGLE_TAG
Definition: Tags.h:50
#define F_TAG_CYCLE
Definition: Tags.h:53
#define F_GUARD_CELLS_TAG
Definition: Tags.h:44
#define F_WRITE_TAG
Definition: Tags.h:45
NDIndex< Dim > AddGuardCells(const NDIndex< Dim > &idx, const GuardCellSizes< Dim > &g)
T * PtrOffset(T *ptr, const NDIndex< 1U > &pos, const NDIndex< 1U > &alloc, LFieldDimTag< 1U, true >)
Definition: BareField.hpp:1109
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define PAssert(c)
Definition: PAssert.h:102
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
#define WARNMSG(msg)
Definition: IpplInfo.h:349
std::string::iterator iterator
Definition: MSLang.h:16
bool CanCompress(const T &) const
Message & getMessage(Message &m)
unsigned size() const
bool touches(const NDIndex< Dim > &) const
Message & putMessage(Message &m) const
Definition: NDIndex.h:130
Message & getMessage(Message &m)
Definition: NDIndex.h:138
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
void getsingle_bc(const NDIndex< Dim > &, T &) const
Definition: BareField.hpp:1271
void setDirtyFlag()
Definition: BareField.h:117
T & localElement(const NDIndex< Dim > &) const
Definition: BareField.hpp:1154
void accumGuardCells()
Definition: BareField.hpp:698
void getsingle(const NDIndex< Dim > &, T &) const
Definition: BareField.hpp:1201
GuardCellSizes< Dim > Gc
Definition: BareField.h:343
const GuardCellSizes< Dim > & getGC() const
Definition: BareField.h:146
iterator_if begin_if()
Definition: BareField.h:100
virtual void notifyUserOfDelete(UserList *)
Definition: BareField.hpp:1079
void setup()
Definition: BareField.hpp:150
ac_id_larray::const_iterator const_iterator_if
Definition: BareField.h:93
ac_id_larray::iterator iterator_if
Definition: BareField.h:92
void Uncompress() const
Definition: BareField.hpp:1005
void Compress() const
Definition: BareField.hpp:991
ac_id_larray Locals_ac
Definition: BareField.h:331
virtual void Repartition(UserList *)
Definition: BareField.hpp:1054
void clearDirtyFlag()
Definition: BareField.h:118
Layout_t & getLayout() const
Definition: BareField.h:131
iterator_if end_if()
Definition: BareField.h:101
void setGuardCells(const T &) const
Definition: BareField.hpp:616
virtual void fillGuardCells(bool reallyFill=true) const
Definition: BareField.hpp:297
void initialize(Layout_t &)
Definition: BareField.hpp:100
double CompressedFraction() const
Definition: BareField.hpp:1021
void write(std::ostream &)
Definition: BareField.hpp:208
Definition: LField.h:58
T * getP()
Definition: LField.h:100
void Compress()
Definition: LField.h:161
const NDIndex< Dim > & getOwned() const
Definition: LField.h:99
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:98
T & getCompressedData()
Definition: LField.h:179
void AddToOverlapCache(LField< T, Dim > *newCacheItem)
Definition: LField.h:188
bool IsCompressed() const
Definition: LField.h:134
const iterator & end() const
Definition: LField.h:111
void Uncompress(bool fill_domain=true)
Definition: LField.h:172
OverlapIterator BeginOverlap()
Definition: LField.h:198
std::vector< LField< T, Dim > * >::iterator OverlapIterator
Definition: LField.h:196
OverlapIterator EndOverlap()
Definition: LField.h:199
const iterator & begin() const
Definition: LField.h:110
bool OverlapCacheInitialized()
Definition: LField.h:186
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
void checkin(FieldLayoutUser &f, const GuardCellSizes< Dim > &gc=gc0())
ac_id_vnodes::iterator iterator_iv
Definition: FieldLayout.h:73
virtual void apply()
Definition: Index.h:237
bool send(Message *, int node, int tag, bool delmsg=true)
virtual int broadcast_others(Message *, int, bool delmsg=true)
Message * receive_block(int &node, int &tag)
size_t size() const
Definition: Message.h:292
Message & put(const T &val)
Definition: Message.h:406
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
static void abort(const char *=0)
Definition: IpplInfo.cpp:616
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84
ID_t getUserListID() const
Definition: UserList.cpp:54
void reserve(size_type n)
Definition: vmap.h:125
iterator end()
Definition: vmap.h:108
std::pair< typename Unique::type, my_auto_ptr< LField< T, Dim > > > value_type
Definition: vmap.h:64
std::pair< iterator, bool > insert(const value_type &x)
Definition: vmap.hpp:73