faMeshDemandDrivenData.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) 2016-2017 Wikki Ltd
9 Copyright (C) 2018-2022 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 "faMesh.H"
30#include "faMeshLduAddressing.H"
31#include "areaFields.H"
32#include "edgeFields.H"
33#include "fac.H"
34#include "cartesianCS.H"
35#include "scalarMatrices.H"
36#include "processorFaPatch.H"
38#include "emptyFaPatchFields.H"
39#include "wedgeFaPatch.H"
40#include "triPointRef.H"
41
42// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
43
44namespace Foam
45{
46
47// Define an area-weighted normal for three points (defining a triangle)
48// (p0, p1, p2) are the base, first, second points respectively
49//
50// From the original Tukovic code:
51//
52// vector n = (d1^d2)/mag(d1^d2);
53// scalar sinAlpha = mag(d1^d2)/(mag(d1)*mag(d2));
54// scalar w = sinAlpha/(mag(d1)*mag(d2));
55//
56// ie, normal weighted by area, sine angle and inverse distance squared.
57// - area : larger weight for larger areas
58// - sin : lower weight for narrow angles (eg, shards)
59// - inv distance squared : lower weights for distant points
60//
61// The above refactored, with 0.5 for area:
62//
63// (d1 ^ d2) / (2 * magSqr(d1) * magSqr(d2))
64
66(
67 const vector& a,
68 const vector& b
69)
70{
71 const scalar s(2*magSqr(a)*magSqr(b));
72
73 return s < VSMALL ? Zero : (a ^ b) / s;
74}
75
76
77// The area normal for the face dual (around base-point)
78// described by the right/left edge points and the centre point
79//
80// The adjustment for 1/2 edge point (the dual point) is done internally
82(
83 const point& basePoint,
84 const point& rightPoint,
85 const point& leftPoint,
86 const point& centrePoint
87)
88{
89 const vector mid(centrePoint - basePoint);
90
91 return
92 (
94 (
95 0.5*(rightPoint - basePoint), // vector to right 1/2 edge
96 mid
97 )
99 (
100 mid,
101 0.5*(leftPoint - basePoint) // vector to left 1/2 edge
102 )
103 );
104}
105
106
107// Calculate transform tensor with reference vector (unitAxis1)
108// and direction vector (axis2).
109//
110// This is nearly identical to the meshTools axesRotation
111// with an E3_E1 transformation with the following exceptions:
112//
113// - axis1 (e3 == unitAxis1): is already normalized (unit vector)
114// - axis2 (e1 == dirn): no difference
115// - transformation is row-vectors, not column-vectors
117(
118 const vector& unitAxis1,
119 vector dirn
120)
121{
122 dirn.removeCollinear(unitAxis1);
123 dirn.normalise();
124
125 // Set row vectors
126 return tensor
127 (
128 dirn,
129 (unitAxis1^dirn),
130 unitAxis1
131 );
132}
133
134
135// Simple area-weighted normal calculation for the specified edge vector
136// and its owner/neighbour face centres (internal edges).
137//
138// Uses four triangles since adjacent faces may be non-planar
139// and/or the edge centre is skewed from the face centres.
140
141/*---------------------------------------------------------------------------*\
142 * * |
143 * /|\ | Triangles (0,1) are on the owner side.
144 * / | \ |
145 * / | \ | Triangles (2,3) are on the neighbour side.
146 * / 1|3 \ |
147 * own *----|----* nbr | Boundary edges are the same, but without a neighbour
148 * \ 0|2 / |
149 * \ | / |
150 * \ | / |
151 * \|/ |
152 * * |
153\*---------------------------------------------------------------------------*/
154
156(
157 const linePointRef& edgeVec,
158 const point& ownCentre,
159 const point& neiCentre
160)
161{
162 const scalar magEdge(edgeVec.mag());
163
164 if (magEdge < ROOTVSMALL)
165 {
166 return Zero;
167 }
168
169 const vector edgeCtr = edgeVec.centre();
170
171 vector edgeNorm
172 (
173 // owner
174 triPointRef(edgeCtr, ownCentre, edgeVec.first()).areaNormal()
175 + triPointRef(edgeCtr, edgeVec.last(), ownCentre).areaNormal()
176 // neighbour
177 + triPointRef(edgeCtr, edgeVec.first(), neiCentre).areaNormal()
178 + triPointRef(edgeCtr, neiCentre, edgeVec.last()).areaNormal()
179 );
180
181 // Requires a unit-vector (already tested its mag)
182 edgeNorm.removeCollinear(edgeVec.vec()/magEdge);
183 edgeNorm.normalise();
184
185 // Scale with the original edge length
186 return magEdge*edgeNorm;
187}
188
189
190// As above, but for boundary edgess (no neighbour)
192(
193 const linePointRef& edgeVec,
194 const point& ownCentre
195)
196{
197 const scalar magEdge(edgeVec.mag());
198
199 if (magEdge < ROOTVSMALL)
200 {
201 return Zero;
202 }
203
204 const vector edgeCtr = edgeVec.centre();
205
206 vector edgeNorm
207 (
208 // owner
209 triPointRef(edgeCtr, ownCentre, edgeVec.first()).areaNormal()
210 + triPointRef(edgeCtr, edgeVec.last(), ownCentre).areaNormal()
211 );
212
213 // Requires a unit-vector (already tested its mag)
214 edgeNorm.removeCollinear(edgeVec.vec()/magEdge);
215 edgeNorm.normalise();
216
217 // Scale with the original edge length
218 return magEdge*edgeNorm;
219}
220
221} // End namespace Foam
222
223
224namespace Foam
225{
226
227// A bitSet (size patch nPoints()) with boundary points marked
229{
230 // Initially all unmarked
231 bitSet markPoints(p.nPoints());
232 for (const edge& e : p.boundaryEdges())
233 {
234 // Mark boundary points
235 markPoints.set(e.first());
236 markPoints.set(e.second());
237 }
238
239 return markPoints;
240}
241
242
243} // End namespace Foam
244
245
246// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
247
248void Foam::faMesh::calcLduAddressing() const
249{
251 << "Calculating addressing" << endl;
252
253 if (lduPtr_)
254 {
256 << "lduPtr_ already allocated"
257 << abort(FatalError);
258 }
259
260 lduPtr_ = new faMeshLduAddressing(*this);
261}
262
263
264void Foam::faMesh::calcPatchStarts() const
265{
267 << "Calculating patch starts" << endl;
268
269 if (patchStartsPtr_)
270 {
272 << "patchStartsPtr_ already allocated"
273 << abort(FatalError);
274 }
275
276 patchStartsPtr_ = new labelList(boundary().patchStarts());
277}
278
279
280void Foam::faMesh::calcLe() const
281{
283 << "Calculating local edges" << endl;
284
285 if (LePtr_)
286 {
288 << "LePtr_ already allocated"
289 << abort(FatalError);
290 }
291
292 LePtr_ =
294 (
295 IOobject
296 (
297 "Le",
298 mesh().pointsInstance(),
299 meshSubDir,
300 mesh()
301 ),
302 *this,
304 );
305
306 edgeVectorField& Le = *LePtr_;
307
308 const pointField& localPoints = points();
309
310 if (faMesh::geometryOrder() < 1)
311 {
312 // Simple (primitive) edge normal calculations.
313 // These are primarly designed to avoid any communication
314 // but are thus necessarily inconsistent across processor boundaries!
315
316 // Reasonable to assume that the volume mesh already has faceCentres
317 // eg, used magSf somewhere.
318 // Can use these instead of triggering our calcAreaCentres().
319
321 << "Using geometryOrder < 1 : "
322 "simplified edge area-normals for Le() calculation"
323 << endl;
324
325 UIndirectList<vector> fCentres(mesh().faceCentres(), faceLabels());
326
327 // Flat addressing
328 vectorField edgeNormals(nEdges_);
329
330 // Internal (edge normals)
331 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
332 {
333 edgeNormals[edgei] =
335 (
336 edges_[edgei].line(localPoints),
337 fCentres[owner()[edgei]],
338 fCentres[neighbour()[edgei]]
339 );
340 }
341
342 // Boundary (edge normals). Like above, but only has owner
343 for (label edgei = nInternalEdges_; edgei < nEdges_; ++edgei)
344 {
345 edgeNormals[edgei] =
347 (
348 edges_[edgei].line(localPoints),
349 fCentres[owner()[edgei]]
350 );
351 }
352
353
354 // Now use these edge normals for calculating Le
355
356 // Internal (edge vector)
357 {
358 vectorField& internalFld = Le.ref();
359 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
360 {
361 vector& leVector = internalFld[edgei];
362
363 vector edgeVec = edges_[edgei].vec(localPoints);
364 const scalar magEdge(mag(edgeVec));
365
366 if (magEdge < ROOTVSMALL)
367 {
368 // Too small
369 leVector = Zero;
370 continue;
371 }
372
373 const vector edgeCtr = edges_[edgei].centre(localPoints);
374 const vector& edgeNorm = edgeNormals[edgei];
375 const vector& ownCentre = fCentres[owner()[edgei]];
376
377 leVector = magEdge*normalised(edgeVec ^ edgeNorm);
378 leVector *= sign(leVector & (edgeCtr - ownCentre));
379 }
380 }
381
382 // Boundary (edge vector)
383
384 forAll(boundary(), patchi)
385 {
386 const labelUList& bndEdgeFaces = boundary()[patchi].edgeFaces();
387
388 const edgeList::subList bndEdges =
389 boundary()[patchi].patchSlice(edges_);
390
391 vectorField& patchLe = Le.boundaryFieldRef()[patchi];
392
393 forAll(patchLe, bndEdgei)
394 {
395 vector& leVector = patchLe[bndEdgei];
396 const label meshEdgei(boundary()[patchi].start() + bndEdgei);
397
398 vector edgeVec = bndEdges[bndEdgei].vec(localPoints);
399 const scalar magEdge(mag(edgeVec));
400
401 if (magEdge < ROOTVSMALL)
402 {
403 // Too small
404 leVector = Zero;
405 continue;
406 }
407
408 const vector edgeCtr = bndEdges[bndEdgei].centre(localPoints);
409 const vector& edgeNorm = edgeNormals[meshEdgei];
410 const vector& ownCentre = fCentres[bndEdgeFaces[bndEdgei]];
411
412 leVector = magEdge*normalised(edgeVec ^ edgeNorm);
413 leVector *= sign(leVector & (edgeCtr - ownCentre));
414 }
415 }
416
417 // Done
418 return;
419 }
420
421
422 // Longer forms.
423 // Using edgeAreaNormals, which uses pointAreaNormals (communication!)
424
425 const edgeVectorField& eCentres = edgeCentres();
426 const areaVectorField& fCentres = areaCentres();
427 const edgeVectorField& edgeNormals = edgeAreaNormals();
428
429 // Internal (edge vector)
430
431 {
432 vectorField& internalFld = Le.ref();
433 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
434 {
435 vector& leVector = internalFld[edgei];
436
437 vector edgeVec = edges_[edgei].vec(localPoints);
438 const scalar magEdge(mag(edgeVec));
439
440 if (magEdge < ROOTVSMALL)
441 {
442 // Too small
443 leVector = Zero;
444 continue;
445 }
446
447 const vector& edgeCtr = eCentres[edgei];
448 const vector& edgeNorm = edgeNormals[edgei];
449 const vector& ownCentre = fCentres[owner()[edgei]];
450
451 leVector = magEdge*normalised(edgeVec ^ edgeNorm);
452 leVector *= sign(leVector & (edgeCtr - ownCentre));
453 }
454 }
455
456 forAll(boundary(), patchi)
457 {
458 const labelUList& bndEdgeFaces = boundary()[patchi].edgeFaces();
459
460 const edgeList::subList bndEdges =
461 boundary()[patchi].patchSlice(edges_);
462
463 const vectorField& bndEdgeNormals =
464 edgeNormals.boundaryField()[patchi];
465
466 vectorField& patchLe = Le.boundaryFieldRef()[patchi];
467 const vectorField& patchECentres = eCentres.boundaryField()[patchi];
468
469 forAll(patchLe, bndEdgei)
470 {
471 vector& leVector = patchLe[bndEdgei];
472
473 vector edgeVec = bndEdges[bndEdgei].vec(localPoints);
474 const scalar magEdge(mag(edgeVec));
475
476 if (magEdge < ROOTVSMALL)
477 {
478 // Too small
479 leVector = Zero;
480 continue;
481 }
482
483 const vector& edgeCtr = patchECentres[bndEdgei];
484 const vector& edgeNorm = bndEdgeNormals[bndEdgei];
485 const vector& ownCentre = fCentres[bndEdgeFaces[bndEdgei]];
486
487 leVector = magEdge*normalised(edgeVec ^ edgeNorm);
488 leVector *= sign(leVector & (edgeCtr - ownCentre));
489 }
490 }
491}
492
493
494void Foam::faMesh::calcMagLe() const
495{
497 << "Calculating local edge magnitudes" << endl;
498
499 if (magLePtr_)
500 {
502 << "magLePtr_ already allocated"
503 << abort(FatalError);
504 }
505
506 magLePtr_ =
508 (
509 IOobject
510 (
511 "magLe",
512 mesh().pointsInstance(),
513 meshSubDir,
514 mesh()
515 ),
516 *this,
518 );
519
520 edgeScalarField& magLe = *magLePtr_;
521
522 const pointField& localPoints = points();
523
524 // Internal (edge length)
525 {
526 auto iter = magLe.primitiveFieldRef().begin();
527
528 for (const edge& e : internalEdges())
529 {
530 *iter = e.mag(localPoints);
531 ++iter;
532 }
533 }
534
535 // Boundary (edge length)
536 {
537 auto& bfld = magLe.boundaryFieldRef();
538
539 forAll(boundary(), patchi)
540 {
541 auto iter = bfld[patchi].begin();
542
543 for (const edge& e : boundary()[patchi].patchSlice(edges_))
544 {
545 *iter = e.mag(localPoints);
546 ++iter;
547 }
548 }
549 }
550}
551
552
553void Foam::faMesh::calcAreaCentres() const
554{
556 << "Calculating face centres" << endl;
557
558 if (centresPtr_)
559 {
561 << "centresPtr_ already allocated"
562 << abort(FatalError);
563 }
564
565 centresPtr_ =
567 (
568 IOobject
569 (
570 "centres",
571 mesh().pointsInstance(),
572 meshSubDir,
573 mesh()
574 ),
575 *this,
577 );
578
579 areaVectorField& centres = *centresPtr_;
580
581 const pointField& localPoints = points();
582 const faceList& localFaces = faces();
583
584 // Internal (face centres)
585 // Could also obtain from volume mesh faceCentres()
586 forAll(localFaces, facei)
587 {
588 centres.ref()[facei] = localFaces[facei].centre(localPoints);
589 }
590
591 // Boundary (edge centres)
592 {
593 auto& bfld = centres.boundaryFieldRef();
594
595 forAll(boundary(), patchi)
596 {
597 auto iter = bfld[patchi].begin();
598
599 for (const edge& e : boundary()[patchi].patchSlice(edges_))
600 {
601 *iter = e.centre(localPoints);
602 ++iter;
603 }
604 }
605 }
606}
607
608
609void Foam::faMesh::calcEdgeCentres() const
610{
612 << "Calculating edge centres" << endl;
613
614 if (edgeCentresPtr_)
615 {
617 << "edgeCentresPtr_ already allocated"
618 << abort(FatalError);
619 }
620
621 edgeCentresPtr_ =
623 (
624 IOobject
625 (
626 "edgeCentres",
627 mesh().pointsInstance(),
628 meshSubDir,
629 mesh()
630 ),
631 *this,
633 );
634
635 edgeVectorField& centres = *edgeCentresPtr_;
636
637 const pointField& localPoints = points();
638
639 // Internal (edge centres)
640 {
641 auto iter = centres.primitiveFieldRef().begin();
642
643 for (const edge& e : internalEdges())
644 {
645 *iter = e.centre(localPoints);
646 ++iter;
647 }
648 }
649
650 // Boundary (edge centres)
651 {
652 auto& bfld = centres.boundaryFieldRef();
653
654 forAll(boundary(), patchi)
655 {
656 auto iter = bfld[patchi].begin();
657
658 for (const edge& e : boundary()[patchi].patchSlice(edges_))
659 {
660 *iter = e.centre(localPoints);
661 ++iter;
662 }
663 }
664 }
665}
666
667
668void Foam::faMesh::calcS() const
669{
671 << "Calculating areas" << endl;
672
673 if (SPtr_)
674 {
676 << "SPtr_ already allocated"
677 << abort(FatalError);
678 }
679
680 SPtr_ = new DimensionedField<scalar, areaMesh>
681 (
682 IOobject
683 (
684 "S",
685 time().timeName(),
686 mesh(),
689 ),
690 *this,
691 dimArea
692 );
693 auto& S = *SPtr_;
694
695 const pointField& localPoints = points();
696 const faceList& localFaces = faces();
697
698 // Could also obtain from volume mesh faceAreas()
699 forAll(S, facei)
700 {
701 S[facei] = localFaces[facei].mag(localPoints);
702 }
703}
704
705
706void Foam::faMesh::calcFaceAreaNormals() const
707{
709 << "Calculating face area normals" << endl;
710
711 if (faceAreaNormalsPtr_)
712 {
714 << "faceAreaNormalsPtr_ already allocated"
715 << abort(FatalError);
716 }
717
718 faceAreaNormalsPtr_ =
720 (
721 IOobject
722 (
723 "faceAreaNormals",
724 mesh().pointsInstance(),
725 meshSubDir,
726 mesh()
727 ),
728 *this,
729 dimless
730 );
731
732 areaVectorField& faceNormals = *faceAreaNormalsPtr_;
733
734 const pointField& localPoints = points();
735 const faceList& localFaces = faces();
736
737 // Internal (faces)
738 // Could also obtain from volume mesh Sf() + normalise
739 vectorField& nInternal = faceNormals.ref();
740 forAll(localFaces, faceI)
741 {
742 nInternal[faceI] = localFaces[faceI].unitNormal(localPoints);
743 }
744
745 // Boundary - copy from edges
746
747 const auto& edgeNormalsBoundary = edgeAreaNormals().boundaryField();
748
749 forAll(boundary(), patchI)
750 {
751 faceNormals.boundaryFieldRef()[patchI] = edgeNormalsBoundary[patchI];
752 }
753}
754
755
756void Foam::faMesh::calcEdgeAreaNormals() const
757{
759 << "Calculating edge area normals" << endl;
760
761 if (edgeAreaNormalsPtr_)
762 {
764 << "edgeAreaNormalsPtr_ already allocated"
765 << abort(FatalError);
766 }
767
768 edgeAreaNormalsPtr_ =
770 (
771 IOobject
772 (
773 "edgeAreaNormals",
774 mesh().pointsInstance(),
775 meshSubDir,
776 mesh()
777 ),
778 *this,
779 dimless
780 );
781 edgeVectorField& edgeAreaNormals = *edgeAreaNormalsPtr_;
782
783
784 // Starting from point area normals
785 const vectorField& pointNormals = pointAreaNormals();
786
787
788 // Internal edges
789 forAll(edgeAreaNormals.internalField(), edgei)
790 {
791 const edge& e = edges_[edgei];
792 const vector edgeVec = e.unitVec(points());
793
794 vector& edgeNorm = edgeAreaNormals.ref()[edgei];
795
796 // Average of both ends
797 edgeNorm = (pointNormals[e.first()] + pointNormals[e.second()]);
798
799 edgeNorm.removeCollinear(edgeVec);
800 edgeNorm.normalise();
801 }
802
803 // Boundary
804 auto& bfld = edgeAreaNormals.boundaryFieldRef();
805
806 forAll(boundary(), patchi)
807 {
808 auto& pfld = bfld[patchi];
809
810 const edgeList::subList patchEdges =
811 boundary()[patchi].patchSlice(edges_);
812
813 forAll(patchEdges, bndEdgei)
814 {
815 const edge& e = patchEdges[bndEdgei];
816 const vector edgeVec = e.unitVec(points());
817
818 vector& edgeNorm = pfld[bndEdgei];
819
820 // Average of both ends
821 edgeNorm = (pointNormals[e.first()] + pointNormals[e.second()]);
822
823 edgeNorm.removeCollinear(edgeVec);
824 edgeNorm.normalise();
825 }
826 }
827}
828
829
830void Foam::faMesh::calcFaceCurvatures() const
831{
833 << "Calculating face curvatures" << endl;
834
835 if (faceCurvaturesPtr_)
836 {
838 << "faceCurvaturesPtr_ already allocated"
839 << abort(FatalError);
840 }
841
842 faceCurvaturesPtr_ =
844 (
845 IOobject
846 (
847 "faceCurvatures",
848 mesh().pointsInstance(),
849 meshSubDir,
850 mesh()
851 ),
852 *this,
854 );
855
856 areaScalarField& faceCurvatures = *faceCurvaturesPtr_;
857
858
859// faceCurvatures =
860// fac::edgeIntegrate(Le()*edgeLengthCorrection())
861// &faceAreaNormals();
862
863 areaVectorField kN(fac::edgeIntegrate(Le()*edgeLengthCorrection()));
864
865 faceCurvatures = sign(kN&faceAreaNormals())*mag(kN);
866}
867
868
869void Foam::faMesh::calcEdgeTransformTensors() const
870{
872 << "Calculating edge transformation tensors" << endl;
873
874 if (edgeTransformTensorsPtr_)
875 {
877 << "edgeTransformTensorsPtr_ already allocated"
878 << abort(FatalError);
879 }
880
881 edgeTransformTensorsPtr_ = new FieldField<Field, tensor>(nEdges_);
882 auto& edgeTransformTensors = *edgeTransformTensorsPtr_;
883
884 // Initialize all transformation tensors
885 for (label edgei = 0; edgei < nEdges_; ++edgei)
886 {
887 edgeTransformTensors.set(edgei, new Field<tensor>(3, tensor::I));
888 }
889
890 const areaVectorField& Nf = faceAreaNormals();
891 const areaVectorField& Cf = areaCentres();
892
893 const edgeVectorField& Ne = edgeAreaNormals();
894 const edgeVectorField& Ce = edgeCentres();
895
896 // Internal edges transformation tensors
897 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
898 {
899 const label ownFacei = owner()[edgei];
900 const label neiFacei = neighbour()[edgei];
901 auto& tensors = edgeTransformTensors[edgei];
902
903 vector edgeCtr = Ce.internalField()[edgei];
904
905 if (skew())
906 {
907 edgeCtr -= skewCorrectionVectors().internalField()[edgei];
908 }
909
910 // Edge transformation tensor
911 tensors[0] =
913 (
914 Ne.internalField()[edgei],
915 (edgeCtr - Cf.internalField()[ownFacei])
916 );
917
918 // Owner transformation tensor
919 tensors[1] =
921 (
922 Nf.internalField()[ownFacei],
923 (edgeCtr - Cf.internalField()[ownFacei])
924 );
925
926 // Neighbour transformation tensor
927 tensors[2] =
929 (
930 Nf.internalField()[neiFacei],
931 (Cf.internalField()[neiFacei] - edgeCtr)
932 );
933 }
934
935 // Boundary edges transformation tensors
936 forAll(boundary(), patchi)
937 {
938 const labelUList& edgeFaces = boundary()[patchi].edgeFaces();
939
940 if (boundary()[patchi].coupled())
941 {
942 vectorField nbrCf(Cf.boundaryField()[patchi].patchNeighbourField());
943 vectorField nbrNf(Nf.boundaryField()[patchi].patchNeighbourField());
944
945 forAll(edgeFaces, bndEdgei)
946 {
947 const label ownFacei = edgeFaces[bndEdgei];
948 const label meshEdgei(boundary()[patchi].start() + bndEdgei);
949
950 auto& tensors = edgeTransformTensors[meshEdgei];
951
952 vector edgeCtr = Ce.boundaryField()[patchi][bndEdgei];
953
954 if (skew())
955 {
956 edgeCtr -= skewCorrectionVectors()
957 .boundaryField()[patchi][bndEdgei];
958 }
959
960 // Edge transformation tensor
961 tensors[0] =
963 (
964 Ne.boundaryField()[patchi][bndEdgei],
965 (edgeCtr - Cf.internalField()[ownFacei])
966 );
967
968 // Owner transformation tensor
969 tensors[1] =
971 (
972 Nf.internalField()[ownFacei],
973 (edgeCtr - Cf.internalField()[ownFacei])
974 );
975
976 // Neighbour transformation tensor
977 tensors[2] =
979 (
980 nbrNf[bndEdgei],
981 (nbrCf[bndEdgei] - edgeCtr)
982 );
983 }
984 }
985 else
986 {
987 forAll(edgeFaces, bndEdgei)
988 {
989 const label ownFacei = edgeFaces[bndEdgei];
990 const label meshEdgei(boundary()[patchi].start() + bndEdgei);
991
992 auto& tensors = edgeTransformTensors[meshEdgei];
993
994 vector edgeCtr = Ce.boundaryField()[patchi][bndEdgei];
995
996 if (skew())
997 {
998 edgeCtr -= skewCorrectionVectors()
999 .boundaryField()[patchi][bndEdgei];
1000 }
1001
1002 // Edge transformation tensor
1003 tensors[0] =
1005 (
1006 Ne.boundaryField()[patchi][bndEdgei],
1007 (edgeCtr - Cf.internalField()[ownFacei])
1008 );
1009
1010 // Owner transformation tensor
1011 tensors[1] =
1013 (
1014 Nf.internalField()[ownFacei],
1015 (edgeCtr - Cf.internalField()[ownFacei])
1016 );
1017
1018 // Neighbour transformation tensor
1019 tensors[2] = tensor::I;
1020 }
1021 }
1022 }
1023}
1024
1025
1027{
1029 << "Calculating internal points" << endl;
1030
1031 bitSet markPoints(markupBoundaryPoints(this->patch()));
1032 markPoints.flip();
1033
1034 return markPoints.sortedToc();
1035}
1036
1037
1039{
1041 << "Calculating boundary points" << endl;
1042
1043 bitSet markPoints(markupBoundaryPoints(this->patch()));
1044
1045 return markPoints.sortedToc();
1046}
1047
1048
1049// ~~~~~~~~~~~~~~~~~~~~~~~~~
1050// Point normal calculations
1051// ~~~~~~~~~~~~~~~~~~~~~~~~~
1052
1053// Revised method (general)
1054// ------------------------
1055//
1056// - For each patch face obtain a centre point (mathematical avg)
1057// and use that to define the face dual as a pair of triangles:
1058// - tri1: base-point / mid-side of right edge / face centre
1059// - tri2: base-point / face centre / mid-side of left edge
1060//
1061// - Walk all face points, inserting directly into the corresponding
1062// locations. No distinction between internal or boundary points (yet).
1063//
1064// Revised method (boundary correction)
1065// ------------------------------------
1066//
1067// - correct wedge directly, use processor patch information to exchange
1068// the current summed values. [No change from original].
1069//
1070// - explicit correction of other boundaries.
1071// Use the new boundary halo information for the face normals.
1072// Calculate the equivalent face-point normals locally and apply
1073// correction as before.
1074
1075void Foam::faMesh::calcPointAreaNormals(vectorField& result) const
1076{
1078 << "Calculating pointAreaNormals : face dual method" << endl;
1079
1080 result.resize_nocopy(nPoints());
1081 result = Zero;
1082
1083 const pointField& points = patch().localPoints();
1084 const faceList& faces = patch().localFaces();
1085
1086
1087 // Loop over all faces
1088
1089 for (const face& f : faces)
1090 {
1091 const label nVerts(f.size());
1092
1093 point centrePoint(Zero);
1094 for (label i = 0; i < nVerts; ++i)
1095 {
1096 centrePoint += points[f[i]];
1097 }
1098 centrePoint /= nVerts;
1099
1100 for (label i = 0; i < nVerts; ++i)
1101 {
1102 const label pt0 = f.thisLabel(i); // base
1103
1104 result[pt0] +=
1106 (
1107 points[pt0], // base
1108 points[f.nextLabel(i)], // right
1109 points[f.prevLabel(i)], // left
1110 centrePoint
1111 );
1112 }
1113 }
1114
1115
1116 // Handle the boundary edges
1117
1118 bitSet nbrBoundaryAdjust(boundary().size(), true);
1119
1120 forAll(boundary(), patchi)
1121 {
1122 const faPatch& fap = boundary()[patchi];
1123
1124 if (isA<wedgeFaPatch>(fap))
1125 {
1126 // Correct wedge points
1127
1128 const auto& wedgePatch = refCast<const wedgeFaPatch>(fap);
1129
1130 const labelList& patchPoints = wedgePatch.pointLabels();
1131
1132 const vector N
1133 (
1134 transform
1135 (
1136 wedgePatch.edgeT(),
1137 wedgePatch.centreNormal()
1138 ).normalise()
1139 );
1140
1141 for (const label pti : patchPoints)
1142 {
1143 result[pti].removeCollinear(N);
1144 }
1145
1146 // Axis point correction
1147 if (wedgePatch.axisPoint() > -1)
1148 {
1149 result[wedgePatch.axisPoint()] =
1150 wedgePatch.axis()
1151 *(
1152 wedgePatch.axis()
1153 &result[wedgePatch.axisPoint()]
1154 );
1155 }
1156
1157 // Handled
1158 nbrBoundaryAdjust.unset(patchi);
1159 }
1160 else if (Pstream::parRun() && isA<processorFaPatch>(fap))
1161 {
1162 // Correct processor patch points
1163
1164 const auto& procPatch = refCast<const processorFaPatch>(fap);
1165
1166 const labelList& patchPoints = procPatch.pointLabels();
1167 const labelList& nbrPatchPoints = procPatch.neighbPoints();
1168
1169 const labelList& nonGlobalPatchPoints =
1170 procPatch.nonGlobalPatchPoints();
1171
1172 // Send my values
1173
1174 vectorField patchPointNormals
1175 (
1176 UIndirectList<vector>(result, patchPoints)
1177 );
1178
1179 {
1181 (
1183 procPatch.neighbProcNo(),
1184 patchPointNormals.cdata_bytes(),
1185 patchPointNormals.size_bytes()
1186 );
1187 }
1188
1189 // Receive neighbour values
1190 patchPointNormals.resize(nbrPatchPoints.size());
1191
1192 {
1194 (
1196 procPatch.neighbProcNo(),
1197 patchPointNormals.data_bytes(),
1198 patchPointNormals.size_bytes()
1199 );
1200 }
1201
1202 for (const label pti : nonGlobalPatchPoints)
1203 {
1204 result[patchPoints[pti]] +=
1205 patchPointNormals[nbrPatchPoints[pti]];
1206 }
1207
1208 // Handled
1209 nbrBoundaryAdjust.unset(patchi);
1210 }
1211 else if (fap.coupled())
1212 {
1213 // Coupled - no further action for neighbour side
1214 nbrBoundaryAdjust.unset(patchi);
1215 }
1216 // TBD:
1222 else if (!correctPatchPointNormals(patchi))
1223 {
1224 // No corrections
1225 nbrBoundaryAdjust.unset(patchi);
1226 }
1227 }
1228
1229
1230 // Correct global points
1231 if (globalData().nGlobalPoints())
1232 {
1233 const labelList& spLabels = globalData().sharedPointLabels();
1234 const labelList& addr = globalData().sharedPointAddr();
1235
1236 vectorField spNormals
1237 (
1238 UIndirectList<vector>(result, spLabels)
1239 );
1240
1241 vectorField gpNormals
1242 (
1243 globalData().nGlobalPoints(),
1244 Zero
1245 );
1246
1247 forAll(addr, i)
1248 {
1249 gpNormals[addr[i]] += spNormals[i];
1250 }
1251
1252 Pstream::combineAllGather(gpNormals, plusEqOp<vectorField>());
1253
1254 // Extract local data
1255 forAll(addr, i)
1256 {
1257 spNormals[i] = gpNormals[addr[i]];
1258 }
1259
1260 forAll(spNormals, pointI)
1261 {
1262 result[spLabels[pointI]] = spNormals[pointI];
1263 }
1264 }
1265
1266
1267 if (returnReduce(nbrBoundaryAdjust.any(), orOp<bool>()))
1268 {
1269 if (debug)
1270 {
1272 << "Apply " << nbrBoundaryAdjust.count()
1273 << " boundary neighbour corrections" << nl;
1274 }
1275
1276 // Apply boundary points correction
1277
1278 // Collect face normals as point normals
1279
1280 const auto& haloNormals = this->haloFaceNormals();
1281
1282 Map<vector> fpNormals(4*nBoundaryEdges());
1283
1284 for (const label patchi : nbrBoundaryAdjust)
1285 {
1286 const faPatch& fap = boundary()[patchi];
1287 const labelList& edgeLabels = fap.edgeLabels();
1288
1289 if (fap.ngbPolyPatchIndex() < 0)
1290 {
1292 << "Neighbour polyPatch index is not defined "
1293 << "for faPatch " << fap.name()
1294 << abort(FatalError);
1295 }
1296
1297 for (const label edgei : edgeLabels)
1298 {
1299 const edge& e = patch().edges()[edgei];
1300
1301 // Halo face unitNormal at boundary edge (starts as 0)
1302 const vector& fnorm = haloNormals[edgei - nInternalEdges_];
1303
1304 fpNormals(e.first()) += fnorm;
1305 fpNormals(e.second()) += fnorm;
1306 }
1307 }
1308
1309 // Apply the correction
1310
1311 // Note from Zeljko Tukovic:
1312 //
1313 // This posibility is used for free-surface tracking
1314 // calculations to enforce 90 deg contact angle between
1315 // finite-area mesh and neighbouring polyPatch. It is very
1316 // important for curvature calculation to have correct normal
1317 // at contact line points.
1318
1319 forAllConstIters(fpNormals, iter)
1320 {
1321 const label pointi = iter.key();
1322 vector fpnorm = normalised(iter.val());
1323
1324 result[pointi].removeCollinear(fpnorm);
1325 }
1326 }
1327
1328 result.normalise();
1329}
1330
1331
1332void Foam::faMesh::calcPointAreaNormalsByQuadricsFit(vectorField& result) const
1333{
1334 const labelList intPoints(internalPoints());
1335 const labelList bndPoints(boundaryPoints());
1336
1337 const pointField& points = patch().localPoints();
1338 const faceList& faces = patch().localFaces();
1339 const labelListList& pointFaces = patch().pointFaces();
1340
1341 forAll(intPoints, pointI)
1342 {
1343 label curPoint = intPoints[pointI];
1344
1345 const labelHashSet faceSet(pointFaces[curPoint]);
1346 const labelList curFaces(faceSet.toc());
1347
1348 labelHashSet pointSet;
1349
1350 for (const label facei : curFaces)
1351 {
1352 const labelList& facePoints = faces[facei];
1353 pointSet.insert(facePoints);
1354 }
1355 pointSet.erase(curPoint);
1356 labelList curPoints(pointSet.toc());
1357
1358 if (pointSet.size() < 5)
1359 {
1360 DebugInfo
1361 << "WARNING: Extending point set for fitting." << endl;
1362
1363 labelHashSet faceSet(pointFaces[curPoint]);
1364 labelList curFaces(faceSet.toc());
1365 for (const label facei : curFaces)
1366 {
1367 const labelList& curFaceFaces = patch().faceFaces()[facei];
1368 faceSet.insert(curFaceFaces);
1369 }
1370 curFaces = faceSet.toc();
1371
1372 pointSet.clear();
1373
1374 for (const label facei : curFaces)
1375 {
1376 const labelList& facePoints = faces[facei];
1377 pointSet.insert(facePoints);
1378 }
1379 pointSet.erase(curPoint);
1380 curPoints = pointSet.toc();
1381 }
1382
1383 pointField allPoints(curPoints.size());
1384 scalarField W(curPoints.size(), 1.0);
1385 for (label i=0; i<curPoints.size(); ++i)
1386 {
1387 allPoints[i] = points[curPoints[i]];
1388 W[i] = 1.0/magSqr(allPoints[i] - points[curPoint]);
1389 }
1390
1391 // Transform points
1392 coordSystem::cartesian cs
1393 (
1394 points[curPoint], // origin
1395 result[curPoint], // axis [e3] (normalized by constructor)
1396 allPoints[0] - points[curPoint] // direction [e1]
1397 );
1398
1399 for (point& p : allPoints)
1400 {
1401 p = cs.localPosition(p);
1402 }
1403
1405 (
1406 allPoints.size(),
1407 5,
1408 0.0
1409 );
1410
1411 for (label i = 0; i < allPoints.size(); ++i)
1412 {
1413 M[i][0] = sqr(allPoints[i].x());
1414 M[i][1] = sqr(allPoints[i].y());
1415 M[i][2] = allPoints[i].x()*allPoints[i].y();
1416 M[i][3] = allPoints[i].x();
1417 M[i][4] = allPoints[i].y();
1418 }
1419
1420 scalarSquareMatrix MtM(5, Zero);
1421
1422 for (label i = 0; i < MtM.n(); ++i)
1423 {
1424 for (label j = 0; j < MtM.m(); ++j)
1425 {
1426 for (label k = 0; k < M.n(); ++k)
1427 {
1428 MtM[i][j] += M[k][i]*M[k][j]*W[k];
1429 }
1430 }
1431 }
1432
1433 scalarField MtR(5, Zero);
1434
1435 for (label i=0; i<MtR.size(); ++i)
1436 {
1437 for (label j=0; j<M.n(); ++j)
1438 {
1439 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1440 }
1441 }
1442
1443 LUsolve(MtM, MtR);
1444
1445 vector curNormal = vector(MtR[3], MtR[4], -1);
1446
1447 curNormal = cs.globalVector(curNormal);
1448
1449 curNormal *= sign(curNormal&result[curPoint]);
1450
1451 result[curPoint] = curNormal;
1452 }
1453
1454
1455 forAll(boundary(), patchI)
1456 {
1457 const faPatch& fap = boundary()[patchI];
1458
1459 if (Pstream::parRun() && isA<processorFaPatch>(fap))
1460 {
1461 const processorFaPatch& procPatch =
1462 refCast<const processorFaPatch>(boundary()[patchI]);
1463
1464 const labelList& patchPointLabels = procPatch.pointLabels();
1465
1466 labelList toNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1467 vectorField toNgbProcLsPoints
1468 (
1469 10*patchPointLabels.size(),
1470 Zero
1471 );
1472 label nPoints = 0;
1473
1474 for (label pointI=0; pointI<patchPointLabels.size(); ++pointI)
1475 {
1476 label curPoint = patchPointLabels[pointI];
1477
1478 toNgbProcLsPointStarts[pointI] = nPoints;
1479
1480 const labelHashSet faceSet(pointFaces[curPoint]);
1481 const labelList curFaces(faceSet.toc());
1482
1483 labelHashSet pointSet;
1484
1485 for (const label facei : curFaces)
1486 {
1487 const labelList& facePoints = faces[facei];
1488 pointSet.insert(facePoints);
1489 }
1490 pointSet.erase(curPoint);
1491 labelList curPoints = pointSet.toc();
1492
1493 for (label i=0; i<curPoints.size(); ++i)
1494 {
1495 toNgbProcLsPoints[nPoints++] = points[curPoints[i]];
1496 }
1497 }
1498
1499 toNgbProcLsPoints.setSize(nPoints);
1500
1501 {
1502 OPstream toNeighbProc
1503 (
1505 procPatch.neighbProcNo(),
1506 toNgbProcLsPoints.size_bytes()
1507 + toNgbProcLsPointStarts.size_bytes()
1508 + 10*sizeof(label)
1509 );
1510
1511 toNeighbProc
1512 << toNgbProcLsPoints
1513 << toNgbProcLsPointStarts;
1514 }
1515 }
1516 }
1517
1518 for (const faPatch& fap : boundary())
1519 {
1520 if (Pstream::parRun() && isA<processorFaPatch>(fap))
1521 {
1522 const processorFaPatch& procPatch =
1523 refCast<const processorFaPatch>(fap);
1524
1525 const labelList& patchPointLabels = procPatch.pointLabels();
1526
1527 labelList fromNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1528 vectorField fromNgbProcLsPoints;
1529
1530 {
1531 IPstream fromNeighbProc
1532 (
1534 procPatch.neighbProcNo(),
1535 10*patchPointLabels.size()*sizeof(vector)
1536 + fromNgbProcLsPointStarts.size_bytes()
1537 + 10*sizeof(label)
1538 );
1539
1540 fromNeighbProc
1541 >> fromNgbProcLsPoints
1542 >> fromNgbProcLsPointStarts;
1543 }
1544
1545 const labelList& nonGlobalPatchPoints =
1546 procPatch.nonGlobalPatchPoints();
1547
1548 forAll(nonGlobalPatchPoints, pointI)
1549 {
1550 label curPoint =
1551 patchPointLabels[nonGlobalPatchPoints[pointI]];
1552 label curNgbPoint =
1553 procPatch.neighbPoints()[nonGlobalPatchPoints[pointI]];
1554
1555 labelHashSet faceSet;
1556 faceSet.insert(pointFaces[curPoint]);
1557
1558 labelList curFaces = faceSet.toc();
1559
1560 labelHashSet pointSet;
1561
1562 for (const label facei : curFaces)
1563 {
1564 const labelList& facePoints = faces[facei];
1565 pointSet.insert(facePoints);
1566 }
1567 pointSet.erase(curPoint);
1568 labelList curPoints = pointSet.toc();
1569
1570 label nAllPoints = curPoints.size();
1571
1572 if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
1573 {
1574 nAllPoints +=
1575 fromNgbProcLsPoints.size()
1576 - fromNgbProcLsPointStarts[curNgbPoint];
1577 }
1578 else
1579 {
1580 nAllPoints +=
1581 fromNgbProcLsPointStarts[curNgbPoint + 1]
1582 - fromNgbProcLsPointStarts[curNgbPoint];
1583 }
1584
1585 vectorField allPointsExt(nAllPoints);
1586 label counter = 0;
1587 for (label i=0; i<curPoints.size(); ++i)
1588 {
1589 allPointsExt[counter++] = points[curPoints[i]];
1590 }
1591
1592 if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
1593 {
1594 for
1595 (
1596 label i=fromNgbProcLsPointStarts[curNgbPoint];
1597 i<fromNgbProcLsPoints.size();
1598 ++i
1599 )
1600 {
1601 allPointsExt[counter++] = fromNgbProcLsPoints[i];
1602 }
1603 }
1604 else
1605 {
1606 for
1607 (
1608 label i=fromNgbProcLsPointStarts[curNgbPoint];
1609 i<fromNgbProcLsPointStarts[curNgbPoint+1];
1610 ++i
1611 )
1612 {
1613 allPointsExt[counter++] = fromNgbProcLsPoints[i];
1614 }
1615 }
1616
1617 // Remove duplicate points
1618 vectorField allPoints(nAllPoints, Zero);
1619 boundBox bb(allPointsExt, false);
1620 scalar tol = 0.001*mag(bb.max() - bb.min());
1621
1622 nAllPoints = 0;
1623 forAll(allPointsExt, pI)
1624 {
1625 bool duplicate = false;
1626 for (label i=0; i<nAllPoints; ++i)
1627 {
1628 if
1629 (
1630 mag
1631 (
1632 allPoints[i]
1633 - allPointsExt[pI]
1634 )
1635 < tol
1636 )
1637 {
1638 duplicate = true;
1639 break;
1640 }
1641 }
1642
1643 if (!duplicate)
1644 {
1645 allPoints[nAllPoints++] = allPointsExt[pI];
1646 }
1647 }
1648
1649 allPoints.setSize(nAllPoints);
1650
1651 if (nAllPoints < 5)
1652 {
1654 << "There are no enough points for quadrics "
1655 << "fitting for a point at processor patch"
1656 << abort(FatalError);
1657 }
1658
1659 // Transform points
1660 const vector& origin = points[curPoint];
1661 const vector axis = normalised(result[curPoint]);
1662 vector dir(allPoints[0] - points[curPoint]);
1663 dir.removeCollinear(axis);
1664 dir.normalise();
1665
1666 const coordinateSystem cs("cs", origin, axis, dir);
1667
1668 scalarField W(allPoints.size(), 1.0);
1669
1670 forAll(allPoints, pI)
1671 {
1672 W[pI] = 1.0/magSqr(allPoints[pI] - points[curPoint]);
1673
1674 allPoints[pI] = cs.localPosition(allPoints[pI]);
1675 }
1676
1678 (
1679 allPoints.size(),
1680 5,
1681 0.0
1682 );
1683
1684 for (label i=0; i<allPoints.size(); ++i)
1685 {
1686 M[i][0] = sqr(allPoints[i].x());
1687 M[i][1] = sqr(allPoints[i].y());
1688 M[i][2] = allPoints[i].x()*allPoints[i].y();
1689 M[i][3] = allPoints[i].x();
1690 M[i][4] = allPoints[i].y();
1691 }
1692
1693 scalarSquareMatrix MtM(5, Zero);
1694
1695 for (label i = 0; i < MtM.n(); ++i)
1696 {
1697 for (label j = 0; j < MtM.m(); ++j)
1698 {
1699 for (label k = 0; k < M.n(); ++k)
1700 {
1701 MtM[i][j] += M[k][i]*M[k][j]*W[k];
1702 }
1703 }
1704 }
1705
1706 scalarField MtR(5, Zero);
1707
1708 for (label i = 0; i < MtR.size(); ++i)
1709 {
1710 for (label j = 0; j < M.n(); ++j)
1711 {
1712 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1713 }
1714 }
1715
1716 LUsolve(MtM, MtR);
1717
1718 vector curNormal = vector(MtR[3], MtR[4], -1);
1719
1720 curNormal = cs.globalVector(curNormal);
1721
1722 curNormal *= sign(curNormal&result[curPoint]);
1723
1724 result[curPoint] = curNormal;
1725 }
1726 }
1727 }
1728
1729 // Correct global points
1730 if (globalData().nGlobalPoints() > 0)
1731 {
1732 const labelList& spLabels = globalData().sharedPointLabels();
1733
1734 const labelList& addr = globalData().sharedPointAddr();
1735
1736 for (label k=0; k<globalData().nGlobalPoints(); ++k)
1737 {
1738 List<List<vector>> procLsPoints(Pstream::nProcs());
1739
1740 const label curSharedPointIndex = addr.find(k);
1741
1742 scalar tol = 0.0;
1743
1744 if (curSharedPointIndex != -1)
1745 {
1746 label curPoint = spLabels[curSharedPointIndex];
1747
1748 const labelHashSet faceSet(pointFaces[curPoint]);
1749 const labelList curFaces(faceSet.toc());
1750
1751 labelHashSet pointSet;
1752 for (const label facei : curFaces)
1753 {
1754 const labelList& facePoints = faces[facei];
1755 pointSet.insert(facePoints);
1756 }
1757 pointSet.erase(curPoint);
1758 labelList curPoints = pointSet.toc();
1759
1760 vectorField locPoints(points, curPoints);
1761
1762 procLsPoints[Pstream::myProcNo()] = locPoints;
1763
1764 const boundBox bb(locPoints, false);
1765 tol = 0.001*mag(bb.max() - bb.min());
1766 }
1767
1768 Pstream::allGatherList(procLsPoints);
1769
1770 if (curSharedPointIndex != -1)
1771 {
1772 label curPoint = spLabels[curSharedPointIndex];
1773
1774 label nAllPoints = 0;
1775 forAll(procLsPoints, procI)
1776 {
1777 nAllPoints += procLsPoints[procI].size();
1778 }
1779
1780 vectorField allPoints(nAllPoints, Zero);
1781
1782 nAllPoints = 0;
1783 forAll(procLsPoints, procI)
1784 {
1785 forAll(procLsPoints[procI], pointI)
1786 {
1787 bool duplicate = false;
1788 for (label i=0; i<nAllPoints; ++i)
1789 {
1790 if
1791 (
1792 mag
1793 (
1794 allPoints[i]
1795 - procLsPoints[procI][pointI]
1796 )
1797 < tol
1798 )
1799 {
1800 duplicate = true;
1801 break;
1802 }
1803 }
1804
1805 if (!duplicate)
1806 {
1807 allPoints[nAllPoints++] =
1808 procLsPoints[procI][pointI];
1809 }
1810 }
1811 }
1812
1813 allPoints.setSize(nAllPoints);
1814
1815 if (nAllPoints < 5)
1816 {
1818 << "There are no enough points for quadratic "
1819 << "fitting for a global processor point "
1820 << abort(FatalError);
1821 }
1822
1823 // Transform points
1824 const vector& origin = points[curPoint];
1825 const vector axis = normalised(result[curPoint]);
1826 vector dir(allPoints[0] - points[curPoint]);
1827 dir.removeCollinear(axis);
1828 dir.normalise();
1829
1830 coordinateSystem cs("cs", origin, axis, dir);
1831
1832 scalarField W(allPoints.size(), 1.0);
1833
1834 forAll(allPoints, pointI)
1835 {
1836 W[pointI]=
1837 1.0/magSqr(allPoints[pointI] - points[curPoint]);
1838
1839 allPoints[pointI] = cs.localPosition(allPoints[pointI]);
1840 }
1841
1843 (
1844 allPoints.size(),
1845 5,
1846 0.0
1847 );
1848
1849 for (label i=0; i<allPoints.size(); ++i)
1850 {
1851 M[i][0] = sqr(allPoints[i].x());
1852 M[i][1] = sqr(allPoints[i].y());
1853 M[i][2] = allPoints[i].x()*allPoints[i].y();
1854 M[i][3] = allPoints[i].x();
1855 M[i][4] = allPoints[i].y();
1856 }
1857
1858 scalarSquareMatrix MtM(5, Zero);
1859 for (label i = 0; i < MtM.n(); ++i)
1860 {
1861 for (label j = 0; j < MtM.m(); ++j)
1862 {
1863 for (label k = 0; k < M.n(); ++k)
1864 {
1865 MtM[i][j] += M[k][i]*M[k][j]*W[k];
1866 }
1867 }
1868 }
1869
1870 scalarField MtR(5, Zero);
1871 for (label i = 0; i < MtR.size(); ++i)
1872 {
1873 for (label j = 0; j < M.n(); ++j)
1874 {
1875 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1876 }
1877 }
1878
1879 LUsolve(MtM, MtR);
1880
1881 vector curNormal = vector(MtR[3], MtR[4], -1);
1882
1883 curNormal = cs.globalVector(curNormal);
1884
1885 curNormal *= sign(curNormal&result[curPoint]);
1886
1887 result[curPoint] = curNormal;
1888 }
1889 }
1890 }
1891
1892 for (vector& n : result)
1893 {
1894 n.normalise();
1895 }
1896}
1897
1898
1900{
1902 << "Calculating edge length correction" << endl;
1903
1904 auto tcorrection = tmp<edgeScalarField>::New
1905 (
1906 IOobject
1907 (
1908 "edgeLengthCorrection",
1909 mesh().pointsInstance(),
1910 meshSubDir,
1911 mesh()
1912 ),
1913 *this,
1914 dimless
1915 );
1916 auto& correction = tcorrection.ref();
1917
1918 const vectorField& pointNormals = pointAreaNormals();
1919
1920 forAll(correction.internalField(), edgeI)
1921 {
1922 scalar sinAlpha = mag
1923 (
1924 pointNormals[edges()[edgeI].start()]^
1925 pointNormals[edges()[edgeI].end()]
1926 );
1927
1928 scalar alpha = asin(sinAlpha);
1929
1930 correction.ref()[edgeI] = cos(0.5*alpha);
1931 }
1932
1933
1934 forAll(boundary(), patchI)
1935 {
1936 const edgeList::subList patchEdges
1937 (
1938 boundary()[patchI].patchSlice(edges())
1939 );
1940
1941 forAll(patchEdges, edgeI)
1942 {
1943 scalar sinAlpha =
1944 mag
1945 (
1946 pointNormals[patchEdges[edgeI].start()]
1947 ^ pointNormals[patchEdges[edgeI].end()]
1948 );
1949
1950 scalar alpha = asin(sinAlpha);
1951
1952 correction.boundaryFieldRef()[patchI][edgeI] = cos(0.5*alpha);
1953 }
1954 }
1955
1956 return tcorrection;
1957}
1958
1959
1960// ************************************************************************* //
scalar y
label k
#define M(I)
label n
void normalise()
Definition: Field.C:538
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
Internal & ref(const bool updateAccessTime=true)
Return a reference to the dimensioned internal field.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
SubList< edge > subList
Declare type of subList.
Definition: List.H:111
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:146
A list of faces which address into the list of points.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
static void allGatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
static void combineAllGather(const List< commsStruct > &comms, T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
virtual bool read()
Re-read model coefficients if they have changed.
A List obtained as a section of another List.
Definition: SubList.H:70
static const Tensor I
Definition: Tensor.H:81
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
T & first()
Return the first element of the list.
Definition: UListI.H:202
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type unset(const label i)
Definition: UList.H:539
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition: VectorI.H:123
Vector< Cmpt > & removeCollinear(const Vector< Cmpt > &unitVec)
Definition: VectorI.H:142
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:66
void flip()
Invert all bits in the addressable region.
Definition: bitSetI.H:634
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition: bitSetI.H:533
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:590
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:66
labelList internalPoints() const
Return internal point labels.
static int geometryOrder() noexcept
Return the current geometry treatment (0: primitive, 1: standard)
Definition: faMesh.H:562
tmp< edgeScalarField > edgeLengthCorrection() const
Return edge length correction.
labelList boundaryPoints() const
Return boundary point labels.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
virtual bool write()
Write the output fields.
A line primitive.
Definition: line.H:68
PointRef first() const noexcept
Return first point.
Definition: lineI.H:64
Point centre() const
Return centre (centroid)
Definition: lineI.H:98
PointRef last() const noexcept
Return last (second) point.
Definition: lineI.H:78
scalar mag() const
Return scalar magnitude.
Definition: lineI.H:105
Point vec() const
Return start-to-end vector.
Definition: lineI.H:112
int myProcNo() const noexcept
Return processor number.
A class for managing temporary objects.
Definition: tmp.H:65
A triangle primitive used to calculate face normals and swept volumes.
Definition: triangle.H:80
vector areaNormal() const
The area normal - with magnitude equal to area of triangle.
Definition: triangleI.H:112
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
volScalarField & p
faceListList boundary
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Namespace of functions to calculate explicit derivatives.
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))
surfaceVectorField faceNormals(mesh.Sf()/mesh.magSf())
word timeName
Definition: getTimeIndex.H:3
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
#define PoutInFunction
Report using Foam::Pout with FUNCTION_NAME prefix.
#define DebugInFunction
Report an information message using Foam::Info.
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
tmp< GeometricField< Type, faPatchField, areaMesh > > edgeIntegrate(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
const std::string patch
OpenFOAM patch number as a std::string.
Namespace for OpenFOAM.
dimensionedScalar asin(const dimensionedScalar &ds)
GeometricField< vector, faePatchField, edgeMesh > edgeVectorField
Definition: edgeFieldsFwd.H:64
const dimensionSet dimless
Dimensionless.
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
dimensionedScalar sign(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition: List.H:66
RectangularMatrix< scalar > scalarRectangularMatrix
dimensionedSymmTensor sqr(const dimensionedVector &dv)
static vector areaInvDistSqrWeightedNormal(const vector &a, const vector &b)
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:680
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:52
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:59
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
static vector areaInvDistSqrWeightedNormalDualEdge(const point &basePoint, const point &rightPoint, const point &leftPoint, const point &centrePoint)
Tensor< scalar > tensor
Definition: symmTensor.H:61
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
static Foam::bitSet markupBoundaryPoints(const uindirectPrimitivePatch &p)
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:79
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
Definition: edgeFieldsFwd.H:63
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangle.H:71
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
Definition: areaFieldsFwd.H:78
static tensor rotation_e3e1(const vector &unitAxis1, vector dirn)
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Field< vector > vectorField
Specialisation of Field<T> for vector.
SquareMatrix< scalar > scalarSquareMatrix
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
error FatalError
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
static vector calcEdgeNormalFromFace(const linePointRef &edgeVec, const point &ownCentre, const point &neiCentre)
void LUsolve(scalarSquareMatrix &matrix, List< Type > &source)
Vector< scalar > vector
Definition: vector.H:61
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar cos(const dimensionedScalar &ds)
dimensionedTensor skew(const dimensionedTensor &dt)
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
volScalarField & alpha
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
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278
const Vector< label > N(dict.get< Vector< label > >("N"))