OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
BCond.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/BCond.h"
28 #include "Field/BareField.h"
29 #include "Index/NDIndex.h"
30 #include "Index/Index.h"
31 #include "Field/GuardCellSizes.h"
32 #include "Field/BrickIterator.h"
33 #include "Field/BrickExpression.h"
34 #include "Meshes/Centering.h"
36 #include "Utility/IpplInfo.h"
37 #include "Utility/PAssert.h"
38 #include "AppTypes/AppTypeTraits.h"
39 
40 
41 #include <iostream>
42 #include <typeinfo>
43 #include <vector>
44 
46 
47 template<class T, unsigned D, class M, class C>
49 
51 
52 // Use this macro to specialize PETE_apply functions for component-wise
53 // operators and built-in types and print an error message.
54 
55 #define COMPONENT_APPLY_BUILTIN(OP,T) \
56 inline void PETE_apply(const OP<T>&, T&, const T&) \
57 { \
58  ERRORMSG("Component boundary condition on a scalar (T)." << endl); \
59  Ippl::abort(); \
60 }
61 
62 
63 /*
64 
65  Constructor for BCondBase<T,D,M,C>
66  Records the face, and figures out what component to remember.
67 
68  */
69 
70 template<class T, unsigned int D, class M, class C>
71 BCondBase<T,D,M,C>::BCondBase(unsigned int face, int i, int j)
72 : m_face(face), m_changePhysical(false)
73 {
74  // Must figure out if two, one, or no component indices are specified
75  // for which this BC is to apply; of none are specified, it applies to
76  // all components of the elements (of type T).
79  ERRORMSG("BCondBase(): component 2 specified, component 1 not."
80  << endl);
81  // For two specified component indices, must turn the two integer component
82  // index values into a single int value for Component, which is used in
83  // pointer offsets in applicative templates elsewhere. How to do this
84  // depends on what kind of two-index multicomponent object T is. Implement
85  // only for Tenzor, AntiSymTenzor, and SymTenzor (for now, at least):
86  if (getTensorOrder(get_tag(T())) == IPPL_TENSOR) {
87  m_component = i + j*D;
88  } else if (getTensorOrder(get_tag(T())) == IPPL_SYMTENSOR) {
89  int lo = i < j ? i : j;
90  int hi = i > j ? i : j;
91  m_component = ((hi+1)*hi/2) + lo;
92  } else if (getTensorOrder(get_tag(T())) == IPPL_ANTISYMTENSOR) {
93  PAssert_GT(i, j);
94  m_component = ((i-1)*i/2) + j;
95  } else {
96  ERRORMSG(
97  "BCondBase(): something other than [Sym,AntiSym]Tenzor specified"
98  << " two component indices; not implemented." << endl);
99  }
100 
101  } else {
102  // For only one specified component index (including the default case of
103  // BCondBase::allComponents meaning apply to all components of T, just
104  // assign the Component value for use in pointer offsets into
105  // single-component-index types in applicative templates elsewhere:
106  m_component = i;
107  }
108 }
109 
111 
112 /*
113 
114  BCondBase::write(ostream&)
115  Print out information about the BCondBase to an ostream.
116  This is called by its subclasses, which is why
117  it calls typeid(*this) to print out the class name.
118 
119  */
120 
121 template<class T, unsigned int D, class M, class C>
122 void BCondBase<T,D,M,C>::write(std::ostream& out) const
123 {
124  out << "BCondBase" << ", Face=" << m_face;
125 }
126 
127 template<class T, unsigned int D, class M, class C>
128 void PeriodicFace<T,D,M,C>::write(std::ostream& out) const
129 {
130  out << "PeriodicFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
131 }
132 
133 //BENI adds Interpolation face BC
134 template<class T, unsigned int D, class M, class C>
135 void InterpolationFace<T,D,M,C>::write(std::ostream& out) const
136 {
137  out << "InterpolationFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
138 }
139 
140 //BENI adds ParallelInterpolation face BC
141 template<class T, unsigned int D, class M, class C>
142 void ParallelInterpolationFace<T,D,M,C>::write(std::ostream& out) const
143 {
144  out << "ParallelInterpolationFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
145 }
146 
147 template<class T, unsigned int D, class M, class C>
148 void ParallelPeriodicFace<T,D,M,C>::write(std::ostream& out) const
149 {
150  out << "ParallelPeriodicFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
151 }
152 
153 template<class T, unsigned int D, class M, class C>
154 void NegReflectFace<T,D,M,C>::write(std::ostream& out) const
155 {
156  out << "NegReflectFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
157 }
158 
159 template<class T, unsigned int D, class M, class C>
160 void NegReflectAndZeroFace<T,D,M,C>::write(std::ostream& out) const
161 {
162  out << "NegReflectAndZeroFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
163 }
164 
165 template<class T, unsigned int D, class M, class C>
166 void PosReflectFace<T,D,M,C>::write(std::ostream& out) const
167 {
168  out << "PosReflectFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
169 }
170 
171 template<class T, unsigned int D, class M, class C>
172 void ZeroFace<T,D,M,C>::write(std::ostream& out) const
173 {
174  out << "ZeroFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
175 }
176 
177 template<class T, unsigned int D, class M, class C>
178 void ZeroGuardsAndZeroFace<T,D,M,C>::write(std::ostream& out) const
179 {
180  out << "ZeroGuardsAndZeroFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
181 }
182 
183 template<class T, unsigned int D, class M, class C>
184 void ConstantFace<T,D,M,C>::write(std::ostream& out) const
185 {
186  out << "ConstantFace"
187  << ", Face=" << BCondBase<T,D,M,C>::m_face
188  << ", Constant=" << this->Offset
189  << endl;
190 }
191 
192 template<class T, unsigned int D, class M, class C>
193 void EurekaFace<T,D,M,C>::write(std::ostream& out) const
194 {
195  out << "EurekaFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
196 }
197 
198 template<class T, unsigned int D, class M, class C>
199 void FunctionFace<T,D,M,C>::write(std::ostream& out) const
200 {
201  out << "FunctionFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
202 }
203 
204 template<class T, unsigned int D, class M, class C>
205 void ComponentFunctionFace<T,D,M,C>::write(std::ostream& out) const
206 {
207  out << "ComponentFunctionFace" << ", Face=" << BCondBase<T,D,M,C>::m_face;
208 }
209 
210 template<class T, unsigned D, class M, class C>
211 void
212 ExtrapolateFace<T,D,M,C>::write(std::ostream& o) const
213 {
214 
215 
216  o << "ExtrapolateFace, Face=" << BCondBase<T,D,M,C>::m_face
217  << ", Offset=" << Offset << ", Slope=" << Slope;
218 }
219 
220 template<class T, unsigned D, class M, class C>
221 void
223 {
224 
225 
226  o << "ExtrapolateAndZeroFace, Face=" << BCondBase<T,D,M,C>::m_face
227  << ", Offset=" << Offset << ", Slope=" << Slope;
228 }
229 
230 template<class T, unsigned D, class M, class C>
231 void
233 {
234 
235 
236  o << "LinearExtrapolateFace, Face=" << BCondBase<T,D,M,C>::m_face;
237 }
238 
239 template<class T, unsigned D, class M, class C>
240 void
242 {
243 
244  o << "ComponentLinearExtrapolateFace, Face=" << BCondBase<T,D,M,C>::m_face;
245 }
246 
248 
249 template<class T, unsigned D, class M, class C>
250 void
251 BConds<T,D,M,C>::write(std::ostream& o) const
252 {
253 
254 
255 
256  o << "BConds:(" << std::endl;
257  const_iterator p=this->begin();
258  while (p!=this->end())
259  {
260  (*p).second->write(o);
261  ++p;
262  if (p!=this->end())
263  o << " , " << std::endl;
264  else
265  o << std::endl << ")" << std::endl << std::endl;
266  }
267 }
268 
270 
271 template<class T, unsigned D, class M, class C>
272 void
274 {
275 
276 
277  for (iterator p=this->begin(); p!=this->end(); ++p)
278  (*p).second->apply(a);
279 }
280 
281 template<class T, unsigned D, class M, class C>
282 bool
284 {
285  for (const_iterator p=this->begin(); p!=this->end(); ++p)
286  if ((*p).second->changesPhysicalCells())
287  return true;
288  return false;
289 }
290 
291 //=============================================================================
292 // Constructors for PeriodicFace, ExtrapolateFace, FunctionFace classes
293 // and, now, ComponentFunctionFace
294 //=============================================================================
295 
296 template<class T, unsigned D, class M, class C>
297 PeriodicFace<T,D,M,C>::PeriodicFace(unsigned f, int i, int j)
298  : BCondBase<T,D,M,C>(f,i,j)
299 {
300  //std::cout << "(1) Constructor periodic face called" << std::endl;
301 
302 
303 }
304 
305 //BENI adds Interpolation face BC
306 template<class T, unsigned D, class M, class C>
308  : BCondBase<T,D,M,C>(f,i,j)
309 {
310 
311 
312 }
313 
314 template<class T, unsigned D, class M, class C>
315 ExtrapolateFace<T,D,M,C>::ExtrapolateFace(unsigned f, T o, T s, int i, int j)
316  : BCondBase<T,D,M,C>(f,i,j), Offset(o), Slope(s)
317 {
318 
319 
320 }
321 
322 template<class T, unsigned D, class M, class C>
324 ExtrapolateAndZeroFace(unsigned f, T o, T s, int i, int j)
325  : BCondBase<T,D,M,C>(f,i,j), Offset(o), Slope(s)
326 {
327 
329 }
330 
331 template<class T, unsigned D, class M, class C>
333 FunctionFace(T (*func)(const T&), unsigned face)
334  : BCondBase<T,D,M,C>(face), Func(func)
335 {
336 
337 
338 }
339 
340 template<class T, unsigned D, class M, class C>
343  (*func)( typename ApplyToComponentType<T>::type),
344  unsigned face, int i, int j)
345  : BCondBase<T,D,M,C>(face,i,j), Func(func)
346 {
347 
348  // Disallow specification of all components (default, unfortunately):
349  if ( (j == BCondBase<T,D,M,C>::allComponents) &&
351  ERRORMSG("ComponentFunctionFace(): allComponents specified; not allowed; "
352  << "use FunctionFace class instead." << endl);
353 }
354 
355 
357 
358 // Applicative templates for PeriodicFace:
359 
360 // Standard, for applying to all components of elemental type:
361 // (N.B.: could just use OpAssign, but put this in for clarity and consistency
362 // with other appliciative templates in this module.)
363 template<class T>
365 {
366 #ifdef IPPL_PURIFY
367  OpPeriodic() {}
368  OpPeriodic(const OpPeriodic<T> &) {}
369  OpPeriodic<T>& operator=(const OpPeriodic<T> &) { return *this; }
370 #endif
371 };
372 template<class T>
373 inline void PETE_apply(const OpPeriodic<T>& e, T& a, const T& b) {a = b; }
374 
375 // Special, for applying to single component of multicomponent elemental type:
376 template<class T>
378 {
381 };
382 
383 template<class T>
384 inline void PETE_apply(const OpPeriodicComponent<T>& e, T& a, const T& b)
385 { a[e.Component] = b[e.Component]; }
386 
387 // Following specializations are necessary because of the runtime branches in
388 // code which unfortunately force instantiation of OpPeriodicComponent
389 // instances for non-multicomponent types like {char,double,...}.
390 // Note: if user uses non-multicomponent (no operator[]) types of his own,
391 // he'll get a compile error. See comments regarding similar specializations
392 // for OpExtrapolateComponent for a more details.
395 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,int)
396 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,unsigned)
397 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,short)
398 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,long)
399 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,float)
400 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,double)
401 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,dcomplex)
402 
403 
405 
406 //----------------------------------------------------------------------------
407 // For unspecified centering, can't implement PeriodicFace::apply()
408 // correctly, and can't partial-specialize yet, so... don't have a prototype
409 // for unspecified centering, so user gets a compile error if he tries to
410 // invoke it for a centering not yet implemented. Implement external functions
411 // which are specializations for the various centerings
412 // {Cell,Vert,CartesianCentering}; these are called from the general
413 // PeriodicFace::apply() function body.
414 //----------------------------------------------------------------------------
415 
416 
417 //BENI: Do the whole operation part with += for Interpolation Boundary Conditions
419 
420 // Applicative templates for PeriodicFace:
421 
422 // Standard, for applying to all components of elemental type:
423 // (N.B.: could just use OpAssign, but put this in for clarity and consistency
424 // with other appliciative templates in this module.)
425 template<class T>
427 {
428 #ifdef IPPL_PURIFY
429  OpInterpolation() {}
430  OpInterpolation(const OpInterpolation<T> &) {}
431  OpInterpolation<T>& operator=(const OpInterpolation<T> &) { return *this; }
432 #endif
433 };
434 template<class T>
435 inline void PETE_apply(const OpInterpolation<T>& e, T& a, const T& b) {a = a + b; }
436 
437 // Special, for applying to single component of multicomponent elemental type:
438 template<class T>
440 {
443 };
444 
445 template<class T>
446 inline void PETE_apply(const OpInterpolationComponent<T>& e, T& a, const T& b)
447 { a[e.Component] = a[e.Component]+b[e.Component]; }
448 
449 // Following specializations are necessary because of the runtime branches in
450 // code which unfortunately force instantiation of OpPeriodicComponent
451 // instances for non-multicomponent types like {char,double,...}.
452 // Note: if user uses non-multicomponent (no operator[]) types of his own,
453 // he'll get a compile error. See comments regarding similar specializations
454 // for OpExtrapolateComponent for a more details.
455 
456 
459 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,int)
460 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,unsigned)
461 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,short)
462 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,long)
463 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,float)
464 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,double)
465 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,dcomplex)
467 
468 //----------------------------------------------------------------------------
469 // For unspecified centering, can't implement PeriodicFace::apply()
470 // correctly, and can't partial-specialize yet, so... don't have a prototype
471 // for unspecified centering, so user gets a compile error if he tries to
472 // invoke it for a centering not yet implemented. Implement external functions
473 // which are specializations for the various centerings
474 // {Cell,Vert,CartesianCentering}; these are called from the general
475 // PeriodicFace::apply() function body.
476 //----------------------------------------------------------------------------
477 
478 
479 template<class T, unsigned D, class M>
480 void PeriodicFaceBCApply(PeriodicFace<T,D,M,Cell>& pf,
481  Field<T,D,M,Cell>& A );
482 //BENI adds InterpolationFace ONLY Cell centered implementation!!!
483 template<class T, unsigned D, class M>
485  Field<T,D,M,Cell>& A );
486 
487 template<class T, unsigned D, class M>
488 void PeriodicFaceBCApply(PeriodicFace<T,D,M,Vert>& pf,
489  Field<T,D,M,Vert>& A );
490 template<class T, unsigned D, class M>
491 void PeriodicFaceBCApply(PeriodicFace<T,D,M,Edge>& pf,
492  Field<T,D,M,Edge>& A );
493 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
495  CartesianCentering<CE,D,NC> >& pf,
496  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
497 
498 template<class T, unsigned D, class M, class C>
499 void PeriodicFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
500 {
501 
502  //std::cout << "(2) PeriodicFace::apply" << std::endl;
503 
504  PeriodicFaceBCApply(*this, A);
505 }
506 //BENI adds InterpolationFace
507 template<class T, unsigned D, class M, class C>
509 {
510 
511 
512  InterpolationFaceBCApply(*this, A);
513 }
514 
515 //-----------------------------------------------------------------------------
516 // Specialization of PeriodicFace::apply() for Cell centering.
517 // Rather, indirectly-called specialized global function PeriodicFaceBCApply
518 //-----------------------------------------------------------------------------
519 template<class T, unsigned D, class M>
521  Field<T,D,M,Cell>& A )
522 {
523 
524 
525  //std::cout << "(3) PeriodicFaceBCApply called" << std::endl;
526  // NOTE: See the PeriodicFaceBCApply functions below for more
527  // comprehensible comments --TJW
528 
529  // Find the slab that is the destination.
530  const NDIndex<D>& domain( A.getDomain() );
531 
532 
533 
534 
535  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
536  unsigned d = pf.getFace()/2;
537  int offset;
538  if ( pf.getFace() & 1 )
539  {
540  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.leftGuard(d) );
541  offset = -domain[d].length();
542  }
543  else
544  {
545  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
546  offset = domain[d].length();
547  }
548 
549  DEBUGMSG("PeriodicFaceBCApply domain" << domain << " d= " << d << " slab= " << slab[d] << endl);
550 
551  // Loop over the ones the slab touches.
552  typename Field<T,D,M,Cell>::iterator_if fill_i;
553  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
554  {
555  // Cache some things we will use often below.
556  LField<T,D> &fill = *(*fill_i).second;
557  const NDIndex<D> &fill_alloc = fill.getAllocated();
558  if ( slab.touches( fill_alloc ) )
559  {
560  // Find what it touches in this LField.
561  NDIndex<D> dest = slab.intersect( fill_alloc );
562 
563  // Find where that comes from.
564  NDIndex<D> src = dest;
565  src[d] = src[d] + offset;
566 
567  // Loop over the ones that src touches.
568  typename Field<T,D,M,Cell>::iterator_if from_i;
569  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
570  {
571  // Cache a few things.
572  LField<T,D> &from = *(*from_i).second;
573  const NDIndex<D> &from_owned = from.getOwned();
574  const NDIndex<D> &from_alloc = from.getAllocated();
575  // If src touches this LField...
576  if ( src.touches( from_owned ) )
577  {
578  // bfh: Worry about compression ...
579  // If 'fill' is a compressed LField, then writing data into
580  // it via the expression will actually write the value for
581  // all elements of the LField. We can do the following:
582  // a) figure out if the 'fill' elements are all the same
583  // value, if 'from' elements are the same value, if
584  // the 'fill' elements are the same as the elements
585  // throughout that LField, and then just do an
586  // assigment for a single element
587  // b) just uncompress the 'fill' LField, to make sure we
588  // do the right thing.
589  // I vote for b).
590  fill.Uncompress();
591 
592  NDIndex<D> from_it = src.intersect( from_alloc );
593  NDIndex<D> fill_it = dest.plugBase( from_it );
594  // Build iterators for the copy...
595  typedef typename LField<T,D>::iterator LFI;
596  LFI lhs = fill.begin(fill_it);
597  LFI rhs = from.begin(from_it);
598  // And do the assignment.
599  // BrickExpression<D,LFI,LFI,OpAssign >(lhs,rhs).apply();
602  (lhs,rhs,OpPeriodic<T>()).apply();
603  } else {
605  (lhs,rhs,OpPeriodicComponent<T>(pf.getComponent())).apply();
606  }
607  }
608  }
609  }
610  }
611 }
612 
613 //BENI adds for InterpolationFace
614 //-----------------------------------------------------------------------------
615 // Specialization of InterpolationFace::apply() for Cell centering.
616 // Rather, indirectly-called specialized global function InerpolationFaceBCApply
617 //-----------------------------------------------------------------------------
618 template<class T, unsigned D, class M>
620  Field<T,D,M,Cell>& A )
621 {
622 
623  // NOTE: See the PeriodicFaceBCApply functions below for more
624  // comprehensible comments --TJW
625 
626  // Find the slab that is the source (BENI: opposite to periodic BC).
627  const NDIndex<D>& domain( A.getDomain() );
628 
629  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
630  unsigned d = pf.getFace()/2;
631  int offset;
632  if ( pf.getFace() & 1 )
633  {
634  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.leftGuard(d) );
635  offset = -domain[d].length();
636  }
637  else
638  {
639  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
640  offset = domain[d].length();
641  }
642 
643  DEBUGMSG("InterpolationFaceBCApply domain" << domain << " d= " << d << " slab= " << slab[d] << endl);
644 
645  // Loop over the ones the slab touches.
646  typename Field<T,D,M,Cell>::iterator_if fill_i;
647  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
648  {
649  // Cache some things we will use often below.
650  LField<T,D> &fill = *(*fill_i).second;
651  const NDIndex<D> &fill_alloc = fill.getAllocated();
652  if ( slab.touches( fill_alloc ) )
653  {
654  // Find what it touches in this LField.
655  //BENI: The ghost values are the source to be accumulated to the boundaries
656  NDIndex<D> src = slab.intersect( fill_alloc );
657 
658  // BENI: destination is the boundary on the other side
659  NDIndex<D> dest = src;
660  dest[d] = dest[d] + offset;
661  // std::cout << "src = " << src << std::endl;
662  // std::cout << "dest = " << dest << std::endl;
663 
664 
665  // Loop over the ones that src touches.
666  typename Field<T,D,M,Cell>::iterator_if from_i;
667  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
668  {
669  // Cache a few things.
670  LField<T,D> &from = *(*from_i).second;
671  const NDIndex<D> &from_owned = from.getOwned();
672  const NDIndex<D> &from_alloc = from.getAllocated();
673  // BENI: If destination touches this LField...
674  if ( dest.touches( from_owned ) )
675  {
676  // bfh: Worry about compression ...
677  // If 'fill' is a compressed LField, then writing data into
678  // it via the expression will actually write the value for
679  // all elements of the LField. We can do the following:
680  // a) figure out if the 'fill' elements are all the same
681  // value, if 'from' elements are the same value, if
682  // the 'fill' elements are the same as the elements
683  // throughout that LField, and then just do an
684  // assigment for a single element
685  // b) just uncompress the 'fill' LField, to make sure we
686  // do the right thing.
687  // I vote for b).
688  fill.Uncompress();
689 
690  NDIndex<D> from_it = src.intersect( from_alloc );
691  NDIndex<D> fill_it = dest.plugBase( from_it );
692  // Build iterators for the copy...
693  typedef typename LField<T,D>::iterator LFI;
694  LFI lhs = fill.begin(fill_it);
695  LFI rhs = from.begin(from_it);
696  // And do the assignment.
697  // BrickExpression<D,LFI,LFI,OpAssign >(lhs,rhs).apply();
699  //std::cout << "TRY to apply OPInterpol" << std::endl;
701  (lhs,rhs,OpInterpolation<T>()).apply();
702  } else {
705  }
706  }
707  }
708  }
709  }
710 }
711 
712 //-----------------------------------------------------------------------------
713 // Specialization of PeriodicFace::apply() for Vert centering.
714 // Rather, indirectly-called specialized global function PeriodicFaceBCApply
715 //-----------------------------------------------------------------------------
716 template<class T, unsigned D, class M>
718  Field<T,D,M,Vert>& A )
719 {
720 
721 
722 
723  // NOTE: See the ExtrapolateFaceBCApply functions below for more
724  // comprehensible comments --TJW
725 
726  // Find the slab that is the destination.
727  const NDIndex<D>& domain( A.getDomain() );
728  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
729  unsigned d = pf.getFace()/2;
730  int offset;
731  if ( pf.getFace() & 1 )
732  {
733  // TJW: this used to say "leftGuard(d)", which I think was wrong:
734  slab[d] = Index(domain[d].max(), domain[d].max() + A.rightGuard(d));
735  // N.B.: the extra +1 here is what distinguishes this Vert-centered
736  // implementation from the Cell-centered one:
737  offset = -domain[d].length() + 1;
738  }
739  else
740  {
741  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
742  // N.B.: the extra -1 here is what distinguishes this Vert-centered
743  // implementation from the Cell-centered one:
744  offset = domain[d].length() - 1;
745  }
746 
747  // Loop over the ones the slab touches.
748  typename Field<T,D,M,Vert>::iterator_if fill_i;
749  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
750  {
751  // Cache some things we will use often below.
752  LField<T,D> &fill = *(*fill_i).second;
753  const NDIndex<D> &fill_alloc = fill.getAllocated();
754  if ( slab.touches( fill_alloc ) )
755  {
756  // Find what it touches in this LField.
757  NDIndex<D> dest = slab.intersect( fill_alloc );
758 
759  // Find where that comes from.
760  NDIndex<D> src = dest;
761  src[d] = src[d] + offset;
762 
763  // Loop over the ones that src touches.
764  typename Field<T,D,M,Vert>::iterator_if from_i;
765  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
766  {
767  // Cache a few things.
768  LField<T,D> &from = *(*from_i).second;
769  const NDIndex<D> &from_owned = from.getOwned();
770  const NDIndex<D> &from_alloc = from.getAllocated();
771  // If src touches this LField...
772  if ( src.touches( from_owned ) )
773  {
774  // bfh: Worry about compression ...
775  // If 'fill' is a compressed LField, then writing data into
776  // it via the expression will actually write the value for
777  // all elements of the LField. We can do the following:
778  // a) figure out if the 'fill' elements are all the same
779  // value, if 'from' elements are the same value, if
780  // the 'fill' elements are the same as the elements
781  // throughout that LField, and then just do an
782  // assigment for a single element
783  // b) just uncompress the 'fill' LField, to make sure we
784  // do the right thing.
785  // I vote for b).
786  fill.Uncompress();
787 
788  NDIndex<D> from_it = src.intersect( from_alloc );
789  NDIndex<D> fill_it = dest.plugBase( from_it );
790  // Build iterators for the copy...
791  typedef typename LField<T,D>::iterator LFI;
792  LFI lhs = fill.begin(fill_it);
793  LFI rhs = from.begin(from_it);
794  // And do the assignment.
795  // BrickExpression<D,LFI,LFI,OpAssign >(lhs,rhs).apply();
798  (lhs,rhs,OpPeriodic<T>()).apply();
799  } else {
801  (lhs,rhs,OpPeriodicComponent<T>(pf.getComponent())).apply();
802  }
803  }
804  }
805  }
806  }
807 }
808 
809 
810 //-----------------------------------------------------------------------------
811 // Specialization of PeriodicFace::apply() for Edge centering.
812 // Rather, indirectly-called specialized global function PeriodicFaceBCApply
813 //-----------------------------------------------------------------------------
814 template<class T, unsigned D, class M>
816  Field<T,D,M,Edge>& A )
817 {
818  // NOTE: See the ExtrapolateFaceBCApply functions below for more
819  // comprehensible comments --TJW
820 
821  // Find the slab that is the destination.
822  const NDIndex<D>& domain( A.getDomain() );
823  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
824  unsigned d = pf.getFace()/2;
825  int offset;
826  if ( pf.getFace() & 1 )
827  {
828  // TJW: this used to say "leftGuard(d)", which I think was wrong:
829  slab[d] = Index(domain[d].max(), domain[d].max() + A.rightGuard(d));
830  // N.B.: the extra +1 here is what distinguishes this Edge-centered
831  // implementation from the Cell-centered one:
832  offset = -domain[d].length() + 1;
833  }
834  else
835  {
836  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
837  // N.B.: the extra -1 here is what distinguishes this Edge-centered
838  // implementation from the Cell-centered one:
839  offset = domain[d].length() - 1;
840  }
841 
842  // Loop over the ones the slab touches.
843  typename Field<T,D,M,Edge>::iterator_if fill_i;
844  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
845  {
846  // Cache some things we will use often below.
847  LField<T,D> &fill = *(*fill_i).second;
848  const NDIndex<D> &fill_alloc = fill.getAllocated();
849  if ( slab.touches( fill_alloc ) )
850  {
851  // Find what it touches in this LField.
852  NDIndex<D> dest = slab.intersect( fill_alloc );
853 
854  // Find where that comes from.
855  NDIndex<D> src = dest;
856  src[d] = src[d] + offset;
857 
858  // Loop over the ones that src touches.
859  typename Field<T,D,M,Edge>::iterator_if from_i;
860  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
861  {
862  // Cache a few things.
863  LField<T,D> &from = *(*from_i).second;
864  const NDIndex<D> &from_owned = from.getOwned();
865  const NDIndex<D> &from_alloc = from.getAllocated();
866  // If src touches this LField...
867  if ( src.touches( from_owned ) )
868  {
869  // bfh: Worry about compression ...
870  // If 'fill' is a compressed LField, then writing data into
871  // it via the expression will actually write the value for
872  // all elements of the LField. We can do the following:
873  // a) figure out if the 'fill' elements are all the same
874  // value, if 'from' elements are the same value, if
875  // the 'fill' elements are the same as the elements
876  // throughout that LField, and then just do an
877  // assigment for a single element
878  // b) just uncompress the 'fill' LField, to make sure we
879  // do the right thing.
880  // I vote for b).
881  fill.Uncompress();
882 
883  NDIndex<D> from_it = src.intersect( from_alloc );
884  NDIndex<D> fill_it = dest.plugBase( from_it );
885  // Build iterators for the copy...
886  typedef typename LField<T,D>::iterator LFI;
887  LFI lhs = fill.begin(fill_it);
888  LFI rhs = from.begin(from_it);
889  // And do the assignment.
890  // BrickExpression<D,LFI,LFI,OpAssign >(lhs,rhs).apply();
893  (lhs,rhs,OpPeriodic<T>()).apply();
894  } else {
896  (lhs,rhs,OpPeriodicComponent<T>(pf.getComponent())).apply();
897  }
898  }
899  }
900  }
901  }
902 }
903 
904 //-----------------------------------------------------------------------------
905 // Specialization of PeriodicFace::apply() for CartesianCentering centering.
906 // Rather, indirectly-called specialized global function PeriodicFaceBCApply
907 //-----------------------------------------------------------------------------
908 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
912 {
913 
914 
915 
916  // NOTE: See the ExtrapolateFaceBCApply functions below for more
917  // comprehensible comments --TJW
918 
919  // Find the slab that is the destination.
920  const NDIndex<D>& domain( A.getDomain() );
921  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
922  unsigned d = pf.getFace()/2;
923  int offset;
924  if ( pf.getFace() & 1 )
925  {
926  // Do the right thing for CELL or VERT centering for this component (or
927  // all components, if the PeriodicFace object so specifies):
928  if (pf.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
929  allComponents) {
930  // Make sure all components are really centered the same, as assumed:
931  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
932  for (int c=1; c<NC; c++) { // Compare other components with 1st
933  if (CE[c + d*NC] != centering0)
934  ERRORMSG("PeriodicFaceBCApply: BCond thinks all components have"
935  << " same centering along direction " << d
936  << ", but it isn't so." << endl);
937  }
938  // Now do the right thing for CELL or VERT centering of all components:
939  if (centering0 == CELL) {
940  offset = -domain[d].length(); // CELL case
941  } else {
942  // TJW: this used to say "leftGuard(d)", which I think was wrong:
943  slab[d] =
944  Index( domain[d].max(), domain[d].max() + A.rightGuard(d));
945  offset = -domain[d].length()+1; // VERT case
946  }
947  } else { // The BC applies only to one component, not all:
948  // Do the right thing for CELL or VERT centering of the component:
949  if (CE[pf.getComponent() + d*NC] == CELL) {
950  offset = -domain[d].length(); // CELL case
951  } else {
952  slab[d] =
953  Index( domain[d].max(), domain[d].max() + A.rightGuard(d));
954  offset = -domain[d].length()+1; // VERT case
955  }
956  }
957  }
958  else
959  {
960  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
961  // Do the right thing for CELL or VERT centering for this component (or
962  // all components, if the PeriodicFace object so specifies):
963  if (pf.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
964  allComponents) {
965  // Make sure all components are really centered the same, as assumed:
966  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
967  for (int c=1; c<NC; c++) { // Compare other components with 1st
968  if (CE[c + d*NC] != centering0)
969  ERRORMSG("PeriodicFaceBCApply: BCond thinks all components have"
970  << " same centering along direction " << d
971  << ", but it isn't so." << endl);
972  }
973  // Now do the right thing for CELL or VERT centering of all components:
974  if (centering0 == CELL) {
975  offset = -domain[d].length(); // CELL case
976  } else {
977  offset = -domain[d].length() + 1; // VERT case
978  }
979  } else { // The BC applies only to one component, not all:
980  // Do the right thing for CELL or VERT centering of the component:
981  if (CE[pf.getComponent() + d*NC] == CELL) {
982  offset = domain[d].length(); // CELL case
983  } else {
984  offset = domain[d].length() - 1; // VERT case
985  }
986  }
987  }
988 
989  // Loop over the ones the slab touches.
990  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
991  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
992  {
993  // Cache some things we will use often below.
994  LField<T,D> &fill = *(*fill_i).second;
995  const NDIndex<D> &fill_alloc = fill.getAllocated();
996  if ( slab.touches( fill_alloc ) )
997  {
998  // Find what it touches in this LField.
999  NDIndex<D> dest = slab.intersect( fill_alloc );
1000 
1001  // Find where that comes from.
1002  NDIndex<D> src = dest;
1003  src[d] = src[d] + offset;
1004 
1005  // Loop over the ones that src touches.
1006  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if from_i;
1007  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
1008  {
1009  // Cache a few things.
1010  LField<T,D> &from = *(*from_i).second;
1011  const NDIndex<D> &from_owned = from.getOwned();
1012  const NDIndex<D> &from_alloc = from.getAllocated();
1013  // If src touches this LField...
1014  if ( src.touches( from_owned ) )
1015  {
1016  // bfh: Worry about compression ...
1017  // If 'fill' is a compressed LField, then writing data into
1018  // it via the expression will actually write the value for
1019  // all elements of the LField. We can do the following:
1020  // a) figure out if the 'fill' elements are all the same
1021  // value, if 'from' elements are the same value, if
1022  // the 'fill' elements are the same as the elements
1023  // throughout that LField, and then just do an
1024  // assigment for a single element
1025  // b) just uncompress the 'fill' LField, to make sure we
1026  // do the right thing.
1027  // I vote for b).
1028  fill.Uncompress();
1029 
1030  NDIndex<D> from_it = src.intersect( from_alloc );
1031  NDIndex<D> fill_it = dest.plugBase( from_it );
1032  // Build iterators for the copy...
1033  typedef typename LField<T,D>::iterator LFI;
1034  LFI lhs = fill.begin(fill_it);
1035  LFI rhs = from.begin(from_it);
1036  // And do the assignment.
1037  // BrickExpression<D,LFI,LFI,OpAssign >(lhs,rhs).apply();
1038  if (pf.getComponent() == BCondBase<T,D,M,
1039  CartesianCentering<CE,D,NC> >::allComponents) {
1041  (lhs,rhs,OpPeriodic<T>()).apply();
1042  } else {
1044  (lhs,rhs,OpPeriodicComponent<T>(pf.getComponent())).apply();
1045  }
1046  }
1047  }
1048  }
1049  }
1050 }
1051 
1052 
1053 //-----------------------------------------------------------------------------
1054 // Specialization of CalcParallelPeriodicDomain for various centerings.
1055 // This is the centering-specific code for ParallelPeriodicFace::apply().
1056 //-----------------------------------------------------------------------------
1057 
1058 #ifdef PRINT_DEBUG
1059 // For distance.
1060 # include <iterator.h>
1061 #endif
1062 
1063 template <class T, unsigned D, class M>
1064 inline void
1067  NDIndex<D> &dest_slab,
1068  int &offset)
1069 {
1070  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1071  // expression converts the face index to the direction index.
1072 
1073  unsigned d = pf.getFace()/2;
1074 
1075  const NDIndex<D>& domain(A.getDomain());
1076 
1077  if (pf.getFace() & 1) // Odd ("top" or "right") face
1078  {
1079  // The cells that we need to fill start one beyond the last
1080  // physical cell at the "top" and continue to the last guard
1081  // cell. Change "dest_slab" to restrict direction "d" to this
1082  // subdomain.
1083 
1084  dest_slab[d] =
1085  Index(domain[d].max() + 1, domain[d].max() + A.leftGuard(d));
1086 
1087  // The offset to the cells that we are going to read; i.e. the
1088  // read domain will be "dest_slab + offset". This is the number of
1089  // physical cells in that direction.
1090 
1091  offset = -domain[d].length();
1092  }
1093  else // Even ("bottom" or "left") face
1094  {
1095  // The cells that we need to fill start with the first guard
1096  // cell on the bottom and continue up through the cell before
1097  // the first physical cell.
1098 
1099  dest_slab[d] =
1100  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
1101 
1102  // See above.
1103 
1104  offset = domain[d].length();
1105  }
1106 }
1107 
1108 // Note: this does the same thing that PeriodicFace::apply() does, but
1109 // I don't think that this is correct.
1110 
1111 template <class T, unsigned D, class M>
1112 inline void
1115  NDIndex<D> &dest_slab,
1116  int &offset)
1117 {
1118  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1119  // expression converts the face index to the direction index.
1120 
1121  const NDIndex<D>& domain(A.getDomain());
1122 
1123  unsigned d = pf.getFace()/2;
1124 
1125  if (pf.getFace() & 1) // Odd ("top" or "right") face
1126  {
1127  // A vert-centered periodic field duplicates the boundary
1128  // point. As a result, the right boundary point is filled from
1129  // the left boundary point. Thus, the points that we need to fill
1130  // include the last physical point (domain[d].max()) and the
1131  // guard points.
1132 
1133  dest_slab[d] =
1134  Index(domain[d].max(), domain[d].max() + A.rightGuard(d));
1135 
1136  // The offset to the points that we are going to read; i.e. the
1137  // read domain will be "dest_slab + offset". This is the number of
1138  // physical points in that direction.
1139 
1140  offset = -domain[d].length() + 1;
1141  }
1142  else // Even ("bottom" or "left") face
1143  {
1144  // The points that we need to fill start with the first guard
1145  // cell on the bottom and continue up through the cell before
1146  // the first physical cell.
1147 
1148  dest_slab[d] =
1149  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
1150 
1151  // See above.
1152 
1153  offset = domain[d].length() - 1;
1154  }
1155 }
1156 
1157 // See comments above - vert centering wrong, I think.
1158 // TODO ckr: compare this with the general case below
1159 template <class T, unsigned D, class M>
1160 inline void
1163  NDIndex<D> &dest_slab,
1164  int &offset)
1165 {
1166  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1167  // expression converts the face index to the direction index.
1168 
1169  const NDIndex<D>& domain(A.getDomain());
1170 
1171  unsigned d = pf.getFace()/2;
1172 
1173  if (pf.getFace() & 1) // Odd ("top" or "right") face
1174  {
1175  // A vert-centered periodic field duplicates the boundary
1176  // point. As a result, the right boundary point is filled from
1177  // the left boundary point. Thus, the points that we need to fill
1178  // include the last physical point (domain[d].max()) and the
1179  // guard points.
1180 
1181  dest_slab[d] =
1182  Index(domain[d].max(), domain[d].max() + A.rightGuard(d));
1183 
1184  // The offset to the points that we are going to read; i.e. the
1185  // read domain will be "dest_slab + offset". This is the number of
1186  // physical points in that direction.
1187 
1188  offset = -domain[d].length() + 1;
1189  }
1190  else // Even ("bottom" or "left") face
1191  {
1192  // The points that we need to fill start with the first guard
1193  // cell on the bottom and continue up through the cell before
1194  // the first physical cell.
1195 
1196  dest_slab[d] =
1197  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
1198 
1199  // See above.
1200 
1201  offset = domain[d].length() - 1;
1202  }
1203 }
1204 
1205 // See comments above - vert centering wrong, I think.
1206 
1207 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
1208 inline void
1210  const ParallelPeriodicFace<T,D,M,
1212  NDIndex<D> &dest_slab,
1213  int &offset)
1214 {
1216 
1217  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1218  // expression converts the face index to the direction index.
1219 
1220  const NDIndex<D>& domain(A.getDomain());
1221 
1222  unsigned d = pf.getFace()/2;
1223 
1224  if (pf.getFace() & 1) // Odd ("top" or "right") face
1225  {
1226  // For this specialization we need to do the right thing for
1227  // CELL or VERT centering for the appropriate components of the
1228  // field. The cells that we need to fill, and the offset to the
1229  // source cells, depend on the centering. See below and the
1230  // comments in the vert and cell versions above.
1231 
1232  if (pf.getComponent() == BCBase_t::allComponents)
1233  {
1234  // Make sure all components are really centered the same, as
1235  // assumed:
1236 
1237  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component
1238  // along dir d
1239  for (int c = 1; c < NC; c++)
1240  {
1241  // Compare other components with 1st
1242  if (CE[c + d*NC] != centering0)
1243  ERRORMSG("ParallelPeriodicFaceBCApply:"
1244  << "BCond thinks all components have"
1245  << " same centering along direction " << d
1246  << ", but it isn't so." << endl);
1247  }
1248 
1249  // Now do the right thing for CELL or VERT centering of all
1250  // components:
1251 
1252  if (centering0 == CELL) {
1253  offset = -domain[d].length(); // CELL case
1254  } else {
1255  dest_slab[d] =
1256  Index(domain[d].max(), domain[d].max() + A.leftGuard(d));
1257  offset = -domain[d].length() + 1; // VERT case
1258  }
1259 
1260  }
1261  else
1262  {
1263  // The BC applies only to one component, not all: Do the
1264  // right thing for CELL or VERT centering of the component:
1265 
1266  if (CE[pf.getComponent() + d*NC] == CELL)
1267  {
1268  offset = -domain[d].length(); // CELL case
1269  }
1270  else
1271  {
1272  dest_slab[d] =
1273  Index(domain[d].max(), domain[d].max() + A.leftGuard(d));
1274  offset = -domain[d].length() + 1; // VERT case
1275  }
1276  }
1277  }
1278  else // Even ("bottom" or "left") face
1279  {
1280  // The cells that we need to fill start with the first guard
1281  // cell on the bottom and continue up through the cell before
1282  // the first physical cell.
1283 
1284  dest_slab[d] =
1285  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
1286 
1287  // See above.
1288 
1289  if (pf.getComponent() == BCBase_t::allComponents)
1290  {
1291  // Make sure all components are really centered the same, as
1292  // assumed:
1293 
1294  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component
1295  // along dir d
1296  for (int c = 1; c < NC; c++)
1297  { // Compare other components with 1st
1298  if (CE[c + d*NC] != centering0)
1299  ERRORMSG("ParallelPeriodicFaceBCApply:"
1300  << "BCond thinks all components have"
1301  << " same centering along direction " << d
1302  << ", but it isn't so." << endl);
1303  }
1304 
1305  // Now do the right thing for CELL or VERT centering of all
1306  // components:
1307 
1308  if (centering0 == CELL) {
1309  offset = -domain[d].length(); // CELL case
1310  } else {
1311  offset = -domain[d].length() + 1; // VERT case
1312  }
1313 
1314  }
1315  else
1316  {
1317  // The BC applies only to one component, not all: Do the
1318  // right thing for CELL or VERT centering of the component:
1319 
1320  if (CE[pf.getComponent() + d*NC] == CELL)
1321  {
1322  offset = domain[d].length(); // CELL case
1323  }
1324  else
1325  {
1326  offset = domain[d].length() - 1; // VERT case
1327  }
1328  }
1329  }
1330 }
1331 
1332 //-----------------------------------------------------------------------------
1333 // ParallelPeriodicFace::apply()
1334 // Apply the periodic boundary condition. This version can handle
1335 // fields that are parallel in the periodic direction. Unlike the
1336 // other BCond types, the Lion's share of the code is in this single
1337 // apply() method. The only centering-specific calculation is that of
1338 // the destination domain and the offset, and that is separated out
1339 // into the CalcParallelPeriodicDomain functions defined above.
1340 //-----------------------------------------------------------------------------
1341 //#define PRINT_DEBUG
1342 template<class T, unsigned D, class M, class C>
1344 {
1345 
1346 #ifdef PRINT_DEBUG
1347  Inform msg("PPeriodicBC", INFORM_ALL_NODES);
1348 #endif
1349 
1350 
1351  // Useful typedefs:
1352 
1353  typedef T Element_t;
1354  typedef NDIndex<D> Domain_t;
1355  typedef LField<T,D> LField_t;
1356  typedef typename LField_t::iterator LFI_t;
1357  typedef Field<T,D,M,C> Field_t;
1358  typedef FieldLayout<D> Layout_t;
1359 
1360  //===========================================================================
1361  //
1362  // Unlike most boundary conditions, periodic BCs are (in general)
1363  // non-local. Indeed, they really are identical to the guard-cell
1364  // seams between LFields internal to the Field. In this case the
1365  // LFields just have a periodic geometry, but the FieldLayout
1366  // doesn't express this, so we duplicate the code, which is quite
1367  // similar to fillGuardCellsr, but somewhat more complicated, here.
1368  // The complications arise from three sources:
1369  //
1370  // - The source and destination domains are offset, not overlapping.
1371  // - Only a subset of all LFields are, in general, involved.
1372  // - The corners must be handled correctly.
1373  //
1374  // Here's the plan:
1375  //
1376  // 0. Calculate source and destination domains.
1377  // 1. Build send and receive lists, and send messages.
1378  // 2. Evaluate local pieces directly.
1379  // 3. Receive messages and evaluate remaining pieces.
1380  //
1381  //===========================================================================
1382 /*
1383 #ifdef PRINT_DEBUG
1384  msg << "Starting BC Calculation for face "
1385  << getFace() << "." << endl;
1386 #endif
1387 */
1388  //===========================================================================
1389  // 0. Calculate destination domain and the offset.
1390  //===========================================================================
1391 
1392  // Find the slab that is the destination. First get the whole
1393  // domain, including guard cells, and then restrict it to the area
1394  // that this BC will fill.
1395 
1396  const NDIndex<D>& domain(A.getDomain());
1397 
1398  NDIndex<D> dest_slab = AddGuardCells(domain,A.getGuardCellSizes());
1399 
1400  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1401  // expression converts the face index to the direction index.
1402 
1403  unsigned d = this->getFace()/2;
1404 
1405  int offset;
1406 
1407  CalcParallelPeriodicDomain(A,*this,dest_slab,offset);
1408 
1409  Domain_t src_slab = dest_slab;
1410  src_slab[d] = src_slab[d] + offset;
1411 
1412 #ifdef PRINT_DEBUG
1413  msg << "dest_slab = " << dest_slab << endl;
1414  msg << "src_slab = " << src_slab << endl;
1415  // stop_here();
1416 #endif
1417 
1418 
1419  //===========================================================================
1420  // 1. Build send and receive lists and send messages
1421  //===========================================================================
1422 
1423  // Declare these at this scope so that we don't have to duplicate
1424  // the local code. (fillguardcells puts these in the scope of the
1425  // "if (nprocs > 1) { ... }" section, but has to duplicate the
1426  // code for the local fills as a result. The cost of this is a bit
1427  // of stackspace, and the cost of allocating an empty map.)
1428 
1429  // Container for holding Domain -> LField mapping
1430  // so that we can sort out which messages go where.
1431 
1432  typedef std::multimap<Domain_t,LField_t*, std::less<Domain_t> > ReceiveMap_t;
1433 
1434  // (Time this since it allocates an empty map.)
1435 
1436 
1437 
1438  ReceiveMap_t receive_map;
1439 
1440 
1441 
1442  // Number of nodes that will send us messages.
1443 
1444  int receive_count = 0;
1445  int send_count = 0;
1446 
1447  // Communications tag
1448 
1449  int bc_comm_tag;
1450 
1451 
1452  // Next fill the dest_list and src_list, lists of the LFields that
1453  // touch the destination and source domains, respectively.
1454 
1455  // (Do we need this for local-only code???)
1456 
1457  // (Also, if a domain ends up in both lists, it will only be
1458  // involved in local communication. We should structure this code to
1459  // take advantage of this, otherwise all existing parallel code is
1460  // going to incur additional overhead that really is unnecessary.)
1461  // (In other words, we should be able to do the general case, but
1462  // this capability shouldn't slow down the typical cases too much.)
1463 
1464  typedef std::vector<LField_t*> DestList_t;
1465  typedef std::vector<LField_t*> SrcList_t;
1466  typedef typename DestList_t::iterator DestListIterator_t;
1467  typedef typename SrcList_t::iterator SrcListIterator_t;
1468 
1469  DestList_t dest_list;
1470  SrcList_t src_list;
1471 
1472  dest_list.reserve(1);
1473  src_list.reserve(1);
1474 
1475  typename Field_t::iterator_if lf_i;
1476 
1477 #ifdef PRINT_DEBUG
1478  msg << "Starting dest & src domain calculation." << endl;
1479 #endif
1480 
1481  for (lf_i = A.begin_if(); lf_i != A.end_if(); ++lf_i)
1482  {
1483  LField_t &lf = *lf_i->second;
1484 
1485  // We fill if our allocated domain touches the
1486  // destination slab.
1487 
1488  const Domain_t &lf_allocated = lf.getAllocated();
1489 
1490 #ifdef PRINT_DEBUG
1491  msg << " Processing subdomain : " << lf_allocated << endl;
1492  // stop_here();
1493 #endif
1494 
1495  if (lf_allocated.touches(dest_slab))
1496  dest_list.push_back(&lf);
1497 
1498  // We only provide data if our owned cells touch
1499  // the source slab (although we actually send the
1500  // allocated data).
1501 
1502  const Domain_t &lf_owned = lf.getOwned();
1503 
1504  if (lf_owned.touches(src_slab))
1505  src_list.push_back(&lf);
1506  }
1507 
1508 #ifdef PRINT_DEBUG
1509  msg << " dest_list has " << dest_list.size() << " elements." << endl;
1510  msg << " src_list has " << src_list.size() << " elements." << endl;
1511 #endif
1512 
1513  DestListIterator_t dest_begin = dest_list.begin();
1514  DestListIterator_t dest_end = dest_list.end();
1515  SrcListIterator_t src_begin = src_list.begin();
1516  SrcListIterator_t src_end = src_list.end();
1517 
1518  // Aliases to some of Field A's properties...
1519 
1520  const Layout_t &layout = A.getLayout();
1521  const GuardCellSizes<D> &gc = A.getGuardCellSizes();
1522 
1523  int nprocs = Ippl::getNodes();
1524 
1525  if (nprocs > 1) // Skip send/receive code if we're single-processor.
1526  {
1527 
1528 
1529 #ifdef PRINT_DEBUG
1530  msg << "Starting receive calculation." << endl;
1531  // stop_here();
1532 #endif
1533 
1534  //---------------------------------------------------
1535  // Receive calculation
1536  //---------------------------------------------------
1537 
1538  // Mask indicating the nodes will send us messages.
1539 
1540  std::vector<bool> receive_mask(nprocs,false);
1541 
1542  DestListIterator_t dest_i;
1543 
1544  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
1545  {
1546  // Cache some information about this local array.
1547 
1548  LField_t &dest_lf = **dest_i;
1549 
1550  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
1551 
1552  // Calculate the destination domain in this LField, and the
1553  // source domain (which may be spread across multipple
1554  // processors) from whence that domain will be filled:
1555 
1556  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
1557 
1558  Domain_t src_domain = dest_domain;
1559  src_domain[d] = src_domain[d] + offset;
1560 
1561  // Find the remote LFields that contain src_domain. Note
1562  // that we have to fill from the full allocated domains in
1563  // order to properly fill the corners of the boundary cells,
1564  // BUT we only need to intersect with the physical domain.
1565  // Intersecting the allocated domain would result in
1566  // unnecessary messages. (In fact, only the corners *need* to
1567  // send the allocated domains, but for regular decompositions,
1568  // sending the allocated domains will result in fewer
1569  // messages [albeit larger ones] than sending only from
1570  // physical cells.)
1571 
1572  typename Layout_t::touch_range_dv
1573  src_range(layout.touch_range_rdv(src_domain));
1574 
1575  // src_range is a begin/end pair into a list of remote
1576  // domain/vnode pairs whose physical domains touch
1577  // src_domain. Iterate through this list and set up the
1578  // receive map and the receive mask.
1579 
1580  typename Layout_t::touch_iterator_dv rv_i;
1581 
1582  for (rv_i = src_range.first; rv_i != src_range.second; ++rv_i)
1583  {
1584  // Intersect src_domain with the allocated cells for the
1585  // remote LField (rv_alloc). This will give us the strip
1586  // that will be sent. Translate this domain back to the
1587  // domain of the receiving LField.
1588 
1589  const Domain_t rv_alloc = AddGuardCells(rv_i->first,gc);
1590 
1591  Domain_t hit = src_domain.intersect(rv_alloc);
1592  hit[d] = hit[d] - offset;
1593 
1594  // Save this domain and the LField pointer
1595 
1596  typedef typename ReceiveMap_t::value_type value_type;
1597 
1598  receive_map.insert(value_type(hit,&dest_lf));
1599 
1600 #ifdef PRINT_DEBUG
1601  msg << " Need remote data for domain: " << hit << endl;
1602 #endif
1603 
1604  // Note who will be sending this data
1605 
1606  int rnode = rv_i->second->getNode();
1607 
1608  receive_mask[rnode] = true;
1609 
1610  } // rv_i
1611  } // dest_i
1612 
1613  receive_count = 0;
1614 
1615  for (int iproc = 0; iproc < nprocs; ++iproc)
1616  if (receive_mask[iproc]) ++receive_count;
1617 
1618 
1619 #ifdef PRINT_DEBUG
1620  msg << " Expecting to see " << receive_count << " messages." << endl;
1621  msg << "Done with receive calculation." << endl;
1622  // stop_here();
1623 #endif
1624 
1625 
1626 
1627 
1628 
1629 
1630 #ifdef PRINT_DEBUG
1631  msg << "Starting send calculation" << endl;
1632 #endif
1633 
1634  //---------------------------------------------------
1635  // Send calculation
1636  //---------------------------------------------------
1637 
1638  // Array of messages to be sent.
1639 
1640  std::vector<Message *> messages(nprocs);
1641  for (int miter=0; miter < nprocs; messages[miter++] = 0);
1642 
1643  // Debugging info.
1644 
1645 #ifdef PRINT_DEBUG
1646  // KCC 3.2d has trouble with this. 3.3 doesn't, but
1647  // some are still using 3.2.
1648  // vector<int> ndomains(nprocs,0);
1649  std::vector<int> ndomains(nprocs);
1650  for(int i = 0; i < nprocs; ++i) ndomains[i] = 0;
1651 #endif
1652 
1653  SrcListIterator_t src_i;
1654 
1655  for (src_i = src_begin; src_i != src_end; ++src_i)
1656  {
1657  // Cache some information about this local array.
1658 
1659  LField_t &src_lf = **src_i;
1660 
1661  // We need to send the allocated data to properly fill the
1662  // corners when using periodic BCs in multipple dimensions.
1663  // However, we don't want to send to nodes that only would
1664  // receive data from our guard cells. Thus we do the
1665  // intersection test with our owned data.
1666 
1667  const Domain_t &src_lf_owned = src_lf.getOwned();
1668  const Domain_t &src_lf_alloc = src_lf.getAllocated();
1669 
1670  // Calculate the owned and allocated parts of the source
1671  // domain in this LField, and corresponding destination
1672  // domains.
1673 
1674  const Domain_t src_owned = src_lf_owned.intersect(src_slab);
1675  const Domain_t src_alloc = src_lf_alloc.intersect(src_slab);
1676 
1677  Domain_t dest_owned = src_owned;
1678  dest_owned[d] = dest_owned[d] - offset;
1679 
1680  Domain_t dest_alloc = src_alloc;
1681  dest_alloc[d] = dest_alloc[d] - offset;
1682 
1683 #ifdef PRINT_DEBUG
1684  msg << " Considering LField with the domains:" << endl;
1685  msg << " owned = " << src_lf_owned << endl;
1686  msg << " alloc = " << src_lf_alloc << endl;
1687  msg << " The intersections with src_slab are:" << endl;
1688  msg << " owned = " << src_owned << endl;
1689  msg << " alloc = " << src_alloc << endl;
1690 #endif
1691 
1692  // Find the remote LFields whose allocated cells (note the
1693  // additional "gc" arg) are touched by dest_owned.
1694 
1695  typename Layout_t::touch_range_dv
1696  dest_range(layout.touch_range_rdv(dest_owned,gc));
1697 
1698  typename Layout_t::touch_iterator_dv rv_i;
1699 /*
1700 #ifdef PRINT_DEBUG
1701  msg << " Touch calculation found "
1702  << distance(dest_range.first, dest_range.second)
1703  << " elements." << endl;
1704 #endif
1705 */
1706 
1707  for (rv_i = dest_range.first; rv_i != dest_range.second; ++rv_i)
1708  {
1709  // Find the intersection of the returned domain with the
1710  // allocated version of the translated source domain.
1711  // Translate this intersection back to the source side.
1712 
1713  Domain_t hit = dest_alloc.intersect(rv_i->first);
1714  hit[d] = hit[d] + offset;
1715 
1716  // Find out who owns this remote domain.
1717 
1718  int rnode = rv_i->second->getNode();
1719 
1720 #ifdef PRINT_DEBUG
1721  msg << " Overlap domain = " << rv_i->first << endl;
1722  msg << " Inters. domain = " << hit;
1723  msg << " --> node " << rnode << endl;
1724 #endif
1725 
1726  // Create an LField iterator for this intersection region,
1727  // and try to compress it. (Copied from fillGuardCells -
1728  // not quite sure how this works yet. JAC)
1729 
1730  // storage for LField compression
1731 
1732  Element_t compressed_value;
1733  LFI_t msgval = src_lf.begin(hit, compressed_value);
1734  msgval.TryCompress();
1735 
1736  // Put intersection domain and field data into message
1737 
1738  if (!messages[rnode])
1739  {
1740  messages[rnode] = new Message;
1741  PAssert(messages[rnode]);
1742  }
1743 
1744  messages[rnode]->put(hit); // puts Dim items in Message
1745  messages[rnode]->put(msgval); // puts 3 items in Message
1746 
1747 #ifdef PRINT_DEBUG
1748  ndomains[rnode]++;
1749 #endif
1750  } // rv_i
1751  } // src_i
1752 
1753  // Get message tag.
1754 
1755  bc_comm_tag =
1757 
1758 
1759 
1760  // Send the messages.
1761 
1762  for (int iproc = 0; iproc < nprocs; ++iproc)
1763  {
1764  if (messages[iproc])
1765  {
1766 
1767 #ifdef PRINT_DEBUG
1768  msg << " ParallelPeriodicBCApply: Sending message to node "
1769  << iproc << endl
1770  << " number of domains = " << ndomains[iproc] << endl
1771  << " number of MsgItems = "
1772  << messages[iproc]->size() << endl;
1773 #endif
1774 
1775  Ippl::Comm->send(messages[iproc], iproc, bc_comm_tag);
1776  ++send_count;
1777 
1778  }
1779 
1780  }
1781 
1782 #ifdef PRINT_DEBUG
1783  msg << " Sent " << send_count << " messages" << endl;
1784  msg << "Done with send." << endl;
1785 #endif
1786 
1787 
1788 
1789 
1790 
1791  } // if (nprocs > 1)
1792 
1793 
1794 
1795 
1796  //===========================================================================
1797  // 2. Evaluate local pieces directly.
1798  //===========================================================================
1799 
1800 #ifdef PRINT_DEBUG
1801  msg << "Starting local calculation." << endl;
1802 #endif
1803 
1804  DestListIterator_t dest_i;
1805 
1806  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
1807  {
1808  // Cache some information about this local array.
1809 
1810  LField_t &dest_lf = **dest_i;
1811 
1812  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
1813 
1814  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
1815 
1816  Domain_t src_domain = dest_domain;
1817  src_domain[d] = src_domain[d] + offset;
1818 
1819  SrcListIterator_t src_i;
1820 
1821  for (src_i = src_begin; src_i != src_end; ++src_i)
1822  {
1823  // Cache some information about this local array.
1824 
1825  LField_t &src_lf = **src_i;
1826 
1827  // Unlike fillGuardCells, we need to send the allocated
1828  // data. This is necessary to properly fill the corners
1829  // when using periodic BCs in multipple dimensions.
1830 
1831  const Domain_t &src_lf_owned = src_lf.getOwned();
1832  const Domain_t &src_lf_alloc = src_lf.getAllocated();
1833 
1834  // Only fill from LFields whose physical domain touches
1835  // the translated destination domain.
1836 
1837  if (src_domain.touches(src_lf_owned))
1838  {
1839  // Worry about compression. Should do this right
1840  // (considering the four different combinations), but
1841  // for now just do what the serial version does:
1842 
1843  dest_lf.Uncompress();
1844 
1845  // Calculate the actual source and destination domains.
1846 
1847  Domain_t real_src_domain =
1848  src_domain.intersect(src_lf_alloc);
1849 
1850  Domain_t real_dest_domain = real_src_domain;
1851  real_dest_domain[d] = real_dest_domain[d] - offset;
1852 
1853 #ifdef PRINT_DEBUG
1854  msg << " Copying local data . . ." << endl;
1855  msg << " source domain = " << real_src_domain << endl;
1856  msg << " dest domain = " << real_dest_domain << endl;
1857 #endif
1858 
1859  // Build the iterators for the copy
1860 
1861  LFI_t lhs = dest_lf.begin(real_dest_domain);
1862  LFI_t rhs = src_lf.begin(real_src_domain);
1863 
1864  // And do the assignment:
1865 
1866  if (this->getComponent() == BCondBase<T,D,M,C>::allComponents)
1867  {
1869  (lhs,rhs,OpPeriodic<T>()).apply();
1870  }
1871  else
1872  {
1874  (lhs,rhs,OpPeriodicComponent<T>(this->getComponent())).apply();
1875  }
1876  }
1877  }
1878  }
1879 
1880 #ifdef PRINT_DEBUG
1881  msg << "Done with local calculation." << endl;
1882 #endif
1883 
1884 
1885 
1886 
1887  //===========================================================================
1888  // 3. Receive messages and evaluate remaining pieces.
1889  //===========================================================================
1890 
1891  if (nprocs > 1)
1892  {
1893 
1894 
1895 
1896 #ifdef PRINT_DEBUG
1897  msg << "Starting receive..." << endl;
1898  // stop_here();
1899 #endif
1900 
1901  while (receive_count > 0)
1902  {
1903 
1904  // Receive the next message.
1905 
1906  int any_node = COMM_ANY_NODE;
1907 
1908 
1909 
1910  Message* message =
1911  Ippl::Comm->receive_block(any_node,bc_comm_tag);
1912  PAssert(message);
1913 
1914  --receive_count;
1915 
1916 
1917 
1918  // Determine the number of domains being sent
1919 
1920  int ndomains = message->size() / (D + 3);
1921 
1922 #ifdef PRINT_DEBUG
1923  msg << " Message received from node "
1924  << any_node << "," << endl
1925  << " number of domains = " << ndomains << endl;
1926 #endif
1927 
1928  for (int idomain=0; idomain < ndomains; ++idomain)
1929  {
1930  // Extract the intersection domain from the message
1931  // and translate it to the destination side.
1932 
1933  Domain_t intersection;
1934  intersection.getMessage(*message);
1935  intersection[d] = intersection[d] - offset;
1936 
1937  // Extract the rhs iterator from it.
1938 
1939  Element_t compressed_value;
1940  LFI_t rhs(compressed_value);
1941  rhs.getMessage(*message);
1942 
1943 #ifdef PRINT_DEBUG
1944  msg << " Received remote overlap region = "
1945  << intersection << endl;
1946 #endif
1947 
1948  // Find the LField it is destined for.
1949 
1950  typename ReceiveMap_t::iterator hit =
1951  receive_map.find(intersection);
1952 
1953  PAssert(hit != receive_map.end());
1954 
1955  // Build the lhs brick iterator.
1956 
1957  // Should have been
1958  // LField<T,D> &lf = *hit->second;
1959  // but SGI's 7.2 multimap doesn't have op->().
1960 
1961  LField<T,D> &lf = *(*hit).second;
1962 
1963  // Check and see if we really have to do this.
1964 
1965 #ifdef PRINT_DEBUG
1966  msg << " LHS compressed ? " << lf.IsCompressed();
1967  msg << ", LHS value = " << *lf.begin() << endl;
1968  msg << " RHS compressed ? " << rhs.IsCompressed();
1969  msg << ", RHS value = " << *rhs << endl;
1970  msg << " *rhs == *lf.begin() ? "
1971  << (*rhs == *lf.begin()) << endl;
1972 #endif
1973  if (!(rhs.IsCompressed() && lf.IsCompressed() &&
1974  (*rhs == *lf.begin())))
1975  {
1976  // Yep. gotta do it.
1977 
1978  lf.Uncompress();
1979  LFI_t lhs = lf.begin(intersection);
1980 
1981  // Do the assignment.
1982 
1983 #ifdef PRINT_DEBUG
1984  msg << " Doing copy." << endl;
1985 #endif
1986 
1987  BrickExpression<D,LFI_t,LFI_t,OpAssign>(lhs,rhs).apply();
1988  }
1989 
1990  // Take that entry out of the receive list.
1991 
1992  receive_map.erase(hit);
1993  }
1994 
1995  delete message;
1996  }
1997 
1998 
1999 #ifdef PRINT_DEBUG
2000  msg << "Done with receive." << endl;
2001 #endif
2002 
2003  }
2004 }
2005 
2006 
2008 // BENI adds CalcParallelInterpolationDomain
2010 template <class T, unsigned D, class M>
2011 inline void
2014  NDIndex<D> &src_slab,
2015  int &offset)
2016 {
2017  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
2018  // expression converts the face index to the direction index.
2019 
2020  unsigned d = pf.getFace()/2;
2021 
2022  const NDIndex<D>& domain(A.getDomain());
2023 
2024  if (pf.getFace() & 1) // Odd ("top" or "right") face
2025  {
2026  // The cells that we need to fill start one beyond the last
2027  // physical cell at the "top" and continue to the last guard
2028  // cell. Change "dest_slab" to restrict direction "d" to this
2029  // subdomain.
2030 
2031  src_slab[d] =
2032  Index(domain[d].max() + 1, domain[d].max() + A.leftGuard(d));
2033 
2034  // The offset to the cells that we are going to read; i.e. the
2035  // read domain will be "dest_slab + offset". This is the number of
2036  // physical cells in that direction.
2037 
2038  offset = -domain[d].length();
2039  }
2040  else // Even ("bottom" or "left") face
2041  {
2042  // The cells that we need to fill start with the first guard
2043  // cell on the bottom and continue up through the cell before
2044  // the first physical cell.
2045 
2046  src_slab[d] =
2047  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
2048 
2049  // See above.
2050 
2051  offset = domain[d].length();
2052  }
2053 }
2054 
2055 
2057 //BENI adds parallelInterpo;lationBC apply
2059 template<class T, unsigned D, class M, class C>
2061 {
2062 
2063 #ifdef PRINT_DEBUG
2064  Inform msg("PInterpolationBC", INFORM_ALL_NODES);
2065 #endif
2066 
2067 
2068  // Useful typedefs:
2069 
2070  typedef T Element_t;
2071  typedef NDIndex<D> Domain_t;
2072  typedef LField<T,D> LField_t;
2073  typedef typename LField_t::iterator LFI_t;
2074  typedef Field<T,D,M,C> Field_t;
2075  typedef FieldLayout<D> Layout_t;
2076 
2077  //===========================================================================
2078  //
2079  // Unlike most boundary conditions, periodic BCs are (in general)
2080  // non-local. Indeed, they really are identical to the guard-cell
2081  // seams between LFields internal to the Field. In this case the
2082  // LFields just have a periodic geometry, but the FieldLayout
2083  // doesn't express this, so we duplicate the code, which is quite
2084  // similar to fillGuardCellsr, but somewhat more complicated, here.
2085  // The complications arise from three sources:
2086  //
2087  // - The source and destination domains are offset, not overlapping.
2088  // - Only a subset of all LFields are, in general, involved.
2089  // - The corners must be handled correctly.
2090  //
2091  // Here's the plan:
2092  //
2093  // 0. Calculate source and destination domains.
2094  // 1. Build send and receive lists, and send messages.
2095  // 2. Evaluate local pieces directly.
2096  // 3. Receive messages and evaluate remaining pieces.
2097  //
2098  //===========================================================================
2099 /*
2100 #ifdef PRINT_DEBUG
2101  msg << "Starting BC Calculation for face "
2102  << getFace() << "." << endl;
2103 #endif
2104 */
2105  //===========================================================================
2106  // 0. Calculate destination domain and the offset.
2107  //===========================================================================
2108 
2109  // Find the slab that is the destination. First get the whole
2110  // domain, including guard cells, and then restrict it to the area
2111  // that this BC will fill.
2112 
2113  const NDIndex<D>& domain(A.getDomain());
2114 
2115  NDIndex<D> src_slab = AddGuardCells(domain,A.getGuardCellSizes());
2116 
2117  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
2118  // expression converts the face index to the direction index.
2119 
2120  unsigned d = this->getFace()/2;
2121 
2122  int offset;
2123 
2124  CalcParallelInterpolationDomain(A,*this,src_slab,offset);
2125 
2126  Domain_t dest_slab = src_slab;
2127  dest_slab[d] = dest_slab[d] + offset;
2128 
2129 #ifdef PRINT_DEBUG
2130  msg << "dest_slab = " << dest_slab << endl;
2131  msg << "src_slab = " << src_slab << endl;
2132  // stop_here();
2133 #endif
2134 
2135 
2136  //===========================================================================
2137  // 1. Build send and receive lists and send messages
2138  //===========================================================================
2139 
2140  // Declare these at this scope so that we don't have to duplicate
2141  // the local code. (fillguardcells puts these in the scope of the
2142  // "if (nprocs > 1) { ... }" section, but has to duplicate the
2143  // code for the local fills as a result. The cost of this is a bit
2144  // of stackspace, and the cost of allocating an empty map.)
2145 
2146  // Container for holding Domain -> LField mapping
2147  // so that we can sort out which messages go where.
2148 
2149  typedef std::multimap<Domain_t,LField_t*, std::less<Domain_t> > ReceiveMap_t;
2150 
2151  // (Time this since it allocates an empty map.)
2152 
2153 
2154 
2155  ReceiveMap_t receive_map;
2156 
2157 
2158 
2159  // Number of nodes that will send us messages.
2160 
2161  int receive_count = 0;
2162  int send_count = 0;
2163 
2164  // Communications tag
2165 
2166  int bc_comm_tag;
2167 
2168 
2169  // Next fill the dest_list and src_list, lists of the LFields that
2170  // touch the destination and source domains, respectively.
2171 
2172  // (Do we need this for local-only code???)
2173 
2174  // (Also, if a domain ends up in both lists, it will only be
2175  // involved in local communication. We should structure this code to
2176  // take advantage of this, otherwise all existing parallel code is
2177  // going to incur additional overhead that really is unnecessary.)
2178  // (In other words, we should be able to do the general case, but
2179  // this capability shouldn't slow down the typical cases too much.)
2180 
2181  typedef std::vector<LField_t*> DestList_t;
2182  typedef std::vector<LField_t*> SrcList_t;
2183  typedef typename DestList_t::iterator DestListIterator_t;
2184  typedef typename SrcList_t::iterator SrcListIterator_t;
2185 
2186  DestList_t dest_list;
2187  SrcList_t src_list;
2188 
2189  dest_list.reserve(1);
2190  src_list.reserve(1);
2191 
2192  typename Field_t::iterator_if lf_i;
2193 
2194 #ifdef PRINT_DEBUG
2195  msg << "Starting dest & src domain calculation." << endl;
2196 #endif
2197 
2198  for (lf_i = A.begin_if(); lf_i != A.end_if(); ++lf_i)
2199  {
2200  LField_t &lf = *lf_i->second;
2201 
2202  // We fill if our OWNED domain touches the
2203  // destination slab.
2204 
2205  //const Domain_t &lf_allocated = lf.getAllocated();
2206  const Domain_t &lf_owned = lf.getOwned();
2207 
2208 #ifdef PRINT_DEBUG
2209  msg << " Processing subdomain : " << lf_owned << endl;
2210  // stop_here();
2211 #endif
2212 
2213  if (lf_owned.touches(dest_slab))
2214  dest_list.push_back(&lf);
2215 
2216  // We only provide data if our owned cells touch
2217  // the source slab (although we actually send the
2218  // allocated data).
2219 
2220  const Domain_t &lf_allocated = lf.getAllocated();
2221 
2222  if (lf_allocated.touches(src_slab))
2223  src_list.push_back(&lf);
2224  }
2225 
2226 #ifdef PRINT_DEBUG
2227  msg << " dest_list has " << dest_list.size() << " elements." << endl;
2228  msg << " src_list has " << src_list.size() << " elements." << endl;
2229 #endif
2230 
2231  DestListIterator_t dest_begin = dest_list.begin();
2232  DestListIterator_t dest_end = dest_list.end();
2233  SrcListIterator_t src_begin = src_list.begin();
2234  SrcListIterator_t src_end = src_list.end();
2235 
2236  // Aliases to some of Field A's properties...
2237 
2238  const Layout_t &layout = A.getLayout();
2239  const GuardCellSizes<D> &gc = A.getGuardCellSizes();
2240 
2241  int nprocs = Ippl::getNodes();
2242 
2243  if (nprocs > 1) // Skip send/receive code if we're single-processor.
2244  {
2245 
2246 
2247 #ifdef PRINT_DEBUG
2248  msg << "Starting receive calculation." << endl;
2249  // stop_here();
2250 #endif
2251 
2252  //---------------------------------------------------
2253  // Receive calculation
2254  //---------------------------------------------------
2255 
2256  // Mask indicating the nodes will send us messages.
2257 
2258  std::vector<bool> receive_mask(nprocs,false);
2259 
2260  DestListIterator_t dest_i;
2261 
2262  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
2263  {
2264  // Cache some information about this local array.
2265 
2266  LField_t &dest_lf = **dest_i;
2267 
2268  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
2269 
2270  // Calculate the destination domain in this LField, and the
2271  // source domain (which may be spread across multipple
2272  // processors) from whence that domain will be filled:
2273 
2274  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
2275 
2276  Domain_t src_domain = dest_domain;
2277  //BENI:sign change for offset occurs when we iterate over destination first and calulate
2278  // src domain from dest domain
2279  src_domain[d] = src_domain[d] - offset;
2280 
2281  // Find the remote LFields that contain src_domain. Note
2282  // that we have to fill from the full allocated domains in
2283  // order to properly fill the corners of the boundary cells,
2284  // BUT we only need to intersect with the physical domain.
2285  // Intersecting the allocated domain would result in
2286  // unnecessary messages. (In fact, only the corners *need* to
2287  // send the allocated domains, but for regular decompositions,
2288  // sending the allocated domains will result in fewer
2289  // messages [albeit larger ones] than sending only from
2290  // physical cells.)
2291 
2292 //BENI: include ghost cells for src_range
2293  typename Layout_t::touch_range_dv
2294  src_range(layout.touch_range_rdv(src_domain,gc));
2295 
2296  // src_range is a begin/end pair into a list of remote
2297  // domain/vnode pairs whose physical domains touch
2298  // src_domain. Iterate through this list and set up the
2299  // receive map and the receive mask.
2300 
2301  typename Layout_t::touch_iterator_dv rv_i;
2302 
2303  for (rv_i = src_range.first; rv_i != src_range.second; ++rv_i)
2304  {
2305  // Intersect src_domain with the allocated cells for the
2306  // remote LField (rv_alloc). This will give us the strip
2307  // that will be sent. Translate this domain back to the
2308  // domain of the receiving LField.
2309 
2310  //const Domain_t rv_alloc = AddGuardCells(rv_i->first,gc);
2311  const Domain_t rv_alloc = rv_i->first;
2312 
2313  Domain_t hit = src_domain.intersect(rv_alloc);
2314  //BENI: sign change
2315  hit[d] = hit[d] + offset;
2316 
2317  // Save this domain and the LField pointer
2318 
2319  typedef typename ReceiveMap_t::value_type value_type;
2320 
2321  receive_map.insert(value_type(hit,&dest_lf));
2322 
2323 #ifdef PRINT_DEBUG
2324  msg << " Need remote data for domain: " << hit << endl;
2325 #endif
2326 
2327  // Note who will be sending this data
2328 
2329  int rnode = rv_i->second->getNode();
2330 
2331  receive_mask[rnode] = true;
2332 
2333  } // rv_i
2334  } // dest_i
2335 
2336  receive_count = 0;
2337 
2338  for (int iproc = 0; iproc < nprocs; ++iproc)
2339  if (receive_mask[iproc]) ++receive_count;
2340 
2341 
2342 #ifdef PRINT_DEBUG
2343  msg << " Expecting to see " << receive_count << " messages." << endl;
2344  msg << "Done with receive calculation." << endl;
2345  // stop_here();
2346 #endif
2347 
2348 
2349 
2350 
2351 
2352 
2353 #ifdef PRINT_DEBUG
2354  msg << "Starting send calculation" << endl;
2355 #endif
2356 
2357  //---------------------------------------------------
2358  // Send calculation
2359  //---------------------------------------------------
2360 
2361  // Array of messages to be sent.
2362 
2363  std::vector<Message *> messages(nprocs);
2364  for (int miter=0; miter < nprocs; messages[miter++] = 0);
2365 
2366  // Debugging info.
2367 
2368 #ifdef PRINT_DEBUG
2369  // KCC 3.2d has trouble with this. 3.3 doesn't, but
2370  // some are still using 3.2.
2371  // vector<int> ndomains(nprocs,0);
2372  std::vector<int> ndomains(nprocs);
2373  for(int i = 0; i < nprocs; ++i) ndomains[i] = 0;
2374 #endif
2375 
2376  SrcListIterator_t src_i;
2377 
2378  for (src_i = src_begin; src_i != src_end; ++src_i)
2379  {
2380  // Cache some information about this local array.
2381 
2382  LField_t &src_lf = **src_i;
2383 
2384  // We need to send the allocated data to properly fill the
2385  // corners when using periodic BCs in multipple dimensions.
2386  // However, we don't want to send to nodes that only would
2387  // receive data from our guard cells. Thus we do the
2388  // intersection test with our owned data.
2389 
2390  const Domain_t &src_lf_owned = src_lf.getOwned();
2391  const Domain_t &src_lf_alloc = src_lf.getAllocated();
2392 
2393  // Calculate the owned and allocated parts of the source
2394  // domain in this LField, and corresponding destination
2395  // domains.
2396 
2397  const Domain_t src_owned = src_lf_owned.intersect(src_slab);
2398  const Domain_t src_alloc = src_lf_alloc.intersect(src_slab);
2399 
2400  Domain_t dest_owned = src_owned;
2401  dest_owned[d] = dest_owned[d] + offset;
2402 
2403  Domain_t dest_alloc = src_alloc;
2404  dest_alloc[d] = dest_alloc[d] + offset;
2405 
2406 #ifdef PRINT_DEBUG
2407  msg << " Considering LField with the domains:" << endl;
2408  msg << " owned = " << src_lf_owned << endl;
2409  msg << " alloc = " << src_lf_alloc << endl;
2410  msg << " The intersections with src_slab are:" << endl;
2411  msg << " owned = " << src_owned << endl;
2412  msg << " alloc = " << src_alloc << endl;
2413 #endif
2414 
2415  // Find the remote LFields whose allocated cells (note the
2416  // additional "gc" arg) are touched by dest_owned.
2417 
2418  typename Layout_t::touch_range_dv
2419  dest_range(layout.touch_range_rdv(dest_owned,gc));
2420 
2421  typename Layout_t::touch_iterator_dv rv_i;
2422 /*
2423 #ifdef PRINT_DEBUG
2424  msg << " Touch calculation found "
2425  << distance(dest_range.first, dest_range.second)
2426  << " elements." << endl;
2427 #endif
2428 */
2429 
2430  for (rv_i = dest_range.first; rv_i != dest_range.second; ++rv_i)
2431  {
2432  // Find the intersection of the returned domain with the
2433  // allocated version of the translated source domain.
2434  // Translate this intersection back to the source side.
2435 
2436  Domain_t hit = dest_alloc.intersect(rv_i->first);
2437  hit[d] = hit[d] - offset;
2438 
2439  // Find out who owns this remote domain.
2440 
2441  int rnode = rv_i->second->getNode();
2442 
2443 #ifdef PRINT_DEBUG
2444  msg << " Overlap domain = " << rv_i->first << endl;
2445  msg << " Inters. domain = " << hit;
2446  msg << " --> node " << rnode << endl;
2447 #endif
2448 
2449  // Create an LField iterator for this intersection region,
2450  // and try to compress it. (Copied from fillGuardCells -
2451  // not quite sure how this works yet. JAC)
2452 
2453  // storage for LField compression
2454 
2455  Element_t compressed_value;
2456  LFI_t msgval = src_lf.begin(hit, compressed_value);
2457  msgval.TryCompress();
2458 
2459  // Put intersection domain and field data into message
2460 
2461  if (!messages[rnode])
2462  {
2463  messages[rnode] = new Message;
2464  PAssert(messages[rnode]);
2465  }
2466 
2467  messages[rnode]->put(hit); // puts Dim items in Message
2468  messages[rnode]->put(msgval); // puts 3 items in Message
2469 
2470 #ifdef PRINT_DEBUG
2471  ndomains[rnode]++;
2472 #endif
2473  } // rv_i
2474  } // src_i
2475 
2476  // Get message tag.
2477 
2478  bc_comm_tag =
2480 
2481 
2482 
2483  // Send the messages.
2484 
2485  for (int iproc = 0; iproc < nprocs; ++iproc)
2486  {
2487  if (messages[iproc])
2488  {
2489 
2490 #ifdef PRINT_DEBUG
2491  msg << " ParallelPeriodicBCApply: Sending message to node "
2492  << iproc << endl
2493  << " number of domains = " << ndomains[iproc] << endl
2494  << " number of MsgItems = "
2495  << messages[iproc]->size() << endl;
2496 #endif
2497 
2498  Ippl::Comm->send(messages[iproc], iproc, bc_comm_tag);
2499  ++send_count;
2500 
2501  }
2502 
2503  }
2504 
2505 #ifdef PRINT_DEBUG
2506  msg << " Sent " << send_count << " messages" << endl;
2507  msg << "Done with send." << endl;
2508 #endif
2509 
2510 
2511 
2512 
2513 
2514  } // if (nprocs > 1)
2515 
2516 
2517 
2518 
2519  //===========================================================================
2520  // 2. Evaluate local pieces directly.
2521  //===========================================================================
2522 
2523 #ifdef PRINT_DEBUG
2524  msg << "Starting local calculation." << endl;
2525 #endif
2526 
2527  DestListIterator_t dest_i;
2528 
2529  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
2530  {
2531  // Cache some information about this local array.
2532 
2533  LField_t &dest_lf = **dest_i;
2534 
2535  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
2536  //const Domain_t &dest_lf_owned = dest_lf.getOwned();
2537 
2538  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
2539 
2540  Domain_t src_domain = dest_domain;
2541  //BENI:sign change for offset occurs when we iterate over destination first and calulate
2542  // src domain from dest domain
2543  src_domain[d] = src_domain[d] - offset;
2544 
2545  SrcListIterator_t src_i;
2546 
2547  for (src_i = src_begin; src_i != src_end; ++src_i)
2548  {
2549  // Cache some information about this local array.
2550 
2551  LField_t &src_lf = **src_i;
2552 
2553  // Unlike fillGuardCells, we need to send the allocated
2554  // data. This is necessary to properly fill the corners
2555  // when using periodic BCs in multipple dimensions.
2556 
2557  //const Domain_t &src_lf_owned = src_lf.getOwned();
2558  const Domain_t &src_lf_alloc = src_lf.getAllocated();
2559 
2560  // Only fill from LFields whose physical domain touches
2561  // the translated destination domain.
2562 
2563  if (src_domain.touches(src_lf_alloc))
2564  {
2565  // Worry about compression. Should do this right
2566  // (considering the four different combinations), but
2567  // for now just do what the serial version does:
2568 
2569  dest_lf.Uncompress();
2570 
2571  // Calculate the actual source and destination domains.
2572 
2573  Domain_t real_src_domain =
2574  src_domain.intersect(src_lf_alloc);
2575 
2576  Domain_t real_dest_domain = real_src_domain;
2577  //BENI: same sign change as above
2578  real_dest_domain[d] = real_dest_domain[d] + offset;
2579 
2580 #ifdef PRINT_DEBUG
2581  msg << " Copying local data . . ." << endl;
2582  msg << " source domain = " << real_src_domain << endl;
2583  msg << " dest domain = " << real_dest_domain << endl;
2584 #endif
2585 
2586  // Build the iterators for the copy
2587 
2588  LFI_t lhs = dest_lf.begin(real_dest_domain);
2589  LFI_t rhs = src_lf.begin(real_src_domain);
2590 
2591  // And do the assignment:
2592 
2593  if (this->getComponent() == BCondBase<T,D,M,C>::allComponents)
2594  {
2596  (lhs,rhs,OpInterpolation<T>()).apply();
2597  }
2598  else
2599  {
2601  (lhs,rhs,OpInterpolationComponent<T>(this->getComponent())).apply();
2602  }
2603  }
2604  }
2605  }
2606 
2607 #ifdef PRINT_DEBUG
2608  msg << "Done with local calculation." << endl;
2609 #endif
2610 
2611 
2612 
2613 
2614  //===========================================================================
2615  // 3. Receive messages and evaluate remaining pieces.
2616  //===========================================================================
2617 
2618  if (nprocs > 1)
2619  {
2620 
2621 
2622 
2623 #ifdef PRINT_DEBUG
2624  msg << "Starting receive..." << endl;
2625  // stop_here();
2626 #endif
2627 
2628  while (receive_count > 0)
2629  {
2630 
2631  // Receive the next message.
2632 
2633  int any_node = COMM_ANY_NODE;
2634 
2635 
2636 
2637  Message* message =
2638  Ippl::Comm->receive_block(any_node,bc_comm_tag);
2639  PAssert(message);
2640 
2641  --receive_count;
2642 
2643 
2644 
2645  // Determine the number of domains being sent
2646 
2647  int ndomains = message->size() / (D + 3);
2648 
2649 #ifdef PRINT_DEBUG
2650  msg << " Message received from node "
2651  << any_node << "," << endl
2652  << " number of domains = " << ndomains << endl;
2653 #endif
2654 
2655  for (int idomain=0; idomain < ndomains; ++idomain)
2656  {
2657  // Extract the intersection domain from the message
2658  // and translate it to the destination side.
2659 
2660  Domain_t intersection;
2661  intersection.getMessage(*message);
2662  //BENI:: sign change
2663  intersection[d] = intersection[d] + offset;
2664 
2665  // Extract the rhs iterator from it.
2666 
2667  Element_t compressed_value;
2668  LFI_t rhs(compressed_value);
2669  rhs.getMessage(*message);
2670 
2671 #ifdef PRINT_DEBUG
2672  msg << " Received remote overlap region = "
2673  << intersection << endl;
2674 #endif
2675 
2676  // Find the LField it is destined for.
2677 
2678  typename ReceiveMap_t::iterator hit =
2679  receive_map.find(intersection);
2680 
2681  PAssert(hit != receive_map.end());
2682 
2683  // Build the lhs brick iterator.
2684 
2685  // Should have been
2686  // LField<T,D> &lf = *hit->second;
2687  // but SGI's 7.2 multimap doesn't have op->().
2688 
2689  LField<T,D> &lf = *(*hit).second;
2690 
2691  // Check and see if we really have to do this.
2692 
2693 #ifdef PRINT_DEBUG
2694  msg << " LHS compressed ? " << lf.IsCompressed();
2695  msg << ", LHS value = " << *lf.begin() << endl;
2696  msg << " RHS compressed ? " << rhs.IsCompressed();
2697  msg << ", RHS value = " << *rhs << endl;
2698  msg << " *rhs == *lf.begin() ? "
2699  << (*rhs == *lf.begin()) << endl;
2700 #endif
2701  if (!(rhs.IsCompressed() && lf.IsCompressed() &&
2702  (*rhs == *lf.begin())))
2703  {
2704  // Yep. gotta do it.
2705 
2706  lf.Uncompress();
2707  LFI_t lhs = lf.begin(intersection);
2708 
2709  // Do the assignment.
2710 
2711 #ifdef PRINT_DEBUG
2712  msg << " Doing copy." << endl;
2713 #endif
2714 
2715  //BrickExpression<D,LFI_t,LFI_t,OpAssign>(lhs,rhs).apply();
2717  }
2718 
2719  // Take that entry out of the receive list.
2720 
2721  receive_map.erase(hit);
2722  }
2723 
2724  delete message;
2725  }
2726 
2727 
2728 #ifdef PRINT_DEBUG
2729  msg << "Done with receive." << endl;
2730 #endif
2731 
2732  }
2733 }
2734 
2735 
2736 
2738 
2739 // Applicative templates for ExtrapolateFace:
2740 
2741 // Standard, for applying to all components of elemental type:
2742 template<class T>
2744 {
2745  OpExtrapolate(const T& o, const T& s) : Offset(o), Slope(s) {}
2747 };
2748 template<class T>
2749 inline void PETE_apply(const OpExtrapolate<T>& e, T& a, const T& b)
2750 { a = b*e.Slope + e.Offset; }
2751 
2752 // Special, for applying to single component of multicomponent elemental type:
2753 template<class T>
2755 {
2756  OpExtrapolateComponent(const T& o, const T& s, int c)
2757  : Offset(o), Slope(s), Component(c) {}
2760 };
2761 template<class T>
2762 inline void PETE_apply(const OpExtrapolateComponent<T>& e, T& a, const T& b)
2763 {
2764  a[e.Component] = b[e.Component]*e.Slope[e.Component] + e.Offset[e.Component];
2765 }
2766 
2767 // Following specializations are necessary because of the runtime branches in
2768 // functions like these in code below:
2769 // if (ef.Component == BCondBase<T,D,M,Cell>::allComponents) {
2770 // BrickExpression<D,LFI,LFI,OpExtrapolate<T> >
2771 // (lhs,rhs,OpExtrapolate<T>(ef.Offset,ef.Slope)).apply();
2772 // } else {
2773 // BrickExpression<D,LFI,LFI,OpExtrapolateComponent<T> >
2774 // (lhs,rhs,OpExtrapolateComponent<T>
2775 // (ef.Offset,ef.Slope,ef.Component)).apply();
2776 // }
2777 // which unfortunately force instantiation of OpExtrapolateComponent instances
2778 // for non-multicomponent types like {char,double,...}. Note: if user uses
2779 // non-multicomponent (no operator[]) types of his own, he'll get a compile
2780 // error.
2781 
2784 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,int)
2785 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,unsigned)
2786 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,short)
2787 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,long)
2788 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,float)
2789 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,double)
2790 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,dcomplex)
2791 
2793 
2794 //----------------------------------------------------------------------------
2795 // For unspecified centering, can't implement ExtrapolateFace::apply()
2796 // correctly, and can't partial-specialize yet, so... don't have a prototype
2797 // for unspecified centering, so user gets a compile error if he tries to
2798 // invoke it for a centering not yet implemented. Implement external functions
2799 // which are specializations for the various centerings
2800 // {Cell,Vert,CartesianCentering}; these are called from the general
2801 // ExtrapolateFace::apply() function body.
2802 //----------------------------------------------------------------------------
2803 
2805 
2806 template<class T, unsigned D, class M>
2808  Field<T,D,M,Cell>& A );
2809 template<class T, unsigned D, class M>
2811  Field<T,D,M,Vert>& A );
2812 template<class T, unsigned D, class M>
2814  Field<T,D,M,Edge>& A );
2815 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
2817  CartesianCentering<CE,D,NC> >& ef,
2818  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
2819 
2820 template<class T, unsigned D, class M, class C>
2821 void ExtrapolateFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
2822 {
2823  ExtrapolateFaceBCApply(*this, A);
2824 }
2825 
2826 
2827 //#pragma GCC push_options
2828 //#pragma GCC optimize "no-tree-vrp"
2829 template<class T, unsigned D, class M, class C>
2830 inline void
2832  LField<T,D> &fill, LField<T,D> &from, const NDIndex<D> &from_alloc,
2834 {
2835  // If both the 'fill' and 'from' are compressed and applying the boundary
2836  // condition on the compressed value would result in no change to
2837  // 'fill' we don't need to uncompress.
2838 
2839  if (fill.IsCompressed() && from.IsCompressed())
2840  {
2841  // So far, so good. Let's check to see if the boundary condition
2842  // would result in filling the guard cells with a different value.
2843 
2844  T a = fill.getCompressedData(), aref = a;
2845  T b = from.getCompressedData();
2847  {
2848  OpExtrapolate<T> op(ef.getOffset(),ef.getSlope());
2849  PETE_apply(op, a, b);
2850  }
2851  else
2852  {
2853  int d = (ef.getComponent() % D + D) % D;
2855  op(ef.getOffset(),ef.getSlope(),d);
2856  PETE_apply(op, a, b);
2857  }
2858  if (a == aref)
2859  {
2860  // Yea! We're outta here.
2861 
2862  return;
2863  }
2864  }
2865 
2866  // Well poop, we have no alternative but to uncompress the region
2867  // we're filling.
2868 
2869  fill.Uncompress();
2870 
2871  NDIndex<D> from_it = src.intersect(from_alloc);
2872  NDIndex<D> fill_it = dest.plugBase(from_it);
2873 
2874  // Build iterators for the copy...
2875 
2876  typedef typename LField<T,D>::iterator LFI;
2877  LFI lhs = fill.begin(fill_it);
2878  LFI rhs = from.begin(from_it);
2879 
2880  // And do the assignment.
2881 
2883  {
2885  (lhs,rhs,OpExtrapolate<T>(ef.getOffset(),ef.getSlope())).apply();
2886  }
2887  else
2888  {
2890  (lhs,rhs,OpExtrapolateComponent<T>
2891  (ef.getOffset(),ef.getSlope(),ef.getComponent())).apply();
2892  }
2893 }
2894 //#pragma GCC pop_options
2895 
2896 
2897 //-----------------------------------------------------------------------------
2898 // Specialization of ExtrapolateFace::apply() for Cell centering.
2899 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
2900 //-----------------------------------------------------------------------------
2901 
2902 template<class T, unsigned D, class M>
2904  Field<T,D,M,Cell>& A )
2905 {
2906 
2907 
2908 
2909  // Find the slab that is the destination.
2910  // That is, in English, get an NDIndex spanning elements in the guard layers
2911  // on the face associated with the ExtrapaloteFace object:
2912 
2913  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
2914  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
2915 
2916  // The direction (dimension of the Field) associated with the active face.
2917  // The numbering convention makes this division by two return the right
2918  // value, which will be between 0 and (D-1):
2919 
2920  unsigned d = ef.getFace()/2;
2921  int offset;
2922 
2923  // The following bitwise AND logical test returns true if ef.m_face is odd
2924  // (meaning the "high" or "right" face in the numbering convention) and
2925  // returns false if ef.m_face is even (meaning the "low" or "left" face in
2926  // the numbering convention):
2927 
2928  if (ef.getFace() & 1)
2929  {
2930  // For "high" face, index in active direction goes from max index of
2931  // Field plus 1 to the same plus number of guard layers:
2932  // TJW: this used to say "leftGuard(d)", which I think was wrong:
2933 
2934  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
2935 
2936  // Used in computing interior elements used in computing fill values for
2937  // boundary guard elements; see below:
2938 
2939  offset = 2*domain[d].max() + 1;
2940  }
2941  else
2942  {
2943  // For "low" face, index in active direction goes from min index of
2944  // Field minus the number of guard layers (usually a negative number)
2945  // to the same min index minus 1 (usually negative, and usually -1):
2946 
2947  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
2948 
2949  // Used in computing interior elements used in computing fill values for
2950  // boundary guard elements; see below:
2951 
2952  offset = 2*domain[d].min() - 1;
2953  }
2954 
2955  // Loop over all the LField's in the Field A:
2956 
2957  typename Field<T,D,M,Cell>::iterator_if fill_i;
2958  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
2959  {
2960  // Cache some things we will use often below.
2961  // Pointer to the data for the current LField (right????):
2962 
2963  LField<T,D> &fill = *(*fill_i).second;
2964 
2965  // NDIndex spanning all elements in the LField, including the guards:
2966 
2967  const NDIndex<D> &fill_alloc = fill.getAllocated();
2968 
2969  // If the previously-created boundary guard-layer NDIndex "slab"
2970  // contains any of the elements in this LField (they will be guard
2971  // elements if it does), assign the values into them here by applying
2972  // the boundary condition:
2973 
2974  if (slab.touches(fill_alloc))
2975  {
2976  // Find what it touches in this LField.
2977 
2978  NDIndex<D> dest = slab.intersect(fill_alloc);
2979 
2980  // For extrapolation boundary conditions, the boundary guard-layer
2981  // elements are typically copied from interior values; the "src"
2982  // NDIndex specifies the interior elements to be copied into the
2983  // "dest" boundary guard-layer elements (possibly after some
2984  // mathematical operations like multipplying by minus 1 later):
2985 
2986  NDIndex<D> src = dest;
2987 
2988  // Now calculate the interior elements; the offset variable computed
2989  // above makes this correct for "low" or "high" face cases:
2990 
2991  src[d] = offset - src[d];
2992 
2993  // At this point, we need to see if 'src' is fully contained by
2994  // by 'fill_alloc'. If it is, we have a lot less work to do.
2995 
2996  if (fill_alloc.contains(src))
2997  {
2998  // Great! Our domain contains the elements we're filling from.
2999 
3000  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3001  fill_alloc, ef);
3002  }
3003  else
3004  {
3005  // Yuck! Our domain doesn't contain all of the src. We
3006  // must loop over LFields to find the ones the touch the src.
3007 
3008  typename Field<T,D,M,Cell>::iterator_if from_i;
3009  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3010  {
3011  // Cache a few things.
3012 
3013  LField<T,D> &from = *(*from_i).second;
3014  const NDIndex<D> &from_owned = from.getOwned();
3015  const NDIndex<D> &from_alloc = from.getAllocated();
3016 
3017  // If src touches this LField...
3018 
3019  if (src.touches(from_owned))
3020  ExtrapolateFaceBCApply2(dest, src, fill, from,
3021  from_alloc, ef);
3022  }
3023  }
3024  }
3025  }
3026 }
3027 
3028 
3029 //-----------------------------------------------------------------------------
3030 // Specialization of ExtrapolateFace::apply() for Vert centering.
3031 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
3032 //-----------------------------------------------------------------------------
3033 
3034 template<class T, unsigned D, class M>
3036  Field<T,D,M,Vert>& A )
3037 {
3038 
3039 
3040 
3041  // Find the slab that is the destination.
3042  // That is, in English, get an NDIndex spanning elements in the guard layers
3043  // on the face associated with the ExtrapaloteFace object:
3044 
3045  const NDIndex<D>& domain(A.getDomain());
3046  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3047 
3048  // The direction (dimension of the Field) associated with the active face.
3049  // The numbering convention makes this division by two return the right
3050  // value, which will be between 0 and (D-1):
3051 
3052  unsigned d = ef.getFace()/2;
3053  int offset;
3054 
3055  // The following bitwise AND logical test returns true if ef.m_face is odd
3056  // (meaning the "high" or "right" face in the numbering convention) and
3057  // returns false if ef.m_face is even (meaning the "low" or "left" face
3058  // in the numbering convention):
3059 
3060  if ( ef.getFace() & 1 )
3061  {
3062  // For "high" face, index in active direction goes from max index of
3063  // Field plus 1 to the same plus number of guard layers:
3064  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3065 
3066  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3067 
3068  // Used in computing interior elements used in computing fill values for
3069  // boundary guard elements; see below:
3070  // N.B.: the extra -1 here is what distinguishes this Vert-centered
3071  // implementation from the Cell-centered one:
3072 
3073  offset = 2*domain[d].max() + 1 - 1;
3074  }
3075  else
3076  {
3077  // For "low" face, index in active direction goes from min index of
3078  // Field minus the number of guard layers (usually a negative number)
3079  // to the same min index minus 1 (usually negative, and usually -1):
3080 
3081  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3082  // Used in computing interior elements used in computing fill values for
3083  // boundary guard elements; see below:
3084  // N.B.: the extra +1 here is what distinguishes this Vert-centered
3085  // implementation from the Cell-centered one:
3086 
3087  offset = 2*domain[d].min() - 1 + 1;
3088  }
3089 
3090  // Loop over all the LField's in the Field A:
3091 
3092  typename Field<T,D,M,Vert>::iterator_if fill_i;
3093  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3094  {
3095  // Cache some things we will use often below.
3096  // Pointer to the data for the current LField (right????):
3097 
3098  LField<T,D> &fill = *(*fill_i).second;
3099  // NDIndex spanning all elements in the LField, including the guards:
3100 
3101  const NDIndex<D> &fill_alloc = fill.getAllocated();
3102  // If the previously-created boundary guard-layer NDIndex "slab"
3103  // contains any of the elements in this LField (they will be guard
3104  // elements if it does), assign the values into them here by applying
3105  // the boundary condition:
3106 
3107  if ( slab.touches( fill_alloc ) )
3108  {
3109  // Find what it touches in this LField.
3110 
3111  NDIndex<D> dest = slab.intersect( fill_alloc );
3112 
3113  // For exrapolation boundary conditions, the boundary guard-layer
3114  // elements are typically copied from interior values; the "src"
3115  // NDIndex specifies the interior elements to be copied into the
3116  // "dest" boundary guard-layer elements (possibly after some
3117  // mathematical operations like multipplying by minus 1 later):
3118 
3119  NDIndex<D> src = dest;
3120 
3121  // Now calculate the interior elements; the offset variable computed
3122  // above makes this correct for "low" or "high" face cases:
3123 
3124  src[d] = offset - src[d];
3125 
3126  // At this point, we need to see if 'src' is fully contained by
3127  // by 'fill_alloc'. If it is, we have a lot less work to do.
3128 
3129  if (fill_alloc.contains(src))
3130  {
3131  // Great! Our domain contains the elements we're filling from.
3132 
3133  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3134  fill_alloc, ef);
3135  }
3136  else
3137  {
3138  // Yuck! Our domain doesn't contain all of the src. We
3139  // must loop over LFields to find the ones the touch the src.
3140 
3141  typename Field<T,D,M,Vert>::iterator_if from_i;
3142  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3143  {
3144  // Cache a few things.
3145 
3146  LField<T,D> &from = *(*from_i).second;
3147  const NDIndex<D> &from_owned = from.getOwned();
3148  const NDIndex<D> &from_alloc = from.getAllocated();
3149 
3150  // If src touches this LField...
3151 
3152  if (src.touches(from_owned))
3153  ExtrapolateFaceBCApply2(dest, src, fill, from,
3154  from_alloc, ef);
3155  }
3156  }
3157  }
3158  }
3159 }
3160 
3161 
3162 
3163 //-----------------------------------------------------------------------------
3164 // Specialization of ExtrapolateFace::apply() for Edge centering.
3165 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
3166 //-----------------------------------------------------------------------------
3167 
3168 template<class T, unsigned D, class M>
3170  Field<T,D,M,Edge>& A )
3171 {
3172  // Find the slab that is the destination.
3173  // That is, in English, get an NDIndex spanning elements in the guard layers
3174  // on the face associated with the ExtrapaloteFace object:
3175 
3176  const NDIndex<D>& domain(A.getDomain());
3177  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3178 
3179  // The direction (dimension of the Field) associated with the active face.
3180  // The numbering convention makes this division by two return the right
3181  // value, which will be between 0 and (D-1):
3182 
3183  unsigned d = ef.getFace()/2;
3184  int offset;
3185 
3186  // The following bitwise AND logical test returns true if ef.m_face is odd
3187  // (meaning the "high" or "right" face in the numbering convention) and
3188  // returns false if ef.m_face is even (meaning the "low" or "left" face
3189  // in the numbering convention):
3190 
3191  if ( ef.getFace() & 1 )
3192  {
3193  // For "high" face, index in active direction goes from max index of
3194  // Field plus 1 to the same plus number of guard layers:
3195  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3196 
3197  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3198 
3199  // Used in computing interior elements used in computing fill values for
3200  // boundary guard elements; see below:
3201  // N.B.: the extra -1 here is what distinguishes this Edge-centered
3202  // implementation from the Cell-centered one:
3203 
3204  offset = 2*domain[d].max() + 1 - 1;
3205  }
3206  else
3207  {
3208  // For "low" face, index in active direction goes from min index of
3209  // Field minus the number of guard layers (usually a negative number)
3210  // to the same min index minus 1 (usually negative, and usually -1):
3211 
3212  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3213  // Used in computing interior elements used in computing fill values for
3214  // boundary guard elements; see below:
3215  // N.B.: the extra +1 here is what distinguishes this Edge-centered
3216  // implementation from the Cell-centered one:
3217 
3218  offset = 2*domain[d].min() - 1 + 1;
3219  }
3220 
3221  // Loop over all the LField's in the Field A:
3222 
3223  typename Field<T,D,M,Edge>::iterator_if fill_i;
3224  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3225  {
3226  // Cache some things we will use often below.
3227  // Pointer to the data for the current LField (right????):
3228 
3229  LField<T,D> &fill = *(*fill_i).second;
3230  // NDIndex spanning all elements in the LField, including the guards:
3231 
3232  const NDIndex<D> &fill_alloc = fill.getAllocated();
3233  // If the previously-created boundary guard-layer NDIndex "slab"
3234  // contains any of the elements in this LField (they will be guard
3235  // elements if it does), assign the values into them here by applying
3236  // the boundary condition:
3237 
3238  if ( slab.touches( fill_alloc ) )
3239  {
3240  // Find what it touches in this LField.
3241 
3242  NDIndex<D> dest = slab.intersect( fill_alloc );
3243 
3244  // For exrapolation boundary conditions, the boundary guard-layer
3245  // elements are typically copied from interior values; the "src"
3246  // NDIndex specifies the interior elements to be copied into the
3247  // "dest" boundary guard-layer elements (possibly after some
3248  // mathematical operations like multipplying by minus 1 later):
3249 
3250  NDIndex<D> src = dest;
3251 
3252  // Now calculate the interior elements; the offset variable computed
3253  // above makes this correct for "low" or "high" face cases:
3254 
3255  src[d] = offset - src[d];
3256 
3257  // At this point, we need to see if 'src' is fully contained by
3258  // by 'fill_alloc'. If it is, we have a lot less work to do.
3259 
3260  if (fill_alloc.contains(src))
3261  {
3262  // Great! Our domain contains the elements we're filling from.
3263 
3264  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3265  fill_alloc, ef);
3266  }
3267  else
3268  {
3269  // Yuck! Our domain doesn't contain all of the src. We
3270  // must loop over LFields to find the ones the touch the src.
3271 
3272  typename Field<T,D,M,Edge>::iterator_if from_i;
3273  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3274  {
3275  // Cache a few things.
3276 
3277  LField<T,D> &from = *(*from_i).second;
3278  const NDIndex<D> &from_owned = from.getOwned();
3279  const NDIndex<D> &from_alloc = from.getAllocated();
3280 
3281  // If src touches this LField...
3282 
3283  if (src.touches(from_owned))
3284  ExtrapolateFaceBCApply2(dest, src, fill, from,
3285  from_alloc, ef);
3286  }
3287  }
3288  }
3289  }
3290 }
3291 
3292 
3293 //-----------------------------------------------------------------------------
3294 // Specialization of ExtrapolateFace::apply() for CartesianCentering centering.
3295 // Rather,indirectly-called specialized global function ExtrapolateFaceBCApply:
3296 //-----------------------------------------------------------------------------
3297 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
3301 {
3302 
3303 
3304 
3305  // Find the slab that is the destination.
3306  // That is, in English, get an NDIndex spanning elements in the guard layers
3307  // on the face associated with the ExtrapaloteFace object:
3308 
3309  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
3310  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3311 
3312  // The direction (dimension of the Field) associated with the active face.
3313  // The numbering convention makes this division by two return the right
3314  // value, which will be between 0 and (D-1):
3315 
3316  unsigned d = ef.getFace()/2;
3317  int offset;
3318 
3319  // The following bitwise AND logical test returns true if ef.m_face is odd
3320  // (meaning the "high" or "right" face in the numbering convention) and
3321  // returns false if ef.m_face is even (meaning the "low" or "left" face
3322  // in the numbering convention):
3323 
3324  if ( ef.getFace() & 1 )
3325  {
3326  // offset is used in computing interior elements used in computing fill
3327  // values for boundary guard elements; see below:
3328  // Do the right thing for CELL or VERT centering for this component (or
3329  // all components, if the PeriodicFace object so specifies):
3330 
3331  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
3332  allComponents)
3333  {
3334  // Make sure all components are really centered the same, as assumed:
3335 
3336  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
3337  for (int c=1; c<NC; c++)
3338  {
3339  // Compare other components with 1st
3340  if (CE[c + d*NC] != centering0)
3341  ERRORMSG("ExtrapolateFaceBCApply: BCond thinks all components"
3342  << " have same centering along direction " << d
3343  << ", but it isn't so." << endl);
3344  }
3345 
3346  // Now do the right thing for CELL or VERT centering of
3347  // all components:
3348 
3349  // For "high" face, index in active direction goes from max index of
3350  // Field plus 1 to the same plus number of guard layers:
3351 
3352  slab[d] = Index(domain[d].max() + 1,
3353  domain[d].max() + A.rightGuard(d));
3354 
3355  if (centering0 == CELL)
3356  {
3357  offset = 2*domain[d].max() + 1 ; // CELL case
3358  }
3359  else
3360  {
3361  offset = 2*domain[d].max() + 1 - 1; // VERT case
3362  }
3363  }
3364  else
3365  {
3366  // The BC applies only to one component, not all:
3367  // Do the right thing for CELL or VERT centering of the component:
3368  if (CE[ef.getComponent() + d*NC] == CELL)
3369  {
3370  // For "high" face, index in active direction goes from max index
3371  // of cells in the Field plus 1 to the same plus number of guard
3372  // layers:
3373  int highcell = A.get_mesh().gridSizes[d] - 2;
3374  slab[d] = Index(highcell + 1, highcell + A.rightGuard(d));
3375 
3376  // offset = 2*domain[d].max() + 1 ; // CELL case
3377  offset = 2*highcell + 1 ; // CELL case
3378  }
3379  else
3380  {
3381  // For "high" face, index in active direction goes from max index
3382  // of verts in the Field plus 1 to the same plus number of guard
3383  // layers:
3384  int highvert = A.get_mesh().gridSizes[d] - 1;
3385  slab[d] = Index(highvert + 1, highvert + A.rightGuard(d));
3386 
3387  // offset = 2*domain[d].max() + 1 - 1; // VERT case
3388  offset = 2*highvert + 1 - 1; // VERT case
3389  }
3390  }
3391  }
3392  else
3393  {
3394  // For "low" face, index in active direction goes from min index of
3395  // Field minus the number of guard layers (usually a negative number)
3396  // to the same min index minus 1 (usually negative, and usually -1):
3397 
3398  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3399 
3400  // offset is used in computing interior elements used in computing fill
3401  // values for boundary guard elements; see below:
3402  // Do the right thing for CELL or VERT centering for this component (or
3403  // all components, if the PeriodicFace object so specifies):
3404 
3405  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
3406  allComponents)
3407  {
3408  // Make sure all components are really centered the same, as assumed:
3409 
3410  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
3411  for (int c=1; c<NC; c++)
3412  {
3413  // Compare other components with 1st
3414 
3415  if (CE[c + d*NC] != centering0)
3416  ERRORMSG("ExtrapolateFaceBCApply: BCond thinks all components"
3417  << " have same centering along direction " << d
3418  << ", but it isn't so." << endl);
3419  }
3420 
3421  // Now do the right thing for CELL or VERT centering of all
3422  // components:
3423 
3424  if (centering0 == CELL)
3425  {
3426  offset = 2*domain[d].min() - 1; // CELL case
3427  }
3428  else
3429  {
3430  offset = 2*domain[d].min() - 1 + 1; // VERT case
3431  }
3432  }
3433  else
3434  {
3435  // The BC applies only to one component, not all:
3436  // Do the right thing for CELL or VERT centering of the component:
3437 
3438  if (CE[ef.getComponent() + d*NC] == CELL)
3439  {
3440  offset = 2*domain[d].min() - 1; // CELL case
3441  }
3442  else
3443  {
3444  offset = 2*domain[d].min() - 1 + 1; // VERT case
3445  }
3446  }
3447  }
3448 
3449  // Loop over all the LField's in the Field A:
3450 
3451  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
3452  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3453  {
3454  // Cache some things we will use often below.
3455  // Pointer to the data for the current LField (right????):
3456 
3457  LField<T,D> &fill = *(*fill_i).second;
3458 
3459  // NDIndex spanning all elements in the LField, including the guards:
3460 
3461  const NDIndex<D> &fill_alloc = fill.getAllocated();
3462 
3463  // If the previously-created boundary guard-layer NDIndex "slab"
3464  // contains any of the elements in this LField (they will be guard
3465  // elements if it does), assign the values into them here by applying
3466  // the boundary condition:
3467 
3468  if ( slab.touches( fill_alloc ) )
3469  {
3470  // Find what it touches in this LField.
3471 
3472  NDIndex<D> dest = slab.intersect( fill_alloc );
3473 
3474  // For exrapolation boundary conditions, the boundary guard-layer
3475  // elements are typically copied from interior values; the "src"
3476  // NDIndex specifies the interior elements to be copied into the
3477  // "dest" boundary guard-layer elements (possibly after some
3478  // mathematical operations like multipplying by minus 1 later):
3479 
3480  NDIndex<D> src = dest;
3481 
3482  // Now calculate the interior elements; the offset variable computed
3483  // above makes this correct for "low" or "high" face cases:
3484 
3485  src[d] = offset - src[d];
3486 
3487  // At this point, we need to see if 'src' is fully contained by
3488  // by 'fill_alloc'. If it is, we have a lot less work to do.
3489 
3490  if (fill_alloc.contains(src))
3491  {
3492  // Great! Our domain contains the elements we're filling from.
3493 
3494  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3495  fill_alloc, ef);
3496  }
3497  else
3498  {
3499  // Yuck! Our domain doesn't contain all of the src. We
3500  // must loop over LFields to find the ones the touch the src.
3501 
3502  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if
3503  from_i;
3504  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3505  {
3506  // Cache a few things.
3507 
3508  LField<T,D> &from = *(*from_i).second;
3509  const NDIndex<D> &from_owned = from.getOwned();
3510  const NDIndex<D> &from_alloc = from.getAllocated();
3511 
3512  // If src touches this LField...
3513 
3514  if (src.touches(from_owned))
3515  ExtrapolateFaceBCApply2(dest, src, fill, from,
3516  from_alloc, ef);
3517  }
3518  }
3519  }
3520  }
3521 }
3522 
3523 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
3524 // TJW added 12/16/1997 as per Tecolote Team's request... BEGIN
3526 
3527 // Applicative templates for ExtrapolateAndZeroFace:
3528 
3529 // Standard, for applying to all components of elemental type:
3530 template<class T>
3532 {
3533  OpExtrapolateAndZero(const T& o, const T& s) : Offset(o), Slope(s) {}
3535 };
3536 template<class T>
3537 inline void PETE_apply(const OpExtrapolateAndZero<T>& e, T& a, const T& b)
3538 { a = b*e.Slope + e.Offset; }
3539 
3540 // Special, for applying to single component of multicomponent elemental type:
3541 template<class T>
3543 {
3544  OpExtrapolateAndZeroComponent(const T& o, const T& s, int c)
3545  : Offset(o), Slope(s), Component(c) {}
3548 };
3549 template<class T>
3551  const T& b)
3552 {
3553  a[e.Component] = b[e.Component]*e.Slope[e.Component] + e.Offset[e.Component];
3554 }
3555 
3556 // Following specializations are necessary because of the runtime branches in
3557 // functions like these in code below:
3558 // if (ef.Component == BCondBase<T,D,M,Cell>::allComponents) {
3559 // BrickExpression<D,LFI,LFI,OpExtrapolateAndZero<T> >
3560 // (lhs,rhs,OpExtrapolateAndZero<T>(ef.Offset,ef.Slope)).
3561 // apply();
3562 // } else {
3563 // BrickExpression<D,LFI,LFI,
3564 // OpExtrapolateAndZeroComponent<T> >
3565 // (lhs,rhs,OpExtrapolateAndZeroComponent<T>
3566 // (ef.Offset,ef.Slope,ef.Component)).apply();
3567 // }
3568 // which unfortunately force instantiation of OpExtrapolateAndZeroComponent
3569 // instances for non-multicomponent types like {char,double,...}. Note: if
3570 // user uses non-multicomponent (no operator[]) types of his own, he'll get a
3571 // compile error.
3572 
3575 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,int)
3576 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,unsigned)
3577 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,short)
3578 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,long)
3579 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,float)
3580 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,double)
3581 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,dcomplex)
3582 
3583 // Special, for assigning to single component of multicomponent elemental type:
3584 template<class T>
3586 {
3588  : Component(c) { }
3590 };
3591 
3592 template<class T, class T1>
3593 inline void PETE_apply(const OpAssignComponent<T>& e, T& a, const T1& b)
3594 {
3595  a[e.Component] = b;
3596 }
3597 
3600 COMPONENT_APPLY_BUILTIN(OpAssignComponent,int)
3601 COMPONENT_APPLY_BUILTIN(OpAssignComponent,unsigned)
3602 COMPONENT_APPLY_BUILTIN(OpAssignComponent,short)
3603 COMPONENT_APPLY_BUILTIN(OpAssignComponent,long)
3604 COMPONENT_APPLY_BUILTIN(OpAssignComponent,float)
3605 COMPONENT_APPLY_BUILTIN(OpAssignComponent,double)
3607 
3609 
3610 //----------------------------------------------------------------------------
3611 // For unspecified centering, can't implement ExtrapolateAndZeroFace::apply()
3612 // correctly, and can't partial-specialize yet, so... don't have a prototype
3613 // for unspecified centering, so user gets a compile error if he tries to
3614 // invoke it for a centering not yet implemented. Implement external functions
3615 // which are specializations for the various centerings
3616 // {Cell,Vert,CartesianCentering}; these are called from the general
3617 // ExtrapolateAndZeroFace::apply() function body.
3618 //----------------------------------------------------------------------------
3619 
3621 
3622 template<class T, unsigned D, class M>
3624  Field<T,D,M,Cell>& A );
3625 template<class T, unsigned D, class M>
3627  Field<T,D,M,Vert>& A );
3628 template<class T, unsigned D, class M>
3630  Field<T,D,M,Edge>& A );
3631 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
3633  CartesianCentering<CE,D,NC> >& ef,
3634  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
3635 
3636 template<class T, unsigned D, class M, class C>
3637 void ExtrapolateAndZeroFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
3638 {
3640 }
3641 
3642 
3643 template<class T, unsigned D, class M, class C>
3644 inline void
3646  const NDIndex<D> &src, LField<T,D> &fill, LField<T,D> &from,
3647  const NDIndex<D> &from_alloc, ExtrapolateAndZeroFace<T,D,M,C> &ef)
3648 {
3649  // If both the 'fill' and 'from' are compressed and applying the boundary
3650  // condition on the compressed value would result in no change to
3651  // 'fill' we don't need to uncompress.
3652 
3653  if (fill.IsCompressed() && from.IsCompressed())
3654  {
3655  // So far, so good. Let's check to see if the boundary condition
3656  // would result in filling the guard cells with a different value.
3657 
3658  T a = fill.getCompressedData(), aref = a;
3659  T b = from.getCompressedData();
3661  {
3663  PETE_apply(op, a, b);
3664  }
3665  else
3666  {
3668  op(ef.getOffset(),ef.getSlope(),ef.getComponent());
3669  PETE_apply(op, a, b);
3670  }
3671  if (a == aref)
3672  {
3673  // Yea! We're outta here.
3674 
3675  return;
3676  }
3677  }
3678 
3679  // Well poop, we have no alternative but to uncompress the region
3680  // we're filling.
3681 
3682  fill.Uncompress();
3683 
3684  NDIndex<D> from_it = src.intersect(from_alloc);
3685  NDIndex<D> fill_it = dest.plugBase(from_it);
3686 
3687  // Build iterators for the copy...
3688 
3689  typedef typename LField<T,D>::iterator LFI;
3690  LFI lhs = fill.begin(fill_it);
3691  LFI rhs = from.begin(from_it);
3692 
3693  // And do the assignment.
3694 
3696  {
3698  (lhs, rhs,
3700  }
3701  else
3702  {
3704  (lhs, rhs,
3706  (ef.getOffset(),ef.getSlope(),ef.getComponent())).apply();
3707  }
3708 }
3709 
3710 
3711 template<class T, unsigned D, class M, class C>
3712 inline void
3715 {
3716  // If the LField we're filling is compressed and setting the
3717  // cells/components to zero wouldn't make any difference, we don't
3718  // need to uncompress.
3719 
3720  if (fill.IsCompressed())
3721  {
3722  // So far, so good. Let's check to see if the boundary condition
3723  // would result in filling the guard cells with a different value.
3724 
3726  {
3727  if (fill.getCompressedData() == T(0))
3728  return;
3729  }
3730  else
3731  {
3732  typedef typename AppTypeTraits<T>::Element_t T1;
3733 
3734  //boo-boo for scalar types T a = fill.getCompressedData();
3735  //boo-boo for scalar types if (a[ef.getComponent()] == T1(0))
3736  //boo-boo for scalar types return;
3737 
3738  T a = fill.getCompressedData(), aref = a;
3740  PETE_apply(op, a, T1(0));
3741  if (a == aref)
3742  return;
3743  }
3744  }
3745 
3746  // Well poop, we have no alternative but to uncompress the region
3747  // we're filling.
3748 
3749  fill.Uncompress();
3750 
3751  // Build iterator for the assignment...
3752 
3753  typedef typename LField<T,D>::iterator LFI;
3754  LFI lhs = fill.begin(dest);
3755 
3756  // And do the assignment.
3757 
3759  {
3761  (lhs,PETE_Scalar<T>(T(0)),OpAssign()).apply();
3762  }
3763  else
3764  {
3765  typedef typename AppTypeTraits<T>::Element_t T1;
3766 
3769  (ef.getComponent())).apply();
3770  }
3771 }
3772 
3773 
3774 //-----------------------------------------------------------------------------
3775 // Specialization of ExtrapolateAndZeroFace::apply() for Cell centering.
3776 // Rather, indirectly-called specialized global function
3777 // ExtrapolateAndZeroFaceBCApply
3778 //-----------------------------------------------------------------------------
3779 
3780 template<class T, unsigned D, class M>
3782  Field<T,D,M,Cell>& A )
3783 {
3784 
3785 
3786 
3787  // Find the slab that is the destination.
3788  // That is, in English, get an NDIndex spanning elements in the guard layers
3789  // on the face associated with the ExtrapaloteFace object:
3790 
3791  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
3792  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3793 
3794  // The direction (dimension of the Field) associated with the active face.
3795  // The numbering convention makes this division by two return the right
3796  // value, which will be between 0 and (D-1):
3797 
3798  unsigned d = ef.getFace()/2;
3799  int offset;
3800 
3801  // The following bitwise AND logical test returns true if ef.m_face is odd
3802  // (meaning the "high" or "right" face in the numbering convention) and
3803  // returns false if ef.m_face is even (meaning the "low" or "left" face
3804  // in the numbering convention):
3805 
3806  if (ef.getFace() & 1)
3807  {
3808  // For "high" face, index in active direction goes from max index of
3809  // Field plus 1 to the same plus number of guard layers:
3810  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3811 
3812  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3813 
3814  // Used in computing interior elements used in computing fill values for
3815  // boundary guard elements; see below:
3816 
3817  offset = 2*domain[d].max() + 1;
3818  }
3819  else
3820  {
3821  // For "low" face, index in active direction goes from min index of
3822  // Field minus the number of guard layers (usually a negative number)
3823  // to the same min index minus 1 (usually negative, and usually -1):
3824 
3825  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3826 
3827  // Used in computing interior elements used in computing fill values for
3828  // boundary guard elements; see below:
3829 
3830  offset = 2*domain[d].min() - 1;
3831  }
3832 
3833  // Loop over all the LField's in the Field A:
3834 
3835  typename Field<T,D,M,Cell>::iterator_if fill_i;
3836  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3837  {
3838  // Cache some things we will use often below.
3839  // Pointer to the data for the current LField (right????):
3840 
3841  LField<T,D> &fill = *(*fill_i).second;
3842 
3843  // NDIndex spanning all elements in the LField, including the guards:
3844 
3845  const NDIndex<D> &fill_alloc = fill.getAllocated();
3846 
3847  // If the previously-created boundary guard-layer NDIndex "slab"
3848  // contains any of the elements in this LField (they will be guard
3849  // elements if it does), assign the values into them here by applying
3850  // the boundary condition:
3851 
3852  if (slab.touches(fill_alloc))
3853  {
3854  // Find what it touches in this LField.
3855 
3856  NDIndex<D> dest = slab.intersect(fill_alloc);
3857 
3858  // For extrapolation boundary conditions, the boundary guard-layer
3859  // elements are typically copied from interior values; the "src"
3860  // NDIndex specifies the interior elements to be copied into the
3861  // "dest" boundary guard-layer elements (possibly after some
3862  // mathematical operations like multipplying by minus 1 later):
3863 
3864  NDIndex<D> src = dest;
3865 
3866  // Now calculate the interior elements; the offset variable computed
3867  // above makes this correct for "low" or "high" face cases:
3868 
3869  src[d] = offset - src[d];
3870 
3871  // At this point, we need to see if 'src' is fully contained by
3872  // by 'fill_alloc'. If it is, we have a lot less work to do.
3873 
3874  if (fill_alloc.contains(src))
3875  {
3876  // Great! Our domain contains the elements we're filling from.
3877 
3878  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
3879  fill_alloc, ef);
3880  }
3881  else
3882  {
3883  // Yuck! Our domain doesn't contain all of the src. We
3884  // must loop over LFields to find the ones the touch the src.
3885 
3886  typename Field<T,D,M,Cell>::iterator_if from_i;
3887  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3888  {
3889  // Cache a few things.
3890 
3891  LField<T,D> &from = *(*from_i).second;
3892  const NDIndex<D> &from_owned = from.getOwned();
3893  const NDIndex<D> &from_alloc = from.getAllocated();
3894 
3895  // If src touches this LField...
3896 
3897  if (src.touches(from_owned))
3898  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
3899  from_alloc, ef);
3900  }
3901  }
3902  }
3903  }
3904 }
3905 
3906 
3907 //-----------------------------------------------------------------------------
3908 // Specialization of ExtrapolateAndZeroFace::apply() for Vert centering.
3909 // Rather, indirectly-called specialized global function
3910 // ExtrapolateAndZeroFaceBCApply
3911 //-----------------------------------------------------------------------------
3912 
3913 template<class T, unsigned D, class M>
3915  Field<T,D,M,Vert>& A )
3916 {
3917 
3918  // Find the slab that is the destination.
3919  // That is, in English, get an NDIndex spanning elements in the guard layers
3920  // on the face associated with the ExtrapaloteFace object:
3921 
3922  const NDIndex<D>& domain(A.getDomain());
3923  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3924  //boo-boo-2 NDIndex<D> phys = domain;
3925  NDIndex<D> phys = slab;
3926 
3927  // The direction (dimension of the Field) associated with the active face.
3928  // The numbering convention makes this division by two return the right
3929  // value, which will be between 0 and (D-1):
3930 
3931  unsigned d = ef.getFace()/2;
3932  int offset;
3933 
3934  // The following bitwise AND logical test returns true if ef.m_face is odd
3935  // (meaning the "high" or "right" face in the numbering convention) and
3936  // returns false if ef.m_face is even (meaning the "low" or "left" face in
3937  // the numbering convention):
3938 
3939  if ( ef.getFace() & 1 )
3940  {
3941  // For "high" face, index in active direction goes from max index of
3942  // Field plus 1 to the same plus number of guard layers:
3943  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3944 
3945  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3946 
3947  // Compute the layer of physical cells we're going to set.
3948 
3949  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
3950 
3951  // Used in computing interior elements used in computing fill values for
3952  // boundary guard elements; see below:
3953  // N.B.: the extra -1 here is what distinguishes this Vert-centered
3954  // implementation from the Cell-centered one:
3955 
3956  offset = 2*domain[d].max() + 1 - 1;
3957  }
3958  else
3959  {
3960  // For "low" face, index in active direction goes from min index of
3961  // Field minus the number of guard layers (usually a negative number)
3962  // to the same min index minus 1 (usually negative, and usually -1):
3963 
3964  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3965 
3966  // Compute the layer of physical cells we're going to set.
3967 
3968  phys[d] = Index( domain[d].min(), domain[d].min(), 1);
3969 
3970  // Used in computing interior elements used in computing fill values for
3971  // boundary guard elements; see below:
3972  // N.B.: the extra +1 here is what distinguishes this Vert-centered
3973  // implementation from the Cell-centered one:
3974 
3975  offset = 2*domain[d].min() - 1 + 1;
3976  }
3977 
3978  // Loop over all the LField's in the Field A:
3979 
3980  typename Field<T,D,M,Vert>::iterator_if fill_i;
3981  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3982  {
3983  // Cache some things we will use often below.
3984  // Pointer to the data for the current LField (right????):
3985 
3986  LField<T,D> &fill = *(*fill_i).second;
3987 
3988  // Get the physical part of this LField and see if that touches
3989  // the physical cells we want to zero.
3990 
3991  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
3992  const NDIndex<D> &fill_alloc = fill.getAllocated();
3993 
3994  //boo-boo-2 if (phys.touches(fill_owned))
3995  if (phys.touches(fill_alloc))
3996  {
3997  // Find out what we're touching.
3998 
3999  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
4000  NDIndex<D> dest = phys.intersect(fill_alloc);
4001 
4002  // Zero the cells.
4003 
4004  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
4005  }
4006 
4007  // NDIndex spanning all elements in the LField, including the guards:
4008 
4009  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
4010 
4011  // If the previously-created boundary guard-layer NDIndex "slab"
4012  // contains any of the elements in this LField (they will be guard
4013  // elements if it does), assign the values into them here by applying
4014  // the boundary condition:
4015 
4016  if ( slab.touches( fill_alloc ) )
4017  {
4018  // Find what it touches in this LField.
4019 
4020  NDIndex<D> dest = slab.intersect( fill_alloc );
4021 
4022  // For exrapolation boundary conditions, the boundary guard-layer
4023  // elements are typically copied from interior values; the "src"
4024  // NDIndex specifies the interior elements to be copied into the
4025  // "dest" boundary guard-layer elements (possibly after some
4026  // mathematical operations like multipplying by minus 1 later):
4027 
4028  NDIndex<D> src = dest;
4029 
4030  // Now calculate the interior elements; the offset variable computed
4031  // above makes this correct for "low" or "high" face cases:
4032 
4033  src[d] = offset - src[d];
4034 
4035  // At this point, we need to see if 'src' is fully contained by
4036  // by 'fill_alloc'. If it is, we have a lot less work to do.
4037 
4038  if (fill_alloc.contains(src))
4039  {
4040  // Great! Our domain contains the elements we're filling from.
4041 
4042  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4043  fill_alloc, ef);
4044  }
4045  else
4046  {
4047  // Yuck! Our domain doesn't contain all of the src. We
4048  // must loop over LFields to find the ones the touch the src.
4049 
4050  typename Field<T,D,M,Vert>::iterator_if from_i;
4051  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4052  {
4053  // Cache a few things.
4054 
4055  LField<T,D> &from = *(*from_i).second;
4056  const NDIndex<D> &from_owned = from.getOwned();
4057  const NDIndex<D> &from_alloc = from.getAllocated();
4058 
4059  // If src touches this LField...
4060 
4061  if (src.touches(from_owned))
4062  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4063  from_alloc, ef);
4064  }
4065  }
4066  }
4067  }
4068 }
4069 
4070 
4071 //-----------------------------------------------------------------------------
4072 // Specialization of ExtrapolateAndZeroFace::apply() for Edge centering.
4073 // Rather, indirectly-called specialized global function
4074 // ExtrapolateAndZeroFaceBCApply
4075 //-----------------------------------------------------------------------------
4076 
4077 template<class T, unsigned D, class M>
4079  Field<T,D,M,Edge>& A )
4080 {
4081  // Find the slab that is the destination.
4082  // That is, in English, get an NDIndex spanning elements in the guard layers
4083  // on the face associated with the ExtrapaloteFace object:
4084 
4085  const NDIndex<D>& domain(A.getDomain());
4086  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4087  //boo-boo-2 NDIndex<D> phys = domain;
4088  NDIndex<D> phys = slab;
4089 
4090  // The direction (dimension of the Field) associated with the active face.
4091  // The numbering convention makes this division by two return the right
4092  // value, which will be between 0 and (D-1):
4093 
4094  unsigned d = ef.getFace()/2;
4095  int offset;
4096 
4097  // The following bitwise AND logical test returns true if ef.m_face is odd
4098  // (meaning the "high" or "right" face in the numbering convention) and
4099  // returns false if ef.m_face is even (meaning the "low" or "left" face in
4100  // the numbering convention):
4101 
4102  if ( ef.getFace() & 1 )
4103  {
4104  // For "high" face, index in active direction goes from max index of
4105  // Field plus 1 to the same plus number of guard layers:
4106  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4107 
4108  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4109 
4110  // Compute the layer of physical cells we're going to set.
4111 
4112  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
4113 
4114  // Used in computing interior elements used in computing fill values for
4115  // boundary guard elements; see below:
4116  // N.B.: the extra -1 here is what distinguishes this Edge-centered
4117  // implementation from the Cell-centered one:
4118 
4119  offset = 2*domain[d].max() + 1 - 1;
4120  }
4121  else
4122  {
4123  // For "low" face, index in active direction goes from min index of
4124  // Field minus the number of guard layers (usually a negative number)
4125  // to the same min index minus 1 (usually negative, and usually -1):
4126 
4127  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4128 
4129  // Compute the layer of physical cells we're going to set.
4130 
4131  phys[d] = Index( domain[d].min(), domain[d].min(), 1);
4132 
4133  // Used in computing interior elements used in computing fill values for
4134  // boundary guard elements; see below:
4135  // N.B.: the extra +1 here is what distinguishes this Edge-centered
4136  // implementation from the Cell-centered one:
4137 
4138  offset = 2*domain[d].min() - 1 + 1;
4139  }
4140 
4141  // Loop over all the LField's in the Field A:
4142 
4143  typename Field<T,D,M,Edge>::iterator_if fill_i;
4144  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4145  {
4146  // Cache some things we will use often below.
4147  // Pointer to the data for the current LField (right????):
4148 
4149  LField<T,D> &fill = *(*fill_i).second;
4150 
4151  // Get the physical part of this LField and see if that touches
4152  // the physical cells we want to zero.
4153 
4154  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
4155  const NDIndex<D> &fill_alloc = fill.getAllocated();
4156 
4157  //boo-boo-2 if (phys.touches(fill_owned))
4158  if (phys.touches(fill_alloc))
4159  {
4160  // Find out what we're touching.
4161 
4162  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
4163  NDIndex<D> dest = phys.intersect(fill_alloc);
4164 
4165  // Zero the cells.
4166 
4167  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
4168  }
4169 
4170  // NDIndex spanning all elements in the LField, including the guards:
4171 
4172  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
4173 
4174  // If the previously-created boundary guard-layer NDIndex "slab"
4175  // contains any of the elements in this LField (they will be guard
4176  // elements if it does), assign the values into them here by applying
4177  // the boundary condition:
4178 
4179  if ( slab.touches( fill_alloc ) )
4180  {
4181  // Find what it touches in this LField.
4182 
4183  NDIndex<D> dest = slab.intersect( fill_alloc );
4184 
4185  // For exrapolation boundary conditions, the boundary guard-layer
4186  // elements are typically copied from interior values; the "src"
4187  // NDIndex specifies the interior elements to be copied into the
4188  // "dest" boundary guard-layer elements (possibly after some
4189  // mathematical operations like multipplying by minus 1 later):
4190 
4191  NDIndex<D> src = dest;
4192 
4193  // Now calculate the interior elements; the offset variable computed
4194  // above makes this correct for "low" or "high" face cases:
4195 
4196  src[d] = offset - src[d];
4197 
4198  // At this point, we need to see if 'src' is fully contained by
4199  // by 'fill_alloc'. If it is, we have a lot less work to do.
4200 
4201  if (fill_alloc.contains(src))
4202  {
4203  // Great! Our domain contains the elements we're filling from.
4204 
4205  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4206  fill_alloc, ef);
4207  }
4208  else
4209  {
4210  // Yuck! Our domain doesn't contain all of the src. We
4211  // must loop over LFields to find the ones the touch the src.
4212 
4213  typename Field<T,D,M,Edge>::iterator_if from_i;
4214  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4215  {
4216  // Cache a few things.
4217 
4218  LField<T,D> &from = *(*from_i).second;
4219  const NDIndex<D> &from_owned = from.getOwned();
4220  const NDIndex<D> &from_alloc = from.getAllocated();
4221 
4222  // If src touches this LField...
4223 
4224  if (src.touches(from_owned))
4225  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4226  from_alloc, ef);
4227  }
4228  }
4229  }
4230  }
4231 }
4232 
4233 //-----------------------------------------------------------------------------
4234 // Specialization of ExtrapolateAndZeroFace::apply() for CartesianCentering
4235 // centering. Rather,indirectly-called specialized global function
4236 // ExtrapolateAndZeroFaceBCApply:
4237 //-----------------------------------------------------------------------------
4238 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
4242 {
4243 
4244  // Find the slab that is the destination.
4245  // That is, in English, get an NDIndex spanning elements in the guard layers
4246  // on the face associated with the ExtrapaloteFace object:
4247 
4248  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
4249  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4250  //boo-boo-2 NDIndex<D> phys = domain;
4251  NDIndex<D> phys = slab;
4252 
4253  // The direction (dimension of the Field) associated with the active face.
4254  // The numbering convention makes this division by two return the right
4255  // value, which will be between 0 and (D-1):
4256 
4257  unsigned d = ef.getFace()/2;
4258  int offset;
4259  bool setPhys = false;
4260 
4261  // The following bitwise AND logical test returns true if ef.m_face is odd
4262  // (meaning the "high" or "right" face in the numbering convention) and
4263  // returns false if ef.m_face is even (meaning the "low" or "left" face in
4264  // the numbering convention):
4265 
4266  if ( ef.getFace() & 1 )
4267  {
4268  // offset is used in computing interior elements used in computing fill
4269  // values for boundary guard elements; see below:
4270  // Do the right thing for CELL or VERT centering for this component (or
4271  // all components, if the PeriodicFace object so specifies):
4272 
4273  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
4274  allComponents)
4275  {
4276  // Make sure all components are really centered the same, as assumed:
4277 
4278  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4279  for (int c=1; c<NC; c++)
4280  {
4281  // Compare other components with 1st
4282  if (CE[c + d*NC] != centering0)
4283  ERRORMSG(
4284  "ExtrapolateAndZeroFaceBCApply: BCond thinks all components"
4285  << " have same centering along direction " << d
4286  << ", but it isn't so." << endl);
4287  }
4288 
4289  // Now do the right thing for CELL or VERT centering of
4290  // all components:
4291 
4292  // For "high" face, index in active direction goes from max index of
4293  // Field plus 1 to the same plus number of guard layers:
4294 
4295  slab[d] = Index(domain[d].max() + 1,
4296  domain[d].max() + A.rightGuard(d));
4297 
4298  if (centering0 == CELL)
4299  {
4300  offset = 2*domain[d].max() + 1 ; // CELL case
4301  }
4302  else
4303  {
4304  offset = 2*domain[d].max() + 1 - 1; // VERT case
4305 
4306  // Compute the layer of physical cells we're going to set.
4307 
4308  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
4309  setPhys = true;
4310  }
4311  }
4312  else
4313  {
4314  // The BC applies only to one component, not all:
4315  // Do the right thing for CELL or VERT centering of the component:
4316  if (CE[ef.getComponent() + d*NC] == CELL)
4317  {
4318  // For "high" face, index in active direction goes from max index
4319  // of cells in the Field plus 1 to the same plus number of guard
4320  // layers:
4321  int highcell = A.get_mesh().gridSizes[d] - 2;
4322  slab[d] = Index(highcell + 1, highcell + A.rightGuard(d));
4323 
4324  // offset = 2*domain[d].max() + 1 ; // CELL case
4325  offset = 2*highcell + 1 ; // CELL case
4326  }
4327  else
4328  {
4329  // For "high" face, index in active direction goes from max index
4330  // of verts in the Field plus 1 to the same plus number of guard
4331  // layers:
4332 
4333  int highvert = A.get_mesh().gridSizes[d] - 1;
4334  slab[d] = Index(highvert + 1, highvert + A.rightGuard(d));
4335 
4336  // offset = 2*domain[d].max() + 1 - 1; // VERT case
4337 
4338  offset = 2*highvert + 1 - 1; // VERT case
4339 
4340  // Compute the layer of physical cells we're going to set.
4341 
4342  phys[d] = Index( highvert, highvert, 1 );
4343  setPhys = true;
4344  }
4345  }
4346  }
4347  else
4348  {
4349  // For "low" face, index in active direction goes from min index of
4350  // Field minus the number of guard layers (usually a negative number)
4351  // to the same min index minus 1 (usually negative, and usually -1):
4352 
4353  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4354 
4355  // offset is used in computing interior elements used in computing fill
4356  // values for boundary guard elements; see below:
4357  // Do the right thing for CELL or VERT centering for this component (or
4358  // all components, if the PeriodicFace object so specifies):
4359 
4360  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
4361  allComponents)
4362  {
4363  // Make sure all components are really centered the same, as assumed:
4364 
4365  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4366  for (int c=1; c<NC; c++)
4367  {
4368  // Compare other components with 1st
4369 
4370  if (CE[c + d*NC] != centering0)
4371  ERRORMSG(
4372  "ExtrapolateAndZeroFaceBCApply: BCond thinks all components"
4373  << " have same centering along direction " << d
4374  << ", but it isn't so." << endl);
4375  }
4376 
4377  // Now do the right thing for CELL or VERT centering of all
4378  // components:
4379 
4380  if (centering0 == CELL)
4381  {
4382  offset = 2*domain[d].min() - 1; // CELL case
4383  }
4384  else
4385  {
4386  offset = 2*domain[d].min() - 1 + 1; // VERT case
4387 
4388  // Compute the layer of physical cells we're going to set.
4389 
4390  phys[d] = Index(domain[d].min(), domain[d].min(), 1);
4391  setPhys = true;
4392  }
4393  }
4394  else
4395  {
4396  // The BC applies only to one component, not all:
4397  // Do the right thing for CELL or VERT centering of the component:
4398 
4399  if (CE[ef.getComponent() + d*NC] == CELL)
4400  {
4401  offset = 2*domain[d].min() - 1; // CELL case
4402  }
4403  else
4404  {
4405  offset = 2*domain[d].min() - 1 + 1; // VERT case
4406 
4407  // Compute the layer of physical cells we're going to set.
4408 
4409  phys[d] = Index(domain[d].min(), domain[d].min(), 1);
4410  setPhys = true;
4411  }
4412  }
4413  }
4414 
4415  // Loop over all the LField's in the Field A:
4416 
4417  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
4418  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4419  {
4420  // Cache some things we will use often below.
4421  // Pointer to the data for the current LField (right????):
4422 
4423  LField<T,D> &fill = *(*fill_i).second;
4424 
4425  // Get the physical part of this LField and see if that touches
4426  // the physical cells we want to zero.
4427 
4428  const NDIndex<D> &fill_alloc = fill.getAllocated(); // moved here 1/27/99
4429 
4430  if (setPhys)
4431  {
4432  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
4433 
4434  //boo-boo-2 if (phys.touches(fill_owned))
4435  if (phys.touches(fill_alloc))
4436  {
4437  // Find out what we're touching.
4438 
4439  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
4440  NDIndex<D> dest = phys.intersect(fill_alloc);
4441 
4442  // Zero the cells.
4443 
4444  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
4445  }
4446  }
4447 
4448  // NDIndex spanning all elements in the LField, including the guards:
4449 
4450  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
4451 
4452  // If the previously-created boundary guard-layer NDIndex "slab"
4453  // contains any of the elements in this LField (they will be guard
4454  // elements if it does), assign the values into them here by applying
4455  // the boundary condition:
4456 
4457  if ( slab.touches( fill_alloc ) )
4458  {
4459  // Find what it touches in this LField.
4460 
4461  NDIndex<D> dest = slab.intersect( fill_alloc );
4462 
4463  // For extrapolation boundary conditions, the boundary guard-layer
4464  // elements are typically copied from interior values; the "src"
4465  // NDIndex specifies the interior elements to be copied into the
4466  // "dest" boundary guard-layer elements (possibly after some
4467  // mathematical operations like multipplying by minus 1 later):
4468 
4469  NDIndex<D> src = dest;
4470 
4471  // Now calculate the interior elements; the offset variable computed
4472  // above makes this correct for "low" or "high" face cases:
4473 
4474  src[d] = offset - src[d];
4475 
4476  // At this point, we need to see if 'src' is fully contained by
4477  // by 'fill_alloc'. If it is, we have a lot less work to do.
4478 
4479  if (fill_alloc.contains(src))
4480  {
4481  // Great! Our domain contains the elements we're filling from.
4482 
4483  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4484  fill_alloc, ef);
4485  }
4486  else
4487  {
4488  // Yuck! Our domain doesn't contain all of the src. We
4489  // must loop over LFields to find the ones the touch the src.
4490 
4491  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if
4492  from_i;
4493  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4494  {
4495  // Cache a few things.
4496 
4497  LField<T,D> &from = *(*from_i).second;
4498  const NDIndex<D> &from_owned = from.getOwned();
4499  const NDIndex<D> &from_alloc = from.getAllocated();
4500 
4501  // If src touches this LField...
4502 
4503  if (src.touches(from_owned))
4504  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4505  from_alloc, ef);
4506  }
4507  }
4508  }
4509  }
4510 
4511 }
4512 
4513 // TJW added 12/16/1997 as per Tecolote Team's request... END
4514 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
4515 
4517 
4518 // Applicative templates for FunctionFace:
4519 
4520 // Standard, for applying to all components of elemental type:
4521 template<class T>
4523 {
4524  OpBCFunctionEq(T (*func)(const T&)) : Func(func) {}
4525  T (*Func)(const T&);
4526 };
4527 template<class T>
4528 //tjw3/12/1999inline void PETE_apply(const OpBCFunctionEq<T>& e, T& a, const T& b)
4529 inline void PETE_apply(const OpBCFunctionEq<T>& e, T& a, T& b)
4530 {
4531  a = e.Func(b);
4532 }
4533 
4534 // Special, for applying to single component of multicomponent elemental type:
4535 // DOESN'T EXIST FOR FunctionFace; use ComponentFunctionFace instead.
4536 
4538 
4539 //----------------------------------------------------------------------------
4540 // For unspecified centering, can't implement FunctionFace::apply()
4541 // correctly, and can't partial-specialize yet, so... don't have a prototype
4542 // for unspecified centering, so user gets a compile error if he tries to
4543 // invoke it for a centering not yet implemented. Implement external functions
4544 // which are specializations for the various centerings
4545 // {Cell,Vert,CartesianCentering}; these are called from the general
4546 // FunctionFace::apply() function body.
4547 //----------------------------------------------------------------------------
4548 
4550 
4551 template<class T, unsigned D, class M>
4553  Field<T,D,M,Cell>& A );
4554 template<class T, unsigned D, class M>
4556  Field<T,D,M,Vert>& A );
4557 template<class T, unsigned D, class M>
4559  Field<T,D,M,Edge>& A );
4560 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
4563  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
4564 
4565 template<class T, unsigned D, class M, class C>
4567 {
4568 
4569 
4570  FunctionFaceBCApply(*this, A);
4571 }
4572 
4573 //-----------------------------------------------------------------------------
4574 // Specialization of FunctionFace::apply() for Cell centering.
4575 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4576 //-----------------------------------------------------------------------------
4577 template<class T, unsigned D, class M>
4579  Field<T,D,M,Cell>& A )
4580 {
4581 
4582 
4583 
4584  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4585  // comprehensible comments --TJW
4586 
4587  // Find the slab that is the destination.
4588  const NDIndex<D>& domain( A.getDomain() );
4589  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4590  unsigned d = ff.getFace()/2;
4591  int offset;
4592  if ( ff.getFace() & 1 ) {
4593  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4594  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4595  offset = 2*domain[d].max() + 1;
4596  }
4597  else {
4598  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4599  offset = 2*domain[d].min() - 1;
4600  }
4601 
4602  // Loop over the ones the slab touches.
4603  typename Field<T,D,M,Cell>::iterator_if fill_i;
4604  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4605  {
4606  // Cache some things we will use often below.
4607  LField<T,D> &fill = *(*fill_i).second;
4608  const NDIndex<D> &fill_alloc = fill.getAllocated();
4609  if ( slab.touches( fill_alloc ) )
4610  {
4611  // Find what it touches in this LField.
4612  NDIndex<D> dest = slab.intersect( fill_alloc );
4613 
4614  // Find where that comes from.
4615  NDIndex<D> src = dest;
4616  src[d] = offset - src[d];
4617 
4618  // Loop over the ones that src touches.
4619  typename Field<T,D,M,Cell>::iterator_if from_i;
4620  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4621  {
4622  // Cache a few things.
4623  LField<T,D> &from = *(*from_i).second;
4624  const NDIndex<D> &from_owned = from.getOwned();
4625  const NDIndex<D> &from_alloc = from.getAllocated();
4626  // If src touches this LField...
4627  if ( src.touches( from_owned ) )
4628  {
4629  // bfh: Worry about compression ...
4630  // If 'fill' is a compressed LField, then writing data into
4631  // it via the expression will actually write the value for
4632  // all elements of the LField. We can do the following:
4633  // a) figure out if the 'fill' elements are all the same
4634  // value, if 'from' elements are the same value, if
4635  // the 'fill' elements are the same as the elements
4636  // throughout that LField, and then just do an
4637  // assigment for a single element
4638  // b) just uncompress the 'fill' LField, to make sure we
4639  // do the right thing.
4640  // I vote for b).
4641  fill.Uncompress();
4642 
4643  NDIndex<D> from_it = src.intersect( from_alloc );
4644  NDIndex<D> fill_it = dest.plugBase( from_it );
4645  // Build iterators for the copy...
4646  typedef typename LField<T,D>::iterator LFI;
4647  LFI lhs = fill.begin(fill_it);
4648  LFI rhs = from.begin(from_it);
4649  // And do the assignment.
4651  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4652  }
4653  }
4654  }
4655  }
4656 }
4657 
4658 //-----------------------------------------------------------------------------
4659 // Specialization of FunctionFace::apply() for Vert centering.
4660 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4661 //-----------------------------------------------------------------------------
4662 template<class T, unsigned D, class M>
4664  Field<T,D,M,Vert>& A )
4665 {
4666 
4667 
4668 
4669  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4670  // comprehensible comments --TJW
4671 
4672  // Find the slab that is the destination.
4673  const NDIndex<D>& domain( A.getDomain() );
4674  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4675  unsigned d = ff.getFace()/2;
4676  int offset;
4677  if ( ff.getFace() & 1 ) {
4678  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4679  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4680  // N.B.: the extra -1 here is what distinguishes this Vert-centered
4681  // implementation from the Cell-centered one:
4682  offset = 2*domain[d].max() + 1 - 1;
4683  }
4684  else {
4685  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4686  // N.B.: the extra +1 here is what distinguishes this Vert-centered
4687  // implementation from the Cell-centered one:
4688  offset = 2*domain[d].min() - 1 + 1;
4689  }
4690 
4691  // Loop over the ones the slab touches.
4692  typename Field<T,D,M,Vert>::iterator_if fill_i;
4693  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4694  {
4695  // Cache some things we will use often below.
4696  LField<T,D> &fill = *(*fill_i).second;
4697  const NDIndex<D> &fill_alloc = fill.getAllocated();
4698  if ( slab.touches( fill_alloc ) )
4699  {
4700  // Find what it touches in this LField.
4701  NDIndex<D> dest = slab.intersect( fill_alloc );
4702 
4703  // Find where that comes from.
4704  NDIndex<D> src = dest;
4705  src[d] = offset - src[d];
4706 
4707  // Loop over the ones that src touches.
4708  typename Field<T,D,M,Vert>::iterator_if from_i;
4709  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4710  {
4711  // Cache a few things.
4712  LField<T,D> &from = *(*from_i).second;
4713  const NDIndex<D> &from_owned = from.getOwned();
4714  const NDIndex<D> &from_alloc = from.getAllocated();
4715  // If src touches this LField...
4716  if ( src.touches( from_owned ) )
4717  {
4718  // bfh: Worry about compression ...
4719  // If 'fill' is a compressed LField, then writing data into
4720  // it via the expression will actually write the value for
4721  // all elements of the LField. We can do the following:
4722  // a) figure out if the 'fill' elements are all the same
4723  // value, if 'from' elements are the same value, if
4724  // the 'fill' elements are the same as the elements
4725  // throughout that LField, and then just do an
4726  // assigment for a single element
4727  // b) just uncompress the 'fill' LField, to make sure we
4728  // do the right thing.
4729  // I vote for b).
4730  fill.Uncompress();
4731 
4732  NDIndex<D> from_it = src.intersect( from_alloc );
4733  NDIndex<D> fill_it = dest.plugBase( from_it );
4734  // Build iterators for the copy...
4735  typedef typename LField<T,D>::iterator LFI;
4736  LFI lhs = fill.begin(fill_it);
4737  LFI rhs = from.begin(from_it);
4738  // And do the assignment.
4740  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4741  }
4742  }
4743  }
4744  }
4745 }
4746 
4747 //-----------------------------------------------------------------------------
4748 // Specialization of FunctionFace::apply() for Edge centering.
4749 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4750 //-----------------------------------------------------------------------------
4751 template<class T, unsigned D, class M>
4753  Field<T,D,M,Edge>& A )
4754 {
4755  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4756  // comprehensible comments --TJW
4757 
4758  // Find the slab that is the destination.
4759  const NDIndex<D>& domain( A.getDomain() );
4760  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4761  unsigned d = ff.getFace()/2;
4762  int offset;
4763  if ( ff.getFace() & 1 ) {
4764  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4765  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4766  // N.B.: the extra -1 here is what distinguishes this Edge-centered
4767  // implementation from the Cell-centered one:
4768  offset = 2*domain[d].max() + 1 - 1;
4769  }
4770  else {
4771  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4772  // N.B.: the extra +1 here is what distinguishes this Edge-centered
4773  // implementation from the Cell-centered one:
4774  offset = 2*domain[d].min() - 1 + 1;
4775  }
4776 
4777  // Loop over the ones the slab touches.
4778  typename Field<T,D,M,Edge>::iterator_if fill_i;
4779  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4780  {
4781  // Cache some things we will use often below.
4782  LField<T,D> &fill = *(*fill_i).second;
4783  const NDIndex<D> &fill_alloc = fill.getAllocated();
4784  if ( slab.touches( fill_alloc ) )
4785  {
4786  // Find what it touches in this LField.
4787  NDIndex<D> dest = slab.intersect( fill_alloc );
4788 
4789  // Find where that comes from.
4790  NDIndex<D> src = dest;
4791  src[d] = offset - src[d];
4792 
4793  // Loop over the ones that src touches.
4794  typename Field<T,D,M,Edge>::iterator_if from_i;
4795  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4796  {
4797  // Cache a few things.
4798  LField<T,D> &from = *(*from_i).second;
4799  const NDIndex<D> &from_owned = from.getOwned();
4800  const NDIndex<D> &from_alloc = from.getAllocated();
4801  // If src touches this LField...
4802  if ( src.touches( from_owned ) )
4803  {
4804  // bfh: Worry about compression ...
4805  // If 'fill' is a compressed LField, then writing data into
4806  // it via the expression will actually write the value for
4807  // all elements of the LField. We can do the following:
4808  // a) figure out if the 'fill' elements are all the same
4809  // value, if 'from' elements are the same value, if
4810  // the 'fill' elements are the same as the elements
4811  // throughout that LField, and then just do an
4812  // assigment for a single element
4813  // b) just uncompress the 'fill' LField, to make sure we
4814  // do the right thing.
4815  // I vote for b).
4816  fill.Uncompress();
4817 
4818  NDIndex<D> from_it = src.intersect( from_alloc );
4819  NDIndex<D> fill_it = dest.plugBase( from_it );
4820  // Build iterators for the copy...
4821  typedef typename LField<T,D>::iterator LFI;
4822  LFI lhs = fill.begin(fill_it);
4823  LFI rhs = from.begin(from_it);
4824  // And do the assignment.
4826  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4827  }
4828  }
4829  }
4830  }
4831 }
4832 
4833 //-----------------------------------------------------------------------------
4834 // Specialization of FunctionFace::apply() for CartesianCentering centering.
4835 // Rather, indirectly-called specialized global function FunctionFaceBCApply:
4836 //-----------------------------------------------------------------------------
4837 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
4841 {
4842 
4843 
4844 
4845  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4846  // comprehensible comments --TJW
4847 
4848  // Find the slab that is the destination.
4849  const NDIndex<D>& domain( A.getDomain() );
4850  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4851  unsigned d = ff.getFace()/2;
4852  int offset;
4853  if ( ff.getFace() & 1 ) {
4854  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4855  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4856  // Do the right thing for CELL or VERT centering for all components:
4857  // Make sure all components are really centered the same, as assumed:
4858  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4859  for (int c=1; c<NC; c++) { // Compare other components with 1st
4860  if (CE[c + d*NC] != centering0)
4861  ERRORMSG("FunctionFaceBCApply: BCond thinks all components have"
4862  << " same centering along direction " << d
4863  << ", but it isn't so." << endl);
4864  }
4865  // Now do the right thing for CELL or VERT centering of all components:
4866  if (centering0 == CELL) {
4867  offset = 2*domain[d].max() + 1; // CELL case
4868  } else {
4869  offset = 2*domain[d].max() + 1 - 1; // VERT case
4870  }
4871  }
4872  else {
4873  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4874  // Do the right thing for CELL or VERT centering for all components:
4875  // Make sure all components are really centered the same, as assumed:
4876  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4877  for (int c=1; c<NC; c++) { // Compare other components with 1st
4878  if (CE[c + d*NC] != centering0)
4879  ERRORMSG("FunctionFaceBCApply: BCond thinks all components have"
4880  << " same centering along direction " << d
4881  << ", but it isn't so." << endl);
4882  }
4883  // Now do the right thing for CELL or VERT centering of all components:
4884  if (centering0 == CELL) {
4885  offset = 2*domain[d].min() - 1; // CELL case
4886  } else {
4887  offset = 2*domain[d].min() - 1 + 1; // VERT case
4888  }
4889  }
4890 
4891  // Loop over the ones the slab touches.
4892  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
4893  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4894  {
4895  // Cache some things we will use often below.
4896  LField<T,D> &fill = *(*fill_i).second;
4897  const NDIndex<D> &fill_alloc = fill.getAllocated();
4898  if ( slab.touches( fill_alloc ) )
4899  {
4900  // Find what it touches in this LField.
4901  NDIndex<D> dest = slab.intersect( fill_alloc );
4902 
4903  // Find where that comes from.
4904  NDIndex<D> src = dest;
4905  src[d] = offset - src[d];
4906 
4907  // Loop over the ones that src touches.
4908  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if from_i;
4909  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4910  {
4911  // Cache a few things.
4912  LField<T,D> &from = *(*from_i).second;
4913  const NDIndex<D> &from_owned = from.getOwned();
4914  const NDIndex<D> &from_alloc = from.getAllocated();
4915  // If src touches this LField...
4916  if ( src.touches( from_owned ) )
4917  {
4918  // bfh: Worry about compression ...
4919  // If 'fill' is a compressed LField, then writing data into
4920  // it via the expression will actually write the value for
4921  // all elements of the LField. We can do the following:
4922  // a) figure out if the 'fill' elements are all the same
4923  // value, if 'from' elements are the same value, if
4924  // the 'fill' elements are the same as the elements
4925  // throughout that LField, and then just do an
4926  // assigment for a single element
4927  // b) just uncompress the 'fill' LField, to make sure we
4928  // do the right thing.
4929  // I vote for b).
4930  fill.Uncompress();
4931 
4932  NDIndex<D> from_it = src.intersect( from_alloc );
4933  NDIndex<D> fill_it = dest.plugBase( from_it );
4934  // Build iterators for the copy...
4935  typedef typename LField<T,D>::iterator LFI;
4936  LFI lhs = fill.begin(fill_it);
4937  LFI rhs = from.begin(from_it);
4938  // And do the assignment.
4940  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4941  }
4942  }
4943  }
4944  }
4945 }
4946 
4948 
4949 // Applicative templates for ComponentFunctionFace:
4950 
4951 // Standard, for applying to all components of elemental type:
4952 // DOESN'T EXIST FOR ComponentFunctionFace; use FunctionFace instead.
4953 
4954 // Special, for applying to single component of multicomponent elemental type:
4955 template<class T>
4957 {
4960  int c) :
4961  Func(func), Component(c) {}
4965 };
4966 template<class T>
4967 inline void PETE_apply(const OpBCFunctionEqComponent<T>& e, T& a, const T& b)
4968 { a[e.Component] = e.Func(b[e.Component]); }
4969 
4970 // Following specializations are necessary because of the runtime branches in
4971 // code which unfortunately force instantiation of OpBCFunctionEqComponent
4972 // instances for non-multicomponent types like {char,double,...}.
4973 // Note: if user uses non-multicomponent (no operator[]) types of his own,
4974 // he'll get a compile error. See comments regarding similar specializations
4975 // for OpExtrapolateComponent for a more details.
4976 
4979 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,int)
4980 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,unsigned)
4981 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,short)
4982 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,long)
4983 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,float)
4984 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,double)
4985 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,dcomplex)
4986 
4987 
4989 
4990 //----------------------------------------------------------------------------
4991 // For unspecified centering, can't implement ComponentFunctionFace::apply()
4992 // correctly, and can't partial-specialize yet, so... don't have a prototype
4993 // for unspecified centering, so user gets a compile error if he tries to
4994 // invoke it for a centering not yet implemented. Implement external functions
4995 // which are specializations for the various centerings
4996 // {Cell,Vert,CartesianCentering}; these are called from the general
4997 // ComponentFunctionFace::apply() function body.
4998 //----------------------------------------------------------------------------
4999 
5001 
5002 template<class T, unsigned D, class M>
5004  Field<T,D,M,Cell>& A );
5005 template<class T, unsigned D, class M>
5007  Field<T,D,M,Vert>& A );
5008 template<class T, unsigned D, class M>
5010  Field<T,D,M,Edge>& A );
5011 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
5013  CartesianCentering<CE,D,NC> >& ff,
5014  Field<T,D,M,
5015  CartesianCentering<CE,D,NC> >& A );
5016 
5017 template<class T, unsigned D, class M, class C>
5018 void ComponentFunctionFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
5019 {
5020  ComponentFunctionFaceBCApply(*this, A);
5021 }
5022 
5023 //-----------------------------------------------------------------------------
5024 //Specialization of ComponentFunctionFace::apply() for Cell centering.
5025 //Rather, indirectly-called specialized global function
5026 //ComponentFunctionFaceBCApply
5027 //-----------------------------------------------------------------------------
5028 template<class T, unsigned D, class M>
5030  Field<T,D,M,Cell>& A )
5031 {
5032 
5033 
5034 
5035  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5036  // comprehensible comments --TJW
5037 
5038  // Find the slab that is the destination.
5039  const NDIndex<D>& domain( A.getDomain() );
5040  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5041  unsigned d = ff.getFace()/2;
5042  int offset;
5043  if ( ff.getFace() & 1 ) {
5044  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5045  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5046  offset = 2*domain[d].max() + 1;
5047  }
5048  else {
5049  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5050  offset = 2*domain[d].min() - 1;
5051  }
5052 
5053  // Loop over the ones the slab touches.
5054  typename Field<T,D,M,Cell>::iterator_if fill_i;
5055  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5056  {
5057  // Cache some things we will use often below.
5058  LField<T,D> &fill = *(*fill_i).second;
5059  const NDIndex<D> &fill_alloc = fill.getAllocated();
5060  if ( slab.touches( fill_alloc ) )
5061  {
5062  // Find what it touches in this LField.
5063  NDIndex<D> dest = slab.intersect( fill_alloc );
5064 
5065  // Find where that comes from.
5066  NDIndex<D> src = dest;
5067  src[d] = offset - src[d];
5068 
5069  // Loop over the ones that src touches.
5070  typename Field<T,D,M,Cell>::iterator_if from_i;
5071  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5072  {
5073  // Cache a few things.
5074  LField<T,D> &from = *(*from_i).second;
5075  const NDIndex<D> &from_owned = from.getOwned();
5076  const NDIndex<D> &from_alloc = from.getAllocated();
5077  // If src touches this LField...
5078  if ( src.touches( from_owned ) )
5079  {
5080  // bfh: Worry about compression ...
5081  // If 'fill' is a compressed LField, then writing data into
5082  // it via the expression will actually write the value for
5083  // all elements of the LField. We can do the following:
5084  // a) figure out if the 'fill' elements are all the same
5085  // value, if 'from' elements are the same value, if
5086  // the 'fill' elements are the same as the elements
5087  // throughout that LField, and then just do an
5088  // assigment for a single element
5089  // b) just uncompress the 'fill' LField, to make sure we
5090  // do the right thing.
5091  // I vote for b).
5092  fill.Uncompress();
5093 
5094  NDIndex<D> from_it = src.intersect( from_alloc );
5095  NDIndex<D> fill_it = dest.plugBase( from_it );
5096  // Build iterators for the copy...
5097  typedef typename LField<T,D>::iterator LFI;
5098  LFI lhs = fill.begin(fill_it);
5099  LFI rhs = from.begin(from_it);
5100  // And do the assignment.
5103  (ff.Func,ff.getComponent())).apply();
5104  }
5105  }
5106  }
5107  }
5108 }
5109 
5110 //-----------------------------------------------------------------------------
5111 //Specialization of ComponentFunctionFace::apply() for Vert centering.
5112 //Rather, indirectly-called specialized global function
5113 //ComponentFunctionFaceBCApply
5114 //-----------------------------------------------------------------------------
5115 template<class T, unsigned D, class M>
5117  Field<T,D,M,Vert>& A )
5118 {
5119 
5120 
5121 
5122  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5123  // comprehensible comments --TJW
5124 
5125  // Find the slab that is the destination.
5126  const NDIndex<D>& domain( A.getDomain() );
5127  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5128  unsigned d = ff.getFace()/2;
5129  int offset;
5130  if ( ff.getFace() & 1 ) {
5131  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5132  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5133  // N.B.: the extra -1 here is what distinguishes this Vert-centered
5134  // implementation from the Cell-centered one:
5135  offset = 2*domain[d].max() + 1 - 1;
5136  }
5137  else {
5138  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5139  // N.B.: the extra +1 here is what distinguishes this Vert-centered
5140  // implementation from the Cell-centered one:
5141  offset = 2*domain[d].min() - 1 + 1;
5142  }
5143 
5144  // Loop over the ones the slab touches.
5145  typename Field<T,D,M,Vert>::iterator_if fill_i;
5146  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5147  {
5148  // Cache some things we will use often below.
5149  LField<T,D> &fill = *(*fill_i).second;
5150  const NDIndex<D> &fill_alloc = fill.getAllocated();
5151  if ( slab.touches( fill_alloc ) )
5152  {
5153  // Find what it touches in this LField.
5154  NDIndex<D> dest = slab.intersect( fill_alloc );
5155 
5156  // Find where that comes from.
5157  NDIndex<D> src = dest;
5158  src[d] = offset - src[d];
5159 
5160  // Loop over the ones that src touches.
5161  typename Field<T,D,M,Vert>::iterator_if from_i;
5162  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5163  {
5164  // Cache a few things.
5165  LField<T,D> &from = *(*from_i).second;
5166  const NDIndex<D> &from_owned = from.getOwned();
5167  const NDIndex<D> &from_alloc = from.getAllocated();
5168  // If src touches this LField...
5169  if ( src.touches( from_owned ) )
5170  {
5171  // bfh: Worry about compression ...
5172  // If 'fill' is a compressed LField, then writing data into
5173  // it via the expression will actually write the value for
5174  // all elements of the LField. We can do the following:
5175  // a) figure out if the 'fill' elements are all the same
5176  // value, if 'from' elements are the same value, if
5177  // the 'fill' elements are the same as the elements
5178  // throughout that LField, and then just do an
5179  // assigment for a single element
5180  // b) just uncompress the 'fill' LField, to make sure we
5181  // do the right thing.
5182  // I vote for b).
5183  fill.Uncompress();
5184 
5185  NDIndex<D> from_it = src.intersect( from_alloc );
5186  NDIndex<D> fill_it = dest.plugBase( from_it );
5187  // Build iterators for the copy...
5188  typedef typename LField<T,D>::iterator LFI;
5189  LFI lhs = fill.begin(fill_it);
5190  LFI rhs = from.begin(from_it);
5191  // And do the assignment.
5194  (ff.Func,ff.getComponent())).apply();
5195  }
5196  }
5197  }
5198  }
5199 }
5200 
5201 //-----------------------------------------------------------------------------
5202 //Specialization of ComponentFunctionFace::apply() for Edge centering.
5203 //Rather, indirectly-called specialized global function
5204 //ComponentFunctionFaceBCApply
5205 //-----------------------------------------------------------------------------
5206 template<class T, unsigned D, class M>
5208  Field<T,D,M,Edge>& A )
5209 {
5210  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5211  // comprehensible comments --TJW
5212 
5213  // Find the slab that is the destination.
5214  const NDIndex<D>& domain( A.getDomain() );
5215  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5216  unsigned d = ff.getFace()/2;
5217  int offset;
5218  if ( ff.getFace() & 1 ) {
5219  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5220  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5221  // N.B.: the extra -1 here is what distinguishes this Edge-centered
5222  // implementation from the Cell-centered one:
5223  offset = 2*domain[d].max() + 1 - 1;
5224  }
5225  else {
5226  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5227  // N.B.: the extra +1 here is what distinguishes this Edge-centered
5228  // implementation from the Cell-centered one:
5229  offset = 2*domain[d].min() - 1 + 1;
5230  }
5231 
5232  // Loop over the ones the slab touches.
5233  typename Field<T,D,M,Edge>::iterator_if fill_i;
5234  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5235  {
5236  // Cache some things we will use often below.
5237  LField<T,D> &fill = *(*fill_i).second;
5238  const NDIndex<D> &fill_alloc = fill.getAllocated();
5239  if ( slab.touches( fill_alloc ) )
5240  {
5241  // Find what it touches in this LField.
5242  NDIndex<D> dest = slab.intersect( fill_alloc );
5243 
5244  // Find where that comes from.
5245  NDIndex<D> src = dest;
5246  src[d] = offset - src[d];
5247 
5248  // Loop over the ones that src touches.
5249  typename Field<T,D,M,Edge>::iterator_if from_i;
5250  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5251  {
5252  // Cache a few things.
5253  LField<T,D> &from = *(*from_i).second;
5254  const NDIndex<D> &from_owned = from.getOwned();
5255  const NDIndex<D> &from_alloc = from.getAllocated();
5256  // If src touches this LField...
5257  if ( src.touches( from_owned ) )
5258  {
5259  // bfh: Worry about compression ...
5260  // If 'fill' is a compressed LField, then writing data into
5261  // it via the expression will actually write the value for
5262  // all elements of the LField. We can do the following:
5263  // a) figure out if the 'fill' elements are all the same
5264  // value, if 'from' elements are the same value, if
5265  // the 'fill' elements are the same as the elements
5266  // throughout that LField, and then just do an
5267  // assigment for a single element
5268  // b) just uncompress the 'fill' LField, to make sure we
5269  // do the right thing.
5270  // I vote for b).
5271  fill.Uncompress();
5272 
5273  NDIndex<D> from_it = src.intersect( from_alloc );
5274  NDIndex<D> fill_it = dest.plugBase( from_it );
5275  // Build iterators for the copy...
5276  typedef typename LField<T,D>::iterator LFI;
5277  LFI lhs = fill.begin(fill_it);
5278  LFI rhs = from.begin(from_it);
5279  // And do the assignment.
5282  (ff.Func,ff.getComponent())).apply();
5283  }
5284  }
5285  }
5286  }
5287 }
5288 
5289 //-----------------------------------------------------------------------------
5290 //Specialization of ComponentFunctionFace::apply() for
5291 //CartesianCentering centering. Rather, indirectly-called specialized
5292 //global function ComponentFunctionFaceBCApply:
5293 //-----------------------------------------------------------------------------
5294 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
5298 {
5299 
5300 
5301 
5302  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5303  // comprehensible comments --TJW
5304 
5305  // Find the slab that is the destination.
5306  const NDIndex<D>& domain( A.getDomain() );
5307  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5308  unsigned d = ff.getFace()/2;
5309  int offset;
5310  if ( ff.getFace() & 1 ) {
5311  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5312  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5313  // Do the right thing for CELL or VERT centering for this component. (The
5314  // ComponentFunctionFace BC always applies only to one component, not all):
5315  if (CE[ff.getComponent() + d*NC] == CELL) { // ada: changed ef to ff
5316  ERRORMSG("check src code, had to change ef (not known) to ff ??? " << endl);
5317  offset = 2*domain[d].max() + 1; // CELL case
5318  } else {
5319  offset = 2*domain[d].max() + 1 - 1; // VERT case
5320  }
5321  }
5322  else {
5323  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5324  // Do the right thing for CELL or VERT centering for this component. (The
5325  // ComponentFunctionFace BC always applies only to one component, not all):
5326  if (CE[ff.getComponent() + d*NC] == CELL) {
5327  offset = 2*domain[d].min() - 1; // CELL case
5328  } else {
5329  offset = 2*domain[d].min() - 1 + 1; // VERT case
5330  }
5331  }
5332 
5333  // Loop over the ones the slab touches.
5334  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
5335  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5336  {
5337  // Cache some things we will use often below.
5338  LField<T,D> &fill = *(*fill_i).second;
5339  const NDIndex<D> &fill_alloc = fill.getAllocated();
5340  if ( slab.touches( fill_alloc ) )
5341  {
5342  // Find what it touches in this LField.
5343  NDIndex<D> dest = slab.intersect( fill_alloc );
5344 
5345  // Find where that comes from.
5346  NDIndex<D> src = dest;
5347  src[d] = offset - src[d];
5348 
5349  // Loop over the ones that src touches.
5350  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if from_i;
5351  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5352  {
5353  // Cache a few things.
5354  LField<T,D> &from = *(*from_i).second;
5355  const NDIndex<D> &from_owned = from.getOwned();
5356  const NDIndex<D> &from_alloc = from.getAllocated();
5357  // If src touches this LField...
5358  if ( src.touches( from_owned ) )
5359  {
5360  // bfh: Worry about compression ...
5361  // If 'fill' is a compressed LField, then writing data into
5362  // it via the expression will actually write the value for
5363  // all elements of the LField. We can do the following:
5364  // a) figure out if the 'fill' elements are all the same
5365  // value, if 'from' elements are the same value, if
5366  // the 'fill' elements are the same as the elements
5367  // throughout that LField, and then just do an
5368  // assigment for a single element
5369  // b) just uncompress the 'fill' LField, to make sure we
5370  // do the right thing.
5371  // I vote for b).
5372  fill.Uncompress();
5373 
5374  NDIndex<D> from_it = src.intersect( from_alloc );
5375  NDIndex<D> fill_it = dest.plugBase( from_it );
5376  // Build iterators for the copy...
5377  typedef typename LField<T,D>::iterator LFI;
5378  LFI lhs = fill.begin(fill_it);
5379  LFI rhs = from.begin(from_it);
5380  // And do the assignment.
5383  (ff.Func,ff.getComponent())).apply();
5384  }
5385  }
5386  }
5387  }
5388 }
5389 
5391 
5392 //
5393 // EurekaFace::apply().
5394 // Apply a Eureka condition on a face.
5395 //
5396 // The general idea is to set the guard cells plus one layer
5397 // of cells to zero in all cases except one:
5398 // When there are mixed centerings, the cell coordinates just
5399 // have their guard cells set to zero.
5400 //
5401 
5402 //------------------------------------------------------------
5403 // The actual member function EurekaFace::apply
5404 // This just uses the functions above to find the slab
5405 // we are going to fill, then it fills it.
5406 //------------------------------------------------------------
5407 
5408 template<class T, unsigned int D, class M, class C>
5410 {
5411  // Calculate the domain we're going to fill
5412  // using the domain of the field.
5413  NDIndex<D> slab = calcEurekaSlabToFill(field,BCondBase<T,D,M,C>::m_face,this->getComponent());
5414 
5415  // Fill that slab.
5416  fillSlabWithZero(field,slab,this->getComponent());
5417 }
5418 
5420 
5421 //
5422 // Tag class for the Eureka assignment.
5423 // This has two functions:
5424 //
5425 // A static member function for getting a component if
5426 // there are subcomponents.
5427 //
5428 // Be a tag class for the BrickExpression for an assignment.
5429 //
5430 
5431 //
5432 // First we have the general template class.
5433 // This ignores the component argument, and will be used
5434 // for any classes except Vektor, Tenzor and SymTenzor.
5435 //
5436 
5437 #ifdef __MWERKS__
5438 // Work around CodeWarrior 4 Professional template-matching bug; requires
5439 // putting D template parameter on EurekaAssign struct and all the
5440 // specializations:
5441 template<class T, int D>
5442 #else
5443 template<class T>
5444 #endif // __MWERKS__
5446 {
5447  static const T& get(const T& x, int) {
5448  ERRORMSG("Eureka assign to a component of class without an op[]!"<<endl);
5449  return x;
5450  }
5451  static T& get(T& x, int) {
5452  ERRORMSG("Eureka assign to a component of class without an op[]!"<<endl);
5453  return x;
5454  }
5457 };
5458 
5459 //------------------------------------------------------------
5460 // Given a Field and a domain, fill the domain with zeros.
5461 // Input:
5462 // field: The field we'll be assigning to.
5463 // fillDomain: The domain we'll be assigning to.
5464 // component: What component of T we'll be filling.
5465 //------------------------------------------------------------
5466 
5467 template<class T, unsigned int D, class M, class C>
5468 static void
5469 fillSlabWithZero(Field<T,D,M,C>& field,
5470  const NDIndex<D>& fillDomain,
5471  int component)
5472 {
5473  //
5474  // Loop over all the vnodes, filling each one in turn.
5475  //
5476  typename Field<T,D,M,C>::iterator_if lp = field.begin_if();
5477  typename Field<T,D,M,C>::iterator_if done = field.end_if();
5478  for (; lp != done ; ++lp )
5479  {
5480  // Get a reference to the current LField.
5481  LField<T,D>& lf = *(*lp).second;
5482 
5483  // Get its domain, including guard cells.
5484  NDIndex<D> localDomain = lf.getAllocated();
5485 
5486  // If localDomain intersects fillDomain, we have work to do.
5487  if ( fillDomain.touches(localDomain) )
5488  {
5489  // If lf is compressed, we may not have to do any work.
5490  if ( lf.IsCompressed() )
5491  {
5492  // Check and see if we're dealing with all components
5493  if ( component == BCondBase<T,D,M,C>::allComponents )
5494  {
5495  // If it is compressed to zero, we really don't have to work
5496  if ( *lf.begin() == 0 )
5497  continue;
5498  }
5499  // We are dealing with just one component
5500  else
5501  {
5502  // Check to see if the component is zero.
5503  // Check through a class so that this statement
5504  // isn't a compile error if T is something like int.
5505 #ifdef __MWERKS__
5506 // Work around CodeWarrior 4 Professional template-matching bug; requires
5507 // putting D template parameter on EurekaAssign struct and all the
5508 // specializations:
5509  if ( EurekaAssign<T,D>::get(*lf.begin(),component)==0 )
5510  continue;
5511 #else
5512  if ( EurekaAssign<T>::get(*lf.begin(),component)==0 )
5513  continue;
5514 #endif // __MWERKS__
5515  }
5516  // Not compressed to zero.
5517  // Have to uncompress.
5518  lf.Uncompress();
5519  }
5520 
5521  // Get the actual intersection.
5522  NDIndex<D> intersectDomain = fillDomain.intersect(localDomain);
5523 
5524  // Get an iterator that will loop over that domain.
5525  typename LField<T,D>::iterator data = lf.begin(intersectDomain);
5526 
5527 
5528  // Build a BrickExpression that will fill it with zeros.
5529  // First some typedefs for the constituents of the expression.
5530  typedef typename LField<T,D>::iterator Lhs_t;
5531  typedef PETE_Scalar<T> Rhs_t;
5532 
5533  // If we are assigning all components, use regular assignment.
5534  if ( component == BCondBase<T,D,M,C>::allComponents )
5535  {
5536  // The type of the expression.
5538 
5539  // Build the expression and evaluate it.
5540  Expr_t(data,Rhs_t(0)).apply();
5541  }
5542  // We are assigning just one component. Use EurekaAssign.
5543  else
5544  {
5545  // The type of the expression.
5546 #ifdef __MWERKS__
5547 // Work around CodeWarrior 4 Professional template-matching bug; requires
5548 // putting D template parameter on EurekaAssign struct and all the
5549 // specializations:
5551 #else
5553 #endif // __MWERKS__
5554 
5555  // Sanity check.
5556  PAssert_GE(component, 0);
5557 
5558  // Build the expression and evaluate it. tjw:mwerks dies here:
5559  Expr_t(data,Rhs_t(0),component).apply();
5560  //try: typedef typename AppTypeTraits<T>::Element_t T1;
5561  //try: Expr_t(data,PETE_Scalar<T1>(T1(0)),component).apply();
5562  }
5563  }
5564  }
5565 }
5566 
5567 //
5568 // Specializations of EurekaAssign for Vektor, Tenzor, SymTenzor.
5569 //
5570 
5571 template<class T, unsigned int D>
5572 #ifdef __MWERKS__
5573 // Work around CodeWarrior 4 Professional template-matching bug; requires
5574 // putting D template parameter on EurekaAssign struct and all the
5575 // specializations:
5576 struct EurekaAssign< Vektor<T,D>, D >
5577 #else
5578 struct EurekaAssign< Vektor<T,D> >
5579 #endif // __MWERKS__
5580 {
5581  static T& get( Vektor<T,D>& x, int c ) { return x[c]; }
5582  static T get( const Vektor<T,D>& x, int c ) { return x[c]; }
5585 };
5586 
5587 template<class T, unsigned int D>
5588 #ifdef __MWERKS__
5589 // Work around CodeWarrior 4 Professional template-matching bug; requires
5590 // putting D template parameter on EurekaAssign struct and all the
5591 // specializations:
5592 struct EurekaAssign< Tenzor<T,D>, D >
5593 #else
5594 struct EurekaAssign< Tenzor<T,D> >
5595 #endif // __MWERKS__
5596 {
5597  static T& get( Tenzor<T,D>& x, int c ) { return x[c]; }
5598  static T get( const Tenzor<T,D>& x, int c ) { return x[c]; }
5601 };
5602 
5603 template<class T, unsigned int D>
5604 #ifdef __MWERKS__
5605 // Work around CodeWarrior 4 Professional template-matching bug; requires
5606 // putting D template parameter on EurekaAssign struct and all the
5607 // specializations:
5608 struct EurekaAssign< AntiSymTenzor<T,D>, D >
5609 #else
5611 #endif // __MWERKS__
5612 {
5613  static T& get( AntiSymTenzor<T,D>& x, int c ) { return x[c]; }
5614  static T get( const AntiSymTenzor<T,D>& x, int c ) { return x[c]; }
5617 };
5618 
5619 template<class T, unsigned int D>
5620 #ifdef __MWERKS__
5621 // Work around CodeWarrior 4 Professional template-matching bug; requires
5622 // putting D template parameter on EurekaAssign struct and all the
5623 // specializations:
5624 struct EurekaAssign< SymTenzor<T,D>, D >
5625 #else
5627 #endif // __MWERKS__
5628 {
5629  static T& get( SymTenzor<T,D>& x, int c ) { return x[c]; }
5630  static T get( const SymTenzor<T,D>& x, int c ) { return x[c]; }
5633 };
5634 
5635 //
5636 // A version of PETE_apply for EurekaAssign.
5637 // Assign a component of the right hand side to a component of the left.
5638 //
5639 
5640 #ifdef __MWERKS__
5641 // Work around CodeWarrior 4 Professional template-matching bug; requires
5642 // putting D template parameter on EurekaAssign struct and all the
5643 // specializations:
5644 template<class T, int D>
5645 inline void PETE_apply(const EurekaAssign<T,D>& e, T& a, const T& b)
5646 {
5649 }
5650 #else
5651 template<class T>
5652 inline void PETE_apply(const EurekaAssign<T>& e, T& a, const T& b)
5653 {
5656 }
5657 #endif // __MWERKS__
5658 
5659 
5661 
5662 //
5663 // calcEurekaDomain
5664 // Given a domain, a face number, and a guard cell spec,
5665 // find the low and high bounds for the domain we will be filling.
5666 // Return the two integers through references.
5667 //
5668 template<unsigned int D>
5669 inline NDIndex<D>
5670 calcEurekaDomain(const NDIndex<D>& realDomain,
5671  int face,
5672  const GuardCellSizes<D>& gc)
5673 {
5674  NDIndex<D> slab = AddGuardCells(realDomain,gc);
5675 
5676  // Find the dimension the slab will be perpendicular to.
5677  int dim = face/2;
5678 
5679  // The upper and lower bounds of the domain.
5680  int low,high;
5681 
5682  // If the face is odd, then it is the "high" end of the dimension.
5683  if ( face&1 )
5684  {
5685  // Find the bounds of the domain.
5686  high = slab[dim].max();
5687  low = high - gc.right(dim);
5688  }
5689  // If the face is even, then it is the "low" end of the dimension.
5690  else
5691  {
5692  // Find the bounds of the domain.
5693  low = slab[dim].min();
5694  high = low + gc.left(dim);
5695  }
5696 
5697  // Sanity checks.
5698  PAssert_LE( low, high );
5699  PAssert_LE( high, slab[dim].max() );
5700  PAssert_GE( low, slab[dim].min() );
5701 
5702  // Build the domain.
5703  slab[dim] = Index(low,high);
5704  return slab;
5705 }
5706 
5708 
5709 //
5710 // Find the appropriate slab to fill for a Cell centered field
5711 // for the Eureka boundary condition.
5712 // It's thickness is the number of guard cells plus one.
5713 //
5714 
5715 template<class T, unsigned int D, class M>
5716 static NDIndex<D>
5717 calcEurekaSlabToFill(const Field<T,D,M,Cell>& field, int face,int)
5718 {
5719  return calcEurekaDomain(field.getDomain(),face,field.getGC());
5720 }
5721 
5722 template<class T, unsigned int D, class M>
5723 static NDIndex<D>
5724 calcEurekaSlabToFill(const Field<T,D,M,Vert>& field, int face,int)
5725 {
5726  return calcEurekaDomain(field.getDomain(),face,field.getGC());
5727 }
5728 
5729 template<class T, unsigned int D, class M>
5730 static NDIndex<D>
5731 calcEurekaSlabToFill(const Field<T,D,M,Edge>& field, int face,int)
5732 {
5733  return calcEurekaDomain(field.getDomain(),face,field.getGC());
5734 }
5735 
5737 
5738 //
5739 // Find the appropriate slab to fill for a mixed centering
5740 // for the Eureka boundary condition.
5741 // It's thickness is:
5742 // If we're filling allComponents, the number guard cells plus 1.
5743 // If we're filling a single component,
5744 // If that component if vert, the number of guard cells plus 1
5745 // If that component is cell, the number of guard cells.
5746 //
5747 
5748 template<class T, unsigned D, class M, const CenteringEnum* CE, unsigned NC>
5749 static NDIndex<D>
5750 calcEurekaSlabToFill(const Field<T,D,M,CartesianCentering<CE,D,NC> >& field,
5751  int face,
5752  int component)
5753 {
5754  // Shorthand for the centering type.
5755  typedef CartesianCentering<CE,D,NC> C;
5756 
5757  // Find the dimension perpendicular to the slab.
5758  int d = face/2;
5759 
5760  // The domain we'll be calculating.
5761  NDIndex<D> slab;
5762 
5763  // First check and see if we are fill all the components.
5764  if ( component == BCondBase<T,D,M,C>::allComponents )
5765  {
5766  // Deal with this like a pure VERT or CELL case.
5767  slab = calcEurekaDomain(field.getDomain(),face,field.getGC());
5768  }
5769  // Only do one component.
5770  else
5771  {
5772  // Our initial approximation to the slab to fill is the whole domain.
5773  // We'll reset the index for dimension d to make it a slab.
5774  slab = AddGuardCells(field.getDomain(),field.getGC());
5775 
5776  // If face is odd, this is the "high" face.
5777  if ( face&1 )
5778  {
5779  // Find the upper and lower bounds of the domain.
5780  int low = field.getDomain()[d].min() + field.get_mesh().gridSizes[d] - 1;
5781  int high = low + field.rightGuard(d);
5782 
5783  // For cell centered, we do one fewer layer of guard cells.
5784  if (CE[component + d*NC] == CELL)
5785  low++;
5786 
5787  // Sanity checks.
5788  PAssert_LE( low, high );
5789  PAssert_LE( high, slab[d].max() );
5790  PAssert_GE( low, slab[d].min() );
5791 
5792  // Record this part of the slab.
5793  slab[d] = Index(low,high);
5794  }
5795  // If face is even, this is the "low" face.
5796  else
5797  {
5798  // Get the lower and upper bounds of the domain.
5799  int low = slab[d].min();
5800  int high = low + field.leftGuard(d) ;
5801 
5802  // For cell centered, we do one fewer layer of guard cells.
5803  if (CE[component + d*NC] == CELL)
5804  high--;
5805 
5806  // Sanity checks.
5807  PAssert_LE( low, high );
5808  PAssert_LE( high, slab[d].max() );
5809  PAssert_GE( low, slab[d].min() );
5810 
5811  // Record this part of the slab.
5812  slab[d] = Index(low,high);
5813  }
5814  }
5815 
5816  // We've found the domain, so return it.
5817  return slab;
5818 }
5819 
5821 
5822 //----------------------------------------------------------------------------
5823 // For unspecified centering, can't implement LinearExtrapolateFace::apply()
5824 // correctly, and can't partial-specialize yet, so... don't have a prototype
5825 // for unspecified centering, so user gets a compile error if he tries to
5826 // invoke it for a centering not yet implemented. Implement external functions
5827 // which are specializations for the various centerings
5828 // {Cell,Vert,CartesianCentering}; these are called from the general
5829 // LinearExtrapolateFace::apply() function body.
5830 //
5831 // TJW: Actually, for LinearExtrapolate, don't need to specialize on
5832 // centering. Probably don't need this indirection here, but leave it in for
5833 // now.
5834 //----------------------------------------------------------------------------
5835 
5837 
5838 template<class T, unsigned D, class M, class C>
5840  Field<T,D,M,C>& A );
5841 
5842 template<class T, unsigned D, class M, class C>
5844 {
5845  LinearExtrapolateFaceBCApply(*this, A);
5846 }
5847 
5848 
5849 template<class T, unsigned D, class M, class C>
5850 inline void
5852  const NDIndex<D> &src1,
5853  const NDIndex<D> &src2,
5854  LField<T,D> &fill,
5856  int slopeMultipplier)
5857 {
5858  // If 'fill' is compressed and applying the boundary condition on the
5859  // compressed value would result in no change to 'fill' we don't need to
5860  // uncompress. For this particular type of BC (linear extrapolation), this
5861  // result would *never* happen, so we already know we're done:
5862 
5863  if (fill.IsCompressed()) { return; } // Yea! We're outta here.
5864 
5865  // Build iterators for the copy:
5866  typedef typename LField<T,D>::iterator LFI;
5867  LFI lhs = fill.begin(dest);
5868  LFI rhs1 = fill.begin(src1);
5869  LFI rhs2 = fill.begin(src2);
5870  LFI endi = fill.end(); // Used for testing end of *any* sub-range iteration
5871 
5872  // Couldn't figure out how to use BrickExpression here. Just iterate through
5873  // all the elements in all 3 LField iterators (which are BrickIterators) and
5874  // do the calculation one element at a time:
5875  for ( ; lhs != endi, rhs1 != endi, rhs2 != endi;
5876  ++lhs, ++rhs1, ++rhs2) {
5877  *lhs = (*rhs2 - *rhs1)*slopeMultipplier + *rhs1;
5878  }
5879 
5880 }
5881 
5882 
5883 // ----------------------------------------------------------------------------
5884 // This type of boundary condition (linear extrapolation) does very much the
5885 // same thing for any centering; Doesn't seem to be a need for specializations
5886 // based on centering.
5887 // ----------------------------------------------------------------------------
5888 
5889 template<class T, unsigned D, class M, class C>
5891  Field<T,D,M,C>& A )
5892 {
5893 
5894 
5895 
5896  // Find the slab that is the destination.
5897  // That is, in English, get an NDIndex spanning elements in the guard layers
5898  // on the face associated with the LinearExtrapaloteFace object:
5899 
5900  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
5901  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5902 
5903  // The direction (dimension of the Field) associated with the active face.
5904  // The numbering convention makes this division by two return the right
5905  // value, which will be between 0 and (D-1):
5906 
5907  unsigned d = ef.getFace()/2;
5908 
5909  // Must loop explicitly over the number of guard layers:
5910  int nGuardLayers;
5911 
5912  // The following bitwise AND logical test returns true if ef.m_face is odd
5913  // (meaning the "high" or "right" face in the numbering convention) and
5914  // returns false if ef.m_face is even (meaning the "low" or "left" face in
5915  // the numbering convention):
5916 
5917  if (ef.getFace() & 1) {
5918 
5919  // For "high" face, index in active direction goes from max index of
5920  // Field plus 1 to the same plus number of guard layers:
5921  nGuardLayers = A.rightGuard(d);
5922 
5923  } else {
5924 
5925  // For "low" face, index in active direction goes from min index of
5926  // Field minus the number of guard layers (usually a negative number)
5927  // to the same min index minus 1 (usually negative, and usually -1):
5928  nGuardLayers = A.leftGuard(d);
5929 
5930  }
5931 
5932  // Loop over the number of guard layers, treating each layer as a separate
5933  // slab (contrast this with all other BC types, where all layers are a single
5934  // slab):
5935  for (int guardLayer = 1; guardLayer <= nGuardLayers; guardLayer++) {
5936 
5937  // For linear extrapolation, the multipplier increases with more distant
5938  // guard layers:
5939  int slopeMultipplier = -1*guardLayer;
5940 
5941  if (ef.getFace() & 1) {
5942  slab[d] = Index(domain[d].max() + guardLayer,
5943  domain[d].max() + guardLayer);
5944  } else {
5945  slab[d] = Index(domain[d].min() - guardLayer,
5946  domain[d].min() - guardLayer);
5947  }
5948 
5949  // Loop over all the LField's in the Field A:
5950 
5951  typename Field<T,D,M,Cell>::iterator_if fill_i;
5952  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i) {
5953 
5954  // Cache some things we will use often below.
5955 
5956  // Pointer to the data for the current LField:
5957  LField<T,D> &fill = *(*fill_i).second;
5958 
5959  // NDIndex spanning all elements in the LField, including the guards:
5960  const NDIndex<D> &fill_alloc = fill.getAllocated();
5961 
5962  // If the previously-created boundary guard-layer NDIndex "slab"
5963  // contains any of the elements in this LField (they will be guard
5964  // elements if it does), assign the values into them here by applying
5965  // the boundary condition:
5966 
5967  if (slab.touches(fill_alloc)) {
5968 
5969  // Find what it touches in this LField.
5970  NDIndex<D> dest = slab.intersect(fill_alloc);
5971 
5972  // For linear extrapolation boundary conditions, the boundary
5973  // guard-layer elements are filled based on a slope and intercept
5974  // derived from two layers of interior values; the src1 and src2
5975  // NDIndexes specify these two interior layers, which are operated on
5976  // by mathematical operations whose results are put into dest. The
5977  // ordering of what is defined as src1 and src2 is set differently for
5978  // hi and lo faces, to make the sign for extrapolation work out right:
5979  NDIndex<D> src1 = dest;
5980  NDIndex<D> src2 = dest;
5981  if (ef.getFace() & 1) {
5982  src2[d] = Index(domain[d].max() - 1, domain[d].max() - 1, 1);
5983  src1[d] = Index(domain[d].max(), domain[d].max(), 1);
5984  } else {
5985  src1[d] = Index(0,0,1); // Note: hardwired to 0-base, stride-1; could
5986  src2[d] = Index(1,1,1); // generalize with domain.min(), etc.
5987  }
5988 
5989  // Assume that src1 and src2 are contained withi nthe fill_alloc LField
5990  // domain; I think this is always true if the vnodes are always at
5991  // least one guard-layer-width wide in number of physical elements:
5992 
5993  LinearExtrapolateFaceBCApply2(dest, src1, src2, fill, ef,
5994  slopeMultipplier);
5995 
5996  }
5997  }
5998  }
5999 }
6000 
6001 
6003 
6004 // ---------------------------------------------------------------------------
6005 // For unspecified centering, can't implement
6006 // ComponentLinearExtrapolateFace::apply() correctly, and can't
6007 // partial-specialize yet, so... don't have a prototype for unspecified
6008 // centering, so user gets a compile error if he tries to invoke it for a
6009 // centering not yet implemented. Implement external functions which are
6010 // specializations for the various centerings {Cell,Vert,CartesianCentering};
6011 // these are called from the general ComponentLinearExtrapolateFace::apply()
6012 // function body.
6013 //
6014 // TJW: Actually, for ComponentLinearExtrapolate, don't need to specialize on
6015 // centering. Probably don't need this indirection here, but leave it in for
6016 // now.
6017 // ---------------------------------------------------------------------------
6018 
6019 template<class T, unsigned D, class M, class C>
6021  <T,D,M,C>& ef,
6022  Field<T,D,M,C>& A );
6023 
6024 template<class T, unsigned D, class M, class C>
6026 {
6028 }
6029 
6030 
6031 template<class T, unsigned D, class M, class C>
6032 inline void
6034  const NDIndex<D> &src1,
6035  const NDIndex<D> &src2,
6036  LField<T,D> &fill,
6038  <T,D,M,C> &ef,
6039  int slopeMultipplier)
6040 {
6041  // If 'fill' is compressed and applying the boundary condition on the
6042  // compressed value would result in no change to 'fill' we don't need to
6043  // uncompress. For this particular type of BC (linear extrapolation), this
6044  // result would *never* happen, so we already know we're done:
6045 
6046  if (fill.IsCompressed()) { return; } // Yea! We're outta here.
6047 
6048  // Build iterators for the copy:
6049  typedef typename LField<T,D>::iterator LFI;
6050  LFI lhs = fill.begin(dest);
6051  LFI rhs1 = fill.begin(src1);
6052  LFI rhs2 = fill.begin(src2);
6053  LFI endi = fill.end(); // Used for testing end of *any* sub-range iteration
6054 
6055  // Couldn't figure out how to use BrickExpression here. Just iterate through
6056  // all the elements in all 3 LField iterators (which are BrickIterators) and
6057  // do the calculation one element at a time:
6058 
6059  int component = ef.getComponent();
6060  for ( ; lhs != endi, rhs1 != endi, rhs2 != endi;
6061  ++lhs, ++rhs1, ++rhs2) {
6062  (*lhs)[component] =
6063  ((*rhs2)[component] - (*rhs1)[component])*slopeMultipplier +
6064  (*rhs1)[component];
6065  }
6066 
6067 }
6068 
6069 
6070 // ----------------------------------------------------------------------------
6071 // This type of boundary condition (linear extrapolation) does very much the
6072 // same thing for any centering; Doesn't seem to be a need for specializations
6073 // based on centering.
6074 // ----------------------------------------------------------------------------
6075 
6076 template<class T, unsigned D, class M, class C>
6078  <T,D,M,C>& ef,
6079  Field<T,D,M,C>& A )
6080 {
6081 
6082  // Find the slab that is the destination.
6083  // That is, in English, get an NDIndex spanning elements in the guard layers
6084  // on the face associated with the ComponentLinearExtrapaloteFace object:
6085 
6086  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
6087  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
6088 
6089  // The direction (dimension of the Field) associated with the active face.
6090  // The numbering convention makes this division by two return the right
6091  // value, which will be between 0 and (D-1):
6092 
6093  unsigned d = ef.getFace()/2;
6094 
6095  // Must loop explicitly over the number of guard layers:
6096  int nGuardLayers;
6097 
6098  // The following bitwise AND logical test returns true if ef.m_face is odd
6099  // (meaning the "high" or "right" face in the numbering convention) and
6100  // returns false if ef.m_face is even (meaning the "low" or "left" face in
6101  // the numbering convention):
6102 
6103  if (ef.getFace() & 1) {
6104 
6105  // For "high" face, index in active direction goes from max index of
6106  // Field plus 1 to the same plus number of guard layers:
6107  nGuardLayers = A.rightGuard(d);
6108 
6109  } else {
6110 
6111  // For "low" face, index in active direction goes from min index of
6112  // Field minus the number of guard layers (usually a negative number)
6113  // to the same min index minus 1 (usually negative, and usually -1):
6114  nGuardLayers = A.leftGuard(d);
6115 
6116  }
6117 
6118  // Loop over the number of guard layers, treating each layer as a separate
6119  // slab (contrast this with all other BC types, where all layers are a single
6120  // slab):
6121  for (int guardLayer = 1; guardLayer <= nGuardLayers; guardLayer++) {
6122 
6123  // For linear extrapolation, the multipplier increases with more distant
6124  // guard layers:
6125  int slopeMultipplier = -1*guardLayer;
6126 
6127  if (ef.getFace() & 1) {
6128  slab[d] = Index(domain[d].max() + guardLayer,
6129  domain[d].max() + guardLayer);
6130  } else {
6131  slab[d] = Index(domain[d].min() - guardLayer,
6132  domain[d].min() - guardLayer);
6133  }
6134 
6135  // Loop over all the LField's in the Field A:
6136 
6137  typename Field<T,D,M,Cell>::iterator_if fill_i;
6138  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i) {
6139 
6140  // Cache some things we will use often below.
6141 
6142  // Pointer to the data for the current LField:
6143  LField<T,D> &fill = *(*fill_i).second;
6144 
6145  // NDIndex spanning all elements in the LField, including the guards:
6146  const NDIndex<D> &fill_alloc = fill.getAllocated();
6147 
6148  // If the previously-created boundary guard-layer NDIndex "slab"
6149  // contains any of the elements in this LField (they will be guard
6150  // elements if it does), assign the values into them here by applying
6151  // the boundary condition:
6152 
6153  if (slab.touches(fill_alloc)) {
6154 
6155  // Find what it touches in this LField.
6156  NDIndex<D> dest = slab.intersect(fill_alloc);
6157 
6158  // For linear extrapolation boundary conditions, the boundary
6159  // guard-layer elements are filled based on a slope and intercept
6160  // derived from two layers of interior values; the src1 and src2
6161  // NDIndexes specify these two interior layers, which are operated on
6162  // by mathematical operations whose results are put into dest. The
6163  // ordering of what is defined as src1 and src2 is set differently for
6164  // hi and lo faces, to make the sign for extrapolation work out right:
6165  NDIndex<D> src1 = dest;
6166  NDIndex<D> src2 = dest;
6167  if (ef.getFace() & 1) {
6168  src2[d] = Index(domain[d].max() - 1, domain[d].max() - 1, 1);
6169  src1[d] = Index(domain[d].max(), domain[d].max(), 1);
6170  } else {
6171  src1[d] = Index(0,0,1); // Note: hardwired to 0-base, stride-1; could
6172  src2[d] = Index(1,1,1); // generalize with domain.min(), etc.
6173  }
6174 
6175  // Assume that src1 and src2 are contained withi nthe fill_alloc LField
6176  // domain; I think this is always true if the vnodes are always at
6177  // least one guard-layer-width wide in number of physical elements:
6178 
6179  ComponentLinearExtrapolateFaceBCApply2(dest, src1, src2, fill, ef,
6180  slopeMultipplier);
6181 
6182  }
6183  }
6184  }
6185 }
6186 
6187 
6188 //----------------------------------------------------------------------
6189 
6190 template<class T, unsigned D, class M, class C>
6192 PatchBC(unsigned face)
6193  : BCondBase<T,D,M,C>(face)
6194 {
6195 
6196 
6197 }
6198 
6199 //-----------------------------------------------------------------------------
6200 // PatchBC::apply(Field)
6201 //
6202 // Loop over the patches of the Field, and call the user supplied
6203 // apply(Field::iterator) member function on each.
6204 //-----------------------------------------------------------------------------
6205 
6206 template<class T, unsigned D, class M, class C>
6208 {
6209 
6210 
6211 
6212  //------------------------------------------------------------
6213  // Find the slab that is the destination.
6214  //------------------------------------------------------------
6215 
6216  //
6217  // Get the physical domain for A.
6218  //
6219  const NDIndex<D>& domain( A.getDomain() );
6220 
6221  //
6222  // Start the calculation for the slab we'll be filling by adding
6223  // guard cells to the domain of A.
6224  //
6225  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
6226 
6227  //
6228  // Get which direction is perpendicular to the face we'll be
6229  // filling.
6230  //
6231  unsigned d = this->getFace()/2;
6232 
6233  //
6234  // If the face is odd, we're looking at the 'upper' face, and if it
6235  // is even we're looking at the 'lower'. Calculate the Index for
6236  // the dimension d.
6237  //
6238  if ( this->getFace() & 1 )
6239  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
6240  else
6241  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
6242 
6243  //
6244  // Loop over all the vnodes. We'll take action if it touches the slab.
6245  //
6246  int lfindex = 0;
6247  typename Field<T,D,M,C>::iterator_if fill_i;
6248  typename Field<T,D,M,C>::iterator p = A.begin();
6249  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i, ++lfindex)
6250  {
6251  //
6252  // Cache some things we will use often below.
6253  // fill: the current lfield.
6254  // fill_alloc: the total domain for that lfield.
6255  //
6256  LField<T,D> &fill = *(*fill_i).second;
6257  const NDIndex<D> &fill_alloc = fill.getAllocated();
6258  const NDIndex<D> &fill_owned = fill.getOwned();
6259 
6260  //
6261  // Is this an lfield we care about?
6262  //
6263  if ( slab.touches( fill_alloc ) )
6264  {
6265  // need to worry about compression here
6266  fill.Uncompress();
6267 
6268  //
6269  // Find what part of this lfield is in the slab.
6270  //
6271  NDIndex<D> dest = slab.intersect( fill_alloc );
6272 
6273  //
6274  // Set the iterator to the right spot in the Field.
6275  //
6276  vec<int,D> v;
6277  for (int i=0; i<D; ++i)
6278  v[i] = dest[i].first();
6279  p.SetCurrentLocation( FieldLoc<D>(v,lfindex) );
6280 
6281  //
6282  // Let the user function do its stuff.
6283  //
6284  applyPatch(p,dest);
6285  }
6286  }
6287 }
6288 
6289 //----------------------------------------------------------------------
6290 
6291 #undef COMPONENT_APPLY_BUILTIN
6292 
6293 /***************************************************************************
6294  * $RCSfile: BCond.cpp,v $ $Author: adelmann $
6295  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
6296  * IPPL_VERSION_ID: $Id: BCond.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
6297  ***************************************************************************/
OpExtrapolateAndZero(const T &o, const T &s)
Definition: BCond.hpp:3533
static int getNodes()
Definition: IpplInfo.cpp:773
void PETE_apply(const OpPeriodic< T > &e, T &a, const T &b)
Definition: BCond.hpp:373
OpExtrapolateComponent(const T &o, const T &s, int c)
Definition: BCond.hpp:2756
void SetCurrentLocation(const FieldLoc< Dim > &loc)
scalar_tag get_tag(dcomplex)
Definition: BCond.h:133
Field< double, 3, Mesh_t, Center_t > Field_t
Definition: PBunchDefs.h:49
void ComponentFunctionFaceBCApply(ComponentFunctionFace< T, D, M, Cell > &ff, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:5029
Layout_t & getLayout() const
Definition: BareField.h:130
virtual void apply(Field< T, D, M, C > &A)
Definition: BCond.hpp:5843
ac_id_larray::iterator iterator_if
Definition: BareField.h:91
NDIndex< D > calcEurekaDomain(const NDIndex< D > &realDomain, int face, const GuardCellSizes< D > &gc)
Definition: BCond.hpp:5670
static const T & get(const T &x, int)
Definition: BCond.hpp:5447
constexpr double e
The value of .
Definition: Physics.h:40
OpExtrapolate(const T &o, const T &s)
Definition: BCond.hpp:2745
virtual void write(std::ostream &out) const
Definition: BCond.hpp:205
const NDIndex< Dim > & getDomain() const
Definition: BareField.h:151
Definition: Offset.h:66
Index intersect(const Index &) const
Definition: Index.cpp:108
PatchBC(unsigned face)
Definition: BCond.hpp:6192
Definition: TSVMeta.h:24
Definition: rbendmap.h:8
virtual void apply()
void ComponentLinearExtrapolateFaceBCApply(ComponentLinearExtrapolateFace< T, D, M, C > &ef, Field< T, D, M, C > &A)
Definition: BCond.hpp:6077
#define INFORM_ALL_NODES
Definition: Inform.h:38
void apply(Field< T, D, M, C > &a)
Definition: BCond.hpp:273
void LinearExtrapolateFaceBCApply(LinearExtrapolateFace< T, D, M, C > &ef, Field< T, D, M, C > &A)
Definition: BCond.hpp:5890
const NDIndex< Dim > & getOwned() const
Definition: LField.h:93
void ExtrapolateFaceBCApply2(const NDIndex< D > &dest, const NDIndex< D > &src, LField< T, D > &fill, LField< T, D > &from, const NDIndex< D > &from_alloc, ExtrapolateFace< T, D, M, C > &ef)
Definition: BCond.hpp:2831
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
virtual void write(std::ostream &) const
Definition: BCond.hpp:222
unsigned left(unsigned d) const
Definition: Centering.h:42
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
void CalcParallelPeriodicDomain(const Field< T, D, M, Cell > &A, const ParallelPeriodicFace< T, D, M, Cell > &pf, NDIndex< D > &dest_slab, int &offset)
Definition: BCond.hpp:1065
virtual void write(std::ostream &out) const
Definition: BCond.hpp:172
CenteringEnum
void FunctionFaceBCApply(FunctionFace< T, D, M, Cell > &ff, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:4578
ExtrapolateFace(unsigned f, T o, T s, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:315
OpExtrapolateAndZeroComponent(const T &o, const T &s, int c)
Definition: BCond.hpp:3544
const int COMM_ANY_NODE
Definition: Communicate.h:40
Definition: FFT.h:31
std::complex< double > dcomplex
Definition: dcomplex.h:30
void Uncompress(bool fill_domain=true)
Definition: LField.h:166
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:5409
int getComponent() const
Definition: BCond.h:207
InterpolationFace(unsigned f, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:307
NDIndex< Dim > AddGuardCells(const NDIndex< Dim > &idx, const GuardCellSizes< Dim > &g)
T(* Func)(const T &)
Definition: BCond.hpp:4525
#define BC_PARALLEL_PERIODIC_TAG
Definition: Tags.h:40
void LinearExtrapolateFaceBCApply2(const NDIndex< D > &dest, const NDIndex< D > &src1, const NDIndex< D > &src2, LField< T, D > &fill, LinearExtrapolateFace< T, D, M, C > &ef, int slopeMultipplier)
Definition: BCond.hpp:5851
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
const iterator & begin() const
Definition: LField.h:104
virtual void write(std::ostream &) const
Definition: BCond.hpp:122
unsigned int length() const
Definition: IndexInlines.h:131
NDIndex< Dim > plugBase(const NDIndex< 1 > &i) const
Definition: NDIndex.h:118
#define PAssert_LE(a, b)
Definition: PAssert.h:122
virtual void write(std::ostream &) const
Definition: BCond.hpp:241
virtual void write(std::ostream &) const
Definition: BCond.hpp:212
virtual void write(std::ostream &out) const
Definition: BCond.hpp:160
void ExtrapolateAndZeroFaceBCApply(ExtrapolateAndZeroFace< T, D, M, Cell > &ef, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:3781
#define BC_TAG_CYCLE
Definition: Tags.h:41
OpInterpolationComponent(int c)
Definition: BCond.hpp:441
iterator_if end_if()
Definition: BareField.h:100
Definition: Centering.h:49
#define PAssert_GE(a, b)
Definition: PAssert.h:124
Definition: Index.h:236
Expression Expr_t
type of an expression
Definition: Expression.h:34
virtual void write(std::ostream &out) const
Definition: BCond.hpp:184
size_t size() const
Definition: Message.h:300
virtual void apply(Field< T, D, M, C > &A)
Definition: BCond.hpp:6025
virtual void write(std::ostream &out) const
Definition: BCond.hpp:193
const iterator & end() const
Definition: LField.h:105
OpPeriodicComponent(int c)
Definition: BCond.hpp:379
unsigned rightGuard(unsigned d) const
Definition: BareField.h:148
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
vmap< int, RefCountedP< BCondBase< T, D, M, C > > >::iterator iterator
Definition: BCond.h:240
bool touches(const NDIndex< Dim > &) const
virtual void write(std::ostream &out) const
Definition: BCond.hpp:199
unsigned leftGuard(unsigned d) const
Definition: BareField.h:147
const T & getOffset() const
Definition: BCond.h:498
virtual void write(std::ostream &) const
Definition: BCond.hpp:251
const T & getOffset() const
Definition: BCond.h:454
bool changesPhysicalCells() const
Definition: BCond.hpp:283
#define COMPONENT_APPLY_BUILTIN(OP, T)
Definition: BCond.hpp:55
virtual void write(std::ostream &out) const
Definition: BCond.hpp:135
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:92
EurekaAssign(int c)
Definition: BCond.hpp:5456
Definition: Centering.h:31
virtual void write(std::ostream &out) const
Definition: BCond.hpp:154
virtual void write(std::ostream &out) const
Definition: BCond.hpp:142
OpBCFunctionEq(T(*func)(const T &))
Definition: BCond.hpp:4524
bool IsCompressed() const
Definition: LField.h:128
void InterpolationFaceBCApply(InterpolationFace< T, D, M, Cell > &pf, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:619
void PeriodicFaceBCApply(PeriodicFace< T, D, M, Cell > &pf, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:520
T * value_type(const SliceIterator< T > &)
bool touches(const Index &a) const
Definition: IndexInlines.h:242
unsigned right(unsigned d) const
int m_component
Definition: BCond.h:219
#define PAssert_GT(a, b)
Definition: PAssert.h:123
T::Element_t Element_t
Definition: AppTypeTraits.h:19
virtual void write(std::ostream &out) const
Definition: BCond.hpp:148
void CalcParallelInterpolationDomain(const Field< T, D, M, Cell > &A, const ParallelInterpolationFace< T, D, M, Cell > &pf, NDIndex< D > &src_slab, int &offset)
Definition: BCond.hpp:2012
Definition: Vec.h:21
ApplyToComponentType< T >::type(* Func)(typename ApplyToComponentType< T >::type)
Definition: BCond.hpp:4963
void ComponentLinearExtrapolateFaceBCApply2(const NDIndex< D > &dest, const NDIndex< D > &src1, const NDIndex< D > &src2, LField< T, D > &fill, ComponentLinearExtrapolateFace< T, D, M, C > &ef, int slopeMultipplier)
Definition: BCond.hpp:6033
void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:6207
ComponentFunctionFace(typename ApplyToComponentType< T >::type(*func)(typename ApplyToComponentType< T >::type), unsigned face, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:342
const T & getSlope() const
Definition: BCond.h:455
ExtrapolateAndZeroFace(unsigned f, T o, T s, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:324
iterator begin() const
Definition: BareField.h:233
ApplyToComponentType< T >::type(* Func)(typename ApplyToComponentType< T >::type)
Definition: BCond.h:734
bool contains(const NDIndex< Dim > &a) const
int max() const
Definition: IndexInlines.h:146
const GuardCellSizes< Dim > & getGC() const
Definition: BareField.h:145
virtual void write(std::ostream &) const
Definition: BCond.hpp:232
FunctionFace(T(*func)(const T &), unsigned face)
Definition: BCond.hpp:333
virtual void write(std::ostream &out) const
Definition: BCond.hpp:128
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
#define PAssert(c)
Definition: PAssert.h:117
void ExtrapolateAndZeroFaceBCApply3(const NDIndex< D > &dest, LField< T, D > &fill, ExtrapolateAndZeroFace< T, D, M, C > &ef)
Definition: BCond.hpp:3713
std::string::iterator iterator
Definition: MSLang.h:16
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:508
const GuardCellSizes< Dim > & getGuardCellSizes() const
Definition: BareField.h:146
BCondBase(unsigned int face, int i=allComponents, int j=allComponents)
Definition: BCond.hpp:71
vmap< int, RefCountedP< BCondBase< T, D, M, C > > >::const_iterator const_iterator
Definition: BCond.h:242
Mesh_t & get_mesh() const
Definition: Field.h:113
Interface for a single beam element.
Definition: Component.h:51
void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:4566
void ExtrapolateAndZeroFaceBCApply2(const NDIndex< D > &dest, const NDIndex< D > &src, LField< T, D > &fill, LField< T, D > &from, const NDIndex< D > &from_alloc, ExtrapolateAndZeroFace< T, D, M, C > &ef)
Definition: BCond.hpp:3645
ParticleSpatialLayout< double, 3, Mesh_t > Layout_t
Definition: PBunchDefs.h:43
virtual void write(std::ostream &out) const
Definition: BCond.hpp:166
iterator_if begin_if()
Definition: BareField.h:99
Message * receive_block(int &node, int &tag)
TensorOrder_e getTensorOrder(const scalar_tag &)
Definition: BCond.h:166
Definition: Inform.h:41
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:1343
const T & getSlope() const
Definition: BCond.h:499
#define DEBUGMSG(msg)
Definition: IpplInfo.h:405
static Communicate * Comm
Definition: IpplInfo.h:93
void ExtrapolateFaceBCApply(ExtrapolateFace< T, D, M, Cell > &ef, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:2903
T & getCompressedData()
Definition: LField.h:173
bool send(Message *, int node, int tag, bool delmsg=true)
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:95
T(* Func)(const T &)
Definition: BCond.h:678
int min() const
Definition: IndexInlines.h:141
PeriodicFace(unsigned f, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:297
virtual void write(std::ostream &out) const
Definition: BCond.hpp:178
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:2060
int m_component
Definition: BCond.hpp:5455
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
unsigned int getFace() const
Definition: BCond.h:210
OpAssignComponent(int c)
Definition: BCond.hpp:3587