cyclicRepeatAMIPolyPatch.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2018-2019 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "SubField.H"
28 #include "Time.H"
30 
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  defineTypeNameAndDebug(cyclicRepeatAMIPolyPatch, 0);
36 
37  addToRunTimeSelectionTable(polyPatch, cyclicRepeatAMIPolyPatch, word);
38  addToRunTimeSelectionTable(polyPatch, cyclicRepeatAMIPolyPatch, dictionary);
39 }
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45 
46 template <class Type>
48 {
49  public:
50 
51  Tuple2<bool, Type> operator()
52  (
53  const Tuple2<bool, Type>& x,
54  const Tuple2<bool, Type>& y
55  ) const
56  {
57  if (x.first())
58  {
59  return x;
60  }
61  else if (y.first())
62  {
63  return y;
64  }
65  else
66  {
67  return Tuple2<bool, Type>(false, Type());
68  }
69  }
70 };
71 
72 }
73 
74 
75 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
76 
78 {
79  if (!owner())
80  {
81  return;
82  }
83 
84  Info<< indent << typeName <<" : Creating addressing and weights between "
85  << returnReduce(this->size(), sumOp<label>()) << " source faces and "
86  << returnReduce(neighbPatch().size(), sumOp<label>()) << " target faces"
87  << endl;
88 
89  // Get the transform associated with the transform patch
91  {
92  const coupledPolyPatch& transformPatch = this->transformPatch();
93 
94  if (transformPatch.name() != neighbPatch().transformPatch().name())
95  {
97  << "Transform patch " << transformPatch.name() << " for "
98  << typeName << " patch " << name() << " is not the same as for "
99  << "the neighbour patch " << neighbPatch().name() << ". "
100  << "This is not allowed." << exit(FatalError);
101  }
102 
103  if
104  (
105  transformPatch.separation().size() > 1
106  || transformPatch.forwardT().size() > 1
107  )
108  {
110  << "Transform patch " << transformPatch.name() << " for "
111  << typeName << " patch " << name() << " has a non-uniform "
112  << "transformation. This is not allowed."
113  << exit(FatalError);
114  }
115 
117  (
118  transformPatch.size(),
120  (
121  transformPatch.separation().size() > 0
122  ? transformPatch.separation()[0]
123  : vector::zero,
124  transformPatch.forwardT().size() > 0
125  ? transformPatch.forwardT()[0]
126  : tensor::zero,
127  transformPatch.forwardT().size() > 0
128  )
129  );
130 
132 
133  if (!bt.first())
134  {
136  << "Transform patch " << transformPatch.name() << " for "
137  << typeName << " patch " << name() << " has zero faces. It may "
138  << "have been converted to a processor cyclic during "
139  << "decomposition. Consider adding " << transformPatch.name()
140  << " and it's neighbour to the list of preserved patches."
141  << exit(FatalError);
142  }
143 
144  t = bt.second();
145  }
146  const vectorTensorTransform tInv(inv(t));
147 
148  // Work out the number of repetitions of the transform that separate this
149  // patch from its neighbour
150  label n = 0;
151  {
152  const scalarField thisMagAreas(mag(this->faceAreas()));
153  const scalarField nbrMagAreas(mag(neighbPatch().faceAreas()));
154 
155  vector thisCentre =
156  gSum(this->faceCentres()*thisMagAreas)/gSum(thisMagAreas);
157  vector nbrCentre =
158  gSum(neighbPatch().faceCentres()*nbrMagAreas)/gSum(nbrMagAreas);
159 
160  scalar dLeft = mag(t.transformPosition(thisCentre) - nbrCentre);
161  scalar d = mag(thisCentre - nbrCentre);
162  scalar dRight = mag(tInv.transformPosition(thisCentre) - nbrCentre);
163 
164  while (dLeft < d)
165  {
166  thisCentre = t.transformPosition(thisCentre);
167 
168  dRight = d;
169  d = dLeft;
170  dLeft = mag(t.transformPosition(thisCentre) - nbrCentre);
171 
172  ++ n;
173  }
174 
175  while (dRight < d)
176  {
177  thisCentre = tInv.transformPosition(thisCentre);
178 
179  dLeft = d;
180  d = dRight;
181  dRight = mag(tInv.transformPosition(thisCentre) - nbrCentre);
182 
183  -- n;
184  }
185  }
186 
187  // Generate the full transformations
188  vectorTensorTransform TLeft(t), T(vectorTensorTransform::I), TRight(tInv);
189  if (n > 0)
190  {
191  for (label i = 0; i < n - 1; ++ i)
192  {
193  T = t & T;
194  }
195 
196  TLeft = T;
197  T = t & T;
198  TRight = t & T;
199  }
200  if (n < 0)
201  {
202  for (label i = 0; i > n + 1; -- i)
203  {
204  T = tInv & T;
205  }
206 
207  TRight = T;
208  T = tInv & T;
209  TLeft = tInv & T;
210  }
211 
212  // Create copies of this patch and the neighbour patch's points
213  pointField thisPoints(localPoints());
214  const pointField nbrPoints(neighbPatch().localPoints());
215 
216  // Create primitive patches
217  primitivePatch thisPatch
218  (
219  SubList<face>(localFaces(), size()),
220  thisPoints
221  );
222  primitivePatch nbrPatch
223  (
224  SubList<face>(neighbPatch().localFaces(), neighbPatch().size()),
225  nbrPoints
226  );
227 
228  // Do the three bounding AMI interpolations
229  thisPoints = TLeft.transformPosition(localPoints());
230  thisPatch.movePoints(thisPoints);
231  autoPtr<AMIInterpolation> AMILeftPtr
232  (
233  new AMIInterpolation
234  (
235  thisPatch,
236  nbrPatch,
238  false,
240  AMILowWeightCorrection_,
241  AMIReverse_,
242  false
243  )
244  );
245  const scalar sLeft =
246  gSum(AMILeftPtr->srcWeightsSum()*AMILeftPtr->srcMagSf())
247  /gSum(AMILeftPtr->srcMagSf());
248 
249  thisPoints = T.transformPosition(localPoints());
250  thisPatch.movePoints(thisPoints);
252  (
253  new AMIInterpolation
254  (
255  thisPatch,
256  nbrPatch,
258  false,
260  AMILowWeightCorrection_,
261  AMIReverse_,
262  false
263  )
264  );
265  const scalar s =
266  gSum(AMIPtr->srcWeightsSum()*AMIPtr->srcMagSf())
267  /gSum(AMIPtr->srcMagSf());
268 
269  thisPoints = TRight.transformPosition(localPoints());
270  thisPatch.movePoints(thisPoints);
271  autoPtr<AMIInterpolation> AMIRightPtr
272  (
273  new AMIInterpolation
274  (
275  thisPatch,
276  nbrPatch,
278  false,
280  AMILowWeightCorrection_,
281  AMIReverse_,
282  false
283  )
284  );
285  const scalar sRight =
286  gSum(AMIRightPtr->srcWeightsSum()*AMIRightPtr->srcMagSf())
287  /gSum(AMIRightPtr->srcMagSf());
288 
289  Info<< typeName << ": number of transforms = " << n << endl
290  << typeName << ": left/centre/right sum(weights) = "
291  << sLeft << ", " << s << ", " << sRight << endl;
292 
293  // Set the AMI interpolators and transforms using the centre and the most
294  // overlapping of the left and right sides
295  AMIs_.resize(2);
296  AMIs_.set(0, sLeft > sRight ? AMILeftPtr.ptr() : AMIPtr.ptr());
297  AMIs_.set(1, sLeft > sRight ? AMIPtr.ptr() : AMIRightPtr.ptr());
298 
299  AMITransforms_.resize(2);
300  AMITransforms_[0] = sLeft > sRight ? TLeft : T;
301  AMITransforms_[1] = sLeft > sRight ? T : TRight;
302 
303  // Sum and normalise the two AMI interpolators
304  AMIInterpolation::sumWeights(AMIs_);
305  AMIInterpolation::reportSumWeights(AMIs_[0]);
306  AMIInterpolation::normaliseWeights(AMIs_);
307 }
308 
309 
310 // * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
311 
313 (
314  const word& name,
315  const label size,
316  const label start,
317  const label index,
318  const polyBoundaryMesh& bm,
319  const word& patchType,
320  const transformType transform
321 )
322 :
324  (
325  name,
326  size,
327  start,
328  index,
329  bm,
330  patchType,
331  transform,
332  false,
334  ),
335  transformPatchName_(word::null),
336  transformPatchID_(-1)
337 {
338  // Transform patch might not be valid yet so cannot determine
339  // associated patchID
340 }
341 
342 
344 (
345  const word& name,
346  const dictionary& dict,
347  const label index,
348  const polyBoundaryMesh& bm,
349  const word& patchType
350 )
351 :
353  (
354  name,
355  dict,
356  index,
357  bm,
358  patchType,
359  false,
361  ),
362  transformPatchName_(dict.lookup("transformPatch")),
363  transformPatchID_(-1)
364 {
365  // Transform patch might not be valid yet so cannot determine
366  // associated patchID
367 }
368 
369 
371 (
372  const cyclicRepeatAMIPolyPatch& pp,
373  const polyBoundaryMesh& bm
374 )
375 :
376  cyclicAMIPolyPatch(pp, bm),
377  transformPatchName_(pp.transformPatchName_),
378  transformPatchID_(-1)
379 {
380  // Transform patch might not be valid yet so cannot determine
381  // associated patchID
382 }
383 
384 
386 (
387  const cyclicRepeatAMIPolyPatch& pp,
388  const polyBoundaryMesh& bm,
389  const label index,
390  const label newSize,
391  const label newStart,
392  const word& nbrPatchName
393 )
394 :
395  cyclicAMIPolyPatch(pp, bm, index, newSize, newStart, nbrPatchName),
396  transformPatchName_(pp.transformPatchName_),
397  transformPatchID_(-1)
398 {
399  // Transform patch might not be valid yet so cannot determine
400  // associated patchID
401 }
402 
403 
405 (
406  const cyclicRepeatAMIPolyPatch& pp,
407  const polyBoundaryMesh& bm,
408  const label index,
409  const labelUList& mapAddressing,
410  const label newStart
411 )
412 :
413  cyclicAMIPolyPatch(pp, bm, index, mapAddressing, newStart),
414  transformPatchName_(pp.transformPatchName_),
415  transformPatchID_(-1)
416 {
417  // Transform patch might not be valid yet so cannot determine
418  // associated patchID
419 }
420 
421 
422 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
423 
425 {}
426 
427 
428 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
429 
432 {
433  const polyPatch& pp = this->boundaryMesh()[neighbPatchID()];
434 
435  return refCast<const cyclicRepeatAMIPolyPatch>(pp);
436 }
437 
438 
440 {
441  if (transformPatchID_ == -1)
442  {
443  transformPatchID_ =
444  this->boundaryMesh().findPatchID(transformPatchName());
445 
446  if (transformPatchID_ == -1)
447  {
449  << "Illegal transformPatch name " << transformPatchName()
450  << nl << "Valid patch names are "
451  << this->boundaryMesh().names()
452  << exit(FatalError);
453  }
454  }
455 
456  return transformPatchID_;
457 }
458 
459 
462 {
463  const polyPatch& pp = this->boundaryMesh()[transformPatchID()];
464 
465  return refCast<const coupledPolyPatch>(pp);
466 }
467 
468 
470 {
471  // The two AMI-interpolation classes have their weights summed together, so
472  // both should contain the same weights sum field. We can, therefore
473  // delegate to the base class and just return the weights sum of the first.
474 
476 }
477 
478 
479 const Foam::scalarField&
481 {
482  // See above.
483 
485 }
486 
487 
489 {
491  writeEntry(os, "transformPatch", transformPatchName_);
492 }
493 
494 
495 // ************************************************************************* //
virtual void resetAMI() const
Reset the AMI interpolator.
virtual ~cyclicRepeatAMIPolyPatch()
Destructor.
virtual void movePoints(const Field< PointType > &)
Correct patch after moving points.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
const word & name() const
Return name.
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:226
virtual const scalarField & weightsSum() const
Return the weights sum for this patch.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
Vector-tensor class used to perform translations and rotations in 3D space.
const Type1 & first() const
Return first.
Definition: Tuple2.H:99
virtual const cyclicRepeatAMIPolyPatch & neighbPatch() const
Return a reference to the neighbour patch.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
virtual const scalarField & neighbWeightsSum() const
Return the weights sum for the neighbour patch.
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
T * ptr()
Return object pointer for reuse.
Definition: autoPtrI.H:90
virtual const vectorField & separation() const
If the planes are separated the separation vector.
Macros for easy insertion into run-time selection tables.
virtual const tensorField & forwardT() const
Return face transformation tensor.
virtual label transformPatchID() const
Neighbour patch ID.
scalar y
A list of faces which address into the list of points.
Repeat patch for Arbitrary Mesh Interface (AMI)
A List obtained as a section of another List.
Definition: SubList.H:53
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Type gSum(const FieldField< Field, Type > &f)
A class for handling words, derived from string.
Definition: word.H:59
static const word null
An empty word.
Definition: word.H:77
word transformPatchName_
Name of the transform patch.
Cyclic patch for Arbitrary Mesh Interface (AMI)
virtual const scalarField & weightsSum() const
Return the weights sum for this patch.
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
Foam::polyBoundaryMesh.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
static const vectorTensorTransform I
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
static const char nl
Definition: Ostream.H:265
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
defineTypeNameAndDebug(combustionModel, 0)
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
void writeEntry(Ostream &os, const HashTable< T, Key, Hash > &ht)
Definition: HashTableIO.C:96
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
messageStream Info
const Type2 & second() const
Return second.
Definition: Tuple2.H:111
dimensioned< scalar > mag(const dimensioned< Type > &)
label n
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
vector transformPosition(const vector &v) const
Transform the given position.
virtual const scalarField & neighbWeightsSum() const
Return the weights sum for the neighbour patch.
cyclicRepeatAMIPolyPatch(const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm, const word &patchType, const transformType transform=UNKNOWN)
Construct from (base couped patch) components.
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:583
virtual const coupledPolyPatch & transformPatch() const
Return a reference to the transform patch.