OPAL (Object Oriented Parallel Accelerator Library)  2024.1
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.
375 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,int)
376 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,unsigned)
377 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,short)
378 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,long)
379 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,float)
380 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,double)
381 COMPONENT_APPLY_BUILTIN(OpPeriodicComponent,std::complex<double>)
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 
434 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,int)
435 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,unsigned)
436 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,short)
437 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,long)
438 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,float)
439 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,double)
440 COMPONENT_APPLY_BUILTIN(OpInterpolationComponent,std::complex<double>)
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 {
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 #ifdef PRINT_DEBUG
1417  int send_count = 0;
1418 #endif
1419 
1420  // Communications tag
1421 
1422  int bc_comm_tag;
1423 
1424 
1425  // Next fill the dest_list and src_list, lists of the LFields that
1426  // touch the destination and source domains, respectively.
1427 
1428  // (Do we need this for local-only code???)
1429 
1430  // (Also, if a domain ends up in both lists, it will only be
1431  // involved in local communication. We should structure this code to
1432  // take advantage of this, otherwise all existing parallel code is
1433  // going to incur additional overhead that really is unnecessary.)
1434  // (In other words, we should be able to do the general case, but
1435  // this capability shouldn't slow down the typical cases too much.)
1436 
1437  typedef std::vector<LField_t*> DestList_t;
1438  typedef std::vector<LField_t*> SrcList_t;
1439  typedef typename DestList_t::iterator DestListIterator_t;
1440  typedef typename SrcList_t::iterator SrcListIterator_t;
1441 
1442  DestList_t dest_list;
1443  SrcList_t src_list;
1444 
1445  dest_list.reserve(1);
1446  src_list.reserve(1);
1447 
1448  typename Field_t::iterator_if lf_i;
1449 
1450 #ifdef PRINT_DEBUG
1451  msg << "Starting dest & src domain calculation." << endl;
1452 #endif
1453 
1454  for (lf_i = A.begin_if(); lf_i != A.end_if(); ++lf_i)
1455  {
1456  LField_t &lf = *lf_i->second;
1457 
1458  // We fill if our allocated domain touches the
1459  // destination slab.
1460 
1461  const Domain_t &lf_allocated = lf.getAllocated();
1462 
1463 #ifdef PRINT_DEBUG
1464  msg << " Processing subdomain : " << lf_allocated << endl;
1465  // stop_here();
1466 #endif
1467 
1468  if (lf_allocated.touches(dest_slab))
1469  dest_list.push_back(&lf);
1470 
1471  // We only provide data if our owned cells touch
1472  // the source slab (although we actually send the
1473  // allocated data).
1474 
1475  const Domain_t &lf_owned = lf.getOwned();
1476 
1477  if (lf_owned.touches(src_slab))
1478  src_list.push_back(&lf);
1479  }
1480 
1481 #ifdef PRINT_DEBUG
1482  msg << " dest_list has " << dest_list.size() << " elements." << endl;
1483  msg << " src_list has " << src_list.size() << " elements." << endl;
1484 #endif
1485 
1486  DestListIterator_t dest_begin = dest_list.begin();
1487  DestListIterator_t dest_end = dest_list.end();
1488  SrcListIterator_t src_begin = src_list.begin();
1489  SrcListIterator_t src_end = src_list.end();
1490 
1491  // Aliases to some of Field A's properties...
1492 
1493  const Layout_t &layout = A.getLayout();
1494  const GuardCellSizes<D> &gc = A.getGuardCellSizes();
1495 
1496  int nprocs = Ippl::getNodes();
1497 
1498  if (nprocs > 1) // Skip send/receive code if we're single-processor.
1499  {
1500 
1501 
1502 #ifdef PRINT_DEBUG
1503  msg << "Starting receive calculation." << endl;
1504  // stop_here();
1505 #endif
1506 
1507  //---------------------------------------------------
1508  // Receive calculation
1509  //---------------------------------------------------
1510 
1511  // Mask indicating the nodes will send us messages.
1512 
1513  std::vector<bool> receive_mask(nprocs,false);
1514 
1515  DestListIterator_t dest_i;
1516 
1517  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
1518  {
1519  // Cache some information about this local array.
1520 
1521  LField_t &dest_lf = **dest_i;
1522 
1523  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
1524 
1525  // Calculate the destination domain in this LField, and the
1526  // source domain (which may be spread across multipple
1527  // processors) from whence that domain will be filled:
1528 
1529  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
1530 
1531  Domain_t src_domain = dest_domain;
1532  src_domain[d] = src_domain[d] + offset;
1533 
1534  // Find the remote LFields that contain src_domain. Note
1535  // that we have to fill from the full allocated domains in
1536  // order to properly fill the corners of the boundary cells,
1537  // BUT we only need to intersect with the physical domain.
1538  // Intersecting the allocated domain would result in
1539  // unnecessary messages. (In fact, only the corners *need* to
1540  // send the allocated domains, but for regular decompositions,
1541  // sending the allocated domains will result in fewer
1542  // messages [albeit larger ones] than sending only from
1543  // physical cells.)
1544 
1545  typename Layout_t::touch_range_dv
1546  src_range(layout.touch_range_rdv(src_domain));
1547 
1548  // src_range is a begin/end pair into a list of remote
1549  // domain/vnode pairs whose physical domains touch
1550  // src_domain. Iterate through this list and set up the
1551  // receive map and the receive mask.
1552 
1553  typename Layout_t::touch_iterator_dv rv_i;
1554 
1555  for (rv_i = src_range.first; rv_i != src_range.second; ++rv_i)
1556  {
1557  // Intersect src_domain with the allocated cells for the
1558  // remote LField (rv_alloc). This will give us the strip
1559  // that will be sent. Translate this domain back to the
1560  // domain of the receiving LField.
1561 
1562  const Domain_t rv_alloc = AddGuardCells(rv_i->first,gc);
1563 
1564  Domain_t hit = src_domain.intersect(rv_alloc);
1565  hit[d] = hit[d] - offset;
1566 
1567  // Save this domain and the LField pointer
1568 
1569  typedef typename ReceiveMap_t::value_type value_type;
1570 
1571  receive_map.insert(value_type(hit,&dest_lf));
1572 
1573 #ifdef PRINT_DEBUG
1574  msg << " Need remote data for domain: " << hit << endl;
1575 #endif
1576 
1577  // Note who will be sending this data
1578 
1579  int rnode = rv_i->second->getNode();
1580 
1581  receive_mask[rnode] = true;
1582 
1583  } // rv_i
1584  } // dest_i
1585 
1586  receive_count = 0;
1587 
1588  for (int iproc = 0; iproc < nprocs; ++iproc)
1589  if (receive_mask[iproc]) ++receive_count;
1590 
1591 
1592 #ifdef PRINT_DEBUG
1593  msg << " Expecting to see " << receive_count << " messages." << endl;
1594  msg << "Done with receive calculation." << endl;
1595  // stop_here();
1596 #endif
1597 
1598 
1599 
1600 
1601 
1602 
1603 #ifdef PRINT_DEBUG
1604  msg << "Starting send calculation" << endl;
1605 #endif
1606 
1607  //---------------------------------------------------
1608  // Send calculation
1609  //---------------------------------------------------
1610 
1611  // Array of messages to be sent.
1612 
1613  std::vector<Message *> messages(nprocs);
1614  for (int miter=0; miter < nprocs; messages[miter++] = 0);
1615 
1616  // Debugging info.
1617 
1618 #ifdef PRINT_DEBUG
1619  // KCC 3.2d has trouble with this. 3.3 doesn't, but
1620  // some are still using 3.2.
1621  // vector<int> ndomains(nprocs,0);
1622  std::vector<int> ndomains(nprocs);
1623  for(int i = 0; i < nprocs; ++i) ndomains[i] = 0;
1624 #endif
1625 
1626  SrcListIterator_t src_i;
1627 
1628  for (src_i = src_begin; src_i != src_end; ++src_i)
1629  {
1630  // Cache some information about this local array.
1631 
1632  LField_t &src_lf = **src_i;
1633 
1634  // We need to send the allocated data to properly fill the
1635  // corners when using periodic BCs in multipple dimensions.
1636  // However, we don't want to send to nodes that only would
1637  // receive data from our guard cells. Thus we do the
1638  // intersection test with our owned data.
1639 
1640  const Domain_t &src_lf_owned = src_lf.getOwned();
1641  const Domain_t &src_lf_alloc = src_lf.getAllocated();
1642 
1643  // Calculate the owned and allocated parts of the source
1644  // domain in this LField, and corresponding destination
1645  // domains.
1646 
1647  const Domain_t src_owned = src_lf_owned.intersect(src_slab);
1648  const Domain_t src_alloc = src_lf_alloc.intersect(src_slab);
1649 
1650  Domain_t dest_owned = src_owned;
1651  dest_owned[d] = dest_owned[d] - offset;
1652 
1653  Domain_t dest_alloc = src_alloc;
1654  dest_alloc[d] = dest_alloc[d] - offset;
1655 
1656 #ifdef PRINT_DEBUG
1657  msg << " Considering LField with the domains:" << endl;
1658  msg << " owned = " << src_lf_owned << endl;
1659  msg << " alloc = " << src_lf_alloc << endl;
1660  msg << " The intersections with src_slab are:" << endl;
1661  msg << " owned = " << src_owned << endl;
1662  msg << " alloc = " << src_alloc << endl;
1663 #endif
1664 
1665  // Find the remote LFields whose allocated cells (note the
1666  // additional "gc" arg) are touched by dest_owned.
1667 
1668  typename Layout_t::touch_range_dv
1669  dest_range(layout.touch_range_rdv(dest_owned,gc));
1670 
1671  typename Layout_t::touch_iterator_dv rv_i;
1672 /*
1673 #ifdef PRINT_DEBUG
1674  msg << " Touch calculation found "
1675  << distance(dest_range.first, dest_range.second)
1676  << " elements." << endl;
1677 #endif
1678 */
1679 
1680  for (rv_i = dest_range.first; rv_i != dest_range.second; ++rv_i)
1681  {
1682  // Find the intersection of the returned domain with the
1683  // allocated version of the translated source domain.
1684  // Translate this intersection back to the source side.
1685 
1686  Domain_t hit = dest_alloc.intersect(rv_i->first);
1687  hit[d] = hit[d] + offset;
1688 
1689  // Find out who owns this remote domain.
1690 
1691  int rnode = rv_i->second->getNode();
1692 
1693 #ifdef PRINT_DEBUG
1694  msg << " Overlap domain = " << rv_i->first << endl;
1695  msg << " Inters. domain = " << hit;
1696  msg << " --> node " << rnode << endl;
1697 #endif
1698 
1699  // Create an LField iterator for this intersection region,
1700  // and try to compress it. (Copied from fillGuardCells -
1701  // not quite sure how this works yet. JAC)
1702 
1703  // storage for LField compression
1704 
1705  Element_t compressed_value;
1706  LFI_t msgval = src_lf.begin(hit, compressed_value);
1707  msgval.TryCompress();
1708 
1709  // Put intersection domain and field data into message
1710 
1711  if (!messages[rnode])
1712  {
1713  messages[rnode] = new Message;
1714  PAssert(messages[rnode]);
1715  }
1716 
1717  messages[rnode]->put(hit); // puts Dim items in Message
1718  messages[rnode]->put(msgval); // puts 3 items in Message
1719 
1720 #ifdef PRINT_DEBUG
1721  ndomains[rnode]++;
1722 #endif
1723  } // rv_i
1724  } // src_i
1725 
1726  // Get message tag.
1727 
1728  bc_comm_tag =
1730 
1731 
1732 
1733  // Send the messages.
1734 
1735  for (int iproc = 0; iproc < nprocs; ++iproc)
1736  {
1737  if (messages[iproc])
1738  {
1739 
1740 #ifdef PRINT_DEBUG
1741  msg << " ParallelPeriodicBCApply: Sending message to node "
1742  << iproc << endl
1743  << " number of domains = " << ndomains[iproc] << endl
1744  << " number of MsgItems = "
1745  << messages[iproc]->size() << endl;
1746 #endif
1747 
1748  Ippl::Comm->send(messages[iproc], iproc, bc_comm_tag);
1749 #ifdef PRINT_DEBUG
1750  ++send_count;
1751 #endif
1752 
1753  }
1754 
1755  }
1756 
1757 #ifdef PRINT_DEBUG
1758  msg << " Sent " << send_count << " messages" << endl;
1759  msg << "Done with send." << endl;
1760 #endif
1761 
1762 
1763 
1764 
1765 
1766  } // if (nprocs > 1)
1767 
1768 
1769 
1770 
1771  //===========================================================================
1772  // 2. Evaluate local pieces directly.
1773  //===========================================================================
1774 
1775 #ifdef PRINT_DEBUG
1776  msg << "Starting local calculation." << endl;
1777 #endif
1778 
1779  DestListIterator_t dest_i;
1780 
1781  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
1782  {
1783  // Cache some information about this local array.
1784 
1785  LField_t &dest_lf = **dest_i;
1786 
1787  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
1788 
1789  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
1790 
1791  Domain_t src_domain = dest_domain;
1792  src_domain[d] = src_domain[d] + offset;
1793 
1794  SrcListIterator_t src_i;
1795 
1796  for (src_i = src_begin; src_i != src_end; ++src_i)
1797  {
1798  // Cache some information about this local array.
1799 
1800  LField_t &src_lf = **src_i;
1801 
1802  // Unlike fillGuardCells, we need to send the allocated
1803  // data. This is necessary to properly fill the corners
1804  // when using periodic BCs in multipple dimensions.
1805 
1806  const Domain_t &src_lf_owned = src_lf.getOwned();
1807  const Domain_t &src_lf_alloc = src_lf.getAllocated();
1808 
1809  // Only fill from LFields whose physical domain touches
1810  // the translated destination domain.
1811 
1812  if (src_domain.touches(src_lf_owned))
1813  {
1814  // Worry about compression. Should do this right
1815  // (considering the four different combinations), but
1816  // for now just do what the serial version does:
1817 
1818  dest_lf.Uncompress();
1819 
1820  // Calculate the actual source and destination domains.
1821 
1822  Domain_t real_src_domain =
1823  src_domain.intersect(src_lf_alloc);
1824 
1825  Domain_t real_dest_domain = real_src_domain;
1826  real_dest_domain[d] = real_dest_domain[d] - offset;
1827 
1828 #ifdef PRINT_DEBUG
1829  msg << " Copying local data . . ." << endl;
1830  msg << " source domain = " << real_src_domain << endl;
1831  msg << " dest domain = " << real_dest_domain << endl;
1832 #endif
1833 
1834  // Build the iterators for the copy
1835 
1836  LFI_t lhs = dest_lf.begin(real_dest_domain);
1837  LFI_t rhs = src_lf.begin(real_src_domain);
1838 
1839  // And do the assignment:
1840 
1841  if (this->getComponent() == BCondBase<T,D,M,C>::allComponents)
1842  {
1844  (lhs,rhs,OpPeriodic<T>()).apply();
1845  }
1846  else
1847  {
1849  (lhs,rhs,OpPeriodicComponent<T>(this->getComponent())).apply();
1850  }
1851  }
1852  }
1853  }
1854 
1855 #ifdef PRINT_DEBUG
1856  msg << "Done with local calculation." << endl;
1857 #endif
1858 
1859 
1860 
1861 
1862  //===========================================================================
1863  // 3. Receive messages and evaluate remaining pieces.
1864  //===========================================================================
1865 
1866  if (nprocs > 1)
1867  {
1868 
1869 
1870 
1871 #ifdef PRINT_DEBUG
1872  msg << "Starting receive..." << endl;
1873  // stop_here();
1874 #endif
1875 
1876  while (receive_count > 0)
1877  {
1878 
1879  // Receive the next message.
1880 
1881  int any_node = COMM_ANY_NODE;
1882 
1883 
1884 
1885  Message* message =
1886  Ippl::Comm->receive_block(any_node,bc_comm_tag);
1887  PAssert(message);
1888 
1889  --receive_count;
1890 
1891 
1892 
1893  // Determine the number of domains being sent
1894 
1895  int ndomains = message->size() / (D + 3);
1896 
1897 #ifdef PRINT_DEBUG
1898  msg << " Message received from node "
1899  << any_node << "," << endl
1900  << " number of domains = " << ndomains << endl;
1901 #endif
1902 
1903  for (int idomain=0; idomain < ndomains; ++idomain)
1904  {
1905  // Extract the intersection domain from the message
1906  // and translate it to the destination side.
1907 
1908  Domain_t intersection;
1909  intersection.getMessage(*message);
1910  intersection[d] = intersection[d] - offset;
1911 
1912  // Extract the rhs iterator from it.
1913 
1914  Element_t compressed_value;
1915  LFI_t rhs(compressed_value);
1916  rhs.getMessage(*message);
1917 
1918 #ifdef PRINT_DEBUG
1919  msg << " Received remote overlap region = "
1920  << intersection << endl;
1921 #endif
1922 
1923  // Find the LField it is destined for.
1924 
1925  typename ReceiveMap_t::iterator hit =
1926  receive_map.find(intersection);
1927 
1928  PAssert(hit != receive_map.end());
1929 
1930  // Build the lhs brick iterator.
1931 
1932  // Should have been
1933  // LField<T,D> &lf = *hit->second;
1934  // but SGI's 7.2 multimap doesn't have op->().
1935 
1936  LField<T,D> &lf = *(*hit).second;
1937 
1938  // Check and see if we really have to do this.
1939 
1940 #ifdef PRINT_DEBUG
1941  msg << " LHS compressed ? " << lf.IsCompressed();
1942  msg << ", LHS value = " << *lf.begin() << endl;
1943  msg << " RHS compressed ? " << rhs.IsCompressed();
1944  msg << ", RHS value = " << *rhs << endl;
1945  msg << " *rhs == *lf.begin() ? "
1946  << (*rhs == *lf.begin()) << endl;
1947 #endif
1948  if (!(rhs.IsCompressed() && lf.IsCompressed() &&
1949  (*rhs == *lf.begin())))
1950  {
1951  // Yep. gotta do it.
1952 
1953  lf.Uncompress();
1954  LFI_t lhs = lf.begin(intersection);
1955 
1956  // Do the assignment.
1957 
1958 #ifdef PRINT_DEBUG
1959  msg << " Doing copy." << endl;
1960 #endif
1961 
1962  BrickExpression<D,LFI_t,LFI_t,OpAssign>(lhs,rhs).apply();
1963  }
1964 
1965  // Take that entry out of the receive list.
1966 
1967  receive_map.erase(hit);
1968  }
1969 
1970  delete message;
1971  }
1972 
1973 
1974 #ifdef PRINT_DEBUG
1975  msg << "Done with receive." << endl;
1976 #endif
1977 
1978  }
1979 }
1980 
1981 
1983 // BENI adds CalcParallelInterpolationDomain
1985 template <class T, unsigned D, class M>
1986 inline void
1989  NDIndex<D> &src_slab,
1990  int &offset)
1991 {
1992  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
1993  // expression converts the face index to the direction index.
1994 
1995  unsigned d = pf.getFace()/2;
1996 
1997  const NDIndex<D>& domain(A.getDomain());
1998 
1999  if (pf.getFace() & 1) // Odd ("top" or "right") face
2000  {
2001  // The cells that we need to fill start one beyond the last
2002  // physical cell at the "top" and continue to the last guard
2003  // cell. Change "dest_slab" to restrict direction "d" to this
2004  // subdomain.
2005 
2006  src_slab[d] =
2007  Index(domain[d].max() + 1, domain[d].max() + A.leftGuard(d));
2008 
2009  // The offset to the cells that we are going to read; i.e. the
2010  // read domain will be "dest_slab + offset". This is the number of
2011  // physical cells in that direction.
2012 
2013  offset = -domain[d].length();
2014  }
2015  else // Even ("bottom" or "left") face
2016  {
2017  // The cells that we need to fill start with the first guard
2018  // cell on the bottom and continue up through the cell before
2019  // the first physical cell.
2020 
2021  src_slab[d] =
2022  Index(domain[d].min() - A.leftGuard(d), domain[d].min()-1);
2023 
2024  // See above.
2025 
2026  offset = domain[d].length();
2027  }
2028 }
2029 
2030 
2032 //BENI adds parallelInterpo;lationBC apply
2034 template<class T, unsigned D, class M, class C>
2036 {
2037 
2038 #ifdef PRINT_DEBUG
2039  Inform msg("PInterpolationBC", INFORM_ALL_NODES);
2040 #endif
2041 
2042 
2043  // Useful typedefs:
2044 
2045  typedef T Element_t;
2046  typedef NDIndex<D> Domain_t;
2047  typedef LField<T,D> LField_t;
2048  typedef typename LField_t::iterator LFI_t;
2049  typedef Field<T,D,M,C> Field_t;
2050  typedef FieldLayout<D> Layout_t;
2051 
2052  //===========================================================================
2053  //
2054  // Unlike most boundary conditions, periodic BCs are (in general)
2055  // non-local. Indeed, they really are identical to the guard-cell
2056  // seams between LFields internal to the Field. In this case the
2057  // LFields just have a periodic geometry, but the FieldLayout
2058  // doesn't express this, so we duplicate the code, which is quite
2059  // similar to fillGuardCellsr, but somewhat more complicated, here.
2060  // The complications arise from three sources:
2061  //
2062  // - The source and destination domains are offset, not overlapping.
2063  // - Only a subset of all LFields are, in general, involved.
2064  // - The corners must be handled correctly.
2065  //
2066  // Here's the plan:
2067  //
2068  // 0. Calculate source and destination domains.
2069  // 1. Build send and receive lists, and send messages.
2070  // 2. Evaluate local pieces directly.
2071  // 3. Receive messages and evaluate remaining pieces.
2072  //
2073  //===========================================================================
2074 /*
2075 #ifdef PRINT_DEBUG
2076  msg << "Starting BC Calculation for face "
2077  << getFace() << "." << endl;
2078 #endif
2079 */
2080  //===========================================================================
2081  // 0. Calculate destination domain and the offset.
2082  //===========================================================================
2083 
2084  // Find the slab that is the destination. First get the whole
2085  // domain, including guard cells, and then restrict it to the area
2086  // that this BC will fill.
2087 
2088  const NDIndex<D>& domain(A.getDomain());
2089 
2090  NDIndex<D> src_slab = AddGuardCells(domain,A.getGuardCellSizes());
2091 
2092  // Direction Dim has faces 2*Dim and 2*Dim + 1, so the following
2093  // expression converts the face index to the direction index.
2094 
2095  unsigned d = this->getFace()/2;
2096 
2097  int offset;
2098 
2099  CalcParallelInterpolationDomain(A,*this,src_slab,offset);
2100 
2101  Domain_t dest_slab = src_slab;
2102  dest_slab[d] = dest_slab[d] + offset;
2103 
2104 #ifdef PRINT_DEBUG
2105  msg << "dest_slab = " << dest_slab << endl;
2106  msg << "src_slab = " << src_slab << endl;
2107  // stop_here();
2108 #endif
2109 
2110 
2111  //===========================================================================
2112  // 1. Build send and receive lists and send messages
2113  //===========================================================================
2114 
2115  // Declare these at this scope so that we don't have to duplicate
2116  // the local code. (fillguardcells puts these in the scope of the
2117  // "if (nprocs > 1) { ... }" section, but has to duplicate the
2118  // code for the local fills as a result. The cost of this is a bit
2119  // of stackspace, and the cost of allocating an empty map.)
2120 
2121  // Container for holding Domain -> LField mapping
2122  // so that we can sort out which messages go where.
2123 
2124  typedef std::multimap<Domain_t,LField_t*, std::less<Domain_t> > ReceiveMap_t;
2125 
2126  // (Time this since it allocates an empty map.)
2127 
2128 
2129 
2130  ReceiveMap_t receive_map;
2131 
2132 
2133 
2134  // Number of nodes that will send us messages.
2135 
2136  int receive_count = 0;
2137 #ifdef PRINT_DEBUG
2138  int send_count = 0;
2139 #endif
2140 
2141  // Communications tag
2142 
2143  int bc_comm_tag;
2144 
2145 
2146  // Next fill the dest_list and src_list, lists of the LFields that
2147  // touch the destination and source domains, respectively.
2148 
2149  // (Do we need this for local-only code???)
2150 
2151  // (Also, if a domain ends up in both lists, it will only be
2152  // involved in local communication. We should structure this code to
2153  // take advantage of this, otherwise all existing parallel code is
2154  // going to incur additional overhead that really is unnecessary.)
2155  // (In other words, we should be able to do the general case, but
2156  // this capability shouldn't slow down the typical cases too much.)
2157 
2158  typedef std::vector<LField_t*> DestList_t;
2159  typedef std::vector<LField_t*> SrcList_t;
2160  typedef typename DestList_t::iterator DestListIterator_t;
2161  typedef typename SrcList_t::iterator SrcListIterator_t;
2162 
2163  DestList_t dest_list;
2164  SrcList_t src_list;
2165 
2166  dest_list.reserve(1);
2167  src_list.reserve(1);
2168 
2169  typename Field_t::iterator_if lf_i;
2170 
2171 #ifdef PRINT_DEBUG
2172  msg << "Starting dest & src domain calculation." << endl;
2173 #endif
2174 
2175  for (lf_i = A.begin_if(); lf_i != A.end_if(); ++lf_i)
2176  {
2177  LField_t &lf = *lf_i->second;
2178 
2179  // We fill if our OWNED domain touches the
2180  // destination slab.
2181 
2182  //const Domain_t &lf_allocated = lf.getAllocated();
2183  const Domain_t &lf_owned = lf.getOwned();
2184 
2185 #ifdef PRINT_DEBUG
2186  msg << " Processing subdomain : " << lf_owned << endl;
2187  // stop_here();
2188 #endif
2189 
2190  if (lf_owned.touches(dest_slab))
2191  dest_list.push_back(&lf);
2192 
2193  // We only provide data if our owned cells touch
2194  // the source slab (although we actually send the
2195  // allocated data).
2196 
2197  const Domain_t &lf_allocated = lf.getAllocated();
2198 
2199  if (lf_allocated.touches(src_slab))
2200  src_list.push_back(&lf);
2201  }
2202 
2203 #ifdef PRINT_DEBUG
2204  msg << " dest_list has " << dest_list.size() << " elements." << endl;
2205  msg << " src_list has " << src_list.size() << " elements." << endl;
2206 #endif
2207 
2208  DestListIterator_t dest_begin = dest_list.begin();
2209  DestListIterator_t dest_end = dest_list.end();
2210  SrcListIterator_t src_begin = src_list.begin();
2211  SrcListIterator_t src_end = src_list.end();
2212 
2213  // Aliases to some of Field A's properties...
2214 
2215  const Layout_t &layout = A.getLayout();
2216  const GuardCellSizes<D> &gc = A.getGuardCellSizes();
2217 
2218  int nprocs = Ippl::getNodes();
2219 
2220  if (nprocs > 1) // Skip send/receive code if we're single-processor.
2221  {
2222 
2223 
2224 #ifdef PRINT_DEBUG
2225  msg << "Starting receive calculation." << endl;
2226  // stop_here();
2227 #endif
2228 
2229  //---------------------------------------------------
2230  // Receive calculation
2231  //---------------------------------------------------
2232 
2233  // Mask indicating the nodes will send us messages.
2234 
2235  std::vector<bool> receive_mask(nprocs,false);
2236 
2237  DestListIterator_t dest_i;
2238 
2239  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
2240  {
2241  // Cache some information about this local array.
2242 
2243  LField_t &dest_lf = **dest_i;
2244 
2245  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
2246 
2247  // Calculate the destination domain in this LField, and the
2248  // source domain (which may be spread across multipple
2249  // processors) from whence that domain will be filled:
2250 
2251  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
2252 
2253  Domain_t src_domain = dest_domain;
2254  //BENI:sign change for offset occurs when we iterate over destination first and calulate
2255  // src domain from dest domain
2256  src_domain[d] = src_domain[d] - offset;
2257 
2258  // Find the remote LFields that contain src_domain. Note
2259  // that we have to fill from the full allocated domains in
2260  // order to properly fill the corners of the boundary cells,
2261  // BUT we only need to intersect with the physical domain.
2262  // Intersecting the allocated domain would result in
2263  // unnecessary messages. (In fact, only the corners *need* to
2264  // send the allocated domains, but for regular decompositions,
2265  // sending the allocated domains will result in fewer
2266  // messages [albeit larger ones] than sending only from
2267  // physical cells.)
2268 
2269 //BENI: include ghost cells for src_range
2270  typename Layout_t::touch_range_dv
2271  src_range(layout.touch_range_rdv(src_domain,gc));
2272 
2273  // src_range is a begin/end pair into a list of remote
2274  // domain/vnode pairs whose physical domains touch
2275  // src_domain. Iterate through this list and set up the
2276  // receive map and the receive mask.
2277 
2278  typename Layout_t::touch_iterator_dv rv_i;
2279 
2280  for (rv_i = src_range.first; rv_i != src_range.second; ++rv_i)
2281  {
2282  // Intersect src_domain with the allocated cells for the
2283  // remote LField (rv_alloc). This will give us the strip
2284  // that will be sent. Translate this domain back to the
2285  // domain of the receiving LField.
2286 
2287  //const Domain_t rv_alloc = AddGuardCells(rv_i->first,gc);
2288  const Domain_t rv_alloc = rv_i->first;
2289 
2290  Domain_t hit = src_domain.intersect(rv_alloc);
2291  //BENI: sign change
2292  hit[d] = hit[d] + offset;
2293 
2294  // Save this domain and the LField pointer
2295 
2296  typedef typename ReceiveMap_t::value_type value_type;
2297 
2298  receive_map.insert(value_type(hit,&dest_lf));
2299 
2300 #ifdef PRINT_DEBUG
2301  msg << " Need remote data for domain: " << hit << endl;
2302 #endif
2303 
2304  // Note who will be sending this data
2305 
2306  int rnode = rv_i->second->getNode();
2307 
2308  receive_mask[rnode] = true;
2309 
2310  } // rv_i
2311  } // dest_i
2312 
2313  receive_count = 0;
2314 
2315  for (int iproc = 0; iproc < nprocs; ++iproc)
2316  if (receive_mask[iproc]) ++receive_count;
2317 
2318 
2319 #ifdef PRINT_DEBUG
2320  msg << " Expecting to see " << receive_count << " messages." << endl;
2321  msg << "Done with receive calculation." << endl;
2322  // stop_here();
2323 #endif
2324 
2325 
2326 
2327 
2328 
2329 
2330 #ifdef PRINT_DEBUG
2331  msg << "Starting send calculation" << endl;
2332 #endif
2333 
2334  //---------------------------------------------------
2335  // Send calculation
2336  //---------------------------------------------------
2337 
2338  // Array of messages to be sent.
2339 
2340  std::vector<Message *> messages(nprocs);
2341  for (int miter=0; miter < nprocs; messages[miter++] = 0);
2342 
2343  // Debugging info.
2344 
2345 #ifdef PRINT_DEBUG
2346  // KCC 3.2d has trouble with this. 3.3 doesn't, but
2347  // some are still using 3.2.
2348  // vector<int> ndomains(nprocs,0);
2349  std::vector<int> ndomains(nprocs);
2350  for(int i = 0; i < nprocs; ++i) ndomains[i] = 0;
2351 #endif
2352 
2353  SrcListIterator_t src_i;
2354 
2355  for (src_i = src_begin; src_i != src_end; ++src_i)
2356  {
2357  // Cache some information about this local array.
2358 
2359  LField_t &src_lf = **src_i;
2360 
2361  // We need to send the allocated data to properly fill the
2362  // corners when using periodic BCs in multipple dimensions.
2363  // However, we don't want to send to nodes that only would
2364  // receive data from our guard cells. Thus we do the
2365  // intersection test with our owned data.
2366 
2367  const Domain_t &src_lf_owned = src_lf.getOwned();
2368  const Domain_t &src_lf_alloc = src_lf.getAllocated();
2369 
2370  // Calculate the owned and allocated parts of the source
2371  // domain in this LField, and corresponding destination
2372  // domains.
2373 
2374  const Domain_t src_owned = src_lf_owned.intersect(src_slab);
2375  const Domain_t src_alloc = src_lf_alloc.intersect(src_slab);
2376 
2377  Domain_t dest_owned = src_owned;
2378  dest_owned[d] = dest_owned[d] + offset;
2379 
2380  Domain_t dest_alloc = src_alloc;
2381  dest_alloc[d] = dest_alloc[d] + offset;
2382 
2383 #ifdef PRINT_DEBUG
2384  msg << " Considering LField with the domains:" << endl;
2385  msg << " owned = " << src_lf_owned << endl;
2386  msg << " alloc = " << src_lf_alloc << endl;
2387  msg << " The intersections with src_slab are:" << endl;
2388  msg << " owned = " << src_owned << endl;
2389  msg << " alloc = " << src_alloc << endl;
2390 #endif
2391 
2392  // Find the remote LFields whose allocated cells (note the
2393  // additional "gc" arg) are touched by dest_owned.
2394 
2395  typename Layout_t::touch_range_dv
2396  dest_range(layout.touch_range_rdv(dest_owned,gc));
2397 
2398  typename Layout_t::touch_iterator_dv rv_i;
2399 /*
2400 #ifdef PRINT_DEBUG
2401  msg << " Touch calculation found "
2402  << distance(dest_range.first, dest_range.second)
2403  << " elements." << endl;
2404 #endif
2405 */
2406 
2407  for (rv_i = dest_range.first; rv_i != dest_range.second; ++rv_i)
2408  {
2409  // Find the intersection of the returned domain with the
2410  // allocated version of the translated source domain.
2411  // Translate this intersection back to the source side.
2412 
2413  Domain_t hit = dest_alloc.intersect(rv_i->first);
2414  hit[d] = hit[d] - offset;
2415 
2416  // Find out who owns this remote domain.
2417 
2418  int rnode = rv_i->second->getNode();
2419 
2420 #ifdef PRINT_DEBUG
2421  msg << " Overlap domain = " << rv_i->first << endl;
2422  msg << " Inters. domain = " << hit;
2423  msg << " --> node " << rnode << endl;
2424 #endif
2425 
2426  // Create an LField iterator for this intersection region,
2427  // and try to compress it. (Copied from fillGuardCells -
2428  // not quite sure how this works yet. JAC)
2429 
2430  // storage for LField compression
2431 
2432  Element_t compressed_value;
2433  LFI_t msgval = src_lf.begin(hit, compressed_value);
2434  msgval.TryCompress();
2435 
2436  // Put intersection domain and field data into message
2437 
2438  if (!messages[rnode])
2439  {
2440  messages[rnode] = new Message;
2441  PAssert(messages[rnode]);
2442  }
2443 
2444  messages[rnode]->put(hit); // puts Dim items in Message
2445  messages[rnode]->put(msgval); // puts 3 items in Message
2446 
2447 #ifdef PRINT_DEBUG
2448  ndomains[rnode]++;
2449 #endif
2450  } // rv_i
2451  } // src_i
2452 
2453  // Get message tag.
2454 
2455  bc_comm_tag =
2457 
2458 
2459 
2460  // Send the messages.
2461 
2462  for (int iproc = 0; iproc < nprocs; ++iproc)
2463  {
2464  if (messages[iproc])
2465  {
2466 
2467 #ifdef PRINT_DEBUG
2468  msg << " ParallelPeriodicBCApply: Sending message to node "
2469  << iproc << endl
2470  << " number of domains = " << ndomains[iproc] << endl
2471  << " number of MsgItems = "
2472  << messages[iproc]->size() << endl;
2473 #endif
2474 
2475  Ippl::Comm->send(messages[iproc], iproc, bc_comm_tag);
2476 #ifdef PRINT_DEBUG
2477  ++send_count;
2478 #endif
2479  }
2480 
2481  }
2482 
2483 #ifdef PRINT_DEBUG
2484  msg << " Sent " << send_count << " messages" << endl;
2485  msg << "Done with send." << endl;
2486 #endif
2487 
2488 
2489 
2490 
2491 
2492  } // if (nprocs > 1)
2493 
2494 
2495 
2496 
2497  //===========================================================================
2498  // 2. Evaluate local pieces directly.
2499  //===========================================================================
2500 
2501 #ifdef PRINT_DEBUG
2502  msg << "Starting local calculation." << endl;
2503 #endif
2504 
2505  DestListIterator_t dest_i;
2506 
2507  for (dest_i = dest_begin; dest_i != dest_end; ++dest_i)
2508  {
2509  // Cache some information about this local array.
2510 
2511  LField_t &dest_lf = **dest_i;
2512 
2513  const Domain_t &dest_lf_alloc = dest_lf.getAllocated();
2514  //const Domain_t &dest_lf_owned = dest_lf.getOwned();
2515 
2516  const Domain_t dest_domain = dest_lf_alloc.intersect(dest_slab);
2517 
2518  Domain_t src_domain = dest_domain;
2519  //BENI:sign change for offset occurs when we iterate over destination first and calulate
2520  // src domain from dest domain
2521  src_domain[d] = src_domain[d] - offset;
2522 
2523  SrcListIterator_t src_i;
2524 
2525  for (src_i = src_begin; src_i != src_end; ++src_i)
2526  {
2527  // Cache some information about this local array.
2528 
2529  LField_t &src_lf = **src_i;
2530 
2531  // Unlike fillGuardCells, we need to send the allocated
2532  // data. This is necessary to properly fill the corners
2533  // when using periodic BCs in multipple dimensions.
2534 
2535  //const Domain_t &src_lf_owned = src_lf.getOwned();
2536  const Domain_t &src_lf_alloc = src_lf.getAllocated();
2537 
2538  // Only fill from LFields whose physical domain touches
2539  // the translated destination domain.
2540 
2541  if (src_domain.touches(src_lf_alloc))
2542  {
2543  // Worry about compression. Should do this right
2544  // (considering the four different combinations), but
2545  // for now just do what the serial version does:
2546 
2547  dest_lf.Uncompress();
2548 
2549  // Calculate the actual source and destination domains.
2550 
2551  Domain_t real_src_domain =
2552  src_domain.intersect(src_lf_alloc);
2553 
2554  Domain_t real_dest_domain = real_src_domain;
2555  //BENI: same sign change as above
2556  real_dest_domain[d] = real_dest_domain[d] + offset;
2557 
2558 #ifdef PRINT_DEBUG
2559  msg << " Copying local data . . ." << endl;
2560  msg << " source domain = " << real_src_domain << endl;
2561  msg << " dest domain = " << real_dest_domain << endl;
2562 #endif
2563 
2564  // Build the iterators for the copy
2565 
2566  LFI_t lhs = dest_lf.begin(real_dest_domain);
2567  LFI_t rhs = src_lf.begin(real_src_domain);
2568 
2569  // And do the assignment:
2570 
2571  if (this->getComponent() == BCondBase<T,D,M,C>::allComponents)
2572  {
2574  (lhs,rhs,OpInterpolation<T>()).apply();
2575  }
2576  else
2577  {
2579  (lhs,rhs,OpInterpolationComponent<T>(this->getComponent())).apply();
2580  }
2581  }
2582  }
2583  }
2584 
2585 #ifdef PRINT_DEBUG
2586  msg << "Done with local calculation." << endl;
2587 #endif
2588 
2589 
2590 
2591 
2592  //===========================================================================
2593  // 3. Receive messages and evaluate remaining pieces.
2594  //===========================================================================
2595 
2596  if (nprocs > 1)
2597  {
2598 
2599 
2600 
2601 #ifdef PRINT_DEBUG
2602  msg << "Starting receive..." << endl;
2603  // stop_here();
2604 #endif
2605 
2606  while (receive_count > 0)
2607  {
2608 
2609  // Receive the next message.
2610 
2611  int any_node = COMM_ANY_NODE;
2612 
2613 
2614 
2615  Message* message =
2616  Ippl::Comm->receive_block(any_node,bc_comm_tag);
2617  PAssert(message);
2618 
2619  --receive_count;
2620 
2621 
2622 
2623  // Determine the number of domains being sent
2624 
2625  int ndomains = message->size() / (D + 3);
2626 
2627 #ifdef PRINT_DEBUG
2628  msg << " Message received from node "
2629  << any_node << "," << endl
2630  << " number of domains = " << ndomains << endl;
2631 #endif
2632 
2633  for (int idomain=0; idomain < ndomains; ++idomain)
2634  {
2635  // Extract the intersection domain from the message
2636  // and translate it to the destination side.
2637 
2638  Domain_t intersection;
2639  intersection.getMessage(*message);
2640  //BENI:: sign change
2641  intersection[d] = intersection[d] + offset;
2642 
2643  // Extract the rhs iterator from it.
2644 
2645  Element_t compressed_value;
2646  LFI_t rhs(compressed_value);
2647  rhs.getMessage(*message);
2648 
2649 #ifdef PRINT_DEBUG
2650  msg << " Received remote overlap region = "
2651  << intersection << endl;
2652 #endif
2653 
2654  // Find the LField it is destined for.
2655 
2656  typename ReceiveMap_t::iterator hit =
2657  receive_map.find(intersection);
2658 
2659  PAssert(hit != receive_map.end());
2660 
2661  // Build the lhs brick iterator.
2662 
2663  // Should have been
2664  // LField<T,D> &lf = *hit->second;
2665  // but SGI's 7.2 multimap doesn't have op->().
2666 
2667  LField<T,D> &lf = *(*hit).second;
2668 
2669  // Check and see if we really have to do this.
2670 
2671 #ifdef PRINT_DEBUG
2672  msg << " LHS compressed ? " << lf.IsCompressed();
2673  msg << ", LHS value = " << *lf.begin() << endl;
2674  msg << " RHS compressed ? " << rhs.IsCompressed();
2675  msg << ", RHS value = " << *rhs << endl;
2676  msg << " *rhs == *lf.begin() ? "
2677  << (*rhs == *lf.begin()) << endl;
2678 #endif
2679  if (!(rhs.IsCompressed() && lf.IsCompressed() &&
2680  (*rhs == *lf.begin())))
2681  {
2682  // Yep. gotta do it.
2683 
2684  lf.Uncompress();
2685  LFI_t lhs = lf.begin(intersection);
2686 
2687  // Do the assignment.
2688 
2689 #ifdef PRINT_DEBUG
2690  msg << " Doing copy." << endl;
2691 #endif
2692 
2693  //BrickExpression<D,LFI_t,LFI_t,OpAssign>(lhs,rhs).apply();
2695  }
2696 
2697  // Take that entry out of the receive list.
2698 
2699  receive_map.erase(hit);
2700  }
2701 
2702  delete message;
2703  }
2704 
2705 
2706 #ifdef PRINT_DEBUG
2707  msg << "Done with receive." << endl;
2708 #endif
2709 
2710  }
2711 }
2712 
2713 
2714 
2716 
2717 // Applicative templates for ExtrapolateFace:
2718 
2719 // Standard, for applying to all components of elemental type:
2720 template<class T>
2722 {
2723  OpExtrapolate(const T& o, const T& s) : Offset(o), Slope(s) {}
2725 };
2726 template<class T>
2727 inline void PETE_apply(const OpExtrapolate<T>& e, T& a, const T& b)
2728 { a = b*e.Slope + e.Offset; }
2729 
2730 // Special, for applying to single component of multicomponent elemental type:
2731 template<class T>
2733 {
2734  OpExtrapolateComponent(const T& o, const T& s, int c)
2735  : Offset(o), Slope(s), Component(c) {}
2738 };
2739 template<class T>
2740 inline void PETE_apply(const OpExtrapolateComponent<T>& e, T& a, const T& b)
2741 {
2742  a[e.Component] = b[e.Component]*e.Slope[e.Component] + e.Offset[e.Component];
2743 }
2744 
2745 // Following specializations are necessary because of the runtime branches in
2746 // functions like these in code below:
2747 // if (ef.Component == BCondBase<T,D,M,Cell>::allComponents) {
2748 // BrickExpression<D,LFI,LFI,OpExtrapolate<T> >
2749 // (lhs,rhs,OpExtrapolate<T>(ef.Offset,ef.Slope)).apply();
2750 // } else {
2751 // BrickExpression<D,LFI,LFI,OpExtrapolateComponent<T> >
2752 // (lhs,rhs,OpExtrapolateComponent<T>
2753 // (ef.Offset,ef.Slope,ef.Component)).apply();
2754 // }
2755 // which unfortunately force instantiation of OpExtrapolateComponent instances
2756 // for non-multicomponent types like {char,double,...}. Note: if user uses
2757 // non-multicomponent (no operator[]) types of his own, he'll get a compile
2758 // error.
2759 
2762 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,int)
2763 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,unsigned)
2764 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,short)
2765 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,long)
2766 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,float)
2767 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,double)
2768 COMPONENT_APPLY_BUILTIN(OpExtrapolateComponent,std::complex<double>)
2769 
2771 
2772 //----------------------------------------------------------------------------
2773 // For unspecified centering, can't implement ExtrapolateFace::apply()
2774 // correctly, and can't partial-specialize yet, so... don't have a prototype
2775 // for unspecified centering, so user gets a compile error if he tries to
2776 // invoke it for a centering not yet implemented. Implement external functions
2777 // which are specializations for the various centerings
2778 // {Cell,Vert,CartesianCentering}; these are called from the general
2779 // ExtrapolateFace::apply() function body.
2780 //----------------------------------------------------------------------------
2781 
2783 
2784 template<class T, unsigned D, class M>
2786  Field<T,D,M,Cell>& A );
2787 template<class T, unsigned D, class M>
2789  Field<T,D,M,Vert>& A );
2790 template<class T, unsigned D, class M>
2792  Field<T,D,M,Edge>& A );
2793 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
2795  CartesianCentering<CE,D,NC> >& ef,
2796  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
2797 
2798 template<class T, unsigned D, class M, class C>
2799 void ExtrapolateFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
2800 {
2801  ExtrapolateFaceBCApply(*this, A);
2802 }
2803 
2804 
2805 template<class T, unsigned D, class M, class C>
2806 inline void
2808  LField<T,D> &fill, LField<T,D> &from, const NDIndex<D> &from_alloc,
2810 {
2811  // If both the 'fill' and 'from' are compressed and applying the boundary
2812  // condition on the compressed value would result in no change to
2813  // 'fill' we don't need to uncompress.
2814 
2815  if (fill.IsCompressed() && from.IsCompressed())
2816  {
2817  // So far, so good. Let's check to see if the boundary condition
2818  // would result in filling the guard cells with a different value.
2819 
2820  T a = fill.getCompressedData(), aref = a;
2821  T b = from.getCompressedData();
2823  {
2824  OpExtrapolate<T> op(ef.getOffset(),ef.getSlope());
2825  PETE_apply(op, a, b);
2826  }
2827  else
2828  {
2829  int d = (ef.getComponent() % D + D) % D;
2831  op(ef.getOffset(),ef.getSlope(),d);
2832  PETE_apply(op, a, b);
2833  }
2834  if (a == aref)
2835  {
2836  // Yea! We're outta here.
2837 
2838  return;
2839  }
2840  }
2841 
2842  // Well poop, we have no alternative but to uncompress the region
2843  // we're filling.
2844 
2845  fill.Uncompress();
2846 
2847  NDIndex<D> from_it = src.intersect(from_alloc);
2848  NDIndex<D> fill_it = dest.plugBase(from_it);
2849 
2850  // Build iterators for the copy...
2851 
2852  typedef typename LField<T,D>::iterator LFI;
2853  LFI lhs = fill.begin(fill_it);
2854  LFI rhs = from.begin(from_it);
2855 
2856  // And do the assignment.
2857 
2859  {
2861  (lhs,rhs,OpExtrapolate<T>(ef.getOffset(),ef.getSlope())).apply();
2862  }
2863  else
2864  {
2866  (lhs,rhs,OpExtrapolateComponent<T>
2867  (ef.getOffset(),ef.getSlope(),ef.getComponent())).apply();
2868  }
2869 }
2870 
2871 
2872 //-----------------------------------------------------------------------------
2873 // Specialization of ExtrapolateFace::apply() for Cell centering.
2874 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
2875 //-----------------------------------------------------------------------------
2876 
2877 template<class T, unsigned D, class M>
2879  Field<T,D,M,Cell>& A )
2880 {
2881 
2882 
2883 
2884  // Find the slab that is the destination.
2885  // That is, in English, get an NDIndex spanning elements in the guard layers
2886  // on the face associated with the ExtrapaloteFace object:
2887 
2888  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
2889  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
2890 
2891  // The direction (dimension of the Field) associated with the active face.
2892  // The numbering convention makes this division by two return the right
2893  // value, which will be between 0 and (D-1):
2894 
2895  unsigned d = ef.getFace()/2;
2896  int offset;
2897 
2898  // The following bitwise AND logical test returns true if ef.m_face is odd
2899  // (meaning the "high" or "right" face in the numbering convention) and
2900  // returns false if ef.m_face is even (meaning the "low" or "left" face in
2901  // the numbering convention):
2902 
2903  if (ef.getFace() & 1)
2904  {
2905  // For "high" face, index in active direction goes from max index of
2906  // Field plus 1 to the same plus number of guard layers:
2907  // TJW: this used to say "leftGuard(d)", which I think was wrong:
2908 
2909  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
2910 
2911  // Used in computing interior elements used in computing fill values for
2912  // boundary guard elements; see below:
2913 
2914  offset = 2*domain[d].max() + 1;
2915  }
2916  else
2917  {
2918  // For "low" face, index in active direction goes from min index of
2919  // Field minus the number of guard layers (usually a negative number)
2920  // to the same min index minus 1 (usually negative, and usually -1):
2921 
2922  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
2923 
2924  // Used in computing interior elements used in computing fill values for
2925  // boundary guard elements; see below:
2926 
2927  offset = 2*domain[d].min() - 1;
2928  }
2929 
2930  // Loop over all the LField's in the Field A:
2931 
2932  typename Field<T,D,M,Cell>::iterator_if fill_i;
2933  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
2934  {
2935  // Cache some things we will use often below.
2936  // Pointer to the data for the current LField (right????):
2937 
2938  LField<T,D> &fill = *(*fill_i).second;
2939 
2940  // NDIndex spanning all elements in the LField, including the guards:
2941 
2942  const NDIndex<D> &fill_alloc = fill.getAllocated();
2943 
2944  // If the previously-created boundary guard-layer NDIndex "slab"
2945  // contains any of the elements in this LField (they will be guard
2946  // elements if it does), assign the values into them here by applying
2947  // the boundary condition:
2948 
2949  if (slab.touches(fill_alloc))
2950  {
2951  // Find what it touches in this LField.
2952 
2953  NDIndex<D> dest = slab.intersect(fill_alloc);
2954 
2955  // For extrapolation boundary conditions, the boundary guard-layer
2956  // elements are typically copied from interior values; the "src"
2957  // NDIndex specifies the interior elements to be copied into the
2958  // "dest" boundary guard-layer elements (possibly after some
2959  // mathematical operations like multipplying by minus 1 later):
2960 
2961  NDIndex<D> src = dest;
2962 
2963  // Now calculate the interior elements; the offset variable computed
2964  // above makes this correct for "low" or "high" face cases:
2965 
2966  src[d] = offset - src[d];
2967 
2968  // At this point, we need to see if 'src' is fully contained by
2969  // by 'fill_alloc'. If it is, we have a lot less work to do.
2970 
2971  if (fill_alloc.contains(src))
2972  {
2973  // Great! Our domain contains the elements we're filling from.
2974 
2975  ExtrapolateFaceBCApply2(dest, src, fill, fill,
2976  fill_alloc, ef);
2977  }
2978  else
2979  {
2980  // Yuck! Our domain doesn't contain all of the src. We
2981  // must loop over LFields to find the ones the touch the src.
2982 
2983  typename Field<T,D,M,Cell>::iterator_if from_i;
2984  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
2985  {
2986  // Cache a few things.
2987 
2988  LField<T,D> &from = *(*from_i).second;
2989  const NDIndex<D> &from_owned = from.getOwned();
2990  const NDIndex<D> &from_alloc = from.getAllocated();
2991 
2992  // If src touches this LField...
2993 
2994  if (src.touches(from_owned))
2995  ExtrapolateFaceBCApply2(dest, src, fill, from,
2996  from_alloc, ef);
2997  }
2998  }
2999  }
3000  }
3001 }
3002 
3003 
3004 //-----------------------------------------------------------------------------
3005 // Specialization of ExtrapolateFace::apply() for Vert centering.
3006 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
3007 //-----------------------------------------------------------------------------
3008 
3009 template<class T, unsigned D, class M>
3011  Field<T,D,M,Vert>& A )
3012 {
3013 
3014 
3015 
3016  // Find the slab that is the destination.
3017  // That is, in English, get an NDIndex spanning elements in the guard layers
3018  // on the face associated with the ExtrapaloteFace object:
3019 
3020  const NDIndex<D>& domain(A.getDomain());
3021  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3022 
3023  // The direction (dimension of the Field) associated with the active face.
3024  // The numbering convention makes this division by two return the right
3025  // value, which will be between 0 and (D-1):
3026 
3027  unsigned d = ef.getFace()/2;
3028  int offset;
3029 
3030  // The following bitwise AND logical test returns true if ef.m_face is odd
3031  // (meaning the "high" or "right" face in the numbering convention) and
3032  // returns false if ef.m_face is even (meaning the "low" or "left" face
3033  // in the numbering convention):
3034 
3035  if ( ef.getFace() & 1 )
3036  {
3037  // For "high" face, index in active direction goes from max index of
3038  // Field plus 1 to the same plus number of guard layers:
3039  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3040 
3041  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3042 
3043  // Used in computing interior elements used in computing fill values for
3044  // boundary guard elements; see below:
3045  // N.B.: the extra -1 here is what distinguishes this Vert-centered
3046  // implementation from the Cell-centered one:
3047 
3048  offset = 2*domain[d].max() + 1 - 1;
3049  }
3050  else
3051  {
3052  // For "low" face, index in active direction goes from min index of
3053  // Field minus the number of guard layers (usually a negative number)
3054  // to the same min index minus 1 (usually negative, and usually -1):
3055 
3056  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3057  // Used in computing interior elements used in computing fill values for
3058  // boundary guard elements; see below:
3059  // N.B.: the extra +1 here is what distinguishes this Vert-centered
3060  // implementation from the Cell-centered one:
3061 
3062  offset = 2*domain[d].min() - 1 + 1;
3063  }
3064 
3065  // Loop over all the LField's in the Field A:
3066 
3067  typename Field<T,D,M,Vert>::iterator_if fill_i;
3068  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3069  {
3070  // Cache some things we will use often below.
3071  // Pointer to the data for the current LField (right????):
3072 
3073  LField<T,D> &fill = *(*fill_i).second;
3074  // NDIndex spanning all elements in the LField, including the guards:
3075 
3076  const NDIndex<D> &fill_alloc = fill.getAllocated();
3077  // If the previously-created boundary guard-layer NDIndex "slab"
3078  // contains any of the elements in this LField (they will be guard
3079  // elements if it does), assign the values into them here by applying
3080  // the boundary condition:
3081 
3082  if ( slab.touches( fill_alloc ) )
3083  {
3084  // Find what it touches in this LField.
3085 
3086  NDIndex<D> dest = slab.intersect( fill_alloc );
3087 
3088  // For exrapolation boundary conditions, the boundary guard-layer
3089  // elements are typically copied from interior values; the "src"
3090  // NDIndex specifies the interior elements to be copied into the
3091  // "dest" boundary guard-layer elements (possibly after some
3092  // mathematical operations like multipplying by minus 1 later):
3093 
3094  NDIndex<D> src = dest;
3095 
3096  // Now calculate the interior elements; the offset variable computed
3097  // above makes this correct for "low" or "high" face cases:
3098 
3099  src[d] = offset - src[d];
3100 
3101  // At this point, we need to see if 'src' is fully contained by
3102  // by 'fill_alloc'. If it is, we have a lot less work to do.
3103 
3104  if (fill_alloc.contains(src))
3105  {
3106  // Great! Our domain contains the elements we're filling from.
3107 
3108  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3109  fill_alloc, ef);
3110  }
3111  else
3112  {
3113  // Yuck! Our domain doesn't contain all of the src. We
3114  // must loop over LFields to find the ones the touch the src.
3115 
3116  typename Field<T,D,M,Vert>::iterator_if from_i;
3117  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3118  {
3119  // Cache a few things.
3120 
3121  LField<T,D> &from = *(*from_i).second;
3122  const NDIndex<D> &from_owned = from.getOwned();
3123  const NDIndex<D> &from_alloc = from.getAllocated();
3124 
3125  // If src touches this LField...
3126 
3127  if (src.touches(from_owned))
3128  ExtrapolateFaceBCApply2(dest, src, fill, from,
3129  from_alloc, ef);
3130  }
3131  }
3132  }
3133  }
3134 }
3135 
3136 
3137 
3138 //-----------------------------------------------------------------------------
3139 // Specialization of ExtrapolateFace::apply() for Edge centering.
3140 // Rather, indirectly-called specialized global function ExtrapolateFaceBCApply
3141 //-----------------------------------------------------------------------------
3142 
3143 template<class T, unsigned D, class M>
3145  Field<T,D,M,Edge>& A )
3146 {
3147  // Find the slab that is the destination.
3148  // That is, in English, get an NDIndex spanning elements in the guard layers
3149  // on the face associated with the ExtrapaloteFace object:
3150 
3151  const NDIndex<D>& domain(A.getDomain());
3152  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3153 
3154  // The direction (dimension of the Field) associated with the active face.
3155  // The numbering convention makes this division by two return the right
3156  // value, which will be between 0 and (D-1):
3157 
3158  unsigned d = ef.getFace()/2;
3159  int offset;
3160 
3161  // The following bitwise AND logical test returns true if ef.m_face is odd
3162  // (meaning the "high" or "right" face in the numbering convention) and
3163  // returns false if ef.m_face is even (meaning the "low" or "left" face
3164  // in the numbering convention):
3165 
3166  if ( ef.getFace() & 1 )
3167  {
3168  // For "high" face, index in active direction goes from max index of
3169  // Field plus 1 to the same plus number of guard layers:
3170  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3171 
3172  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3173 
3174  // Used in computing interior elements used in computing fill values for
3175  // boundary guard elements; see below:
3176  // N.B.: the extra -1 here is what distinguishes this Edge-centered
3177  // implementation from the Cell-centered one:
3178 
3179  offset = 2*domain[d].max() + 1 - 1;
3180  }
3181  else
3182  {
3183  // For "low" face, index in active direction goes from min index of
3184  // Field minus the number of guard layers (usually a negative number)
3185  // to the same min index minus 1 (usually negative, and usually -1):
3186 
3187  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3188  // Used in computing interior elements used in computing fill values for
3189  // boundary guard elements; see below:
3190  // N.B.: the extra +1 here is what distinguishes this Edge-centered
3191  // implementation from the Cell-centered one:
3192 
3193  offset = 2*domain[d].min() - 1 + 1;
3194  }
3195 
3196  // Loop over all the LField's in the Field A:
3197 
3198  typename Field<T,D,M,Edge>::iterator_if fill_i;
3199  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3200  {
3201  // Cache some things we will use often below.
3202  // Pointer to the data for the current LField (right????):
3203 
3204  LField<T,D> &fill = *(*fill_i).second;
3205  // NDIndex spanning all elements in the LField, including the guards:
3206 
3207  const NDIndex<D> &fill_alloc = fill.getAllocated();
3208  // If the previously-created boundary guard-layer NDIndex "slab"
3209  // contains any of the elements in this LField (they will be guard
3210  // elements if it does), assign the values into them here by applying
3211  // the boundary condition:
3212 
3213  if ( slab.touches( fill_alloc ) )
3214  {
3215  // Find what it touches in this LField.
3216 
3217  NDIndex<D> dest = slab.intersect( fill_alloc );
3218 
3219  // For exrapolation boundary conditions, the boundary guard-layer
3220  // elements are typically copied from interior values; the "src"
3221  // NDIndex specifies the interior elements to be copied into the
3222  // "dest" boundary guard-layer elements (possibly after some
3223  // mathematical operations like multipplying by minus 1 later):
3224 
3225  NDIndex<D> src = dest;
3226 
3227  // Now calculate the interior elements; the offset variable computed
3228  // above makes this correct for "low" or "high" face cases:
3229 
3230  src[d] = offset - src[d];
3231 
3232  // At this point, we need to see if 'src' is fully contained by
3233  // by 'fill_alloc'. If it is, we have a lot less work to do.
3234 
3235  if (fill_alloc.contains(src))
3236  {
3237  // Great! Our domain contains the elements we're filling from.
3238 
3239  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3240  fill_alloc, ef);
3241  }
3242  else
3243  {
3244  // Yuck! Our domain doesn't contain all of the src. We
3245  // must loop over LFields to find the ones the touch the src.
3246 
3247  typename Field<T,D,M,Edge>::iterator_if from_i;
3248  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3249  {
3250  // Cache a few things.
3251 
3252  LField<T,D> &from = *(*from_i).second;
3253  const NDIndex<D> &from_owned = from.getOwned();
3254  const NDIndex<D> &from_alloc = from.getAllocated();
3255 
3256  // If src touches this LField...
3257 
3258  if (src.touches(from_owned))
3259  ExtrapolateFaceBCApply2(dest, src, fill, from,
3260  from_alloc, ef);
3261  }
3262  }
3263  }
3264  }
3265 }
3266 
3267 
3268 //-----------------------------------------------------------------------------
3269 // Specialization of ExtrapolateFace::apply() for CartesianCentering centering.
3270 // Rather,indirectly-called specialized global function ExtrapolateFaceBCApply:
3271 //-----------------------------------------------------------------------------
3272 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
3276 {
3277 
3278 
3279 
3280  // Find the slab that is the destination.
3281  // That is, in English, get an NDIndex spanning elements in the guard layers
3282  // on the face associated with the ExtrapaloteFace object:
3283 
3284  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
3285  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3286 
3287  // The direction (dimension of the Field) associated with the active face.
3288  // The numbering convention makes this division by two return the right
3289  // value, which will be between 0 and (D-1):
3290 
3291  unsigned d = ef.getFace()/2;
3292  int offset;
3293 
3294  // The following bitwise AND logical test returns true if ef.m_face is odd
3295  // (meaning the "high" or "right" face in the numbering convention) and
3296  // returns false if ef.m_face is even (meaning the "low" or "left" face
3297  // in the numbering convention):
3298 
3299  if ( ef.getFace() & 1 )
3300  {
3301  // offset is used in computing interior elements used in computing fill
3302  // values for boundary guard elements; see below:
3303  // Do the right thing for CELL or VERT centering for this component (or
3304  // all components, if the PeriodicFace object so specifies):
3305 
3306  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
3307  allComponents)
3308  {
3309  // Make sure all components are really centered the same, as assumed:
3310 
3311  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
3312  for (unsigned int c=1; c<NC; c++)
3313  {
3314  // Compare other components with 1st
3315  if (CE[c + d*NC] != centering0)
3316  ERRORMSG("ExtrapolateFaceBCApply: BCond thinks all components"
3317  << " have same centering along direction " << d
3318  << ", but it isn't so." << endl);
3319  }
3320 
3321  // Now do the right thing for CELL or VERT centering of
3322  // all components:
3323 
3324  // For "high" face, index in active direction goes from max index of
3325  // Field plus 1 to the same plus number of guard layers:
3326 
3327  slab[d] = Index(domain[d].max() + 1,
3328  domain[d].max() + A.rightGuard(d));
3329 
3330  if (centering0 == CELL)
3331  {
3332  offset = 2*domain[d].max() + 1 ; // CELL case
3333  }
3334  else
3335  {
3336  offset = 2*domain[d].max() + 1 - 1; // VERT case
3337  }
3338  }
3339  else
3340  {
3341  // The BC applies only to one component, not all:
3342  // Do the right thing for CELL or VERT centering of the component:
3343  if (CE[ef.getComponent() + d*NC] == CELL)
3344  {
3345  // For "high" face, index in active direction goes from max index
3346  // of cells in the Field plus 1 to the same plus number of guard
3347  // layers:
3348  int highcell = A.get_mesh().gridSizes[d] - 2;
3349  slab[d] = Index(highcell + 1, highcell + A.rightGuard(d));
3350 
3351  // offset = 2*domain[d].max() + 1 ; // CELL case
3352  offset = 2*highcell + 1 ; // CELL case
3353  }
3354  else
3355  {
3356  // For "high" face, index in active direction goes from max index
3357  // of verts in the Field plus 1 to the same plus number of guard
3358  // layers:
3359  int highvert = A.get_mesh().gridSizes[d] - 1;
3360  slab[d] = Index(highvert + 1, highvert + A.rightGuard(d));
3361 
3362  // offset = 2*domain[d].max() + 1 - 1; // VERT case
3363  offset = 2*highvert + 1 - 1; // VERT case
3364  }
3365  }
3366  }
3367  else
3368  {
3369  // For "low" face, index in active direction goes from min index of
3370  // Field minus the number of guard layers (usually a negative number)
3371  // to the same min index minus 1 (usually negative, and usually -1):
3372 
3373  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3374 
3375  // offset is used in computing interior elements used in computing fill
3376  // values for boundary guard elements; see below:
3377  // Do the right thing for CELL or VERT centering for this component (or
3378  // all components, if the PeriodicFace object so specifies):
3379 
3380  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
3381  allComponents)
3382  {
3383  // Make sure all components are really centered the same, as assumed:
3384 
3385  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
3386  for (unsigned int c=1; c<NC; c++)
3387  {
3388  // Compare other components with 1st
3389 
3390  if (CE[c + d*NC] != centering0)
3391  ERRORMSG("ExtrapolateFaceBCApply: BCond thinks all components"
3392  << " have same centering along direction " << d
3393  << ", but it isn't so." << endl);
3394  }
3395 
3396  // Now do the right thing for CELL or VERT centering of all
3397  // components:
3398 
3399  if (centering0 == CELL)
3400  {
3401  offset = 2*domain[d].min() - 1; // CELL case
3402  }
3403  else
3404  {
3405  offset = 2*domain[d].min() - 1 + 1; // VERT case
3406  }
3407  }
3408  else
3409  {
3410  // The BC applies only to one component, not all:
3411  // Do the right thing for CELL or VERT centering of the component:
3412 
3413  if (CE[ef.getComponent() + d*NC] == CELL)
3414  {
3415  offset = 2*domain[d].min() - 1; // CELL case
3416  }
3417  else
3418  {
3419  offset = 2*domain[d].min() - 1 + 1; // VERT case
3420  }
3421  }
3422  }
3423 
3424  // Loop over all the LField's in the Field A:
3425 
3426  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
3427  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3428  {
3429  // Cache some things we will use often below.
3430  // Pointer to the data for the current LField (right????):
3431 
3432  LField<T,D> &fill = *(*fill_i).second;
3433 
3434  // NDIndex spanning all elements in the LField, including the guards:
3435 
3436  const NDIndex<D> &fill_alloc = fill.getAllocated();
3437 
3438  // If the previously-created boundary guard-layer NDIndex "slab"
3439  // contains any of the elements in this LField (they will be guard
3440  // elements if it does), assign the values into them here by applying
3441  // the boundary condition:
3442 
3443  if ( slab.touches( fill_alloc ) )
3444  {
3445  // Find what it touches in this LField.
3446 
3447  NDIndex<D> dest = slab.intersect( fill_alloc );
3448 
3449  // For exrapolation boundary conditions, the boundary guard-layer
3450  // elements are typically copied from interior values; the "src"
3451  // NDIndex specifies the interior elements to be copied into the
3452  // "dest" boundary guard-layer elements (possibly after some
3453  // mathematical operations like multipplying by minus 1 later):
3454 
3455  NDIndex<D> src = dest;
3456 
3457  // Now calculate the interior elements; the offset variable computed
3458  // above makes this correct for "low" or "high" face cases:
3459 
3460  src[d] = offset - src[d];
3461 
3462  // At this point, we need to see if 'src' is fully contained by
3463  // by 'fill_alloc'. If it is, we have a lot less work to do.
3464 
3465  if (fill_alloc.contains(src))
3466  {
3467  // Great! Our domain contains the elements we're filling from.
3468 
3469  ExtrapolateFaceBCApply2(dest, src, fill, fill,
3470  fill_alloc, ef);
3471  }
3472  else
3473  {
3474  // Yuck! Our domain doesn't contain all of the src. We
3475  // must loop over LFields to find the ones the touch the src.
3476 
3477  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if
3478  from_i;
3479  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3480  {
3481  // Cache a few things.
3482 
3483  LField<T,D> &from = *(*from_i).second;
3484  const NDIndex<D> &from_owned = from.getOwned();
3485  const NDIndex<D> &from_alloc = from.getAllocated();
3486 
3487  // If src touches this LField...
3488 
3489  if (src.touches(from_owned))
3490  ExtrapolateFaceBCApply2(dest, src, fill, from,
3491  from_alloc, ef);
3492  }
3493  }
3494  }
3495  }
3496 }
3497 
3498 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
3499 // TJW added 12/16/1997 as per Tecolote Team's request... BEGIN
3501 
3502 // Applicative templates for ExtrapolateAndZeroFace:
3503 
3504 // Standard, for applying to all components of elemental type:
3505 template<class T>
3507 {
3508  OpExtrapolateAndZero(const T& o, const T& s) : Offset(o), Slope(s) {}
3510 };
3511 template<class T>
3512 inline void PETE_apply(const OpExtrapolateAndZero<T>& e, T& a, const T& b)
3513 { a = b*e.Slope + e.Offset; }
3514 
3515 // Special, for applying to single component of multicomponent elemental type:
3516 template<class T>
3518 {
3519  OpExtrapolateAndZeroComponent(const T& o, const T& s, int c)
3520  : Offset(o), Slope(s), Component(c) {}
3523 };
3524 template<class T>
3526  const T& b)
3527 {
3528  a[e.Component] = b[e.Component]*e.Slope[e.Component] + e.Offset[e.Component];
3529 }
3530 
3531 // Following specializations are necessary because of the runtime branches in
3532 // functions like these in code below:
3533 // if (ef.Component == BCondBase<T,D,M,Cell>::allComponents) {
3534 // BrickExpression<D,LFI,LFI,OpExtrapolateAndZero<T> >
3535 // (lhs,rhs,OpExtrapolateAndZero<T>(ef.Offset,ef.Slope)).
3536 // apply();
3537 // } else {
3538 // BrickExpression<D,LFI,LFI,
3539 // OpExtrapolateAndZeroComponent<T> >
3540 // (lhs,rhs,OpExtrapolateAndZeroComponent<T>
3541 // (ef.Offset,ef.Slope,ef.Component)).apply();
3542 // }
3543 // which unfortunately force instantiation of OpExtrapolateAndZeroComponent
3544 // instances for non-multicomponent types like {char,double,...}. Note: if
3545 // user uses non-multicomponent (no operator[]) types of his own, he'll get a
3546 // compile error.
3547 
3550 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,int)
3551 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,unsigned)
3552 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,short)
3553 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,long)
3554 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,float)
3555 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,double)
3556 COMPONENT_APPLY_BUILTIN(OpExtrapolateAndZeroComponent,std::complex<double>)
3557 
3558 // Special, for assigning to single component of multicomponent elemental type:
3559 template<class T>
3561 {
3563  : Component(c) { }
3565 };
3566 
3567 template<class T, class T1>
3568 inline void PETE_apply(const OpAssignComponent<T>& e, T& a, const T1& b)
3569 {
3570  a[e.Component] = b;
3571 }
3572 
3575 COMPONENT_APPLY_BUILTIN(OpAssignComponent,int)
3576 COMPONENT_APPLY_BUILTIN(OpAssignComponent,unsigned)
3577 COMPONENT_APPLY_BUILTIN(OpAssignComponent,short)
3578 COMPONENT_APPLY_BUILTIN(OpAssignComponent,long)
3579 COMPONENT_APPLY_BUILTIN(OpAssignComponent,float)
3580 COMPONENT_APPLY_BUILTIN(OpAssignComponent,double)
3581 COMPONENT_APPLY_BUILTIN(OpAssignComponent,std::complex<double>)
3582 
3584 
3585 //----------------------------------------------------------------------------
3586 // For unspecified centering, can't implement ExtrapolateAndZeroFace::apply()
3587 // correctly, and can't partial-specialize yet, so... don't have a prototype
3588 // for unspecified centering, so user gets a compile error if he tries to
3589 // invoke it for a centering not yet implemented. Implement external functions
3590 // which are specializations for the various centerings
3591 // {Cell,Vert,CartesianCentering}; these are called from the general
3592 // ExtrapolateAndZeroFace::apply() function body.
3593 //----------------------------------------------------------------------------
3594 
3596 
3597 template<class T, unsigned D, class M>
3599  Field<T,D,M,Cell>& A );
3600 template<class T, unsigned D, class M>
3602  Field<T,D,M,Vert>& A );
3603 template<class T, unsigned D, class M>
3605  Field<T,D,M,Edge>& A );
3606 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
3608  CartesianCentering<CE,D,NC> >& ef,
3609  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
3610 
3611 template<class T, unsigned D, class M, class C>
3612 void ExtrapolateAndZeroFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
3613 {
3615 }
3616 
3617 
3618 template<class T, unsigned D, class M, class C>
3619 inline void
3621  const NDIndex<D> &src, LField<T,D> &fill, LField<T,D> &from,
3622  const NDIndex<D> &from_alloc, ExtrapolateAndZeroFace<T,D,M,C> &ef)
3623 {
3624  // If both the 'fill' and 'from' are compressed and applying the boundary
3625  // condition on the compressed value would result in no change to
3626  // 'fill' we don't need to uncompress.
3627 
3628  if (fill.IsCompressed() && from.IsCompressed())
3629  {
3630  // So far, so good. Let's check to see if the boundary condition
3631  // would result in filling the guard cells with a different value.
3632 
3633  T a = fill.getCompressedData(), aref = a;
3634  T b = from.getCompressedData();
3636  {
3638  PETE_apply(op, a, b);
3639  }
3640  else
3641  {
3643  op(ef.getOffset(),ef.getSlope(),ef.getComponent());
3644  PETE_apply(op, a, b);
3645  }
3646  if (a == aref)
3647  {
3648  // Yea! We're outta here.
3649 
3650  return;
3651  }
3652  }
3653 
3654  // Well poop, we have no alternative but to uncompress the region
3655  // we're filling.
3656 
3657  fill.Uncompress();
3658 
3659  NDIndex<D> from_it = src.intersect(from_alloc);
3660  NDIndex<D> fill_it = dest.plugBase(from_it);
3661 
3662  // Build iterators for the copy...
3663 
3664  typedef typename LField<T,D>::iterator LFI;
3665  LFI lhs = fill.begin(fill_it);
3666  LFI rhs = from.begin(from_it);
3667 
3668  // And do the assignment.
3669 
3671  {
3673  (lhs, rhs,
3675  }
3676  else
3677  {
3679  (lhs, rhs,
3681  (ef.getOffset(),ef.getSlope(),ef.getComponent())).apply();
3682  }
3683 }
3684 
3685 
3686 template<class T, unsigned D, class M, class C>
3687 inline void
3690 {
3691  // If the LField we're filling is compressed and setting the
3692  // cells/components to zero wouldn't make any difference, we don't
3693  // need to uncompress.
3694 
3695  if (fill.IsCompressed())
3696  {
3697  // So far, so good. Let's check to see if the boundary condition
3698  // would result in filling the guard cells with a different value.
3699 
3701  {
3702  if (fill.getCompressedData() == T(0))
3703  return;
3704  }
3705  else
3706  {
3707  typedef typename AppTypeTraits<T>::Element_t T1;
3708 
3709  //boo-boo for scalar types T a = fill.getCompressedData();
3710  //boo-boo for scalar types if (a[ef.getComponent()] == T1(0))
3711  //boo-boo for scalar types return;
3712 
3713  T a = fill.getCompressedData(), aref = a;
3715  PETE_apply(op, a, T1(0));
3716  if (a == aref)
3717  return;
3718  }
3719  }
3720 
3721  // Well poop, we have no alternative but to uncompress the region
3722  // we're filling.
3723 
3724  fill.Uncompress();
3725 
3726  // Build iterator for the assignment...
3727 
3728  typedef typename LField<T,D>::iterator LFI;
3729  LFI lhs = fill.begin(dest);
3730 
3731  // And do the assignment.
3732 
3734  {
3736  (lhs,PETE_Scalar<T>(T(0)),OpAssign()).apply();
3737  }
3738  else
3739  {
3740  typedef typename AppTypeTraits<T>::Element_t T1;
3741 
3744  (ef.getComponent())).apply();
3745  }
3746 }
3747 
3748 
3749 //-----------------------------------------------------------------------------
3750 // Specialization of ExtrapolateAndZeroFace::apply() for Cell centering.
3751 // Rather, indirectly-called specialized global function
3752 // ExtrapolateAndZeroFaceBCApply
3753 //-----------------------------------------------------------------------------
3754 
3755 template<class T, unsigned D, class M>
3757  Field<T,D,M,Cell>& A )
3758 {
3759 
3760 
3761 
3762  // Find the slab that is the destination.
3763  // That is, in English, get an NDIndex spanning elements in the guard layers
3764  // on the face associated with the ExtrapaloteFace object:
3765 
3766  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
3767  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3768 
3769  // The direction (dimension of the Field) associated with the active face.
3770  // The numbering convention makes this division by two return the right
3771  // value, which will be between 0 and (D-1):
3772 
3773  unsigned d = ef.getFace()/2;
3774  int offset;
3775 
3776  // The following bitwise AND logical test returns true if ef.m_face is odd
3777  // (meaning the "high" or "right" face in the numbering convention) and
3778  // returns false if ef.m_face is even (meaning the "low" or "left" face
3779  // in the numbering convention):
3780 
3781  if (ef.getFace() & 1)
3782  {
3783  // For "high" face, index in active direction goes from max index of
3784  // Field plus 1 to the same plus number of guard layers:
3785  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3786 
3787  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3788 
3789  // Used in computing interior elements used in computing fill values for
3790  // boundary guard elements; see below:
3791 
3792  offset = 2*domain[d].max() + 1;
3793  }
3794  else
3795  {
3796  // For "low" face, index in active direction goes from min index of
3797  // Field minus the number of guard layers (usually a negative number)
3798  // to the same min index minus 1 (usually negative, and usually -1):
3799 
3800  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3801 
3802  // Used in computing interior elements used in computing fill values for
3803  // boundary guard elements; see below:
3804 
3805  offset = 2*domain[d].min() - 1;
3806  }
3807 
3808  // Loop over all the LField's in the Field A:
3809 
3810  typename Field<T,D,M,Cell>::iterator_if fill_i;
3811  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3812  {
3813  // Cache some things we will use often below.
3814  // Pointer to the data for the current LField (right????):
3815 
3816  LField<T,D> &fill = *(*fill_i).second;
3817 
3818  // NDIndex spanning all elements in the LField, including the guards:
3819 
3820  const NDIndex<D> &fill_alloc = fill.getAllocated();
3821 
3822  // If the previously-created boundary guard-layer NDIndex "slab"
3823  // contains any of the elements in this LField (they will be guard
3824  // elements if it does), assign the values into them here by applying
3825  // the boundary condition:
3826 
3827  if (slab.touches(fill_alloc))
3828  {
3829  // Find what it touches in this LField.
3830 
3831  NDIndex<D> dest = slab.intersect(fill_alloc);
3832 
3833  // For extrapolation boundary conditions, the boundary guard-layer
3834  // elements are typically copied from interior values; the "src"
3835  // NDIndex specifies the interior elements to be copied into the
3836  // "dest" boundary guard-layer elements (possibly after some
3837  // mathematical operations like multipplying by minus 1 later):
3838 
3839  NDIndex<D> src = dest;
3840 
3841  // Now calculate the interior elements; the offset variable computed
3842  // above makes this correct for "low" or "high" face cases:
3843 
3844  src[d] = offset - src[d];
3845 
3846  // At this point, we need to see if 'src' is fully contained by
3847  // by 'fill_alloc'. If it is, we have a lot less work to do.
3848 
3849  if (fill_alloc.contains(src))
3850  {
3851  // Great! Our domain contains the elements we're filling from.
3852 
3853  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
3854  fill_alloc, ef);
3855  }
3856  else
3857  {
3858  // Yuck! Our domain doesn't contain all of the src. We
3859  // must loop over LFields to find the ones the touch the src.
3860 
3861  typename Field<T,D,M,Cell>::iterator_if from_i;
3862  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
3863  {
3864  // Cache a few things.
3865 
3866  LField<T,D> &from = *(*from_i).second;
3867  const NDIndex<D> &from_owned = from.getOwned();
3868  const NDIndex<D> &from_alloc = from.getAllocated();
3869 
3870  // If src touches this LField...
3871 
3872  if (src.touches(from_owned))
3873  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
3874  from_alloc, ef);
3875  }
3876  }
3877  }
3878  }
3879 }
3880 
3881 
3882 //-----------------------------------------------------------------------------
3883 // Specialization of ExtrapolateAndZeroFace::apply() for Vert centering.
3884 // Rather, indirectly-called specialized global function
3885 // ExtrapolateAndZeroFaceBCApply
3886 //-----------------------------------------------------------------------------
3887 
3888 template<class T, unsigned D, class M>
3890  Field<T,D,M,Vert>& A )
3891 {
3892 
3893  // Find the slab that is the destination.
3894  // That is, in English, get an NDIndex spanning elements in the guard layers
3895  // on the face associated with the ExtrapaloteFace object:
3896 
3897  const NDIndex<D>& domain(A.getDomain());
3898  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
3899  //boo-boo-2 NDIndex<D> phys = domain;
3900  NDIndex<D> phys = slab;
3901 
3902  // The direction (dimension of the Field) associated with the active face.
3903  // The numbering convention makes this division by two return the right
3904  // value, which will be between 0 and (D-1):
3905 
3906  unsigned d = ef.getFace()/2;
3907  int offset;
3908 
3909  // The following bitwise AND logical test returns true if ef.m_face is odd
3910  // (meaning the "high" or "right" face in the numbering convention) and
3911  // returns false if ef.m_face is even (meaning the "low" or "left" face in
3912  // the numbering convention):
3913 
3914  if ( ef.getFace() & 1 )
3915  {
3916  // For "high" face, index in active direction goes from max index of
3917  // Field plus 1 to the same plus number of guard layers:
3918  // TJW: this used to say "leftGuard(d)", which I think was wrong:
3919 
3920  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
3921 
3922  // Compute the layer of physical cells we're going to set.
3923 
3924  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
3925 
3926  // Used in computing interior elements used in computing fill values for
3927  // boundary guard elements; see below:
3928  // N.B.: the extra -1 here is what distinguishes this Vert-centered
3929  // implementation from the Cell-centered one:
3930 
3931  offset = 2*domain[d].max() + 1 - 1;
3932  }
3933  else
3934  {
3935  // For "low" face, index in active direction goes from min index of
3936  // Field minus the number of guard layers (usually a negative number)
3937  // to the same min index minus 1 (usually negative, and usually -1):
3938 
3939  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
3940 
3941  // Compute the layer of physical cells we're going to set.
3942 
3943  phys[d] = Index( domain[d].min(), domain[d].min(), 1);
3944 
3945  // Used in computing interior elements used in computing fill values for
3946  // boundary guard elements; see below:
3947  // N.B.: the extra +1 here is what distinguishes this Vert-centered
3948  // implementation from the Cell-centered one:
3949 
3950  offset = 2*domain[d].min() - 1 + 1;
3951  }
3952 
3953  // Loop over all the LField's in the Field A:
3954 
3955  typename Field<T,D,M,Vert>::iterator_if fill_i;
3956  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
3957  {
3958  // Cache some things we will use often below.
3959  // Pointer to the data for the current LField (right????):
3960 
3961  LField<T,D> &fill = *(*fill_i).second;
3962 
3963  // Get the physical part of this LField and see if that touches
3964  // the physical cells we want to zero.
3965 
3966  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
3967  const NDIndex<D> &fill_alloc = fill.getAllocated();
3968 
3969  //boo-boo-2 if (phys.touches(fill_owned))
3970  if (phys.touches(fill_alloc))
3971  {
3972  // Find out what we're touching.
3973 
3974  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
3975  NDIndex<D> dest = phys.intersect(fill_alloc);
3976 
3977  // Zero the cells.
3978 
3979  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
3980  }
3981 
3982  // NDIndex spanning all elements in the LField, including the guards:
3983 
3984  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
3985 
3986  // If the previously-created boundary guard-layer NDIndex "slab"
3987  // contains any of the elements in this LField (they will be guard
3988  // elements if it does), assign the values into them here by applying
3989  // the boundary condition:
3990 
3991  if ( slab.touches( fill_alloc ) )
3992  {
3993  // Find what it touches in this LField.
3994 
3995  NDIndex<D> dest = slab.intersect( fill_alloc );
3996 
3997  // For exrapolation boundary conditions, the boundary guard-layer
3998  // elements are typically copied from interior values; the "src"
3999  // NDIndex specifies the interior elements to be copied into the
4000  // "dest" boundary guard-layer elements (possibly after some
4001  // mathematical operations like multipplying by minus 1 later):
4002 
4003  NDIndex<D> src = dest;
4004 
4005  // Now calculate the interior elements; the offset variable computed
4006  // above makes this correct for "low" or "high" face cases:
4007 
4008  src[d] = offset - src[d];
4009 
4010  // At this point, we need to see if 'src' is fully contained by
4011  // by 'fill_alloc'. If it is, we have a lot less work to do.
4012 
4013  if (fill_alloc.contains(src))
4014  {
4015  // Great! Our domain contains the elements we're filling from.
4016 
4017  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4018  fill_alloc, ef);
4019  }
4020  else
4021  {
4022  // Yuck! Our domain doesn't contain all of the src. We
4023  // must loop over LFields to find the ones the touch the src.
4024 
4025  typename Field<T,D,M,Vert>::iterator_if from_i;
4026  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4027  {
4028  // Cache a few things.
4029 
4030  LField<T,D> &from = *(*from_i).second;
4031  const NDIndex<D> &from_owned = from.getOwned();
4032  const NDIndex<D> &from_alloc = from.getAllocated();
4033 
4034  // If src touches this LField...
4035 
4036  if (src.touches(from_owned))
4037  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4038  from_alloc, ef);
4039  }
4040  }
4041  }
4042  }
4043 }
4044 
4045 
4046 //-----------------------------------------------------------------------------
4047 // Specialization of ExtrapolateAndZeroFace::apply() for Edge centering.
4048 // Rather, indirectly-called specialized global function
4049 // ExtrapolateAndZeroFaceBCApply
4050 //-----------------------------------------------------------------------------
4051 
4052 template<class T, unsigned D, class M>
4054  Field<T,D,M,Edge>& A )
4055 {
4056  // Find the slab that is the destination.
4057  // That is, in English, get an NDIndex spanning elements in the guard layers
4058  // on the face associated with the ExtrapaloteFace object:
4059 
4060  const NDIndex<D>& domain(A.getDomain());
4061  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4062  //boo-boo-2 NDIndex<D> phys = domain;
4063  NDIndex<D> phys = slab;
4064 
4065  // The direction (dimension of the Field) associated with the active face.
4066  // The numbering convention makes this division by two return the right
4067  // value, which will be between 0 and (D-1):
4068 
4069  unsigned d = ef.getFace()/2;
4070  int offset;
4071 
4072  // The following bitwise AND logical test returns true if ef.m_face is odd
4073  // (meaning the "high" or "right" face in the numbering convention) and
4074  // returns false if ef.m_face is even (meaning the "low" or "left" face in
4075  // the numbering convention):
4076 
4077  if ( ef.getFace() & 1 )
4078  {
4079  // For "high" face, index in active direction goes from max index of
4080  // Field plus 1 to the same plus number of guard layers:
4081  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4082 
4083  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4084 
4085  // Compute the layer of physical cells we're going to set.
4086 
4087  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
4088 
4089  // Used in computing interior elements used in computing fill values for
4090  // boundary guard elements; see below:
4091  // N.B.: the extra -1 here is what distinguishes this Edge-centered
4092  // implementation from the Cell-centered one:
4093 
4094  offset = 2*domain[d].max() + 1 - 1;
4095  }
4096  else
4097  {
4098  // For "low" face, index in active direction goes from min index of
4099  // Field minus the number of guard layers (usually a negative number)
4100  // to the same min index minus 1 (usually negative, and usually -1):
4101 
4102  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4103 
4104  // Compute the layer of physical cells we're going to set.
4105 
4106  phys[d] = Index( domain[d].min(), domain[d].min(), 1);
4107 
4108  // Used in computing interior elements used in computing fill values for
4109  // boundary guard elements; see below:
4110  // N.B.: the extra +1 here is what distinguishes this Edge-centered
4111  // implementation from the Cell-centered one:
4112 
4113  offset = 2*domain[d].min() - 1 + 1;
4114  }
4115 
4116  // Loop over all the LField's in the Field A:
4117 
4118  typename Field<T,D,M,Edge>::iterator_if fill_i;
4119  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4120  {
4121  // Cache some things we will use often below.
4122  // Pointer to the data for the current LField (right????):
4123 
4124  LField<T,D> &fill = *(*fill_i).second;
4125 
4126  // Get the physical part of this LField and see if that touches
4127  // the physical cells we want to zero.
4128 
4129  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
4130  const NDIndex<D> &fill_alloc = fill.getAllocated();
4131 
4132  //boo-boo-2 if (phys.touches(fill_owned))
4133  if (phys.touches(fill_alloc))
4134  {
4135  // Find out what we're touching.
4136 
4137  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
4138  NDIndex<D> dest = phys.intersect(fill_alloc);
4139 
4140  // Zero the cells.
4141 
4142  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
4143  }
4144 
4145  // NDIndex spanning all elements in the LField, including the guards:
4146 
4147  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
4148 
4149  // If the previously-created boundary guard-layer NDIndex "slab"
4150  // contains any of the elements in this LField (they will be guard
4151  // elements if it does), assign the values into them here by applying
4152  // the boundary condition:
4153 
4154  if ( slab.touches( fill_alloc ) )
4155  {
4156  // Find what it touches in this LField.
4157 
4158  NDIndex<D> dest = slab.intersect( fill_alloc );
4159 
4160  // For exrapolation boundary conditions, the boundary guard-layer
4161  // elements are typically copied from interior values; the "src"
4162  // NDIndex specifies the interior elements to be copied into the
4163  // "dest" boundary guard-layer elements (possibly after some
4164  // mathematical operations like multipplying by minus 1 later):
4165 
4166  NDIndex<D> src = dest;
4167 
4168  // Now calculate the interior elements; the offset variable computed
4169  // above makes this correct for "low" or "high" face cases:
4170 
4171  src[d] = offset - src[d];
4172 
4173  // At this point, we need to see if 'src' is fully contained by
4174  // by 'fill_alloc'. If it is, we have a lot less work to do.
4175 
4176  if (fill_alloc.contains(src))
4177  {
4178  // Great! Our domain contains the elements we're filling from.
4179 
4180  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4181  fill_alloc, ef);
4182  }
4183  else
4184  {
4185  // Yuck! Our domain doesn't contain all of the src. We
4186  // must loop over LFields to find the ones the touch the src.
4187 
4188  typename Field<T,D,M,Edge>::iterator_if from_i;
4189  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4190  {
4191  // Cache a few things.
4192 
4193  LField<T,D> &from = *(*from_i).second;
4194  const NDIndex<D> &from_owned = from.getOwned();
4195  const NDIndex<D> &from_alloc = from.getAllocated();
4196 
4197  // If src touches this LField...
4198 
4199  if (src.touches(from_owned))
4200  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4201  from_alloc, ef);
4202  }
4203  }
4204  }
4205  }
4206 }
4207 
4208 //-----------------------------------------------------------------------------
4209 // Specialization of ExtrapolateAndZeroFace::apply() for CartesianCentering
4210 // centering. Rather,indirectly-called specialized global function
4211 // ExtrapolateAndZeroFaceBCApply:
4212 //-----------------------------------------------------------------------------
4213 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
4217 {
4218 
4219  // Find the slab that is the destination.
4220  // That is, in English, get an NDIndex spanning elements in the guard layers
4221  // on the face associated with the ExtrapaloteFace object:
4222 
4223  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
4224  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4225  //boo-boo-2 NDIndex<D> phys = domain;
4226  NDIndex<D> phys = slab;
4227 
4228  // The direction (dimension of the Field) associated with the active face.
4229  // The numbering convention makes this division by two return the right
4230  // value, which will be between 0 and (D-1):
4231 
4232  unsigned d = ef.getFace()/2;
4233  int offset;
4234  bool setPhys = false;
4235 
4236  // The following bitwise AND logical test returns true if ef.m_face is odd
4237  // (meaning the "high" or "right" face in the numbering convention) and
4238  // returns false if ef.m_face is even (meaning the "low" or "left" face in
4239  // the numbering convention):
4240 
4241  if ( ef.getFace() & 1 )
4242  {
4243  // offset is used in computing interior elements used in computing fill
4244  // values for boundary guard elements; see below:
4245  // Do the right thing for CELL or VERT centering for this component (or
4246  // all components, if the PeriodicFace object so specifies):
4247 
4248  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
4249  allComponents)
4250  {
4251  // Make sure all components are really centered the same, as assumed:
4252 
4253  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4254  for (unsigned int c=1; c<NC; c++)
4255  {
4256  // Compare other components with 1st
4257  if (CE[c + d*NC] != centering0)
4258  ERRORMSG(
4259  "ExtrapolateAndZeroFaceBCApply: BCond thinks all components"
4260  << " have same centering along direction " << d
4261  << ", but it isn't so." << endl);
4262  }
4263 
4264  // Now do the right thing for CELL or VERT centering of
4265  // all components:
4266 
4267  // For "high" face, index in active direction goes from max index of
4268  // Field plus 1 to the same plus number of guard layers:
4269 
4270  slab[d] = Index(domain[d].max() + 1,
4271  domain[d].max() + A.rightGuard(d));
4272 
4273  if (centering0 == CELL)
4274  {
4275  offset = 2*domain[d].max() + 1 ; // CELL case
4276  }
4277  else
4278  {
4279  offset = 2*domain[d].max() + 1 - 1; // VERT case
4280 
4281  // Compute the layer of physical cells we're going to set.
4282 
4283  phys[d] = Index( domain[d].max(), domain[d].max(), 1);
4284  setPhys = true;
4285  }
4286  }
4287  else
4288  {
4289  // The BC applies only to one component, not all:
4290  // Do the right thing for CELL or VERT centering of the component:
4291  if (CE[ef.getComponent() + d*NC] == CELL)
4292  {
4293  // For "high" face, index in active direction goes from max index
4294  // of cells in the Field plus 1 to the same plus number of guard
4295  // layers:
4296  int highcell = A.get_mesh().gridSizes[d] - 2;
4297  slab[d] = Index(highcell + 1, highcell + A.rightGuard(d));
4298 
4299  // offset = 2*domain[d].max() + 1 ; // CELL case
4300  offset = 2*highcell + 1 ; // CELL case
4301  }
4302  else
4303  {
4304  // For "high" face, index in active direction goes from max index
4305  // of verts in the Field plus 1 to the same plus number of guard
4306  // layers:
4307 
4308  int highvert = A.get_mesh().gridSizes[d] - 1;
4309  slab[d] = Index(highvert + 1, highvert + A.rightGuard(d));
4310 
4311  // offset = 2*domain[d].max() + 1 - 1; // VERT case
4312 
4313  offset = 2*highvert + 1 - 1; // VERT case
4314 
4315  // Compute the layer of physical cells we're going to set.
4316 
4317  phys[d] = Index( highvert, highvert, 1 );
4318  setPhys = true;
4319  }
4320  }
4321  }
4322  else
4323  {
4324  // For "low" face, index in active direction goes from min index of
4325  // Field minus the number of guard layers (usually a negative number)
4326  // to the same min index minus 1 (usually negative, and usually -1):
4327 
4328  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4329 
4330  // offset is used in computing interior elements used in computing fill
4331  // values for boundary guard elements; see below:
4332  // Do the right thing for CELL or VERT centering for this component (or
4333  // all components, if the PeriodicFace object so specifies):
4334 
4335  if (ef.getComponent() == BCondBase<T,D,M,CartesianCentering<CE,D,NC> >::
4336  allComponents)
4337  {
4338  // Make sure all components are really centered the same, as assumed:
4339 
4340  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4341  for (unsigned int c=1; c<NC; c++)
4342  {
4343  // Compare other components with 1st
4344 
4345  if (CE[c + d*NC] != centering0)
4346  ERRORMSG(
4347  "ExtrapolateAndZeroFaceBCApply: BCond thinks all components"
4348  << " have same centering along direction " << d
4349  << ", but it isn't so." << endl);
4350  }
4351 
4352  // Now do the right thing for CELL or VERT centering of all
4353  // components:
4354 
4355  if (centering0 == CELL)
4356  {
4357  offset = 2*domain[d].min() - 1; // CELL case
4358  }
4359  else
4360  {
4361  offset = 2*domain[d].min() - 1 + 1; // VERT case
4362 
4363  // Compute the layer of physical cells we're going to set.
4364 
4365  phys[d] = Index(domain[d].min(), domain[d].min(), 1);
4366  setPhys = true;
4367  }
4368  }
4369  else
4370  {
4371  // The BC applies only to one component, not all:
4372  // Do the right thing for CELL or VERT centering of the component:
4373 
4374  if (CE[ef.getComponent() + d*NC] == CELL)
4375  {
4376  offset = 2*domain[d].min() - 1; // CELL case
4377  }
4378  else
4379  {
4380  offset = 2*domain[d].min() - 1 + 1; // VERT case
4381 
4382  // Compute the layer of physical cells we're going to set.
4383 
4384  phys[d] = Index(domain[d].min(), domain[d].min(), 1);
4385  setPhys = true;
4386  }
4387  }
4388  }
4389 
4390  // Loop over all the LField's in the Field A:
4391 
4392  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
4393  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4394  {
4395  // Cache some things we will use often below.
4396  // Pointer to the data for the current LField (right????):
4397 
4398  LField<T,D> &fill = *(*fill_i).second;
4399 
4400  // Get the physical part of this LField and see if that touches
4401  // the physical cells we want to zero.
4402 
4403  const NDIndex<D> &fill_alloc = fill.getAllocated(); // moved here 1/27/99
4404 
4405  if (setPhys)
4406  {
4407  //boo-boo-2 const NDIndex<D> &fill_owned = fill.getOwned();
4408 
4409  //boo-boo-2 if (phys.touches(fill_owned))
4410  if (phys.touches(fill_alloc))
4411  {
4412  // Find out what we're touching.
4413 
4414  //boo-boo-2 NDIndex<D> dest = phys.intersect(fill_owned);
4415  NDIndex<D> dest = phys.intersect(fill_alloc);
4416 
4417  // Zero the cells.
4418 
4419  ExtrapolateAndZeroFaceBCApply3(dest, fill, ef);
4420  }
4421  }
4422 
4423  // NDIndex spanning all elements in the LField, including the guards:
4424 
4425  //boo-boo-2 const NDIndex<D> &fill_alloc = fill.getAllocated();
4426 
4427  // If the previously-created boundary guard-layer NDIndex "slab"
4428  // contains any of the elements in this LField (they will be guard
4429  // elements if it does), assign the values into them here by applying
4430  // the boundary condition:
4431 
4432  if ( slab.touches( fill_alloc ) )
4433  {
4434  // Find what it touches in this LField.
4435 
4436  NDIndex<D> dest = slab.intersect( fill_alloc );
4437 
4438  // For extrapolation boundary conditions, the boundary guard-layer
4439  // elements are typically copied from interior values; the "src"
4440  // NDIndex specifies the interior elements to be copied into the
4441  // "dest" boundary guard-layer elements (possibly after some
4442  // mathematical operations like multipplying by minus 1 later):
4443 
4444  NDIndex<D> src = dest;
4445 
4446  // Now calculate the interior elements; the offset variable computed
4447  // above makes this correct for "low" or "high" face cases:
4448 
4449  src[d] = offset - src[d];
4450 
4451  // At this point, we need to see if 'src' is fully contained by
4452  // by 'fill_alloc'. If it is, we have a lot less work to do.
4453 
4454  if (fill_alloc.contains(src))
4455  {
4456  // Great! Our domain contains the elements we're filling from.
4457 
4458  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, fill,
4459  fill_alloc, ef);
4460  }
4461  else
4462  {
4463  // Yuck! Our domain doesn't contain all of the src. We
4464  // must loop over LFields to find the ones the touch the src.
4465 
4466  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if
4467  from_i;
4468  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4469  {
4470  // Cache a few things.
4471 
4472  LField<T,D> &from = *(*from_i).second;
4473  const NDIndex<D> &from_owned = from.getOwned();
4474  const NDIndex<D> &from_alloc = from.getAllocated();
4475 
4476  // If src touches this LField...
4477 
4478  if (src.touches(from_owned))
4479  ExtrapolateAndZeroFaceBCApply2(dest, src, fill, from,
4480  from_alloc, ef);
4481  }
4482  }
4483  }
4484  }
4485 
4486 }
4487 
4488 // TJW added 12/16/1997 as per Tecolote Team's request... END
4489 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
4490 
4492 
4493 // Applicative templates for FunctionFace:
4494 
4495 // Standard, for applying to all components of elemental type:
4496 template<class T>
4498 {
4499  OpBCFunctionEq(T (*func)(const T&)) : Func(func) {}
4500  T (*Func)(const T&);
4501 };
4502 template<class T>
4503 //tjw3/12/1999inline void PETE_apply(const OpBCFunctionEq<T>& e, T& a, const T& b)
4504 inline void PETE_apply(const OpBCFunctionEq<T>& e, T& a, T& b)
4505 {
4506  a = e.Func(b);
4507 }
4508 
4509 // Special, for applying to single component of multicomponent elemental type:
4510 // DOESN'T EXIST FOR FunctionFace; use ComponentFunctionFace instead.
4511 
4513 
4514 //----------------------------------------------------------------------------
4515 // For unspecified centering, can't implement FunctionFace::apply()
4516 // correctly, and can't partial-specialize yet, so... don't have a prototype
4517 // for unspecified centering, so user gets a compile error if he tries to
4518 // invoke it for a centering not yet implemented. Implement external functions
4519 // which are specializations for the various centerings
4520 // {Cell,Vert,CartesianCentering}; these are called from the general
4521 // FunctionFace::apply() function body.
4522 //----------------------------------------------------------------------------
4523 
4525 
4526 template<class T, unsigned D, class M>
4528  Field<T,D,M,Cell>& A );
4529 template<class T, unsigned D, class M>
4531  Field<T,D,M,Vert>& A );
4532 template<class T, unsigned D, class M>
4534  Field<T,D,M,Edge>& A );
4535 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
4538  Field<T,D,M,CartesianCentering<CE,D,NC> >& A );
4539 
4540 template<class T, unsigned D, class M, class C>
4542 {
4543 
4544 
4545  FunctionFaceBCApply(*this, A);
4546 }
4547 
4548 //-----------------------------------------------------------------------------
4549 // Specialization of FunctionFace::apply() for Cell centering.
4550 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4551 //-----------------------------------------------------------------------------
4552 template<class T, unsigned D, class M>
4554  Field<T,D,M,Cell>& A )
4555 {
4556 
4557 
4558 
4559  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4560  // comprehensible comments --TJW
4561 
4562  // Find the slab that is the destination.
4563  const NDIndex<D>& domain( A.getDomain() );
4564  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4565  unsigned d = ff.getFace()/2;
4566  int offset;
4567  if ( ff.getFace() & 1 ) {
4568  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4569  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4570  offset = 2*domain[d].max() + 1;
4571  }
4572  else {
4573  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4574  offset = 2*domain[d].min() - 1;
4575  }
4576 
4577  // Loop over the ones the slab touches.
4578  typename Field<T,D,M,Cell>::iterator_if fill_i;
4579  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4580  {
4581  // Cache some things we will use often below.
4582  LField<T,D> &fill = *(*fill_i).second;
4583  const NDIndex<D> &fill_alloc = fill.getAllocated();
4584  if ( slab.touches( fill_alloc ) )
4585  {
4586  // Find what it touches in this LField.
4587  NDIndex<D> dest = slab.intersect( fill_alloc );
4588 
4589  // Find where that comes from.
4590  NDIndex<D> src = dest;
4591  src[d] = offset - src[d];
4592 
4593  // Loop over the ones that src touches.
4594  typename Field<T,D,M,Cell>::iterator_if from_i;
4595  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4596  {
4597  // Cache a few things.
4598  LField<T,D> &from = *(*from_i).second;
4599  const NDIndex<D> &from_owned = from.getOwned();
4600  const NDIndex<D> &from_alloc = from.getAllocated();
4601  // If src touches this LField...
4602  if ( src.touches( from_owned ) )
4603  {
4604  // bfh: Worry about compression ...
4605  // If 'fill' is a compressed LField, then writing data into
4606  // it via the expression will actually write the value for
4607  // all elements of the LField. We can do the following:
4608  // a) figure out if the 'fill' elements are all the same
4609  // value, if 'from' elements are the same value, if
4610  // the 'fill' elements are the same as the elements
4611  // throughout that LField, and then just do an
4612  // assigment for a single element
4613  // b) just uncompress the 'fill' LField, to make sure we
4614  // do the right thing.
4615  // I vote for b).
4616  fill.Uncompress();
4617 
4618  NDIndex<D> from_it = src.intersect( from_alloc );
4619  NDIndex<D> fill_it = dest.plugBase( from_it );
4620  // Build iterators for the copy...
4621  typedef typename LField<T,D>::iterator LFI;
4622  LFI lhs = fill.begin(fill_it);
4623  LFI rhs = from.begin(from_it);
4624  // And do the assignment.
4626  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4627  }
4628  }
4629  }
4630  }
4631 }
4632 
4633 //-----------------------------------------------------------------------------
4634 // Specialization of FunctionFace::apply() for Vert centering.
4635 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4636 //-----------------------------------------------------------------------------
4637 template<class T, unsigned D, class M>
4639  Field<T,D,M,Vert>& A )
4640 {
4641 
4642 
4643 
4644  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4645  // comprehensible comments --TJW
4646 
4647  // Find the slab that is the destination.
4648  const NDIndex<D>& domain( A.getDomain() );
4649  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4650  unsigned d = ff.getFace()/2;
4651  int offset;
4652  if ( ff.getFace() & 1 ) {
4653  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4654  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4655  // N.B.: the extra -1 here is what distinguishes this Vert-centered
4656  // implementation from the Cell-centered one:
4657  offset = 2*domain[d].max() + 1 - 1;
4658  }
4659  else {
4660  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4661  // N.B.: the extra +1 here is what distinguishes this Vert-centered
4662  // implementation from the Cell-centered one:
4663  offset = 2*domain[d].min() - 1 + 1;
4664  }
4665 
4666  // Loop over the ones the slab touches.
4667  typename Field<T,D,M,Vert>::iterator_if fill_i;
4668  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4669  {
4670  // Cache some things we will use often below.
4671  LField<T,D> &fill = *(*fill_i).second;
4672  const NDIndex<D> &fill_alloc = fill.getAllocated();
4673  if ( slab.touches( fill_alloc ) )
4674  {
4675  // Find what it touches in this LField.
4676  NDIndex<D> dest = slab.intersect( fill_alloc );
4677 
4678  // Find where that comes from.
4679  NDIndex<D> src = dest;
4680  src[d] = offset - src[d];
4681 
4682  // Loop over the ones that src touches.
4683  typename Field<T,D,M,Vert>::iterator_if from_i;
4684  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4685  {
4686  // Cache a few things.
4687  LField<T,D> &from = *(*from_i).second;
4688  const NDIndex<D> &from_owned = from.getOwned();
4689  const NDIndex<D> &from_alloc = from.getAllocated();
4690  // If src touches this LField...
4691  if ( src.touches( from_owned ) )
4692  {
4693  // bfh: Worry about compression ...
4694  // If 'fill' is a compressed LField, then writing data into
4695  // it via the expression will actually write the value for
4696  // all elements of the LField. We can do the following:
4697  // a) figure out if the 'fill' elements are all the same
4698  // value, if 'from' elements are the same value, if
4699  // the 'fill' elements are the same as the elements
4700  // throughout that LField, and then just do an
4701  // assigment for a single element
4702  // b) just uncompress the 'fill' LField, to make sure we
4703  // do the right thing.
4704  // I vote for b).
4705  fill.Uncompress();
4706 
4707  NDIndex<D> from_it = src.intersect( from_alloc );
4708  NDIndex<D> fill_it = dest.plugBase( from_it );
4709  // Build iterators for the copy...
4710  typedef typename LField<T,D>::iterator LFI;
4711  LFI lhs = fill.begin(fill_it);
4712  LFI rhs = from.begin(from_it);
4713  // And do the assignment.
4715  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4716  }
4717  }
4718  }
4719  }
4720 }
4721 
4722 //-----------------------------------------------------------------------------
4723 // Specialization of FunctionFace::apply() for Edge centering.
4724 // Rather, indirectly-called specialized global function FunctionFaceBCApply
4725 //-----------------------------------------------------------------------------
4726 template<class T, unsigned D, class M>
4728  Field<T,D,M,Edge>& A )
4729 {
4730  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4731  // comprehensible comments --TJW
4732 
4733  // Find the slab that is the destination.
4734  const NDIndex<D>& domain( A.getDomain() );
4735  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4736  unsigned d = ff.getFace()/2;
4737  int offset;
4738  if ( ff.getFace() & 1 ) {
4739  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4740  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4741  // N.B.: the extra -1 here is what distinguishes this Edge-centered
4742  // implementation from the Cell-centered one:
4743  offset = 2*domain[d].max() + 1 - 1;
4744  }
4745  else {
4746  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4747  // N.B.: the extra +1 here is what distinguishes this Edge-centered
4748  // implementation from the Cell-centered one:
4749  offset = 2*domain[d].min() - 1 + 1;
4750  }
4751 
4752  // Loop over the ones the slab touches.
4753  typename Field<T,D,M,Edge>::iterator_if fill_i;
4754  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4755  {
4756  // Cache some things we will use often below.
4757  LField<T,D> &fill = *(*fill_i).second;
4758  const NDIndex<D> &fill_alloc = fill.getAllocated();
4759  if ( slab.touches( fill_alloc ) )
4760  {
4761  // Find what it touches in this LField.
4762  NDIndex<D> dest = slab.intersect( fill_alloc );
4763 
4764  // Find where that comes from.
4765  NDIndex<D> src = dest;
4766  src[d] = offset - src[d];
4767 
4768  // Loop over the ones that src touches.
4769  typename Field<T,D,M,Edge>::iterator_if from_i;
4770  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4771  {
4772  // Cache a few things.
4773  LField<T,D> &from = *(*from_i).second;
4774  const NDIndex<D> &from_owned = from.getOwned();
4775  const NDIndex<D> &from_alloc = from.getAllocated();
4776  // If src touches this LField...
4777  if ( src.touches( from_owned ) )
4778  {
4779  // bfh: Worry about compression ...
4780  // If 'fill' is a compressed LField, then writing data into
4781  // it via the expression will actually write the value for
4782  // all elements of the LField. We can do the following:
4783  // a) figure out if the 'fill' elements are all the same
4784  // value, if 'from' elements are the same value, if
4785  // the 'fill' elements are the same as the elements
4786  // throughout that LField, and then just do an
4787  // assigment for a single element
4788  // b) just uncompress the 'fill' LField, to make sure we
4789  // do the right thing.
4790  // I vote for b).
4791  fill.Uncompress();
4792 
4793  NDIndex<D> from_it = src.intersect( from_alloc );
4794  NDIndex<D> fill_it = dest.plugBase( from_it );
4795  // Build iterators for the copy...
4796  typedef typename LField<T,D>::iterator LFI;
4797  LFI lhs = fill.begin(fill_it);
4798  LFI rhs = from.begin(from_it);
4799  // And do the assignment.
4801  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4802  }
4803  }
4804  }
4805  }
4806 }
4807 
4808 //-----------------------------------------------------------------------------
4809 // Specialization of FunctionFace::apply() for CartesianCentering centering.
4810 // Rather, indirectly-called specialized global function FunctionFaceBCApply:
4811 //-----------------------------------------------------------------------------
4812 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
4816 {
4817 
4818 
4819 
4820  // NOTE: See the ExtrapolateFaceBCApply functions above for more
4821  // comprehensible comments --TJW
4822 
4823  // Find the slab that is the destination.
4824  const NDIndex<D>& domain( A.getDomain() );
4825  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
4826  unsigned d = ff.getFace()/2;
4827  int offset;
4828  if ( ff.getFace() & 1 ) {
4829  // TJW: this used to say "leftGuard(d)", which I think was wrong:
4830  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
4831  // Do the right thing for CELL or VERT centering for all components:
4832  // Make sure all components are really centered the same, as assumed:
4833  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4834  for (int c=1; c<NC; c++) { // Compare other components with 1st
4835  if (CE[c + d*NC] != centering0)
4836  ERRORMSG("FunctionFaceBCApply: BCond thinks all components have"
4837  << " same centering along direction " << d
4838  << ", but it isn't so." << endl);
4839  }
4840  // Now do the right thing for CELL or VERT centering of all components:
4841  if (centering0 == CELL) {
4842  offset = 2*domain[d].max() + 1; // CELL case
4843  } else {
4844  offset = 2*domain[d].max() + 1 - 1; // VERT case
4845  }
4846  }
4847  else {
4848  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
4849  // Do the right thing for CELL or VERT centering for all components:
4850  // Make sure all components are really centered the same, as assumed:
4851  CenteringEnum centering0 = CE[0 + d*NC]; // 1st component along dir d
4852  for (int c=1; c<NC; c++) { // Compare other components with 1st
4853  if (CE[c + d*NC] != centering0)
4854  ERRORMSG("FunctionFaceBCApply: BCond thinks all components have"
4855  << " same centering along direction " << d
4856  << ", but it isn't so." << endl);
4857  }
4858  // Now do the right thing for CELL or VERT centering of all components:
4859  if (centering0 == CELL) {
4860  offset = 2*domain[d].min() - 1; // CELL case
4861  } else {
4862  offset = 2*domain[d].min() - 1 + 1; // VERT case
4863  }
4864  }
4865 
4866  // Loop over the ones the slab touches.
4867  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
4868  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
4869  {
4870  // Cache some things we will use often below.
4871  LField<T,D> &fill = *(*fill_i).second;
4872  const NDIndex<D> &fill_alloc = fill.getAllocated();
4873  if ( slab.touches( fill_alloc ) )
4874  {
4875  // Find what it touches in this LField.
4876  NDIndex<D> dest = slab.intersect( fill_alloc );
4877 
4878  // Find where that comes from.
4879  NDIndex<D> src = dest;
4880  src[d] = offset - src[d];
4881 
4882  // Loop over the ones that src touches.
4883  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if from_i;
4884  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
4885  {
4886  // Cache a few things.
4887  LField<T,D> &from = *(*from_i).second;
4888  const NDIndex<D> &from_owned = from.getOwned();
4889  const NDIndex<D> &from_alloc = from.getAllocated();
4890  // If src touches this LField...
4891  if ( src.touches( from_owned ) )
4892  {
4893  // bfh: Worry about compression ...
4894  // If 'fill' is a compressed LField, then writing data into
4895  // it via the expression will actually write the value for
4896  // all elements of the LField. We can do the following:
4897  // a) figure out if the 'fill' elements are all the same
4898  // value, if 'from' elements are the same value, if
4899  // the 'fill' elements are the same as the elements
4900  // throughout that LField, and then just do an
4901  // assigment for a single element
4902  // b) just uncompress the 'fill' LField, to make sure we
4903  // do the right thing.
4904  // I vote for b).
4905  fill.Uncompress();
4906 
4907  NDIndex<D> from_it = src.intersect( from_alloc );
4908  NDIndex<D> fill_it = dest.plugBase( from_it );
4909  // Build iterators for the copy...
4910  typedef typename LField<T,D>::iterator LFI;
4911  LFI lhs = fill.begin(fill_it);
4912  LFI rhs = from.begin(from_it);
4913  // And do the assignment.
4915  (lhs,rhs,OpBCFunctionEq<T>(ff.Func)).apply();
4916  }
4917  }
4918  }
4919  }
4920 }
4921 
4923 
4924 // Applicative templates for ComponentFunctionFace:
4925 
4926 // Standard, for applying to all components of elemental type:
4927 // DOESN'T EXIST FOR ComponentFunctionFace; use FunctionFace instead.
4928 
4929 // Special, for applying to single component of multicomponent elemental type:
4930 template<class T>
4932 {
4935  int c) :
4936  Func(func), Component(c) {}
4940 };
4941 template<class T>
4942 inline void PETE_apply(const OpBCFunctionEqComponent<T>& e, T& a, const T& b)
4943 { a[e.Component] = e.Func(b[e.Component]); }
4944 
4945 // Following specializations are necessary because of the runtime branches in
4946 // code which unfortunately force instantiation of OpBCFunctionEqComponent
4947 // instances for non-multicomponent types like {char,double,...}.
4948 // Note: if user uses non-multicomponent (no operator[]) types of his own,
4949 // he'll get a compile error. See comments regarding similar specializations
4950 // for OpExtrapolateComponent for a more details.
4951 
4954 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,int)
4955 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,unsigned)
4956 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,short)
4957 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,long)
4958 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,float)
4959 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,double)
4960 COMPONENT_APPLY_BUILTIN(OpBCFunctionEqComponent,std::complex<double>)
4961 
4962 
4964 
4965 //----------------------------------------------------------------------------
4966 // For unspecified centering, can't implement ComponentFunctionFace::apply()
4967 // correctly, and can't partial-specialize yet, so... don't have a prototype
4968 // for unspecified centering, so user gets a compile error if he tries to
4969 // invoke it for a centering not yet implemented. Implement external functions
4970 // which are specializations for the various centerings
4971 // {Cell,Vert,CartesianCentering}; these are called from the general
4972 // ComponentFunctionFace::apply() function body.
4973 //----------------------------------------------------------------------------
4974 
4976 
4977 template<class T, unsigned D, class M>
4979  Field<T,D,M,Cell>& A );
4980 template<class T, unsigned D, class M>
4982  Field<T,D,M,Vert>& A );
4983 template<class T, unsigned D, class M>
4985  Field<T,D,M,Edge>& A );
4986 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
4988  CartesianCentering<CE,D,NC> >& ff,
4989  Field<T,D,M,
4990  CartesianCentering<CE,D,NC> >& A );
4991 
4992 template<class T, unsigned D, class M, class C>
4993 void ComponentFunctionFace<T,D,M,C>::apply( Field<T,D,M,C>& A )
4994 {
4995  ComponentFunctionFaceBCApply(*this, A);
4996 }
4997 
4998 //-----------------------------------------------------------------------------
4999 //Specialization of ComponentFunctionFace::apply() for Cell centering.
5000 //Rather, indirectly-called specialized global function
5001 //ComponentFunctionFaceBCApply
5002 //-----------------------------------------------------------------------------
5003 template<class T, unsigned D, class M>
5005  Field<T,D,M,Cell>& A )
5006 {
5007 
5008 
5009 
5010  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5011  // comprehensible comments --TJW
5012 
5013  // Find the slab that is the destination.
5014  const NDIndex<D>& domain( A.getDomain() );
5015  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5016  unsigned d = ff.getFace()/2;
5017  int offset;
5018  if ( ff.getFace() & 1 ) {
5019  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5020  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5021  offset = 2*domain[d].max() + 1;
5022  }
5023  else {
5024  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5025  offset = 2*domain[d].min() - 1;
5026  }
5027 
5028  // Loop over the ones the slab touches.
5029  typename Field<T,D,M,Cell>::iterator_if fill_i;
5030  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5031  {
5032  // Cache some things we will use often below.
5033  LField<T,D> &fill = *(*fill_i).second;
5034  const NDIndex<D> &fill_alloc = fill.getAllocated();
5035  if ( slab.touches( fill_alloc ) )
5036  {
5037  // Find what it touches in this LField.
5038  NDIndex<D> dest = slab.intersect( fill_alloc );
5039 
5040  // Find where that comes from.
5041  NDIndex<D> src = dest;
5042  src[d] = offset - src[d];
5043 
5044  // Loop over the ones that src touches.
5045  typename Field<T,D,M,Cell>::iterator_if from_i;
5046  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5047  {
5048  // Cache a few things.
5049  LField<T,D> &from = *(*from_i).second;
5050  const NDIndex<D> &from_owned = from.getOwned();
5051  const NDIndex<D> &from_alloc = from.getAllocated();
5052  // If src touches this LField...
5053  if ( src.touches( from_owned ) )
5054  {
5055  // bfh: Worry about compression ...
5056  // If 'fill' is a compressed LField, then writing data into
5057  // it via the expression will actually write the value for
5058  // all elements of the LField. We can do the following:
5059  // a) figure out if the 'fill' elements are all the same
5060  // value, if 'from' elements are the same value, if
5061  // the 'fill' elements are the same as the elements
5062  // throughout that LField, and then just do an
5063  // assigment for a single element
5064  // b) just uncompress the 'fill' LField, to make sure we
5065  // do the right thing.
5066  // I vote for b).
5067  fill.Uncompress();
5068 
5069  NDIndex<D> from_it = src.intersect( from_alloc );
5070  NDIndex<D> fill_it = dest.plugBase( from_it );
5071  // Build iterators for the copy...
5072  typedef typename LField<T,D>::iterator LFI;
5073  LFI lhs = fill.begin(fill_it);
5074  LFI rhs = from.begin(from_it);
5075  // And do the assignment.
5078  (ff.Func,ff.getComponent())).apply();
5079  }
5080  }
5081  }
5082  }
5083 }
5084 
5085 //-----------------------------------------------------------------------------
5086 //Specialization of ComponentFunctionFace::apply() for Vert centering.
5087 //Rather, indirectly-called specialized global function
5088 //ComponentFunctionFaceBCApply
5089 //-----------------------------------------------------------------------------
5090 template<class T, unsigned D, class M>
5092  Field<T,D,M,Vert>& A )
5093 {
5094 
5095 
5096 
5097  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5098  // comprehensible comments --TJW
5099 
5100  // Find the slab that is the destination.
5101  const NDIndex<D>& domain( A.getDomain() );
5102  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5103  unsigned d = ff.getFace()/2;
5104  int offset;
5105  if ( ff.getFace() & 1 ) {
5106  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5107  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5108  // N.B.: the extra -1 here is what distinguishes this Vert-centered
5109  // implementation from the Cell-centered one:
5110  offset = 2*domain[d].max() + 1 - 1;
5111  }
5112  else {
5113  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5114  // N.B.: the extra +1 here is what distinguishes this Vert-centered
5115  // implementation from the Cell-centered one:
5116  offset = 2*domain[d].min() - 1 + 1;
5117  }
5118 
5119  // Loop over the ones the slab touches.
5120  typename Field<T,D,M,Vert>::iterator_if fill_i;
5121  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5122  {
5123  // Cache some things we will use often below.
5124  LField<T,D> &fill = *(*fill_i).second;
5125  const NDIndex<D> &fill_alloc = fill.getAllocated();
5126  if ( slab.touches( fill_alloc ) )
5127  {
5128  // Find what it touches in this LField.
5129  NDIndex<D> dest = slab.intersect( fill_alloc );
5130 
5131  // Find where that comes from.
5132  NDIndex<D> src = dest;
5133  src[d] = offset - src[d];
5134 
5135  // Loop over the ones that src touches.
5136  typename Field<T,D,M,Vert>::iterator_if from_i;
5137  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5138  {
5139  // Cache a few things.
5140  LField<T,D> &from = *(*from_i).second;
5141  const NDIndex<D> &from_owned = from.getOwned();
5142  const NDIndex<D> &from_alloc = from.getAllocated();
5143  // If src touches this LField...
5144  if ( src.touches( from_owned ) )
5145  {
5146  // bfh: Worry about compression ...
5147  // If 'fill' is a compressed LField, then writing data into
5148  // it via the expression will actually write the value for
5149  // all elements of the LField. We can do the following:
5150  // a) figure out if the 'fill' elements are all the same
5151  // value, if 'from' elements are the same value, if
5152  // the 'fill' elements are the same as the elements
5153  // throughout that LField, and then just do an
5154  // assigment for a single element
5155  // b) just uncompress the 'fill' LField, to make sure we
5156  // do the right thing.
5157  // I vote for b).
5158  fill.Uncompress();
5159 
5160  NDIndex<D> from_it = src.intersect( from_alloc );
5161  NDIndex<D> fill_it = dest.plugBase( from_it );
5162  // Build iterators for the copy...
5163  typedef typename LField<T,D>::iterator LFI;
5164  LFI lhs = fill.begin(fill_it);
5165  LFI rhs = from.begin(from_it);
5166  // And do the assignment.
5169  (ff.Func,ff.getComponent())).apply();
5170  }
5171  }
5172  }
5173  }
5174 }
5175 
5176 //-----------------------------------------------------------------------------
5177 //Specialization of ComponentFunctionFace::apply() for Edge centering.
5178 //Rather, indirectly-called specialized global function
5179 //ComponentFunctionFaceBCApply
5180 //-----------------------------------------------------------------------------
5181 template<class T, unsigned D, class M>
5183  Field<T,D,M,Edge>& A )
5184 {
5185  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5186  // comprehensible comments --TJW
5187 
5188  // Find the slab that is the destination.
5189  const NDIndex<D>& domain( A.getDomain() );
5190  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5191  unsigned d = ff.getFace()/2;
5192  int offset;
5193  if ( ff.getFace() & 1 ) {
5194  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5195  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5196  // N.B.: the extra -1 here is what distinguishes this Edge-centered
5197  // implementation from the Cell-centered one:
5198  offset = 2*domain[d].max() + 1 - 1;
5199  }
5200  else {
5201  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5202  // N.B.: the extra +1 here is what distinguishes this Edge-centered
5203  // implementation from the Cell-centered one:
5204  offset = 2*domain[d].min() - 1 + 1;
5205  }
5206 
5207  // Loop over the ones the slab touches.
5208  typename Field<T,D,M,Edge>::iterator_if fill_i;
5209  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5210  {
5211  // Cache some things we will use often below.
5212  LField<T,D> &fill = *(*fill_i).second;
5213  const NDIndex<D> &fill_alloc = fill.getAllocated();
5214  if ( slab.touches( fill_alloc ) )
5215  {
5216  // Find what it touches in this LField.
5217  NDIndex<D> dest = slab.intersect( fill_alloc );
5218 
5219  // Find where that comes from.
5220  NDIndex<D> src = dest;
5221  src[d] = offset - src[d];
5222 
5223  // Loop over the ones that src touches.
5224  typename Field<T,D,M,Edge>::iterator_if from_i;
5225  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5226  {
5227  // Cache a few things.
5228  LField<T,D> &from = *(*from_i).second;
5229  const NDIndex<D> &from_owned = from.getOwned();
5230  const NDIndex<D> &from_alloc = from.getAllocated();
5231  // If src touches this LField...
5232  if ( src.touches( from_owned ) )
5233  {
5234  // bfh: Worry about compression ...
5235  // If 'fill' is a compressed LField, then writing data into
5236  // it via the expression will actually write the value for
5237  // all elements of the LField. We can do the following:
5238  // a) figure out if the 'fill' elements are all the same
5239  // value, if 'from' elements are the same value, if
5240  // the 'fill' elements are the same as the elements
5241  // throughout that LField, and then just do an
5242  // assigment for a single element
5243  // b) just uncompress the 'fill' LField, to make sure we
5244  // do the right thing.
5245  // I vote for b).
5246  fill.Uncompress();
5247 
5248  NDIndex<D> from_it = src.intersect( from_alloc );
5249  NDIndex<D> fill_it = dest.plugBase( from_it );
5250  // Build iterators for the copy...
5251  typedef typename LField<T,D>::iterator LFI;
5252  LFI lhs = fill.begin(fill_it);
5253  LFI rhs = from.begin(from_it);
5254  // And do the assignment.
5257  (ff.Func,ff.getComponent())).apply();
5258  }
5259  }
5260  }
5261  }
5262 }
5263 
5264 //-----------------------------------------------------------------------------
5265 //Specialization of ComponentFunctionFace::apply() for
5266 //CartesianCentering centering. Rather, indirectly-called specialized
5267 //global function ComponentFunctionFaceBCApply:
5268 //-----------------------------------------------------------------------------
5269 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
5273 {
5274 
5275 
5276 
5277  // NOTE: See the ExtrapolateFaceBCApply functions above for more
5278  // comprehensible comments --TJW
5279 
5280  // Find the slab that is the destination.
5281  const NDIndex<D>& domain( A.getDomain() );
5282  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5283  unsigned d = ff.getFace()/2;
5284  int offset;
5285  if ( ff.getFace() & 1 ) {
5286  // TJW: this used to say "leftGuard(d)", which I think was wrong:
5287  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
5288  // Do the right thing for CELL or VERT centering for this component. (The
5289  // ComponentFunctionFace BC always applies only to one component, not all):
5290  if (CE[ff.getComponent() + d*NC] == CELL) { // ada: changed ef to ff
5291  ERRORMSG("check src code, had to change ef (not known) to ff ??? " << endl);
5292  offset = 2*domain[d].max() + 1; // CELL case
5293  } else {
5294  offset = 2*domain[d].max() + 1 - 1; // VERT case
5295  }
5296  }
5297  else {
5298  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
5299  // Do the right thing for CELL or VERT centering for this component. (The
5300  // ComponentFunctionFace BC always applies only to one component, not all):
5301  if (CE[ff.getComponent() + d*NC] == CELL) {
5302  offset = 2*domain[d].min() - 1; // CELL case
5303  } else {
5304  offset = 2*domain[d].min() - 1 + 1; // VERT case
5305  }
5306  }
5307 
5308  // Loop over the ones the slab touches.
5309  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if fill_i;
5310  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i)
5311  {
5312  // Cache some things we will use often below.
5313  LField<T,D> &fill = *(*fill_i).second;
5314  const NDIndex<D> &fill_alloc = fill.getAllocated();
5315  if ( slab.touches( fill_alloc ) )
5316  {
5317  // Find what it touches in this LField.
5318  NDIndex<D> dest = slab.intersect( fill_alloc );
5319 
5320  // Find where that comes from.
5321  NDIndex<D> src = dest;
5322  src[d] = offset - src[d];
5323 
5324  // Loop over the ones that src touches.
5325  typename Field<T,D,M,CartesianCentering<CE,D,NC> >::iterator_if from_i;
5326  for (from_i=A.begin_if(); from_i!=A.end_if(); ++from_i)
5327  {
5328  // Cache a few things.
5329  LField<T,D> &from = *(*from_i).second;
5330  const NDIndex<D> &from_owned = from.getOwned();
5331  const NDIndex<D> &from_alloc = from.getAllocated();
5332  // If src touches this LField...
5333  if ( src.touches( from_owned ) )
5334  {
5335  // bfh: Worry about compression ...
5336  // If 'fill' is a compressed LField, then writing data into
5337  // it via the expression will actually write the value for
5338  // all elements of the LField. We can do the following:
5339  // a) figure out if the 'fill' elements are all the same
5340  // value, if 'from' elements are the same value, if
5341  // the 'fill' elements are the same as the elements
5342  // throughout that LField, and then just do an
5343  // assigment for a single element
5344  // b) just uncompress the 'fill' LField, to make sure we
5345  // do the right thing.
5346  // I vote for b).
5347  fill.Uncompress();
5348 
5349  NDIndex<D> from_it = src.intersect( from_alloc );
5350  NDIndex<D> fill_it = dest.plugBase( from_it );
5351  // Build iterators for the copy...
5352  typedef typename LField<T,D>::iterator LFI;
5353  LFI lhs = fill.begin(fill_it);
5354  LFI rhs = from.begin(from_it);
5355  // And do the assignment.
5358  (ff.Func,ff.getComponent())).apply();
5359  }
5360  }
5361  }
5362  }
5363 }
5364 
5366 
5367 //
5368 // EurekaFace::apply().
5369 // Apply a Eureka condition on a face.
5370 //
5371 // The general idea is to set the guard cells plus one layer
5372 // of cells to zero in all cases except one:
5373 // When there are mixed centerings, the cell coordinates just
5374 // have their guard cells set to zero.
5375 //
5376 
5377 //------------------------------------------------------------
5378 // The actual member function EurekaFace::apply
5379 // This just uses the functions above to find the slab
5380 // we are going to fill, then it fills it.
5381 //------------------------------------------------------------
5382 
5383 template<class T, unsigned int D, class M, class C>
5385 {
5386  // Calculate the domain we're going to fill
5387  // using the domain of the field.
5388  NDIndex<D> slab = calcEurekaSlabToFill(field,BCondBase<T,D,M,C>::m_face,this->getComponent());
5389 
5390  // Fill that slab.
5391  fillSlabWithZero(field,slab,this->getComponent());
5392 }
5393 
5395 
5396 //
5397 // Tag class for the Eureka assignment.
5398 // This has two functions:
5399 //
5400 // A static member function for getting a component if
5401 // there are subcomponents.
5402 //
5403 // Be a tag class for the BrickExpression for an assignment.
5404 //
5405 
5406 //
5407 // First we have the general template class.
5408 // This ignores the component argument, and will be used
5409 // for any classes except Vektor, Tenzor and SymTenzor.
5410 //
5411 
5412 template<class T>
5414 {
5415  static const T& get(const T& x, int) {
5416  ERRORMSG("Eureka assign to a component of class without an op[]!"<<endl);
5417  return x;
5418  }
5419  static T& get(T& x, int) {
5420  ERRORMSG("Eureka assign to a component of class without an op[]!"<<endl);
5421  return x;
5422  }
5425 };
5426 
5427 //------------------------------------------------------------
5428 // Given a Field and a domain, fill the domain with zeros.
5429 // Input:
5430 // field: The field we'll be assigning to.
5431 // fillDomain: The domain we'll be assigning to.
5432 // component: What component of T we'll be filling.
5433 //------------------------------------------------------------
5434 
5435 template<class T, unsigned int D, class M, class C>
5436 static void
5437 fillSlabWithZero(Field<T,D,M,C>& field,
5438  const NDIndex<D>& fillDomain,
5439  int component)
5440 {
5441  //
5442  // Loop over all the vnodes, filling each one in turn.
5443  //
5444  typename Field<T,D,M,C>::iterator_if lp = field.begin_if();
5445  typename Field<T,D,M,C>::iterator_if done = field.end_if();
5446  for (; lp != done ; ++lp )
5447  {
5448  // Get a reference to the current LField.
5449  LField<T,D>& lf = *(*lp).second;
5450 
5451  // Get its domain, including guard cells.
5452  NDIndex<D> localDomain = lf.getAllocated();
5453 
5454  // If localDomain intersects fillDomain, we have work to do.
5455  if ( fillDomain.touches(localDomain) )
5456  {
5457  // If lf is compressed, we may not have to do any work.
5458  if ( lf.IsCompressed() )
5459  {
5460  // Check and see if we're dealing with all components
5461  if ( component == BCondBase<T,D,M,C>::allComponents )
5462  {
5463  // If it is compressed to zero, we really don't have to work
5464  if ( *lf.begin() == 0 )
5465  continue;
5466  }
5467  // We are dealing with just one component
5468  else
5469  {
5470  // Check to see if the component is zero.
5471  // Check through a class so that this statement
5472  // isn't a compile error if T is something like int.
5473  if ( EurekaAssign<T>::get(*lf.begin(),component)==0 )
5474  continue;
5475  }
5476  // Not compressed to zero.
5477  // Have to uncompress.
5478  lf.Uncompress();
5479  }
5480 
5481  // Get the actual intersection.
5482  NDIndex<D> intersectDomain = fillDomain.intersect(localDomain);
5483 
5484  // Get an iterator that will loop over that domain.
5485  typename LField<T,D>::iterator data = lf.begin(intersectDomain);
5486 
5487 
5488  // Build a BrickExpression that will fill it with zeros.
5489  // First some typedefs for the constituents of the expression.
5490  typedef typename LField<T,D>::iterator Lhs_t;
5491  typedef PETE_Scalar<T> Rhs_t;
5492 
5493  // If we are assigning all components, use regular assignment.
5494  if ( component == BCondBase<T,D,M,C>::allComponents )
5495  {
5496  // The type of the expression.
5498 
5499  // Build the expression and evaluate it.
5500  Expr_t(data,Rhs_t(0)).apply();
5501  }
5502  // We are assigning just one component. Use EurekaAssign.
5503  else
5504  {
5505  // The type of the expression.
5507 
5508  // Sanity check.
5509  PAssert_GE(component, 0);
5510 
5511  // Build the expression and evaluate it. tjw:mwerks dies here:
5512  Expr_t(data,Rhs_t(0),component).apply();
5513  //try: typedef typename AppTypeTraits<T>::Element_t T1;
5514  //try: Expr_t(data,PETE_Scalar<T1>(T1(0)),component).apply();
5515  }
5516  }
5517  }
5518 }
5519 
5520 //
5521 // Specializations of EurekaAssign for Vektor, Tenzor, SymTenzor.
5522 //
5523 
5524 template<class T, unsigned int D>
5525 struct EurekaAssign< Vektor<T,D> >
5526 {
5527  static T& get( Vektor<T,D>& x, int c ) { return x[c]; }
5528  static T get( const Vektor<T,D>& x, int c ) { return x[c]; }
5531 };
5532 
5533 template<class T, unsigned int D>
5534 struct EurekaAssign< Tenzor<T,D> >
5535 {
5536  static T& get( Tenzor<T,D>& x, int c ) { return x[c]; }
5537  static T get( const Tenzor<T,D>& x, int c ) { return x[c]; }
5540 };
5541 
5542 template<class T, unsigned int D>
5544 {
5545  static T& get( AntiSymTenzor<T,D>& x, int c ) { return x[c]; }
5546  static T get( const AntiSymTenzor<T,D>& x, int c ) { return x[c]; }
5549 };
5550 
5551 template<class T, unsigned int D>
5553 {
5554  static T& get( SymTenzor<T,D>& x, int c ) { return x[c]; }
5555  static T get( const SymTenzor<T,D>& x, int c ) { return x[c]; }
5558 };
5559 
5560 //
5561 // A version of PETE_apply for EurekaAssign.
5562 // Assign a component of the right hand side to a component of the left.
5563 //
5564 
5565 template<class T>
5566 inline void PETE_apply(const EurekaAssign<T>& e, T& a, const T& b)
5567 {
5570 }
5571 
5573 
5574 //
5575 // calcEurekaDomain
5576 // Given a domain, a face number, and a guard cell spec,
5577 // find the low and high bounds for the domain we will be filling.
5578 // Return the two integers through references.
5579 //
5580 template<unsigned int D>
5581 inline NDIndex<D>
5582 calcEurekaDomain(const NDIndex<D>& realDomain,
5583  int face,
5584  const GuardCellSizes<D>& gc)
5585 {
5586  NDIndex<D> slab = AddGuardCells(realDomain,gc);
5587 
5588  // Find the dimension the slab will be perpendicular to.
5589  int dim = face/2;
5590 
5591  // The upper and lower bounds of the domain.
5592  int low,high;
5593 
5594  // If the face is odd, then it is the "high" end of the dimension.
5595  if ( face&1 )
5596  {
5597  // Find the bounds of the domain.
5598  high = slab[dim].max();
5599  low = high - gc.right(dim);
5600  }
5601  // If the face is even, then it is the "low" end of the dimension.
5602  else
5603  {
5604  // Find the bounds of the domain.
5605  low = slab[dim].min();
5606  high = low + gc.left(dim);
5607  }
5608 
5609  // Sanity checks.
5610  PAssert_LE( low, high );
5611  PAssert_LE( high, slab[dim].max() );
5612  PAssert_GE( low, slab[dim].min() );
5613 
5614  // Build the domain.
5615  slab[dim] = Index(low,high);
5616  return slab;
5617 }
5618 
5620 
5621 //
5622 // Find the appropriate slab to fill for a Cell centered field
5623 // for the Eureka boundary condition.
5624 // It's thickness is the number of guard cells plus one.
5625 //
5626 
5627 template<class T, unsigned int D, class M>
5628 static NDIndex<D>
5629 calcEurekaSlabToFill(const Field<T,D,M,Cell>& 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,Vert>& field, int face,int)
5637 {
5638  return calcEurekaDomain(field.getDomain(),face,field.getGC());
5639 }
5640 
5641 template<class T, unsigned int D, class M>
5642 static NDIndex<D>
5643 calcEurekaSlabToFill(const Field<T,D,M,Edge>& field, int face,int)
5644 {
5645  return calcEurekaDomain(field.getDomain(),face,field.getGC());
5646 }
5647 
5649 
5650 //
5651 // Find the appropriate slab to fill for a mixed centering
5652 // for the Eureka boundary condition.
5653 // It's thickness is:
5654 // If we're filling allComponents, the number guard cells plus 1.
5655 // If we're filling a single component,
5656 // If that component if vert, the number of guard cells plus 1
5657 // If that component is cell, the number of guard cells.
5658 //
5659 
5660 template<class T, unsigned D, class M, CenteringEnum* CE, unsigned NC>
5661 static NDIndex<D>
5662 calcEurekaSlabToFill(const Field<T,D,M,CartesianCentering<CE,D,NC> >& field,
5663  int face,
5664  int component)
5665 {
5666  // Shorthand for the centering type.
5667  typedef CartesianCentering<CE,D,NC> C;
5668 
5669  // Find the dimension perpendicular to the slab.
5670  int d = face/2;
5671 
5672  // The domain we'll be calculating.
5673  NDIndex<D> slab;
5674 
5675  // First check and see if we are fill all the components.
5676  if ( component == BCondBase<T,D,M,C>::allComponents )
5677  {
5678  // Deal with this like a pure VERT or CELL case.
5679  slab = calcEurekaDomain(field.getDomain(),face,field.getGC());
5680  }
5681  // Only do one component.
5682  else
5683  {
5684  // Our initial approximation to the slab to fill is the whole domain.
5685  // We'll reset the index for dimension d to make it a slab.
5686  slab = AddGuardCells(field.getDomain(),field.getGC());
5687 
5688  // If face is odd, this is the "high" face.
5689  if ( face&1 )
5690  {
5691  // Find the upper and lower bounds of the domain.
5692  int low = field.getDomain()[d].min() + field.get_mesh().gridSizes[d] - 1;
5693  int high = low + field.rightGuard(d);
5694 
5695  // For cell centered, we do one fewer layer of guard cells.
5696  if (CE[component + d*NC] == CELL)
5697  low++;
5698 
5699  // Sanity checks.
5700  PAssert_LE( low, high );
5701  PAssert_LE( high, slab[d].max() );
5702  PAssert_GE( low, slab[d].min() );
5703 
5704  // Record this part of the slab.
5705  slab[d] = Index(low,high);
5706  }
5707  // If face is even, this is the "low" face.
5708  else
5709  {
5710  // Get the lower and upper bounds of the domain.
5711  int low = slab[d].min();
5712  int high = low + field.leftGuard(d) ;
5713 
5714  // For cell centered, we do one fewer layer of guard cells.
5715  if (CE[component + d*NC] == CELL)
5716  high--;
5717 
5718  // Sanity checks.
5719  PAssert_LE( low, high );
5720  PAssert_LE( high, slab[d].max() );
5721  PAssert_GE( low, slab[d].min() );
5722 
5723  // Record this part of the slab.
5724  slab[d] = Index(low,high);
5725  }
5726  }
5727 
5728  // We've found the domain, so return it.
5729  return slab;
5730 }
5731 
5733 
5734 //----------------------------------------------------------------------------
5735 // For unspecified centering, can't implement LinearExtrapolateFace::apply()
5736 // correctly, and can't partial-specialize yet, so... don't have a prototype
5737 // for unspecified centering, so user gets a compile error if he tries to
5738 // invoke it for a centering not yet implemented. Implement external functions
5739 // which are specializations for the various centerings
5740 // {Cell,Vert,CartesianCentering}; these are called from the general
5741 // LinearExtrapolateFace::apply() function body.
5742 //
5743 // TJW: Actually, for LinearExtrapolate, don't need to specialize on
5744 // centering. Probably don't need this indirection here, but leave it in for
5745 // now.
5746 //----------------------------------------------------------------------------
5747 
5749 
5750 template<class T, unsigned D, class M, class C>
5752  Field<T,D,M,C>& A );
5753 
5754 template<class T, unsigned D, class M, class C>
5756 {
5757  LinearExtrapolateFaceBCApply(*this, A);
5758 }
5759 
5760 
5761 template<class T, unsigned D, class M, class C>
5762 inline void
5764  const NDIndex<D> &src1,
5765  const NDIndex<D> &src2,
5766  LField<T,D> &fill,
5768  int slopeMultipplier)
5769 {
5770  // If 'fill' is compressed and applying the boundary condition on the
5771  // compressed value would result in no change to 'fill' we don't need to
5772  // uncompress. For this particular type of BC (linear extrapolation), this
5773  // result would *never* happen, so we already know we're done:
5774 
5775  if (fill.IsCompressed()) { return; } // Yea! We're outta here.
5776 
5777  // Build iterators for the copy:
5778  typedef typename LField<T,D>::iterator LFI;
5779  LFI lhs = fill.begin(dest);
5780  LFI rhs1 = fill.begin(src1);
5781  LFI rhs2 = fill.begin(src2);
5782  LFI endi = fill.end(); // Used for testing end of *any* sub-range iteration
5783 
5784  // Couldn't figure out how to use BrickExpression here. Just iterate through
5785  // all the elements in all 3 LField iterators (which are BrickIterators) and
5786  // do the calculation one element at a time:
5787  for ( ; lhs != endi && rhs1 != endi && rhs2 != endi;
5788  ++lhs, ++rhs1, ++rhs2) {
5789  *lhs = (*rhs2 - *rhs1)*slopeMultipplier + *rhs1;
5790  }
5791 
5792 }
5793 
5794 
5795 // ----------------------------------------------------------------------------
5796 // This type of boundary condition (linear extrapolation) does very much the
5797 // same thing for any centering; Doesn't seem to be a need for specializations
5798 // based on centering.
5799 // ----------------------------------------------------------------------------
5800 
5801 template<class T, unsigned D, class M, class C>
5803  Field<T,D,M,C>& A )
5804 {
5805 
5806 
5807 
5808  // Find the slab that is the destination.
5809  // That is, in English, get an NDIndex spanning elements in the guard layers
5810  // on the face associated with the LinearExtrapaloteFace object:
5811 
5812  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
5813  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
5814 
5815  // The direction (dimension of the Field) associated with the active face.
5816  // The numbering convention makes this division by two return the right
5817  // value, which will be between 0 and (D-1):
5818 
5819  unsigned d = ef.getFace()/2;
5820 
5821  // Must loop explicitly over the number of guard layers:
5822  int nGuardLayers;
5823 
5824  // The following bitwise AND logical test returns true if ef.m_face is odd
5825  // (meaning the "high" or "right" face in the numbering convention) and
5826  // returns false if ef.m_face is even (meaning the "low" or "left" face in
5827  // the numbering convention):
5828 
5829  if (ef.getFace() & 1) {
5830 
5831  // For "high" face, index in active direction goes from max index of
5832  // Field plus 1 to the same plus number of guard layers:
5833  nGuardLayers = A.rightGuard(d);
5834 
5835  } else {
5836 
5837  // For "low" face, index in active direction goes from min index of
5838  // Field minus the number of guard layers (usually a negative number)
5839  // to the same min index minus 1 (usually negative, and usually -1):
5840  nGuardLayers = A.leftGuard(d);
5841 
5842  }
5843 
5844  // Loop over the number of guard layers, treating each layer as a separate
5845  // slab (contrast this with all other BC types, where all layers are a single
5846  // slab):
5847  for (int guardLayer = 1; guardLayer <= nGuardLayers; guardLayer++) {
5848 
5849  // For linear extrapolation, the multipplier increases with more distant
5850  // guard layers:
5851  int slopeMultipplier = -1*guardLayer;
5852 
5853  if (ef.getFace() & 1) {
5854  slab[d] = Index(domain[d].max() + guardLayer,
5855  domain[d].max() + guardLayer);
5856  } else {
5857  slab[d] = Index(domain[d].min() - guardLayer,
5858  domain[d].min() - guardLayer);
5859  }
5860 
5861  // Loop over all the LField's in the Field A:
5862 
5863  typename Field<T,D,M,Cell>::iterator_if fill_i;
5864  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i) {
5865 
5866  // Cache some things we will use often below.
5867 
5868  // Pointer to the data for the current LField:
5869  LField<T,D> &fill = *(*fill_i).second;
5870 
5871  // NDIndex spanning all elements in the LField, including the guards:
5872  const NDIndex<D> &fill_alloc = fill.getAllocated();
5873 
5874  // If the previously-created boundary guard-layer NDIndex "slab"
5875  // contains any of the elements in this LField (they will be guard
5876  // elements if it does), assign the values into them here by applying
5877  // the boundary condition:
5878 
5879  if (slab.touches(fill_alloc)) {
5880 
5881  // Find what it touches in this LField.
5882  NDIndex<D> dest = slab.intersect(fill_alloc);
5883 
5884  // For linear extrapolation boundary conditions, the boundary
5885  // guard-layer elements are filled based on a slope and intercept
5886  // derived from two layers of interior values; the src1 and src2
5887  // NDIndexes specify these two interior layers, which are operated on
5888  // by mathematical operations whose results are put into dest. The
5889  // ordering of what is defined as src1 and src2 is set differently for
5890  // hi and lo faces, to make the sign for extrapolation work out right:
5891  NDIndex<D> src1 = dest;
5892  NDIndex<D> src2 = dest;
5893  if (ef.getFace() & 1) {
5894  src2[d] = Index(domain[d].max() - 1, domain[d].max() - 1, 1);
5895  src1[d] = Index(domain[d].max(), domain[d].max(), 1);
5896  } else {
5897  src1[d] = Index(0,0,1); // Note: hardwired to 0-base, stride-1; could
5898  src2[d] = Index(1,1,1); // generalize with domain.min(), etc.
5899  }
5900 
5901  // Assume that src1 and src2 are contained withi nthe fill_alloc LField
5902  // domain; I think this is always true if the vnodes are always at
5903  // least one guard-layer-width wide in number of physical elements:
5904 
5905  LinearExtrapolateFaceBCApply2(dest, src1, src2, fill, ef,
5906  slopeMultipplier);
5907 
5908  }
5909  }
5910  }
5911 }
5912 
5913 
5915 
5916 // ---------------------------------------------------------------------------
5917 // For unspecified centering, can't implement
5918 // ComponentLinearExtrapolateFace::apply() correctly, and can't
5919 // partial-specialize yet, so... don't have a prototype for unspecified
5920 // centering, so user gets a compile error if he tries to invoke it for a
5921 // centering not yet implemented. Implement external functions which are
5922 // specializations for the various centerings {Cell,Vert,CartesianCentering};
5923 // these are called from the general ComponentLinearExtrapolateFace::apply()
5924 // function body.
5925 //
5926 // TJW: Actually, for ComponentLinearExtrapolate, don't need to specialize on
5927 // centering. Probably don't need this indirection here, but leave it in for
5928 // now.
5929 // ---------------------------------------------------------------------------
5930 
5931 template<class T, unsigned D, class M, class C>
5933  <T,D,M,C>& ef,
5934  Field<T,D,M,C>& A );
5935 
5936 template<class T, unsigned D, class M, class C>
5938 {
5940 }
5941 
5942 
5943 template<class T, unsigned D, class M, class C>
5944 inline void
5946  const NDIndex<D> &src1,
5947  const NDIndex<D> &src2,
5948  LField<T,D> &fill,
5950  <T,D,M,C> &ef,
5951  int slopeMultipplier)
5952 {
5953  // If 'fill' is compressed and applying the boundary condition on the
5954  // compressed value would result in no change to 'fill' we don't need to
5955  // uncompress. For this particular type of BC (linear extrapolation), this
5956  // result would *never* happen, so we already know we're done:
5957 
5958  if (fill.IsCompressed()) { return; } // Yea! We're outta here.
5959 
5960  // Build iterators for the copy:
5961  typedef typename LField<T,D>::iterator LFI;
5962  LFI lhs = fill.begin(dest);
5963  LFI rhs1 = fill.begin(src1);
5964  LFI rhs2 = fill.begin(src2);
5965  LFI endi = fill.end(); // Used for testing end of *any* sub-range iteration
5966 
5967  // Couldn't figure out how to use BrickExpression here. Just iterate through
5968  // all the elements in all 3 LField iterators (which are BrickIterators) and
5969  // do the calculation one element at a time:
5970 
5971  int component = ef.getComponent();
5972  for ( ; lhs != endi, rhs1 != endi, rhs2 != endi;
5973  ++lhs, ++rhs1, ++rhs2) {
5974  (*lhs)[component] =
5975  ((*rhs2)[component] - (*rhs1)[component])*slopeMultipplier +
5976  (*rhs1)[component];
5977  }
5978 
5979 }
5980 
5981 
5982 // ----------------------------------------------------------------------------
5983 // This type of boundary condition (linear extrapolation) does very much the
5984 // same thing for any centering; Doesn't seem to be a need for specializations
5985 // based on centering.
5986 // ----------------------------------------------------------------------------
5987 
5988 template<class T, unsigned D, class M, class C>
5990  <T,D,M,C>& ef,
5991  Field<T,D,M,C>& A )
5992 {
5993 
5994  // Find the slab that is the destination.
5995  // That is, in English, get an NDIndex spanning elements in the guard layers
5996  // on the face associated with the ComponentLinearExtrapaloteFace object:
5997 
5998  const NDIndex<D>& domain( A.getDomain() ); // Spans whole Field
5999  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
6000 
6001  // The direction (dimension of the Field) associated with the active face.
6002  // The numbering convention makes this division by two return the right
6003  // value, which will be between 0 and (D-1):
6004 
6005  unsigned d = ef.getFace()/2;
6006 
6007  // Must loop explicitly over the number of guard layers:
6008  int nGuardLayers;
6009 
6010  // The following bitwise AND logical test returns true if ef.m_face is odd
6011  // (meaning the "high" or "right" face in the numbering convention) and
6012  // returns false if ef.m_face is even (meaning the "low" or "left" face in
6013  // the numbering convention):
6014 
6015  if (ef.getFace() & 1) {
6016 
6017  // For "high" face, index in active direction goes from max index of
6018  // Field plus 1 to the same plus number of guard layers:
6019  nGuardLayers = A.rightGuard(d);
6020 
6021  } else {
6022 
6023  // For "low" face, index in active direction goes from min index of
6024  // Field minus the number of guard layers (usually a negative number)
6025  // to the same min index minus 1 (usually negative, and usually -1):
6026  nGuardLayers = A.leftGuard(d);
6027 
6028  }
6029 
6030  // Loop over the number of guard layers, treating each layer as a separate
6031  // slab (contrast this with all other BC types, where all layers are a single
6032  // slab):
6033  for (int guardLayer = 1; guardLayer <= nGuardLayers; guardLayer++) {
6034 
6035  // For linear extrapolation, the multipplier increases with more distant
6036  // guard layers:
6037  int slopeMultipplier = -1*guardLayer;
6038 
6039  if (ef.getFace() & 1) {
6040  slab[d] = Index(domain[d].max() + guardLayer,
6041  domain[d].max() + guardLayer);
6042  } else {
6043  slab[d] = Index(domain[d].min() - guardLayer,
6044  domain[d].min() - guardLayer);
6045  }
6046 
6047  // Loop over all the LField's in the Field A:
6048 
6049  typename Field<T,D,M,Cell>::iterator_if fill_i;
6050  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i) {
6051 
6052  // Cache some things we will use often below.
6053 
6054  // Pointer to the data for the current LField:
6055  LField<T,D> &fill = *(*fill_i).second;
6056 
6057  // NDIndex spanning all elements in the LField, including the guards:
6058  const NDIndex<D> &fill_alloc = fill.getAllocated();
6059 
6060  // If the previously-created boundary guard-layer NDIndex "slab"
6061  // contains any of the elements in this LField (they will be guard
6062  // elements if it does), assign the values into them here by applying
6063  // the boundary condition:
6064 
6065  if (slab.touches(fill_alloc)) {
6066 
6067  // Find what it touches in this LField.
6068  NDIndex<D> dest = slab.intersect(fill_alloc);
6069 
6070  // For linear extrapolation boundary conditions, the boundary
6071  // guard-layer elements are filled based on a slope and intercept
6072  // derived from two layers of interior values; the src1 and src2
6073  // NDIndexes specify these two interior layers, which are operated on
6074  // by mathematical operations whose results are put into dest. The
6075  // ordering of what is defined as src1 and src2 is set differently for
6076  // hi and lo faces, to make the sign for extrapolation work out right:
6077  NDIndex<D> src1 = dest;
6078  NDIndex<D> src2 = dest;
6079  if (ef.getFace() & 1) {
6080  src2[d] = Index(domain[d].max() - 1, domain[d].max() - 1, 1);
6081  src1[d] = Index(domain[d].max(), domain[d].max(), 1);
6082  } else {
6083  src1[d] = Index(0,0,1); // Note: hardwired to 0-base, stride-1; could
6084  src2[d] = Index(1,1,1); // generalize with domain.min(), etc.
6085  }
6086 
6087  // Assume that src1 and src2 are contained withi nthe fill_alloc LField
6088  // domain; I think this is always true if the vnodes are always at
6089  // least one guard-layer-width wide in number of physical elements:
6090 
6091  ComponentLinearExtrapolateFaceBCApply2(dest, src1, src2, fill, ef,
6092  slopeMultipplier);
6093 
6094  }
6095  }
6096  }
6097 }
6098 
6099 
6100 //----------------------------------------------------------------------
6101 
6102 template<class T, unsigned D, class M, class C>
6104 PatchBC(unsigned face)
6105  : BCondBase<T,D,M,C>(face)
6106 {
6107 
6108 
6109 }
6110 
6111 //-----------------------------------------------------------------------------
6112 // PatchBC::apply(Field)
6113 //
6114 // Loop over the patches of the Field, and call the user supplied
6115 // apply(Field::iterator) member function on each.
6116 //-----------------------------------------------------------------------------
6117 
6118 template<class T, unsigned D, class M, class C>
6120 {
6121 
6122 
6123 
6124  //------------------------------------------------------------
6125  // Find the slab that is the destination.
6126  //------------------------------------------------------------
6127 
6128  //
6129  // Get the physical domain for A.
6130  //
6131  const NDIndex<D>& domain( A.getDomain() );
6132 
6133  //
6134  // Start the calculation for the slab we'll be filling by adding
6135  // guard cells to the domain of A.
6136  //
6137  NDIndex<D> slab = AddGuardCells(domain,A.getGuardCellSizes());
6138 
6139  //
6140  // Get which direction is perpendicular to the face we'll be
6141  // filling.
6142  //
6143  unsigned d = this->getFace()/2;
6144 
6145  //
6146  // If the face is odd, we're looking at the 'upper' face, and if it
6147  // is even we're looking at the 'lower'. Calculate the Index for
6148  // the dimension d.
6149  //
6150  if ( this->getFace() & 1 )
6151  slab[d] = Index( domain[d].max() + 1, domain[d].max() + A.rightGuard(d));
6152  else
6153  slab[d] = Index( domain[d].min() - A.leftGuard(d), domain[d].min()-1 );
6154 
6155  //
6156  // Loop over all the vnodes. We'll take action if it touches the slab.
6157  //
6158  int lfindex = 0;
6159  typename Field<T,D,M,C>::iterator_if fill_i;
6160  typename Field<T,D,M,C>::iterator p = A.begin();
6161  for (fill_i=A.begin_if(); fill_i!=A.end_if(); ++fill_i, ++lfindex)
6162  {
6163  //
6164  // Cache some things we will use often below.
6165  // fill: the current lfield.
6166  // fill_alloc: the total domain for that lfield.
6167  //
6168  LField<T,D> &fill = *(*fill_i).second;
6169  const NDIndex<D> &fill_alloc = fill.getAllocated();
6170  const NDIndex<D> &fill_owned = fill.getOwned();
6171 
6172  //
6173  // Is this an lfield we care about?
6174  //
6175  if ( slab.touches( fill_alloc ) )
6176  {
6177  // need to worry about compression here
6178  fill.Uncompress();
6179 
6180  //
6181  // Find what part of this lfield is in the slab.
6182  //
6183  NDIndex<D> dest = slab.intersect( fill_alloc );
6184 
6185  //
6186  // Set the iterator to the right spot in the Field.
6187  //
6188  vec<int,D> v;
6189  for (int i=0; i<D; ++i)
6190  v[i] = dest[i].first();
6191  p.SetCurrentLocation( FieldLoc<D>(v,lfindex) );
6192 
6193  //
6194  // Let the user function do its stuff.
6195  //
6196  applyPatch(p,dest);
6197  }
6198  }
6199 }
6200 
6201 //----------------------------------------------------------------------
6202 
6203 #undef COMPONENT_APPLY_BUILTIN
Expression Expr_t
type of an expression
Definition: Expression.h:63
#define PAssert_GE(a, b)
Definition: PAssert.h:109
Field< double, 3, Mesh_t, Center_t > Field_t
Definition: PBunchDefs.h:30
int getComponent() const
Definition: BCond.h:169
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:1987
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
CenteringEnum
InterpolationFace(unsigned f, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:292
const NDIndex< Dim > & getOwned() const
Definition: LField.h:99
virtual void write(std::ostream &out) const
Definition: BCond.hpp:178
unsigned int length() const
Definition: IndexInlines.h:131
Definition: Centering.h:49
iterator_if end_if()
Definition: BareField.h:101
#define BC_PARALLEL_PERIODIC_TAG
Definition: Tags.h:40
bool touches(const NDIndex< Dim > &) const
vmap< int, RefCountedP< BCondBase< T, D, M, C > > >::iterator iterator
Definition: BCond.h:202
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:98
virtual void write(std::ostream &out) const
Definition: BCond.hpp:127
virtual void apply()
#define BC_TAG_CYCLE
Definition: Tags.h:41
Message * receive_block(int &node, int &tag)
void SetCurrentLocation(const FieldLoc< Dim > &loc)
void PeriodicFaceBCApply(PeriodicFace< T, D, M, Cell > &pf, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:495
T::Element_t Element_t
Definition: AppTypeTraits.h:19
item[EANGLE] Entrance edge counterclockwise This enables to obtain skew at each point along the its radius is computed such that the reference trajectory always remains in the centre of the magnet In the body of the magnet the radius is set from the LENGTH and ANGLE attributes It is then continuously changed to be proportional to the dipole field on the reference trajectory while entering the end fields This attribute is only to be set TRUE for a non zero dipole component(Default:FALSE)\item[VARSTEP] The step size(meters) used in calculating the reference trajectory for VARRARDIUS
#define PAssert_LE(a, b)
Definition: PAssert.h:107
NDIndex< Dim > plugBase(const NDIndex< D > &i) const
Definition: NDIndex.h:114
OpBCFunctionEq(T(*func)(const T &))
Definition: BCond.hpp:4499
virtual void write(std::ostream &out) const
Definition: BCond.hpp:133
OpExtrapolateAndZero(const T &o, const T &s)
Definition: BCond.hpp:3508
OpAssignComponent(int c)
Definition: BCond.hpp:3562
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
bool IsCompressed() const
Definition: LField.h:134
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:2807
Definition: TSVMeta.h:24
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:483
void Uncompress(bool fill_domain=true)
Definition: LField.h:172
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
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
virtual void write(std::ostream &out) const
Definition: BCond.hpp:190
const GuardCellSizes< Dim > & getGC() const
Definition: BareField.h:146
virtual void write(std::ostream &out) const
Definition: BCond.hpp:169
Definition: Offset.h:53
TensorOrder_e getTensorOrder(const scalar_tag &)
Definition: BCond.h:133
OpInterpolationComponent(int c)
Definition: BCond.hpp:416
const int COMM_ANY_NODE
Definition: Communicate.h:40
T & getCompressedData()
Definition: LField.h:179
void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:4541
clearpage the user may choose between constant or variable radius This model includes fringe fields begin
Definition: multipole_t.tex:6
virtual void write(std::ostream &out) const
Definition: BCond.hpp:113
virtual void write(std::ostream &) const
Definition: BCond.hpp:217
Definition: Index.h:236
const T & getOffset() const
Definition: BCond.h:458
static const T & get(const T &x, int)
Definition: BCond.hpp:5415
virtual void write(std::ostream &) const
Definition: BCond.hpp:197
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Index intersect(const Index &) const
Definition: Index.cpp:108
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
int max() const
Definition: IndexInlines.h:146
PeriodicFace(unsigned f, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:282
virtual void apply(Field< T, D, M, C > &A)
Definition: BCond.hpp:5937
bool touches(const Index &a) const
Definition: IndexInlines.h:242
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
int m_component
Definition: BCond.h:181
size_t size() const
Definition: Message.h:292
Definition: Centering.h:31
std::string::iterator iterator
Definition: MSLang.h:15
virtual void write(std::ostream &out) const
Definition: BCond.hpp:157
const GuardCellSizes< Dim > & getGuardCellSizes() const
Definition: BareField.h:147
virtual void apply(Field< T, D, M, C > &A)
Definition: BCond.hpp:5755
virtual void write(std::ostream &) const
Definition: BCond.hpp:207
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:2035
vmap< int, RefCountedP< BCondBase< T, D, M, C > > >::const_iterator const_iterator
Definition: BCond.h:204
static int getNodes()
Definition: IpplInfo.cpp:670
T(* Func)(const T &)
Definition: BCond.hpp:4500
void ExtrapolateAndZeroFaceBCApply(ExtrapolateAndZeroFace< T, D, M, Cell > &ef, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:3756
OpExtrapolateAndZeroComponent(const T &o, const T &s, int c)
Definition: BCond.hpp:3519
bool contains(const NDIndex< Dim > &a) const
iterator_if begin_if()
Definition: BareField.h:100
static Communicate * Comm
Definition: IpplInfo.h:84
unsigned rightGuard(unsigned d) const
Definition: BareField.h:149
#define COMPONENT_APPLY_BUILTIN(OP, T)
Definition: BCond.hpp:40
void PETE_apply(const OpPeriodic< T > &, T &a, const T &b)
Definition: BCond.hpp:353
virtual void write(std::ostream &out) const
Definition: BCond.hpp:120
scalar_tag get_tag(std::complex< double >)
Definition: BCond.h:100
Definition: Vec.h:21
Definition: Inform.h:42
FunctionFace(T(*func)(const T &), unsigned face)
Definition: BCond.hpp:318
virtual void write(std::ostream &out) const
Definition: BCond.hpp:151
ComponentFunctionFace(typename ApplyToComponentType< T >::type(*func)(typename ApplyToComponentType< T >::type), unsigned face, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:327
void apply(Field< T, D, M, C > &a)
Definition: BCond.hpp:258
unsigned left(unsigned d) const
int min() const
Definition: IndexInlines.h:141
Layout_t & getLayout() const
Definition: BareField.h:131
ExtrapolateAndZeroFace(unsigned f, T o, T s, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:309
#define INFORM_ALL_NODES
Definition: Inform.h:39
BCondBase(unsigned int face, int i=allComponents, int j=allComponents)
Definition: BCond.hpp:56
ExtrapolateFace(unsigned f, T o, T s, int i=BCondBaseTDMC::allComponents, int j=BCondBaseTDMC::allComponents)
Definition: BCond.hpp:300
virtual void write(std::ostream &out) const
Definition: BCond.hpp:145
OpExtrapolateComponent(const T &o, const T &s, int c)
Definition: BCond.hpp:2734
bool send(Message *, int node, int tag, bool delmsg=true)
OpPeriodicComponent(int c)
Definition: BCond.hpp:359
virtual void write(std::ostream &) const
Definition: BCond.hpp:107
const T & getSlope() const
Definition: BCond.h:459
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:5384
const iterator & end() const
Definition: LField.h:111
T(* Func)(const T &)
Definition: BCond.h:632
bool changesPhysicalCells() const
Definition: BCond.hpp:268
Mesh_t & get_mesh() const
Definition: Field.h:110
void ComponentLinearExtrapolateFaceBCApply(ComponentLinearExtrapolateFace< T, D, M, C > &ef, Field< T, D, M, C > &A)
Definition: BCond.hpp:5989
void LinearExtrapolateFaceBCApply(LinearExtrapolateFace< T, D, M, C > &ef, Field< T, D, M, C > &A)
Definition: BCond.hpp:5802
ApplyToComponentType< T >::type(* Func)(typename ApplyToComponentType< T >::type)
Definition: BCond.hpp:4938
unsigned int getFace() const
Definition: BCond.h:172
void InterpolationFaceBCApply(InterpolationFace< T, D, M, Cell > &pf, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:592
const T & getSlope() const
Definition: BCond.h:415
virtual void write(std::ostream &out) const
Definition: BCond.hpp:163
void FunctionFaceBCApply(FunctionFace< T, D, M, Cell > &ff, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:4553
unsigned right(unsigned d) const
virtual void write(std::ostream &) const
Definition: BCond.hpp:226
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:5945
T * value_type(const SliceIterator< T > &)
ac_id_larray::iterator iterator_if
Definition: BareField.h:92
int m_component
Definition: BCond.hpp:5423
Definition: FFT.h:27
virtual void write(std::ostream &out) const
Definition: BCond.hpp:184
Definition: Tenzor.h:34
constexpr double e
The value of .
Definition: Physics.h:39
#define PAssert(c)
Definition: PAssert.h:102
iterator begin() const
Definition: BareField.h:234
virtual void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:1314
Interface for a single beam element.
Definition: Component.h:50
EurekaAssign(int c)
Definition: BCond.hpp:5424
NDIndex< Dim > AddGuardCells(const NDIndex< Dim > &idx, const GuardCellSizes< Dim > &g)
void ExtrapolateFaceBCApply(ExtrapolateFace< T, D, M, Cell > &ef, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:2878
OpExtrapolate(const T &o, const T &s)
Definition: BCond.hpp:2723
const T & getOffset() const
Definition: BCond.h:414
ParticleSpatialLayout< double, 3, Mesh_t > Layout_t
Definition: PBunchDefs.h:24
const NDIndex< Dim > & getDomain() const
Definition: BareField.h:152
PatchBC(unsigned face)
Definition: BCond.hpp:6104
MMatrix< m_complex > complex(MMatrix< double > real)
Definition: MMatrix.cpp:396
unsigned leftGuard(unsigned d) const
Definition: BareField.h:148
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:3620
#define PAssert_GT(a, b)
Definition: PAssert.h:108
void ExtrapolateAndZeroFaceBCApply3(const NDIndex< D > &dest, LField< T, D > &fill, ExtrapolateAndZeroFace< T, D, M, C > &ef)
Definition: BCond.hpp:3688
ApplyToComponentType< T >::type(* Func)(typename ApplyToComponentType< T >::type)
Definition: BCond.h:682
const iterator & begin() const
Definition: LField.h:110
end
Definition: multipole_t.tex:9
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:5763
virtual void write(std::ostream &) const
Definition: BCond.hpp:236
NDIndex< D > calcEurekaDomain(const NDIndex< D > &realDomain, int face, const GuardCellSizes< D > &gc)
Definition: BCond.hpp:5582
void apply(Field< T, D, M, C > &)
Definition: BCond.hpp:6119
virtual void write(std::ostream &out) const
Definition: BCond.hpp:139
void ComponentFunctionFaceBCApply(ComponentFunctionFace< T, D, M, Cell > &ff, Field< T, D, M, Cell > &A)
Definition: BCond.hpp:5004
Definition: Centering.h:42