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