cyclicAMIPolyPatch.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2018 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "cyclicAMIPolyPatch.H"
30 #include "transformField.H"
31 #include "SubField.H"
32 #include "polyMesh.H"
33 #include "Time.H"
35 #include "faceAreaIntersect.H"
36 #include "ops.H"
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(cyclicAMIPolyPatch, 0);
43 
44  addToRunTimeSelectionTable(polyPatch, cyclicAMIPolyPatch, word);
45  addToRunTimeSelectionTable(polyPatch, cyclicAMIPolyPatch, dictionary);
46 }
47 
48 
49 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
50 
51 Foam::vector Foam::cyclicAMIPolyPatch::findFaceNormalMaxRadius
52 (
53  const pointField& faceCentres
54 ) const
55 {
56  // Determine a face furthest away from the axis
57 
59 
60  const scalarField magRadSqr(magSqr(n));
61 
62  label facei = findMax(magRadSqr);
63 
64  if (debug)
65  {
66  Info<< "findFaceMaxRadius(const pointField&) : patch: " << name() << nl
67  << " rotFace = " << facei << nl
68  << " point = " << faceCentres[facei] << nl
69  << " distance = " << Foam::sqrt(magRadSqr[facei])
70  << endl;
71  }
72 
73  return n[facei];
74 }
75 
76 
78 (
79  const primitivePatch& half0,
80  const pointField& half0Ctrs,
81  const vectorField& half0Areas,
82  const pointField& half1Ctrs,
83  const vectorField& half1Areas
84 )
85 {
86  if (transform() != neighbPatch().transform())
87  {
89  << "Patch " << name()
90  << " has transform type " << transformTypeNames[transform()]
91  << ", neighbour patch " << neighbPatchName()
92  << " has transform type "
93  << neighbPatch().transformTypeNames[neighbPatch().transform()]
94  << exit(FatalError);
95  }
96 
97 
98  // Calculate transformation tensors
99 
100  switch (transform())
101  {
102  case ROTATIONAL:
103  {
104  tensor revT = Zero;
105 
106  if (rotationAngleDefined_)
107  {
108  const tensor T(rotationAxis_*rotationAxis_);
109 
110  const tensor S
111  (
112  0, -rotationAxis_.z(), rotationAxis_.y(),
113  rotationAxis_.z(), 0, -rotationAxis_.x(),
114  -rotationAxis_.y(), rotationAxis_.x(), 0
115  );
116 
117  const tensor revTPos
118  (
119  T
120  + cos(rotationAngle_)*(tensor::I - T)
121  + sin(rotationAngle_)*S
122  );
123 
124  const tensor revTNeg
125  (
126  T
127  + cos(-rotationAngle_)*(tensor::I - T)
128  + sin(-rotationAngle_)*S
129  );
130 
131  // Check - assume correct angle when difference in face areas
132  // is the smallest
133  const vector transformedAreaPos = gSum(half1Areas & revTPos);
134  const vector transformedAreaNeg = gSum(half1Areas & revTNeg);
135  const vector area0 = gSum(half0Areas);
136  const scalar magArea0 = mag(area0) + ROOTVSMALL;
137 
138  // Areas have opposite sign, so sum should be zero when correct
139  // rotation applied
140  const scalar errorPos = mag(transformedAreaPos + area0);
141  const scalar errorNeg = mag(transformedAreaNeg + area0);
142 
143  const scalar normErrorPos = errorPos/magArea0;
144  const scalar normErrorNeg = errorNeg/magArea0;
145 
146  if (errorPos > errorNeg && normErrorNeg < matchTolerance())
147  {
148  revT = revTNeg;
149  rotationAngle_ *= -1;
150  }
151  else
152  {
153  revT = revTPos;
154  }
155 
156  const scalar areaError = min(normErrorPos, normErrorNeg);
157 
158  if (areaError > matchTolerance())
159  {
161  << "Patch areas are not consistent within "
162  << 100*matchTolerance()
163  << " % indicating a possible error in the specified "
164  << "angle of rotation" << nl
165  << " owner patch : " << name() << nl
166  << " neighbour patch : " << neighbPatch().name()
167  << nl
168  << " angle : "
169  << radToDeg(rotationAngle_) << " deg" << nl
170  << " area error : " << 100*areaError << " %"
171  << " match tolerance : " << matchTolerance()
172  << endl;
173  }
174 
175  if (debug)
176  {
177  scalar theta = radToDeg(rotationAngle_);
178 
179  Pout<< "cyclicAMIPolyPatch::calcTransforms: patch:"
180  << name()
181  << " Specified rotation:"
182  << " swept angle: " << theta << " [deg]"
183  << " reverse transform: " << revT
184  << endl;
185  }
186  }
187  else
188  {
189  point n0 = Zero;
190  point n1 = Zero;
191  if (half0Ctrs.size())
192  {
193  n0 = findFaceNormalMaxRadius(half0Ctrs);
194  }
195  if (half1Ctrs.size())
196  {
197  n1 = -findFaceNormalMaxRadius(half1Ctrs);
198  }
199 
200  reduce(n0, maxMagSqrOp<point>());
201  reduce(n1, maxMagSqrOp<point>());
202 
203  n0.normalise();
204  n1.normalise();
205 
206  // Extended tensor from two local coordinate systems calculated
207  // using normal and rotation axis
208  const tensor E0
209  (
210  rotationAxis_,
211  (n0 ^ rotationAxis_),
212  n0
213  );
214  const tensor E1
215  (
216  rotationAxis_,
217  (-n1 ^ rotationAxis_),
218  -n1
219  );
220  revT = E1.T() & E0;
221 
222  if (debug)
223  {
224  scalar theta = radToDeg(acos(-(n0 & n1)));
225 
226  Pout<< "cyclicAMIPolyPatch::calcTransforms: patch:"
227  << name()
228  << " Specified rotation:"
229  << " n0:" << n0 << " n1:" << n1
230  << " swept angle: " << theta << " [deg]"
231  << " reverse transform: " << revT
232  << endl;
233  }
234  }
235 
236  const_cast<tensorField&>(forwardT()) = tensorField(1, revT.T());
237  const_cast<tensorField&>(reverseT()) = tensorField(1, revT);
238  const_cast<vectorField&>(separation()).setSize(0);
239  const_cast<boolList&>(collocated()) = boolList(1, false);
240 
241  break;
242  }
243  case TRANSLATIONAL:
244  {
245  if (debug)
246  {
247  Pout<< "cyclicAMIPolyPatch::calcTransforms : patch:" << name()
248  << " Specified translation : " << separationVector_
249  << endl;
250  }
251 
252  const_cast<tensorField&>(forwardT()).clear();
253  const_cast<tensorField&>(reverseT()).clear();
254  const_cast<vectorField&>(separation()) = vectorField
255  (
256  1,
257  separationVector_
258  );
259  const_cast<boolList&>(collocated()) = boolList(1, false);
260 
261  break;
262  }
263  default:
264  {
265  if (debug)
266  {
267  Pout<< "patch:" << name()
268  << " Assuming cyclic AMI pairs are colocated" << endl;
269  }
270 
271  const_cast<tensorField&>(forwardT()).clear();
272  const_cast<tensorField&>(reverseT()).clear();
273  const_cast<vectorField&>(separation()).setSize(0);
274  const_cast<boolList&>(collocated()) = boolList(1, true);
275 
276  break;
277  }
278  }
279 
280  if (debug)
281  {
282  Pout<< "patch: " << name() << nl
283  << " forwardT = " << forwardT() << nl
284  << " reverseT = " << reverseT() << nl
285  << " separation = " << separation() << nl
286  << " collocated = " << collocated() << nl << endl;
287  }
288 }
289 
290 
291 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
292 
294 (
296 ) const
297 {
298  if (owner())
299  {
300  AMIPtr_.clear();
301 
302  const polyPatch& nbr = neighbPatch();
303  pointField nbrPoints
304  (
305  neighbPatch().boundaryMesh().mesh().points(),
306  neighbPatch().meshPoints()
307  );
308 
309  if (debug)
310  {
311  const Time& t = boundaryMesh().mesh().time();
312  OFstream os(t.path()/name() + "_neighbourPatch-org.obj");
313  meshTools::writeOBJ(os, neighbPatch().localFaces(), nbrPoints);
314  }
315 
316  // Transform neighbour patch to local system
317  transformPosition(nbrPoints);
318  primitivePatch nbrPatch0
319  (
321  (
322  nbr.localFaces(),
323  nbr.size()
324  ),
325  nbrPoints
326  );
327 
328  if (debug)
329  {
330  const Time& t = boundaryMesh().mesh().time();
331  OFstream osN(t.path()/name() + "_neighbourPatch-trans.obj");
332  meshTools::writeOBJ(osN, nbrPatch0.localFaces(), nbrPoints);
333 
334  OFstream osO(t.path()/name() + "_ownerPatch.obj");
335  meshTools::writeOBJ(osO, this->localFaces(), localPoints());
336  }
337 
338  // Construct/apply AMI interpolation to determine addressing and weights
339  AMIPtr_.reset
340  (
342  (
343  *this,
344  nbrPatch0,
345  surfPtr(),
347  AMIRequireMatch_,
348  AMIMethod,
349  AMILowWeightCorrection_,
350  AMIReverse_
351  )
352  );
353 
354  if (debug)
355  {
356  Pout<< "cyclicAMIPolyPatch : " << name()
357  << " constructed AMI with " << nl
358  << " " << "srcAddress:" << AMIPtr_().srcAddress().size()
359  << nl
360  << " " << "tgAddress :" << AMIPtr_().tgtAddress().size()
361  << nl << endl;
362  }
363  }
364 }
365 
366 
368 {
369  const cyclicAMIPolyPatch& half0 = *this;
370  vectorField half0Areas(half0.size());
371  forAll(half0, facei)
372  {
373  half0Areas[facei] = half0[facei].areaNormal(half0.points());
374  }
375 
376  const cyclicAMIPolyPatch& half1 = neighbPatch();
377  vectorField half1Areas(half1.size());
378  forAll(half1, facei)
379  {
380  half1Areas[facei] = half1[facei].areaNormal(half1.points());
381  }
382 
383  calcTransforms
384  (
385  half0,
386  half0.faceCentres(),
387  half0Areas,
388  half1.faceCentres(),
389  half1Areas
390  );
391 
392  if (debug)
393  {
394  Pout<< "calcTransforms() : patch: " << name() << nl
395  << " forwardT = " << forwardT() << nl
396  << " reverseT = " << reverseT() << nl
397  << " separation = " << separation() << nl
398  << " collocated = " << collocated() << nl << endl;
399  }
400 }
401 
402 
404 {
405  // The AMI is no longer valid. Leave it up to demand-driven calculation
406  AMIPtr_.clear();
407 
409 
410  // Early calculation of transforms so e.g. cyclicACMI can use them.
411  // Note: also triggers primitiveMesh face centre. Note that cell
412  // centres should -not- be calculated
413  // since e.g. cyclicACMI override face areas
414  calcTransforms();
415 }
416 
417 
419 {
420  // All geometry done inside initGeometry
421 }
422 
423 
425 (
426  PstreamBuffers& pBufs,
427  const pointField& p
428 )
429 {
430  // The AMI is no longer valid. Leave it up to demand-driven calculation
431  AMIPtr_.clear();
432 
434 
435  // See below. Clear out any local geometry
437 
438  // Early calculation of transforms. See above.
439  calcTransforms();
440 }
441 
442 
444 (
445  PstreamBuffers& pBufs,
446  const pointField& p
447 )
448 {
449  polyPatch::movePoints(pBufs, p);
450 
451  // All transformation tensors already done in initMovePoints
452 }
453 
454 
456 {
457  // The AMI is no longer valid. Leave it up to demand-driven calculation
458  AMIPtr_.clear();
459 
461 }
462 
463 
465 {
466  polyPatch::updateMesh(pBufs);
467 }
468 
469 
471 {
472  AMIPtr_.clear();
474 }
475 
476 
477 // * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
478 
480 (
481  const word& name,
482  const label size,
483  const label start,
484  const label index,
485  const polyBoundaryMesh& bm,
486  const word& patchType,
488 )
489 :
490  coupledPolyPatch(name, size, start, index, bm, patchType, transform),
491  nbrPatchName_(word::null),
492  nbrPatchID_(-1),
493  rotationAxis_(Zero),
494  rotationCentre_(Zero),
495  rotationAngleDefined_(false),
496  rotationAngle_(0.0),
497  separationVector_(Zero),
498  AMIPtr_(nullptr),
500  AMIReverse_(false),
501  AMIRequireMatch_(true),
502  AMILowWeightCorrection_(-1.0),
503  surfPtr_(nullptr),
504  surfDict_(fileName("surface"))
505 {
506  // Neighbour patch might not be valid yet so no transformation
507  // calculation possible
508 }
509 
510 
512 (
513  const word& name,
514  const dictionary& dict,
515  const label index,
516  const polyBoundaryMesh& bm,
517  const word& patchType
518 )
519 :
520  coupledPolyPatch(name, dict, index, bm, patchType),
521  nbrPatchName_(dict.lookupOrDefault<word>("neighbourPatch", "")),
522  coupleGroup_(dict),
523  nbrPatchID_(-1),
524  rotationAxis_(Zero),
525  rotationCentre_(Zero),
526  rotationAngleDefined_(false),
527  rotationAngle_(0.0),
528  separationVector_(Zero),
529  AMIPtr_(nullptr),
530  AMIMethod_
531  (
533  [
535  (
536  "method",
538  [
540  ]
541  )
542  ]
543  ),
544  AMIReverse_(dict.lookupOrDefault("flipNormals", false)),
545  AMIRequireMatch_(true),
546  AMILowWeightCorrection_(dict.lookupOrDefault("lowWeightCorrection", -1.0)),
547  surfPtr_(nullptr),
548  surfDict_(dict.subOrEmptyDict("surface"))
549 {
550  if (nbrPatchName_ == word::null && !coupleGroup_.valid())
551  {
553  << "No \"neighbourPatch\" or \"coupleGroup\" provided."
554  << exit(FatalIOError);
555  }
556 
557  if (nbrPatchName_ == name)
558  {
560  << "Neighbour patch name " << nbrPatchName_
561  << " cannot be the same as this patch " << name
562  << exit(FatalIOError);
563  }
564 
565  switch (transform())
566  {
567  case ROTATIONAL:
568  {
569  dict.readEntry("rotationAxis", rotationAxis_);
570  dict.readEntry("rotationCentre", rotationCentre_);
571  if (dict.readIfPresent("rotationAngle", rotationAngle_))
572  {
573  rotationAngleDefined_ = true;
574  rotationAngle_ = degToRad(rotationAngle_);
575 
576  if (debug)
577  {
578  Info<< "rotationAngle: " << rotationAngle_ << " [rad]"
579  << endl;
580  }
581  }
582 
583  scalar magRot = mag(rotationAxis_);
584  if (magRot < SMALL)
585  {
587  << "Illegal rotationAxis " << rotationAxis_ << endl
588  << "Please supply a non-zero vector."
589  << exit(FatalIOError);
590  }
591  rotationAxis_ /= magRot;
592 
593  break;
594  }
595  case TRANSLATIONAL:
596  {
597  dict.readEntry("separationVector", separationVector_);
598  break;
599  }
600  default:
601  {
602  // No additional info required
603  }
604  }
605 
606  // Neighbour patch might not be valid yet so no transformation
607  // calculation possible
608 }
609 
610 
612 (
613  const cyclicAMIPolyPatch& pp,
614  const polyBoundaryMesh& bm
615 )
616 :
617  coupledPolyPatch(pp, bm),
618  nbrPatchName_(pp.nbrPatchName_),
619  coupleGroup_(pp.coupleGroup_),
620  nbrPatchID_(-1),
621  rotationAxis_(pp.rotationAxis_),
622  rotationCentre_(pp.rotationCentre_),
623  rotationAngleDefined_(pp.rotationAngleDefined_),
624  rotationAngle_(pp.rotationAngle_),
625  separationVector_(pp.separationVector_),
626  AMIPtr_(nullptr),
627  AMIMethod_(pp.AMIMethod_),
628  AMIReverse_(pp.AMIReverse_),
629  AMIRequireMatch_(pp.AMIRequireMatch_),
630  AMILowWeightCorrection_(pp.AMILowWeightCorrection_),
631  surfPtr_(nullptr),
632  surfDict_(pp.surfDict_)
633 {
634  // Neighbour patch might not be valid yet so no transformation
635  // calculation possible
636 }
637 
638 
640 (
641  const cyclicAMIPolyPatch& pp,
642  const polyBoundaryMesh& bm,
643  const label index,
644  const label newSize,
645  const label newStart,
646  const word& nbrPatchName
647 )
648 :
649  coupledPolyPatch(pp, bm, index, newSize, newStart),
650  nbrPatchName_(nbrPatchName),
651  coupleGroup_(pp.coupleGroup_),
652  nbrPatchID_(-1),
653  rotationAxis_(pp.rotationAxis_),
654  rotationCentre_(pp.rotationCentre_),
655  rotationAngleDefined_(pp.rotationAngleDefined_),
656  rotationAngle_(pp.rotationAngle_),
657  separationVector_(pp.separationVector_),
658  AMIPtr_(nullptr),
659  AMIMethod_(pp.AMIMethod_),
660  AMIReverse_(pp.AMIReverse_),
661  AMIRequireMatch_(pp.AMIRequireMatch_),
662  AMILowWeightCorrection_(pp.AMILowWeightCorrection_),
663  surfPtr_(nullptr),
664  surfDict_(pp.surfDict_)
665 {
666  if (nbrPatchName_ == name())
667  {
669  << "Neighbour patch name " << nbrPatchName_
670  << " cannot be the same as this patch " << name()
671  << exit(FatalError);
672  }
673 
674  // Neighbour patch might not be valid yet so no transformation
675  // calculation possible
676 }
677 
678 
680 (
681  const cyclicAMIPolyPatch& pp,
682  const polyBoundaryMesh& bm,
683  const label index,
684  const labelUList& mapAddressing,
685  const label newStart
686 )
687 :
688  coupledPolyPatch(pp, bm, index, mapAddressing, newStart),
689  nbrPatchName_(pp.nbrPatchName_),
690  coupleGroup_(pp.coupleGroup_),
691  nbrPatchID_(-1),
692  rotationAxis_(pp.rotationAxis_),
693  rotationCentre_(pp.rotationCentre_),
694  rotationAngleDefined_(pp.rotationAngleDefined_),
695  rotationAngle_(pp.rotationAngle_),
696  separationVector_(pp.separationVector_),
697  AMIPtr_(nullptr),
698  AMIMethod_(pp.AMIMethod_),
699  AMIReverse_(pp.AMIReverse_),
700  AMIRequireMatch_(pp.AMIRequireMatch_),
701  AMILowWeightCorrection_(pp.AMILowWeightCorrection_),
702  surfPtr_(nullptr),
703  surfDict_(pp.surfDict_)
704 {}
705 
706 
707 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
708 
710 {}
711 
712 
713 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
714 
716 {
717  if (nbrPatchID_ == -1)
718  {
719  nbrPatchID_ = this->boundaryMesh().findPatchID(neighbPatchName());
720 
721  if (nbrPatchID_ == -1)
722  {
724  << "Illegal neighbourPatch name " << neighbPatchName()
725  << nl << "Valid patch names are "
726  << this->boundaryMesh().names()
727  << exit(FatalError);
728  }
729 
730  // Check that it is a cyclic AMI patch
731  const cyclicAMIPolyPatch& nbrPatch =
732  refCast<const cyclicAMIPolyPatch>
733  (
734  this->boundaryMesh()[nbrPatchID_]
735  );
736 
737  if (nbrPatch.neighbPatchName() != name())
738  {
740  << "Patch " << name()
741  << " specifies neighbour patch " << neighbPatchName()
742  << nl << " but that in return specifies "
743  << nbrPatch.neighbPatchName() << endl;
744  }
745  }
746 
747  return nbrPatchID_;
748 }
749 
750 
752 {
753  return index() < neighbPatchID();
754 }
755 
756 
758 {
759  const polyPatch& pp = this->boundaryMesh()[neighbPatchID()];
760  return refCast<const cyclicAMIPolyPatch>(pp);
761 }
762 
763 
766 {
767  const word surfType(surfDict_.lookupOrDefault<word>("type", "none"));
768 
769  if (!surfPtr_.valid() && owner() && surfType != "none")
770  {
771  word surfName(surfDict_.lookupOrDefault("name", name()));
772 
773  const polyMesh& mesh = boundaryMesh().mesh();
774 
775  surfPtr_ =
777  (
778  surfType,
779  IOobject
780  (
781  surfName,
782  mesh.time().constant(),
783  "triSurface",
784  mesh,
787  ),
788  surfDict_
789  );
790  }
791 
792  return surfPtr_;
793 }
794 
795 
797 {
798  if (!owner())
799  {
801  << "AMI interpolator only available to owner patch"
802  << abort(FatalError);
803  }
804 
805  if (!AMIPtr_.valid())
806  {
807  resetAMI(AMIMethod_);
808  }
809 
810  return *AMIPtr_;
811 }
812 
813 
815 {
816  if (owner())
817  {
818  return AMI().applyLowWeightCorrection();
819  }
820  else
821  {
822  return neighbPatch().AMI().applyLowWeightCorrection();
823  }
824 }
825 
826 
828 {
829  if (!parallel())
830  {
831  if (transform() == ROTATIONAL)
832  {
833  l = Foam::transform(forwardT(), l - rotationCentre_)
834  + rotationCentre_;
835  }
836  else
837  {
838  l = Foam::transform(forwardT(), l);
839  }
840  }
841  else if (separated())
842  {
843  // transformPosition gets called on the receiving side,
844  // separation gets calculated on the sending side so subtract
845 
846  const vectorField& s = separation();
847  if (s.size() == 1)
848  {
849  forAll(l, i)
850  {
851  l[i] -= s[0];
852  }
853  }
854  else
855  {
856  l -= s;
857  }
858  }
859 }
860 
861 
863 (
864  point& l,
865  const label facei
866 ) const
867 {
868  if (!parallel())
869  {
870  const tensor& T =
871  (
872  forwardT().size() == 1
873  ? forwardT()[0]
874  : forwardT()[facei]
875  );
876 
877  if (transform() == ROTATIONAL)
878  {
879  l = Foam::transform(T, l - rotationCentre_) + rotationCentre_;
880  }
881  else
882  {
883  l = Foam::transform(T, l);
884  }
885  }
886  else if (separated())
887  {
888  const vector& s =
889  (
890  separation().size() == 1
891  ? separation()[0]
892  : separation()[facei]
893  );
894 
895  l -= s;
896  }
897 }
898 
899 
901 (
902  point& l,
903  const label facei
904 ) const
905 {
906  if (!parallel())
907  {
908  const tensor& T =
909  (
910  reverseT().size() == 1
911  ? reverseT()[0]
912  : reverseT()[facei]
913  );
914 
915  if (transform() == ROTATIONAL)
916  {
917  l = Foam::transform(T, l - rotationCentre_) + rotationCentre_;
918  }
919  else
920  {
921  l = Foam::transform(T, l);
922  }
923  }
924  else if (separated())
925  {
926  const vector& s =
927  (
928  separation().size() == 1
929  ? separation()[0]
930  : separation()[facei]
931  );
932 
933  l += s;
934  }
935 }
936 
937 
939 (
940  vector& d,
941  const label facei
942 ) const
943 {
944  if (!parallel())
945  {
946  const tensor& T =
947  (
948  reverseT().size() == 1
949  ? reverseT()[0]
950  : reverseT()[facei]
951  );
952 
953  d = Foam::transform(T, d);
954  }
955 }
956 
957 
959 (
960  const primitivePatch& referPatch,
961  const pointField& thisCtrs,
962  const vectorField& thisAreas,
963  const pointField& thisCc,
964  const pointField& nbrCtrs,
965  const vectorField& nbrAreas,
966  const pointField& nbrCc
967 )
968 {}
969 
970 
972 (
973  PstreamBuffers& pBufs,
974  const primitivePatch& pp
975 ) const
976 {}
977 
978 
980 (
981  PstreamBuffers& pBufs,
982  const primitivePatch& pp,
984  labelList& rotation
985 ) const
986 {
987  faceMap.setSize(pp.size());
988  faceMap = -1;
989 
990  rotation.setSize(pp.size());
991  rotation = 0;
992 
993  return false;
994 }
995 
996 
998 (
999  const label facei,
1000  const vector& n,
1001  point& p
1002 ) const
1003 {
1004  point prt(p);
1005  reverseTransformPosition(prt, facei);
1006 
1007  vector nrt(n);
1008  reverseTransformDirection(nrt, facei);
1009 
1010  label nbrFacei = -1;
1011 
1012  if (owner())
1013  {
1014  nbrFacei = AMI().tgtPointFace
1015  (
1016  *this,
1017  neighbPatch(),
1018  nrt,
1019  facei,
1020  prt
1021  );
1022  }
1023  else
1024  {
1025  nbrFacei = neighbPatch().AMI().srcPointFace
1026  (
1027  neighbPatch(),
1028  *this,
1029  nrt,
1030  facei,
1031  prt
1032  );
1033  }
1034 
1035  if (nbrFacei >= 0)
1036  {
1037  p = prt;
1038  }
1039 
1040  return nbrFacei;
1041 }
1042 
1043 
1045 {
1047  if (!nbrPatchName_.empty())
1048  {
1049  os.writeEntry("neighbourPatch", nbrPatchName_);
1050  }
1051  coupleGroup_.write(os);
1052 
1053  switch (transform())
1054  {
1055  case ROTATIONAL:
1056  {
1057  os.writeEntry("rotationAxis", rotationAxis_);
1058  os.writeEntry("rotationCentre", rotationCentre_);
1059 
1060  if (rotationAngleDefined_)
1061  {
1062  os.writeEntry("rotationAngle", radToDeg(rotationAngle_));
1063  }
1064 
1065  break;
1066  }
1067  case TRANSLATIONAL:
1068  {
1069  os.writeEntry("separationVector", separationVector_);
1070  break;
1071  }
1072  case NOORDERING:
1073  {
1074  break;
1075  }
1076  default:
1077  {
1078  // No additional info to write
1079  }
1080  }
1081 
1083  {
1084  os.writeEntry
1085  (
1086  "method",
1088  [
1089  AMIMethod_
1090  ]
1091  );
1092  }
1093 
1094  if (AMIReverse_)
1095  {
1096  os.writeEntry("flipNormals", AMIReverse_);
1097  }
1098 
1099  if (AMILowWeightCorrection_ > 0)
1100  {
1101  os.writeEntry("lowWeightCorrection", AMILowWeightCorrection_);
1102  }
1103 
1104  if (!surfDict_.empty())
1105  {
1106  surfDict_.writeEntry(surfDict_.dictName(), os);
1107  }
1108 }
1109 
1110 
1111 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary)
Foam::AMIInterpolation::interpolationMethod
interpolationMethod
Enumeration specifying interpolation method.
Definition: AMIInterpolation.H:90
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
Foam::cyclicAMIPolyPatch::order
virtual bool order(PstreamBuffers &, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for primitivePatch.
Definition: cyclicAMIPolyPatch.C:980
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::boundaryMesh::mesh
const bMesh & mesh() const
Definition: boundaryMesh.H:205
Foam::Tensor< scalar >
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
setSize
points setSize(newPointi)
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:104
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::AMIInterpolation::interpolationMethodNames_
static const Enum< interpolationMethod > interpolationMethodNames_
Definition: AMIInterpolation.H:98
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:73
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeFast.C:94
Foam::PrimitivePatch::points
const Field< PointType > & points() const
Return reference to global points.
Definition: PrimitivePatch.H:300
Foam::cyclicAMIPolyPatch::owner
virtual bool owner() const
Does this side own the patch?
Definition: cyclicAMIPolyPatch.C:751
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
SubField.H
Foam::Tensor::I
static const Tensor I
Definition: Tensor.H:84
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.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))
Definition: gmvOutputSpray.H:25
Foam::polyPatch::movePoints
virtual void movePoints(PstreamBuffers &, const pointField &p)
Correct patches after moving points.
Definition: polyPatch.C:60
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::cyclicAMIPolyPatch::nbrPatchName_
word nbrPatchName_
Name of other half.
Definition: cyclicAMIPolyPatch.H:77
Foam::cyclicAMIPolyPatch::initOrder
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialize ordering for primitivePatch. Does not.
Definition: cyclicAMIPolyPatch.C:972
Foam::Zero
static constexpr const zero Zero
Global zero.
Definition: zero.H:128
Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
cyclicAMIPolyPatch(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 coupled patch) components.
Definition: cyclicAMIPolyPatch.C:480
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Foam::cyclicAMIPolyPatch::rotationCentre_
point rotationCentre_
Point on axis of rotation for rotational cyclics.
Definition: cyclicAMIPolyPatch.H:94
Foam::AMIInterpolation::imFaceAreaWeight
Definition: AMIInterpolation.H:94
Foam::sin
dimensionedScalar sin(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:264
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:53
Foam::cyclicAMIPolyPatch::initGeometry
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
Definition: cyclicAMIPolyPatch.C:403
Foam::tensor
Tensor< scalar > tensor
Tensor of scalars.
Definition: tensor.H:53
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:88
Foam::polyPatch::clearGeom
virtual void clearGeom()
Clear geometry.
Definition: polyPatch.C:72
Foam::cyclicAMIPolyPatch::reverseTransformPosition
virtual void reverseTransformPosition(point &l, const label facei) const
Transform a patch-based position from this side to nbr side.
Definition: cyclicAMIPolyPatch.C:901
ops.H
Various functors for unary and binary operations. Can be used for parallel combine-reduce operations ...
Foam::cyclicAMIPolyPatch::surfDict_
const dictionary surfDict_
Dictionary used during projection surface construction.
Definition: cyclicAMIPolyPatch.H:128
Foam::tensorField
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
Definition: primitiveFieldsFwd.H:57
Foam::cyclicAMIPolyPatch::surfPtr
const autoPtr< searchableSurface > & surfPtr() const
Return a reference to the projection surface.
Definition: cyclicAMIPolyPatch.C:765
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:72
Foam::cyclicAMIPolyPatch::coupleGroup_
const coupleGroupIdentifier coupleGroup_
Optional patchGroup to find neighbPatch.
Definition: cyclicAMIPolyPatch.H:80
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::coupledPolyPatch
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
Definition: coupledPolyPatch.H:53
Foam::gSum
Type gSum(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:594
Foam::dictionary::lookupOrDefault
T lookupOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionary.H:1241
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:519
polyMesh.H
Foam::polyPatch::updateMesh
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Definition: polyPatch.C:65
Foam::AMIMethod
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: AMIMethod.H:60
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
transformField.H
Spatial transformation functions for primitive fields.
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::cyclicAMIPolyPatch::initMovePoints
virtual void initMovePoints(PstreamBuffers &pBufs, const pointField &)
Initialise the patches for moving points.
Definition: cyclicAMIPolyPatch.C:425
faceAreaIntersect.H
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::cyclicAMIPolyPatch::updateMesh
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Definition: cyclicAMIPolyPatch.C:464
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::cyclicAMIPolyPatch::transformPosition
virtual void transformPosition(pointField &) const
Transform patch-based positions from nbr side to this side.
Definition: cyclicAMIPolyPatch.C:827
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::polyPatch::initUpdateMesh
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: polyPatch.H:115
Foam::label
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:62
Foam::cyclicAMIPolyPatch::separationVector_
vector separationVector_
Translation vector.
Definition: cyclicAMIPolyPatch.H:106
Foam::cyclicAMIPolyPatch::calcGeometry
virtual void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
Definition: cyclicAMIPolyPatch.C:418
Foam::Field< vector >
Foam::cyclicAMIPolyPatch::write
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
Definition: cyclicAMIPolyPatch.C:1044
Foam::polyPatch::initMovePoints
virtual void initMovePoints(PstreamBuffers &, const pointField &)
Initialise the patches for moving points.
Definition: polyPatch.H:108
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::cyclicAMIPolyPatch::pointFace
label pointFace(const label facei, const vector &n, point &p) const
Return face index on neighbour patch which shares point p.
Definition: cyclicAMIPolyPatch.C:998
Foam::cyclicAMIPolyPatch::movePoints
virtual void movePoints(PstreamBuffers &pBufs, const pointField &)
Correct patches after moving points.
Definition: cyclicAMIPolyPatch.C:444
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:58
Foam::dictionary::readEntry
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
Definition: dictionaryTemplates.C:314
Foam::PrimitivePatch::movePoints
virtual void movePoints(const Field< PointType > &)
Correct patch after moving points.
Definition: PrimitivePatch.C:213
Foam::radToDeg
constexpr scalar radToDeg(const scalar rad) noexcept
Conversion from radians to degrees.
Definition: unitConversion.H:54
Foam::polyPatch::initGeometry
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
Definition: polyPatch.H:100
Foam::coupledPolyPatch::write
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
Definition: coupledPolyPatch.C:566
Foam::cyclicAMIPolyPatch::calcTransforms
virtual void calcTransforms()
Recalculate the transformation tensors.
Definition: cyclicAMIPolyPatch.C:367
Foam::cyclicAMIPolyPatch::rotationAxis_
vector rotationAxis_
Axis of rotation for rotational cyclics.
Definition: cyclicAMIPolyPatch.H:91
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::cyclicAMIPolyPatch::rotationAngle_
scalar rotationAngle_
Rotation angle.
Definition: cyclicAMIPolyPatch.H:100
Foam::cyclicAMIPolyPatch::neighbPatchID
virtual label neighbPatchID() const
Neighbour patch ID.
Definition: cyclicAMIPolyPatch.C:715
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::cyclicAMIPolyPatch::neighbPatch
virtual const cyclicAMIPolyPatch & neighbPatch() const
Return a reference to the neighbour patch.
Definition: cyclicAMIPolyPatch.C:757
Foam::word::valid
static bool valid(char c)
Is this character valid for a word?
Definition: wordI.H:130
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::cyclicAMIPolyPatch::rotationAngleDefined_
bool rotationAngleDefined_
Flag to show whether the rotation angle is defined.
Definition: cyclicAMIPolyPatch.H:97
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::searchableSurface::New
static autoPtr< searchableSurface > New(const word &surfaceType, const IOobject &io, const dictionary &dict)
Return a reference to the selected searchableSurface.
Definition: searchableSurface.C:43
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::dictionary::subOrEmptyDict
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Definition: dictionary.C:603
cyclicAMIPolyPatch.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:99
Foam::cyclicAMIPolyPatch::resetAMI
virtual void resetAMI(const AMIPatchToPatchInterpolation::interpolationMethod &AMIMethod=AMIPatchToPatchInterpolation::imFaceAreaWeight) const
Reset the AMI interpolator.
Definition: cyclicAMIPolyPatch.C:294
Time.H
Foam::autoPtr< Foam::searchableSurface >
Foam::cyclicAMIPolyPatch::AMI
const AMIPatchToPatchInterpolation & AMI() const
Return a reference to the AMI interpolator.
Definition: cyclicAMIPolyPatch.C:796
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:303
Foam::polyPatch::faceCentres
const vectorField::subField faceCentres() const
Return face centres.
Definition: polyPatch.C:311
Foam::cyclicAMIPolyPatch::applyLowWeightCorrection
bool applyLowWeightCorrection() const
Return true if applying the low weight correction.
Definition: cyclicAMIPolyPatch.C:814
Foam::cyclicAMIPolyPatch::initUpdateMesh
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: cyclicAMIPolyPatch.C:455
Foam::cyclicAMIPolyPatch::clearGeom
virtual void clearGeom()
Clear geometry.
Definition: cyclicAMIPolyPatch.C:470
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::findMax
label findMax(const ListType &input, label start=0)
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::cyclicAMIPolyPatch::reverseTransformDirection
virtual void reverseTransformDirection(vector &d, const label facei) const
Transform a patch-based direction from this side to nbr side.
Definition: cyclicAMIPolyPatch.C:939
Foam::acos
dimensionedScalar acos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:268
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::start
label ListType::const_reference const label start
Definition: ListOps.H:408
Foam::AMIInterpolation
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
Definition: AMIInterpolation.H:81
Foam::UList< label >
Foam::cyclicAMIPolyPatch::neighbPatchName
const word & neighbPatchName() const
Neighbour patch name.
Definition: cyclicAMIPolyPatchI.H:30
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::word::null
static const word null
An empty word.
Definition: word.H:77
Foam::Ostream::writeEntry
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:219
Foam::cyclicAMIPolyPatch::AMIMethod_
const AMIPatchToPatchInterpolation::interpolationMethod AMIMethod_
AMI method.
Definition: cyclicAMIPolyPatch.H:113
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:246
Foam::PrimitivePatch::localFaces
const List< Face > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatch.C:398
Foam::boundaryMesh
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:61
Foam::primitivePatch
PrimitivePatch< face, SubList, const pointField & > primitivePatch
Addressing for a faceList slice.
Definition: primitivePatch.H:47
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:375
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::cyclicAMIPolyPatch::AMILowWeightCorrection_
const scalar AMILowWeightCorrection_
Low weight correction threshold for AMI.
Definition: cyclicAMIPolyPatch.H:122
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::coupledPolyPatch::transformType
transformType
Definition: coupledPolyPatch.H:59
Foam::cyclicAMIPolyPatch::AMIRequireMatch_
bool AMIRequireMatch_
Flag to indicate that patches should match/overlap.
Definition: cyclicAMIPolyPatch.H:119
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::TimePaths::constant
const word & constant() const
Return constant name.
Definition: TimePathsI.H:88
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::cyclicAMIPolyPatch::AMIReverse_
const bool AMIReverse_
Flag to indicate that slave patch should be reversed for AMI.
Definition: cyclicAMIPolyPatch.H:116
Foam::patchIdentifier::name
const word & name() const
Return the patch name.
Definition: patchIdentifier.H:109
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::cyclicAMIPolyPatch::~cyclicAMIPolyPatch
virtual ~cyclicAMIPolyPatch()
Destructor.
Definition: cyclicAMIPolyPatch.C:709
Foam::dictionary::readIfPresent
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:417
Foam::faceAreaIntersect::tmMesh
Definition: faceAreaIntersect.H:65
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:90
Foam::IOobject::MUST_READ
Definition: IOobject.H:120
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265
Foam::cyclicAMIPolyPatch
Cyclic patch for Arbitrary Mesh Interface (AMI)
Definition: cyclicAMIPolyPatch.H:53