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