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