cyclicPolyPatch.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) 2015-2020 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "cyclicPolyPatch.H"
31#include "polyBoundaryMesh.H"
32#include "polyMesh.H"
33#include "demandDrivenData.H"
34#include "OFstream.H"
35#include "matchPoints.H"
36#include "edgeHashes.H"
37#include "Time.H"
38#include "transformField.H"
39#include "SubField.H"
40#include "unitConversion.H"
41
42// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43
44namespace Foam
45{
47
50}
51
52
53// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
54
55Foam::label Foam::cyclicPolyPatch::findMaxArea
56(
57 const pointField& points,
58 const faceList& faces
59)
60{
61 label maxI = -1;
62 scalar maxAreaSqr = -GREAT;
63
64 forAll(faces, facei)
65 {
66 scalar areaSqr = magSqr(faces[facei].areaNormal(points));
67
68 if (maxAreaSqr < areaSqr)
69 {
70 maxAreaSqr = areaSqr;
71 maxI = facei;
72 }
73 }
74 return maxI;
75}
76
77
79{
80 if (size())
81 {
82 // Half0
83 const cyclicPolyPatch& half0 = *this;
84 vectorField half0Areas(half0.size());
85 forAll(half0, facei)
86 {
87 half0Areas[facei] = half0[facei].areaNormal(half0.points());
88 }
89
90 // Half1
91 const cyclicPolyPatch& half1 = neighbPatch();
92 vectorField half1Areas(half1.size());
93 forAll(half1, facei)
94 {
95 half1Areas[facei] = half1[facei].areaNormal(half1.points());
96 }
97
98 calcTransforms
99 (
100 half0,
101 half0.faceCentres(),
102 half0Areas,
103 half1.faceCentres(),
104 half1Areas
105 );
106 }
107}
108
109
111(
112 const primitivePatch& half0,
113 const pointField& half0Ctrs,
114 const vectorField& half0Areas,
115 const pointField& half1Ctrs,
116 const vectorField& half1Areas
117)
118{
119 if (debug && owner())
120 {
121 fileName casePath(boundaryMesh().mesh().time().path());
122 {
123 fileName nm0(casePath/name()+"_faces.obj");
124 Pout<< "cyclicPolyPatch::calcTransforms : Writing " << name()
125 << " faces to OBJ file " << nm0 << endl;
126 writeOBJ(nm0, half0, half0.points());
127 }
128 const cyclicPolyPatch& half1 = neighbPatch();
129 {
130 fileName nm1(casePath/half1.name()+"_faces.obj");
131 Pout<< "cyclicPolyPatch::calcTransforms : Writing " << half1.name()
132 << " faces to OBJ file " << nm1 << endl;
133 writeOBJ(nm1, half1, half1.points());
134 }
135 {
136 OFstream str(casePath/name()+"_to_" + half1.name() + ".obj");
137 label vertI = 0;
138 Pout<< "cyclicPolyPatch::calcTransforms :"
139 << " Writing coupled face centres as lines to " << str.name()
140 << endl;
141 forAll(half0Ctrs, i)
142 {
143 const point& p0 = half0Ctrs[i];
144 str << "v " << p0.x() << ' ' << p0.y() << ' ' << p0.z() << nl;
145 vertI++;
146 const point& p1 = half1Ctrs[i];
147 str << "v " << p1.x() << ' ' << p1.y() << ' ' << p1.z() << nl;
148 vertI++;
149 str << "l " << vertI-1 << ' ' << vertI << nl;
150 }
151 }
152 }
153
154
155 // Some sanity checks
156
157 if (half0Ctrs.size() != half1Ctrs.size())
158 {
160 << "For patch " << name()
161 << " there are " << half0Ctrs.size()
162 << " face centres, for the neighbour patch " << neighbPatch().name()
163 << " there are " << half1Ctrs.size()
164 << exit(FatalError);
165 }
166
167 if (transform() != neighbPatch().transform())
168 {
170 << "Patch " << name()
171 << " has transform type " << transformTypeNames[transform()]
172 << ", neighbour patch " << neighbPatchName()
173 << " has transform type "
174 << neighbPatch().transformTypeNames[neighbPatch().transform()]
175 << exit(FatalError);
176 }
177
178
179 // Calculate transformation tensors
180
181 if (half0Ctrs.size() > 0)
182 {
183 vectorField half0Normals(half0Areas.size());
184 vectorField half1Normals(half1Areas.size());
185
186 scalar maxAreaDiff = -GREAT;
187 label maxAreaFacei = -1;
188
189 forAll(half0, facei)
190 {
191 scalar magSf = mag(half0Areas[facei]);
192 scalar nbrMagSf = mag(half1Areas[facei]);
193 scalar avSf = (magSf + nbrMagSf)/2.0;
194
195 if (magSf < ROOTVSMALL && nbrMagSf < ROOTVSMALL)
196 {
197 // Undetermined normal. Use dummy normal to force separation
198 // check. (note use of sqrt(VSMALL) since that is how mag
199 // scales)
200 half0Normals[facei] = point(1, 0, 0);
201 half1Normals[facei] = half0Normals[facei];
202 }
203 else
204 {
205 scalar areaDiff = mag(magSf - nbrMagSf)/avSf;
206
207 if (areaDiff > maxAreaDiff)
208 {
209 maxAreaDiff = areaDiff;
210 maxAreaFacei = facei;
211 }
212
213 if (areaDiff > matchTolerance())
214 {
216 << "face " << facei
217 << " area does not match neighbour by "
218 << 100*areaDiff
219 << "% -- possible face ordering problem." << endl
220 << "patch:" << name()
221 << " my area:" << magSf
222 << " neighbour area:" << nbrMagSf
223 << " matching tolerance:" << matchTolerance()
224 << endl
225 << "Mesh face:" << start()+facei
226 << " fc:" << half0Ctrs[facei]
227 << endl
228 << "Neighbour fc:" << half1Ctrs[facei]
229 << endl
230 << "If you are certain your matching is correct"
231 << " you can increase the 'matchTolerance' setting"
232 << " in the patch dictionary in the boundary file."
233 << endl
234 << "Rerun with cyclic debug flag set"
235 << " for more information." << exit(FatalError);
236 }
237 else
238 {
239 half0Normals[facei] = half0Areas[facei] / magSf;
240 half1Normals[facei] = half1Areas[facei] / nbrMagSf;
241 }
242 }
243 }
244
245
246 // Print area match
247 if (debug)
248 {
249 Pout<< "cyclicPolyPatch::calcTransforms :"
250 << " patch:" << name()
251 << " Max area error:" << 100*maxAreaDiff << "% at face:"
252 << maxAreaFacei << " at:" << half0Ctrs[maxAreaFacei]
253 << " coupled face at:" << half1Ctrs[maxAreaFacei]
254 << endl;
255 }
256
257
258 // Calculate transformation tensors
259
260 if (transform() == ROTATIONAL)
261 {
262 // Calculate using the given rotation axis and centre. Do not
263 // use calculated normals.
264 vector n0 = findFaceMaxRadius(half0Ctrs);
265 vector n1 = -findFaceMaxRadius(half1Ctrs);
266 n0.normalise();
267 n1.normalise();
268
269 if (debug)
270 {
271 Pout<< "cyclicPolyPatch::calcTransforms :"
272 << " patch:" << name()
273 << " Specified rotation :"
274 << " n0:" << n0 << " n1:" << n1
275 << " swept angle: " << radToDeg(acos(n0 & n1))
276 << " [deg]" << endl;
277 }
278
279 // Extended tensor from two local coordinate systems calculated
280 // using normal and rotation axis
281 const tensor E0
282 (
283 rotationAxis_,
284 (n0 ^ rotationAxis_),
285 n0
286 );
287 const tensor E1
288 (
289 rotationAxis_,
290 (-n1 ^ rotationAxis_),
291 -n1
292 );
293 const tensor revT(E1.T() & E0);
294
295 const_cast<tensorField&>(forwardT()) = tensorField(1, revT.T());
296 const_cast<tensorField&>(reverseT()) = tensorField(1, revT);
297 const_cast<vectorField&>(separation()).setSize(0);
298 const_cast<boolList&>(collocated()) = boolList(1, false);
299 }
300 else
301 {
302 scalarField half0Tols
303 (
304 matchTolerance()
305 *calcFaceTol
306 (
307 half0,
308 half0.points(),
309 static_cast<const pointField&>(half0Ctrs)
310 )
311 );
312
313 calcTransformTensors
314 (
315 static_cast<const pointField&>(half0Ctrs),
316 static_cast<const pointField&>(half1Ctrs),
317 half0Normals,
318 half1Normals,
319 half0Tols,
320 matchTolerance(),
321 transform()
322 );
323
324
325 if (transform() == TRANSLATIONAL)
326 {
327 if (debug)
328 {
329 Pout<< "cyclicPolyPatch::calcTransforms :"
330 << " patch:" << name()
331 << " Specified separation vector : "
332 << separationVector_ << endl;
333 }
334
335 // Check that separation vectors are same.
336 const scalar avgTol = average(half0Tols);
337 if
338 (
339 mag(separationVector_ + neighbPatch().separationVector_)
340 > avgTol
341 )
342 {
344 << "Specified separation vector " << separationVector_
345 << " differs by that of neighbouring patch "
346 << neighbPatch().separationVector_
347 << " by more than tolerance " << avgTol << endl
348 << "patch:" << name()
349 << " neighbour:" << neighbPatchName()
350 << endl;
351 }
352
353
354 // Override computed transform with specified.
355 if
356 (
357 separation().size() != 1
358 || mag(separation()[0] - separationVector_) > avgTol
359 )
360 {
362 << "Specified separationVector " << separationVector_
363 << " differs from computed separation vector "
364 << separation() << endl
365 << "This probably means your geometry is not consistent"
366 << " with the specified separation and might lead"
367 << " to problems." << endl
368 << "Continuing with specified separation vector "
369 << separationVector_ << endl
370 << "patch:" << name()
371 << " neighbour:" << neighbPatchName()
372 << endl;
373 }
374
375 // Set tensors
376 const_cast<tensorField&>(forwardT()).clear();
377 const_cast<tensorField&>(reverseT()).clear();
378 const_cast<vectorField&>(separation()) = vectorField
379 (
380 1,
381 separationVector_
382 );
383 const_cast<boolList&>(collocated()) = boolList(1, false);
384 }
385 }
386 }
387}
388
389
390void Foam::cyclicPolyPatch::getCentresAndAnchors
391(
392 const primitivePatch& pp0,
393 const primitivePatch& pp1,
394
395 pointField& half0Ctrs,
396 pointField& half1Ctrs,
397 pointField& anchors0,
398 scalarField& tols
399) const
400{
401 // Get geometric data on both halves.
402 half0Ctrs = pp0.faceCentres();
403 anchors0 = getAnchorPoints(pp0, pp0.points(), transform());
404 half1Ctrs = pp1.faceCentres();
405
406 if (debug)
407 {
408 Pout<< "cyclicPolyPatch::getCentresAndAnchors :"
409 << " patch:" << name() << nl
410 << "half0 untransformed faceCentres (avg) : "
411 << gAverage(half0Ctrs) << nl
412 << "half1 untransformed faceCentres (avg) : "
413 << gAverage(half1Ctrs) << endl;
414 }
415
416 if (half0Ctrs.size())
417 {
418 switch (transform())
419 {
420 case ROTATIONAL:
421 {
422 vector n0 = findFaceMaxRadius(half0Ctrs);
423 vector n1 = -findFaceMaxRadius(half1Ctrs);
424 n0.normalise();
425 n1.normalise();
426
427 if (debug)
428 {
429 Pout<< "cyclicPolyPatch::getCentresAndAnchors :"
430 << " patch:" << name()
431 << " Specified rotation :"
432 << " n0:" << n0 << " n1:" << n1
433 << " swept angle: "
434 << radToDeg(acos(n0 & n1)) << " [deg]"
435 << endl;
436 }
437
438 // Extended tensor from two local coordinate systems calculated
439 // using normal and rotation axis
440 const tensor E0
441 (
442 rotationAxis_,
443 (n0 ^ rotationAxis_),
444 n0
445 );
446 const tensor E1
447 (
448 rotationAxis_,
449 (-n1 ^ rotationAxis_),
450 -n1
451 );
452 const tensor revT(E1.T() & E0);
453
454 // Rotation
455 forAll(half0Ctrs, facei)
456 {
457 half0Ctrs[facei] =
459 (
460 revT,
461 half0Ctrs[facei] - rotationCentre_
462 )
463 + rotationCentre_;
464 anchors0[facei] =
466 (
467 revT,
468 anchors0[facei] - rotationCentre_
469 )
470 + rotationCentre_;
471 }
472
473 break;
474 }
475 case TRANSLATIONAL:
476 {
477 // Transform 0 points.
478
479 if (debug)
480 {
481 Pout<< "cyclicPolyPatch::getCentresAndAnchors :"
482 << " patch:" << name()
483 << "Specified translation : " << separationVector_
484 << endl;
485 }
486
487 // Note: getCentresAndAnchors gets called on the neighbour side
488 // so separationVector is owner-neighbour points.
489
490 half0Ctrs -= separationVector_;
491 anchors0 -= separationVector_;
492 break;
493 }
494 default:
495 {
496 // Assumes that cyclic is rotational. This is also the initial
497 // condition for patches without faces.
498
499 // Determine the face with max area on both halves. These
500 // two faces are used to determine the transformation tensors
501 label max0I = findMaxArea(pp0.points(), pp0);
502 const vector n0 = pp0[max0I].unitNormal(pp0.points());
503
504 label max1I = findMaxArea(pp1.points(), pp1);
505 const vector n1 = pp1[max1I].unitNormal(pp1.points());
506
507 if (mag(n0 & n1) < 1-matchTolerance())
508 {
509 if (debug)
510 {
511 Pout<< "cyclicPolyPatch::getCentresAndAnchors :"
512 << " patch:" << name()
513 << " Detected rotation :"
514 << " n0:" << n0 << " n1:" << n1 << endl;
515 }
516
517 // Rotation (around origin)
518 const tensor revT(rotationTensor(n0, -n1));
519
520 // Rotation
521 forAll(half0Ctrs, facei)
522 {
523 half0Ctrs[facei] = Foam::transform
524 (
525 revT,
526 half0Ctrs[facei]
527 );
528 anchors0[facei] = Foam::transform
529 (
530 revT,
531 anchors0[facei]
532 );
533 }
534 }
535 else
536 {
537 // Parallel translation. Get average of all used points.
538
539 const point ctr0(sum(pp0.localPoints())/pp0.nPoints());
540 const point ctr1(sum(pp1.localPoints())/pp1.nPoints());
541
542 if (debug)
543 {
544 Pout<< "cyclicPolyPatch::getCentresAndAnchors :"
545 << " patch:" << name()
546 << " Detected translation :"
547 << " n0:" << n0 << " n1:" << n1
548 << " ctr0:" << ctr0 << " ctr1:" << ctr1 << endl;
549 }
550
551 half0Ctrs += ctr1 - ctr0;
552 anchors0 += ctr1 - ctr0;
553 }
554 break;
555 }
556 }
557 }
558
559 // Calculate typical distance per face
560 tols = matchTolerance()*calcFaceTol(pp1, pp1.points(), half1Ctrs);
561}
562
563
564Foam::vector Foam::cyclicPolyPatch::findFaceMaxRadius
565(
566 const pointField& faceCentres
567) const
568{
569 // Determine a face furthest away from the axis
570
571 const vectorField n((faceCentres - rotationCentre_) ^ rotationAxis_);
572
573 const scalarField magRadSqr(magSqr(n));
574
575 label facei = findMax(magRadSqr);
576
577 if (debug)
578 {
579 Info<< "findFaceMaxRadius(const pointField&) : patch: " << name() << nl
580 << " rotFace = " << facei << nl
581 << " point = " << faceCentres[facei] << nl
582 << " distance = " << Foam::sqrt(magRadSqr[facei])
583 << endl;
584 }
585
586 return n[facei];
587}
588
589
590// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
591
593(
594 const word& name,
595 const label size,
596 const label start,
597 const label index,
598 const polyBoundaryMesh& bm,
599 const word& patchType,
601)
602:
603 coupledPolyPatch(name, size, start, index, bm, patchType, transform),
604 neighbPatchName_(word::null),
605 neighbPatchID_(-1),
606 rotationAxis_(Zero),
607 rotationCentre_(Zero),
608 separationVector_(Zero),
609 coupledPointsPtr_(nullptr),
610 coupledEdgesPtr_(nullptr)
611{
612 // Neighbour patch might not be valid yet so no transformation
613 // calculation possible.
614}
615
616
618(
619 const word& name,
620 const label size,
621 const label start,
622 const label index,
623 const polyBoundaryMesh& bm,
624 const word& neighbPatchName,
626 const vector& rotationAxis,
627 const point& rotationCentre,
628 const vector& separationVector
629)
630:
631 coupledPolyPatch(name, size, start, index, bm, typeName, transform),
632 neighbPatchName_(neighbPatchName),
633 neighbPatchID_(-1),
634 rotationAxis_(rotationAxis),
635 rotationCentre_(rotationCentre),
636 separationVector_(separationVector),
637 coupledPointsPtr_(nullptr),
638 coupledEdgesPtr_(nullptr)
639{
640 // Neighbour patch might not be valid yet so no transformation
641 // calculation possible.
642}
643
644
646(
647 const word& name,
648 const dictionary& dict,
649 const label index,
650 const polyBoundaryMesh& bm,
651 const word& patchType
652)
653:
654 coupledPolyPatch(name, dict, index, bm, patchType),
655 neighbPatchName_(dict.getOrDefault("neighbourPatch", word::null)),
656 coupleGroup_(dict),
657 neighbPatchID_(-1),
658 rotationAxis_(Zero),
659 rotationCentre_(Zero),
660 separationVector_(Zero),
661 coupledPointsPtr_(nullptr),
662 coupledEdgesPtr_(nullptr)
663{
664 if (neighbPatchName_ == word::null && !coupleGroup_.valid())
665 {
667 << "No \"neighbourPatch\" provided." << endl
668 << "Is your mesh uptodate with split cyclics?" << endl
669 << "Run foamUpgradeCyclics to convert mesh and fields"
670 << " to split cyclics." << exit(FatalIOError);
671 }
672
673 if (neighbPatchName_ == name)
674 {
676 << "Neighbour patch name " << neighbPatchName_
677 << " cannot be the same as this patch " << name
678 << exit(FatalIOError);
679 }
680
681 switch (transform())
682 {
683 case ROTATIONAL:
684 {
685 dict.readEntry("rotationAxis", rotationAxis_);
686 dict.readEntry("rotationCentre", rotationCentre_);
687
688 scalar magRot = mag(rotationAxis_);
689 if (magRot < SMALL)
690 {
692 << "Illegal rotationAxis " << rotationAxis_ << endl
693 << "Please supply a non-zero vector."
694 << exit(FatalIOError);
695 }
696 rotationAxis_ /= magRot;
697
698 break;
699 }
700 case TRANSLATIONAL:
701 {
702 dict.readEntry("separationVector", separationVector_);
703 break;
704 }
705 default:
706 {
707 // no additional info required
708 }
709 }
710
711 // Neighbour patch might not be valid yet so no transformation
712 // calculation possible.
713}
714
715
717(
718 const cyclicPolyPatch& pp,
719 const polyBoundaryMesh& bm
720)
721:
722 coupledPolyPatch(pp, bm),
723 neighbPatchName_(pp.neighbPatchName_),
724 coupleGroup_(pp.coupleGroup_),
725 neighbPatchID_(-1),
726 rotationAxis_(pp.rotationAxis_),
727 rotationCentre_(pp.rotationCentre_),
728 separationVector_(pp.separationVector_),
729 coupledPointsPtr_(nullptr),
730 coupledEdgesPtr_(nullptr)
731{
732 // Neighbour patch might not be valid yet so no transformation
733 // calculation possible.
734}
735
736
738(
739 const cyclicPolyPatch& pp,
740 const label nrbPatchID,
741 const labelList& faceCells
742)
743:
745 neighbPatchName_(pp.neighbPatchName_),
746 coupleGroup_(pp.coupleGroup_),
747 neighbPatchID_(nrbPatchID),
748 rotationAxis_(pp.rotationAxis_),
749 rotationCentre_(pp.rotationCentre_),
750 separationVector_(pp.separationVector_),
751 coupledPointsPtr_(nullptr),
752 coupledEdgesPtr_(nullptr)
753{
754 // Neighbour patch might not be valid yet so no transformation
755 // calculation possible.
756}
757
758
760(
761 const cyclicPolyPatch& pp,
762 const polyBoundaryMesh& bm,
763 const label index,
764 const label newSize,
765 const label newStart,
766 const word& neighbName
767)
768:
769 coupledPolyPatch(pp, bm, index, newSize, newStart),
770 neighbPatchName_(neighbName),
771 coupleGroup_(pp.coupleGroup_),
772 neighbPatchID_(-1),
773 rotationAxis_(pp.rotationAxis_),
774 rotationCentre_(pp.rotationCentre_),
775 separationVector_(pp.separationVector_),
776 coupledPointsPtr_(nullptr),
777 coupledEdgesPtr_(nullptr)
778{
779 if (neighbName == name())
780 {
782 << "Neighbour patch name " << neighbName
783 << " cannot be the same as this patch " << name()
784 << exit(FatalError);
785 }
786
787 // Neighbour patch might not be valid yet so no transformation
788 // calculation possible.
789}
790
791
793(
794 const cyclicPolyPatch& pp,
795 const polyBoundaryMesh& bm,
796 const label index,
797 const labelUList& mapAddressing,
798 const label newStart
799)
800:
801 coupledPolyPatch(pp, bm, index, mapAddressing, newStart),
802 neighbPatchName_(pp.neighbPatchName_),
803 coupleGroup_(pp.coupleGroup_),
804 neighbPatchID_(-1),
805 rotationAxis_(pp.rotationAxis_),
806 rotationCentre_(pp.rotationCentre_),
807 separationVector_(pp.separationVector_),
808 coupledPointsPtr_(nullptr),
809 coupledEdgesPtr_(nullptr)
810{}
811
812
813// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
814
816{
817 deleteDemandDrivenData(coupledPointsPtr_);
818 deleteDemandDrivenData(coupledEdgesPtr_);
819}
820
821
822// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
823
825{
826 if (neighbPatchName_.empty())
827 {
828 // Try and use patchGroup to find samplePatch and sampleRegion
829 label patchID = coupleGroup_.findOtherPatchID(*this);
830
831 neighbPatchName_ = boundaryMesh()[patchID].name();
832 }
833 return neighbPatchName_;
834}
835
836
838{
839 if (neighbPatchID_ == -1)
840 {
841 neighbPatchID_ = this->boundaryMesh().findPatchID(neighbPatchName());
842
843 if (neighbPatchID_ == -1)
844 {
846 << "Illegal neighbourPatch name " << neighbPatchName()
847 << endl << "Valid patch names are "
848 << this->boundaryMesh().names()
849 << exit(FatalError);
850 }
851
852 // Check that it is a cyclic
853 const cyclicPolyPatch& nbrPatch = refCast<const cyclicPolyPatch>
854 (
855 this->boundaryMesh()[neighbPatchID_]
856 );
857
858 if (nbrPatch.neighbPatchName() != name())
859 {
861 << "Patch " << name()
862 << " specifies neighbour patch " << neighbPatchName()
863 << endl << " but that in return specifies "
864 << nbrPatch.neighbPatchName()
865 << endl;
866 }
867 }
868 return neighbPatchID_;
869}
870
871
873{
874 if (!parallel())
875 {
876 if (transform() == ROTATIONAL)
877 {
878 l =
879 Foam::transform(forwardT(), l-rotationCentre_)
880 + rotationCentre_;
881 }
882 else
883 {
884 l = Foam::transform(forwardT(), l);
885 }
886 }
887 else if (separated())
888 {
889 // transformPosition gets called on the receiving side,
890 // separation gets calculated on the sending side so subtract.
891
892 const vectorField& s = separation();
893 if (s.size() == 1)
894 {
895 forAll(l, i)
896 {
897 l[i] -= s[0];
898 }
899 }
900 else
901 {
902 l -= s;
903 }
904 }
905}
906
907
908void Foam::cyclicPolyPatch::transformPosition(point& l, const label facei) const
909{
910 if (!parallel())
911 {
912 const tensor& T =
913 (
914 forwardT().size() == 1
915 ? forwardT()[0]
916 : forwardT()[facei]
917 );
918
919 if (transform() == ROTATIONAL)
920 {
921 l = Foam::transform(T, l-rotationCentre_) + rotationCentre_;
922 }
923 else
924 {
925 l = Foam::transform(T, l);
926 }
927 }
928 else if (separated())
929 {
930 const vector& s =
931 (
932 separation().size() == 1
933 ? separation()[0]
934 : separation()[facei]
935 );
936
937 l -= s;
938 }
939}
940
941
943{
945}
946
947
949(
950 const primitivePatch& referPatch,
951 pointField& nbrCtrs,
952 vectorField& nbrAreas,
953 pointField& nbrCc
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 calcTransforms
970 (
971 referPatch,
972 thisCtrs,
973 thisAreas,
974 nbrCtrs,
975 nbrAreas
976 );
977}
978
979
981{
982 calcGeometry
983 (
984 *this,
985 faceCentres(),
986 faceAreas(),
987 faceCellCentres(),
988 neighbPatch().faceCentres(),
989 neighbPatch().faceAreas(),
990 neighbPatch().faceCellCentres()
991 );
992}
993
994
996(
997 PstreamBuffers& pBufs,
998 const pointField& p
999)
1000{
1002}
1003
1004
1006(
1007 PstreamBuffers& pBufs,
1008 const pointField& p
1009)
1010{
1011 polyPatch::movePoints(pBufs, p);
1012 calcTransforms();
1013}
1014
1015
1017{
1019}
1020
1021
1023{
1024 polyPatch::updateMesh(pBufs);
1025 deleteDemandDrivenData(coupledPointsPtr_);
1026 deleteDemandDrivenData(coupledEdgesPtr_);
1027}
1028
1029
1031{
1032 if (!coupledPointsPtr_)
1033 {
1034 const faceList& nbrLocalFaces = neighbPatch().localFaces();
1035 const labelList& nbrMeshPoints = neighbPatch().meshPoints();
1036
1037 // Now all we know is that relative face index in *this is same
1038 // as coupled face in nbrPatch and also that the 0th vertex
1039 // corresponds.
1040
1041 // From local point to nbrPatch or -1.
1042 labelList coupledPoint(nPoints(), -1);
1043
1044 forAll(*this, patchFacei)
1045 {
1046 const face& fA = localFaces()[patchFacei];
1047 const face& fB = nbrLocalFaces[patchFacei];
1048
1049 forAll(fA, indexA)
1050 {
1051 label patchPointA = fA[indexA];
1052
1053 if (coupledPoint[patchPointA] == -1)
1054 {
1055 label indexB = (fB.size() - indexA) % fB.size();
1056
1057 // Filter out points on wedge axis
1058 if (meshPoints()[patchPointA] != nbrMeshPoints[fB[indexB]])
1059 {
1060 coupledPoint[patchPointA] = fB[indexB];
1061 }
1062 }
1063 }
1064 }
1065
1066 coupledPointsPtr_ = new edgeList(nPoints());
1067 edgeList& connected = *coupledPointsPtr_;
1068
1069 // Extract coupled points.
1070 label connectedI = 0;
1071
1072 forAll(coupledPoint, i)
1073 {
1074 if (coupledPoint[i] != -1)
1075 {
1076 connected[connectedI++] = edge(i, coupledPoint[i]);
1077 }
1078 }
1079
1080 connected.setSize(connectedI);
1081
1082 if (debug)
1083 {
1084 OFstream str
1085 (
1086 boundaryMesh().mesh().time().path()
1087 /name() + "_coupledPoints.obj"
1088 );
1089 label vertI = 0;
1090
1091 Pout<< "Writing file " << str.name() << " with coordinates of "
1092 << "coupled points" << endl;
1093
1094 forAll(connected, i)
1095 {
1096 const point& a = points()[meshPoints()[connected[i][0]]];
1097 const point& b = points()[nbrMeshPoints[connected[i][1]]];
1098
1099 str<< "v " << a.x() << ' ' << a.y() << ' ' << a.z() << nl;
1100 str<< "v " << b.x() << ' ' << b.y() << ' ' << b.z() << nl;
1101 vertI += 2;
1102
1103 str<< "l " << vertI-1 << ' ' << vertI << nl;
1104 }
1105 }
1106 }
1107 return *coupledPointsPtr_;
1108}
1109
1110
1112{
1113 if (!coupledEdgesPtr_)
1114 {
1115 const edgeList& pointCouples = coupledPoints();
1116
1117 // Build map from points on *this (A) to points on neighbourpatch (B)
1118 Map<label> aToB(2*pointCouples.size());
1119
1120 for (const edge& e : pointCouples)
1121 {
1122 aToB.insert(e[0], e[1]);
1123 }
1124
1125 // Map from edge on A to points (in B indices)
1126 EdgeMap<label> edgeMap(nEdges());
1127
1128 forAll(*this, patchFacei)
1129 {
1130 const labelList& fEdges = faceEdges()[patchFacei];
1131
1132 for (const label edgeI : fEdges)
1133 {
1134 const edge& e = edges()[edgeI];
1135
1136 // Convert edge end points to corresponding points on B side.
1137 const auto fnd0 = aToB.cfind(e[0]);
1138 if (fnd0.found())
1139 {
1140 const auto fnd1 = aToB.cfind(e[1]);
1141 if (fnd1.found())
1142 {
1143 edgeMap.insert(edge(fnd0(), fnd1()), edgeI);
1144 }
1145 }
1146 }
1147 }
1148
1149 // Use the edgeMap to get the edges on the B side.
1150
1151 const cyclicPolyPatch& neighbPatch = this->neighbPatch();
1152 const labelList& nbrMp = neighbPatch.meshPoints();
1153 const labelList& mp = meshPoints();
1154
1155
1156 coupledEdgesPtr_ = new edgeList(edgeMap.size());
1157 edgeList& coupledEdges = *coupledEdgesPtr_;
1158 label coupleI = 0;
1159
1160 forAll(neighbPatch, patchFacei)
1161 {
1162 const labelList& fEdges = neighbPatch.faceEdges()[patchFacei];
1163
1164 for (const label edgeI : fEdges)
1165 {
1166 const edge& e = neighbPatch.edges()[edgeI];
1167
1168 // Look up A edge from HashTable.
1169 auto iter = edgeMap.find(e);
1170
1171 if (iter.found())
1172 {
1173 const label edgeA = iter.val();
1174 const edge& eA = edges()[edgeA];
1175
1176 // Store correspondence. Filter out edges on wedge axis.
1177 if
1178 (
1179 edge(mp[eA[0]], mp[eA[1]])
1180 != edge(nbrMp[e[0]], nbrMp[e[1]])
1181 )
1182 {
1183 coupledEdges[coupleI++] = edge(edgeA, edgeI);
1184 }
1185
1186 // Remove so we build unique list
1187 edgeMap.erase(iter);
1188 }
1189 }
1190 }
1191 coupledEdges.setSize(coupleI);
1192
1193
1194 // Some checks
1195
1196 forAll(coupledEdges, i)
1197 {
1198 const edge& e = coupledEdges[i];
1199
1200 if (e[0] < 0 || e[1] < 0)
1201 {
1203 << "Problem : at position " << i
1204 << " illegal couple:" << e
1205 << abort(FatalError);
1206 }
1207 }
1208
1209 if (debug)
1210 {
1211 OFstream str
1212 (
1213 boundaryMesh().mesh().time().path()
1214 /name() + "_coupledEdges.obj"
1215 );
1216 label vertI = 0;
1217
1218 Pout<< "Writing file " << str.name() << " with centres of "
1219 << "coupled edges" << endl;
1220
1221 for (const edge& e : coupledEdges)
1222 {
1223 const point& a = edges()[e[0]].centre(localPoints());
1224 const point& b = neighbPatch.edges()[e[1]].centre
1225 (
1226 neighbPatch.localPoints()
1227 );
1228
1229 str<< "v " << a.x() << ' ' << a.y() << ' ' << a.z() << nl;
1230 str<< "v " << b.x() << ' ' << b.y() << ' ' << b.z() << nl;
1231 vertI += 2;
1232
1233 str<< "l " << vertI-1 << ' ' << vertI << nl;
1234 }
1235 }
1236 }
1237 return *coupledEdgesPtr_;
1238}
1239
1240
1242(
1244 const primitivePatch& pp
1245) const
1246{
1247 if (owner())
1248 {
1249 // Save patch for use in non-owner side ordering. Equivalent to
1250 // processorPolyPatch using OPstream.
1251 ownerPatchPtr_.reset
1252 (
1253 new primitivePatch
1254 (
1255 pp,
1256 pp.points()
1257 )
1258 );
1259 }
1260}
1261
1262
1264(
1265 PstreamBuffers& pBufs,
1266 const primitivePatch& pp,
1268 labelList& rotation
1269) const
1270{
1271 if (debug)
1272 {
1273 Pout<< "order : of " << pp.size()
1274 << " faces of patch:" << name()
1275 << " neighbour:" << neighbPatchName()
1276 << endl;
1277 }
1278 faceMap.setSize(pp.size());
1279 faceMap = -1;
1280
1281 rotation.setSize(pp.size());
1282 rotation = 0;
1283
1284 if (transform() == NOORDERING)
1285 {
1286 // No faces, nothing to change.
1287 return false;
1288 }
1289
1290 if (owner())
1291 {
1292 // Do nothing (i.e. identical mapping, zero rotation).
1293 // See comment at top.
1294 forAll(faceMap, patchFacei)
1295 {
1296 faceMap[patchFacei] = patchFacei;
1297 }
1298
1299 return false;
1300 }
1301 else
1302 {
1303 // Get stored geometry from initOrder invocation of owner.
1304 const primitivePatch& pp0 = neighbPatch().ownerPatchPtr_();
1305
1306 // Get geometric quantities
1307 pointField half0Ctrs, half1Ctrs, anchors0;
1308 scalarField tols;
1309 getCentresAndAnchors
1310 (
1311 pp0,
1312 pp,
1313
1314 half0Ctrs,
1315 half1Ctrs,
1316 anchors0,
1317 tols
1318 );
1319
1320 if (debug)
1321 {
1322 Pout<< "half0 transformed faceCentres (avg) : "
1323 << gAverage(half0Ctrs) << nl
1324 << "half1 untransformed faceCentres (avg) : "
1325 << gAverage(half1Ctrs) << endl;
1326 }
1327
1328 // Geometric match of face centre vectors
1329 bool matchedAll = matchPoints
1330 (
1331 half1Ctrs,
1332 half0Ctrs,
1333 tols,
1334 true,
1335 faceMap
1336 );
1337
1338 if (!matchedAll || debug)
1339 {
1340 // Dump halves
1341 fileName nm0
1342 (
1343 boundaryMesh().mesh().time().path()
1344 /neighbPatch().name()+"_faces.obj"
1345 );
1346 Pout<< "cyclicPolyPatch::order : Writing neighbour"
1347 << " faces to OBJ file " << nm0 << endl;
1348 writeOBJ(nm0, pp0, pp0.points());
1349
1350 fileName nm1
1351 (
1352 boundaryMesh().mesh().time().path()
1353 /name()+"_faces.obj"
1354 );
1355 Pout<< "cyclicPolyPatch::order : Writing my"
1356 << " faces to OBJ file " << nm1 << endl;
1357 writeOBJ(nm1, pp, pp.points());
1358
1359 OFstream ccStr
1360 (
1361 boundaryMesh().mesh().time().path()
1362 /name() + "_faceCentres.obj"
1363 );
1364 Pout<< "cyclicPolyPatch::order : "
1365 << "Dumping currently found cyclic match as lines between"
1366 << " corresponding face centres to file " << ccStr.name()
1367 << endl;
1368
1369 // Recalculate untransformed face centres
1370 //pointField rawHalf0Ctrs =
1371 // calcFaceCentres(half0Faces, pp.points());
1372 label vertI = 0;
1373
1374 forAll(half1Ctrs, i)
1375 {
1376 if (faceMap[i] != -1)
1377 {
1378 // Write edge between c1 and c0
1379 const point& c0 = half0Ctrs[faceMap[i]];
1380 const point& c1 = half1Ctrs[i];
1381 writeOBJ(ccStr, c0, c1, vertI);
1382 }
1383 }
1384 }
1385
1386 if (!matchedAll)
1387 {
1389 << "Patch:" << name() << " : "
1390 << "Cannot match vectors to faces on both sides of patch"
1391 << endl
1392 << " Perhaps your faces do not match?"
1393 << " The obj files written contain the current match." << endl
1394 << " Continuing with incorrect face ordering from now on!"
1395 << endl;
1396
1397 return false;
1398 }
1399
1400
1401 // Set rotation.
1402 forAll(faceMap, oldFacei)
1403 {
1404 // The face f will be at newFacei (after morphing) and we want its
1405 // anchorPoint (= f[0]) to align with the anchorpoint for the
1406 // corresponding face on the other side.
1407
1408 label newFacei = faceMap[oldFacei];
1409
1410 const point& wantedAnchor = anchors0[newFacei];
1411
1412 rotation[newFacei] = getRotation
1413 (
1414 pp.points(),
1415 pp[oldFacei],
1416 wantedAnchor,
1417 tols[oldFacei]
1418 );
1419
1420 if (rotation[newFacei] == -1)
1421 {
1423 << "in patch " << name()
1424 << " : "
1425 << "Cannot find point on face " << pp[oldFacei]
1426 << " with vertices "
1427 << UIndirectList<point>(pp.points(), pp[oldFacei])
1428 << " that matches point " << wantedAnchor
1429 << " when matching the halves of processor patch " << name()
1430 << "Continuing with incorrect face ordering from now on!"
1431 << endl;
1432
1433 return false;
1434 }
1435 }
1436
1437 ownerPatchPtr_.clear();
1438
1439 // Return false if no change necessary, true otherwise.
1440
1441 forAll(faceMap, facei)
1442 {
1443 if (faceMap[facei] != facei || rotation[facei] != 0)
1444 {
1445 return true;
1446 }
1447 }
1448
1449 return false;
1450 }
1451}
1452
1453
1455{
1457 if (!neighbPatchName_.empty())
1458 {
1459 os.writeEntry("neighbourPatch", neighbPatchName_);
1460 }
1461 coupleGroup_.write(os);
1462 switch (transform())
1463 {
1464 case ROTATIONAL:
1465 {
1466 os.writeEntry("rotationAxis", rotationAxis_);
1467 os.writeEntry("rotationCentre", rotationCentre_);
1468 break;
1469 }
1470 case TRANSLATIONAL:
1471 {
1472 os.writeEntry("separationVector", separationVector_);
1473 break;
1474 }
1475 case NOORDERING:
1476 {
1477 break;
1478 }
1479 default:
1480 {
1481 // no additional info to write
1482 }
1483 }
1484}
1485
1486
1487// ************************************************************************* //
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
Map from edge (expressed as its endpoints) to value. For easier forward declaration it is currently i...
Definition: EdgeMap.H:54
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:141
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: HashTableI.H:114
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition: HashTable.C:440
void setSize(const label n)
Alias for resize()
Definition: List.H:218
A HashTable to objects of type <T> with a label key.
Definition: Map.H:60
Output to file stream, using an OSstream.
Definition: OFstream.H:57
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:239
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
A list of faces which address into the list of points.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const Field< point_type > & localPoints() const
Return pointField of points in patch.
const Field< point_type > & points() const noexcept
Return reference to global points.
const labelListList & faceEdges() const
Return face-edge addressing.
Buffers for inter-processor communications streams (UOPstream, UIPstream).
A List with indirect addressing. Like IndirectList but does not store addressing.
Definition: IndirectList.H:79
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
const Vector< Cmpt > & centre(const Foam::UList< Vector< Cmpt > > &) const
Return *this (used for point which is a typedef to Vector<scalar>.
Definition: VectorI.H:114
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:63
bool valid() const noexcept
Is a valid patchGroup (non-empty) name.
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
virtual transformType transform() const
Type of transform.
Cyclic plane patch.
const word & neighbPatchName() const
Neighbour patch name.
const edgeList & coupledEdges() const
Return connected edges (from patch local to neighbour patch local).
const edgeList & coupledPoints() const
Return connected points (from patch local to neighbour patch local)
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialize ordering for primitivePatch. Does not.
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
virtual ~cyclicPolyPatch()
Destructor.
virtual void calcTransforms()
Recalculate the transformation tensors.
virtual label neighbPatchID() const
Neighbour patchID.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:66
void calcGeometry()
Calculate the geometry for the patches.
Smooth ATC in cells next to a set of patches supplied by type.
Definition: faceCells.H:59
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
A class for handling file names.
Definition: fileName.H:76
virtual bool write()
Write the output fields.
virtual void initMovePoints()
Initialise the patches for moving points.
Definition: fvPatch.C:188
Default transformation behaviour for position.
order
Enumeration specifying required accuracy.
Definition: meshToMesh0.H:148
void movePoints()
Update for new mesh geometry.
void updateMesh()
Update for new mesh topology.
const word & name() const noexcept
The patch name.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
Definition: polyPatch.H:102
const vectorField::subField faceCentres() const
Return face centres.
Definition: polyPatch.C:321
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: polyPatch.H:117
Tensor of scalars, i.e. Tensor<scalar>.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
volScalarField & p
const volScalarField & T
const volScalarField & p0
Definition: EEqn.H:36
patchWriters clear()
dynamicFvMesh & mesh
Template functions to aid in the implementation of demand driven data.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const labelList nEdges(UPstream::listGatherValues< label >(aMesh.nEdges()))
const pointField & points
label nPoints
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))
Determine correspondence between points. See below.
#define WarningInFunction
Report a warning using Foam::Warning.
#define SeriousErrorInFunction
Report an error message using Foam::SeriousError.
Namespace for OpenFOAM.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from vector n1 to n2.
Definition: transform.H:51
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &df)
vector point
Point is a vector.
Definition: point.H:43
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
constexpr scalar radToDeg() noexcept
Multiplication factor for radians to degrees conversion.
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Field< vector > vectorField
Specialisation of Field<T> for vector.
IOerror FatalIOError
List< bool > boolList
A List of bools.
Definition: List.H:64
Type gAverage(const FieldField< Field, Type > &f)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:36
error FatalError
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
label findMax(const ListType &input, label start=0)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
void deleteDemandDrivenData(DataPtr &dataPtr)
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar acos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
points setSize(newPointi)
dictionary dict
volScalarField & b
Definition: createFields.H:27
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
Spatial transformation functions for primitive fields.
Unit conversion functions.