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