Loading...
Searching...
No Matches
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-2023 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 "triangle.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 // TBD: Use volatile to avoid aggressive branch optimization
72 const scalar s(2*magSqr(a)*magSqr(b));
73
74 return s < ROOTVSMALL ? Zero : (a ^ b) / s;
76
77
78// The area normal for the face dual (around base-point)
79// described by the right/left edge points and the centre point
80//
81// The adjustment for 1/2 edge point (the dual point) is done internally
83(
84 const point& basePoint,
85 const point& rightPoint,
86 const point& leftPoint,
87 const point& centrePoint
88)
89{
90 const vector mid(centrePoint - basePoint);
91
92 return
93 (
95 (
96 0.5*(rightPoint - basePoint), // vector to right 1/2 edge
97 mid
98 )
100 (
101 mid,
102 0.5*(leftPoint - basePoint) // vector to left 1/2 edge
103 )
104 );
105}
106
107
108// Weighted area normal for the face triangle (around base-point)
109// to the edge points and the centre point.
110// Used for example for area-weighted edge normals
111// ---------------------------------------------------------------------------
112// own |
113// * | Don't bother trying to split the triangle into
114// /.\ | sub-triangles. Planar anyhow and skew weighting
115// / . \ | is less relevant here.
116// / . \ |
117// / . \ | Note: need negative for neighbour side orientation.
118// e0 *----:----* e1 |
119// ---------------------------------------------------------------------------
120
122(
123 const linePointRef& edgeLine,
124 const point& faceCentre
125)
126{
127 return
128 (
130 (
131 (edgeLine.a() - faceCentre), // From centre to right edge
132 (edgeLine.b() - faceCentre) // From centre to left edge
134 );
135}
136
137
138// Simple area normal calculation for specified edge vector and face centre
139// The face centre comes last since it is less accurate
140static inline vector areaNormalFaceTriangle
141(
142 const linePointRef& edgeLine,
143 const point& faceCentre
144)
145{
146 return triPointRef::areaNormal(edgeLine.a(), edgeLine.b(), faceCentre);
147}
148
149} // End namespace Foam
150
151
152// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
153
154namespace Foam
155{
156
157// Calculate transform tensor with reference vector (unitAxis1)
158// and direction vector (axis2).
160// This is nearly identical to the meshTools axesRotation
161// with an E3_E1 transformation with the following exceptions:
162//
163// - axis1 (e3 == unitAxis1): is already normalized (unit vector)
164// - axis2 (e1 == dirn): no difference
165// - transformation is row-vectors, not column-vectors
166static inline tensor rotation_e3e1
167(
168 const vector& unitAxis1,
169 vector dirn
170)
171{
172 dirn.removeCollinear(unitAxis1);
173 dirn.normalise();
174
175 // Set row vectors
176 return tensor
177 (
178 dirn,
179 (unitAxis1^dirn),
180 unitAxis1
181 );
182}
183
184} // End namespace Foam
185
187// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
188
189namespace Foam
190{
191
192// A bitSet (size patch nPoints()) with boundary points marked
194{
195 // Initially all unmarked
196 bitSet markPoints(p.nPoints());
197 for (const edge& e : p.boundaryEdges())
198 {
199 // Mark boundary points
200 markPoints.set(e.first());
201 markPoints.set(e.second());
202 }
203
204 return markPoints;
205}
206
207
208} // End namespace Foam
209
210
211// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
212
213void Foam::faMesh::calcLduAddressing() const
214{
216 << "Calculating addressing" << endl;
217
218 if (lduPtr_)
219 {
221 << "lduPtr_ already allocated"
222 << abort(FatalError);
223 }
224
225 lduPtr_ = std::make_unique<faMeshLduAddressing>(*this);
226}
227
228
229void Foam::faMesh::calcPatchStarts() const
230{
232 << "Calculating patch starts" << endl;
233
234 if (patchStartsPtr_)
235 {
237 << "patchStarts already allocated"
238 << abort(FatalError);
239 }
240
241 patchStartsPtr_ = std::make_unique<labelList>(boundary().patchStarts());
242}
243
244
245void Foam::faMesh::calcWhichPatchFaces() const
246{
247 // Usually need both together
248 if (polyPatchFacesPtr_ || polyPatchIdsPtr_)
249 {
251 << "Already allocated polyPatchFaces/polyPatchIds"
252 << abort(FatalError);
253 }
254
256
257 polyPatchFacesPtr_ = std::make_unique<List<labelPair>>
258 (
259 pbm.whichPatchFace(faceLabels_)
260 );
261
262 labelHashSet ids;
263
264 // Extract patch ids from (patch, facei) tuples
265 for (const labelPair& tup : *polyPatchFacesPtr_)
266 {
267 ids.insert(tup.first());
268 }
269
270 ids.erase(-1); // Without internal faces (patchi == -1)
271
272 // parSync
274 (
275 ids,
278 this->comm()
279 );
280
281 polyPatchIdsPtr_ = std::make_unique<labelList>(ids.sortedToc());
282}
283
284
285// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
286
287namespace Foam
288{
289
290//- Calculate the 'Le' vector from faceCentre to edge centre
291// using the edge normal to correct for curvature
292//
293// Normalise and rescaled to the edge length
294static inline vector calcLeVector
295(
296 const point& faceCentre,
297 const linePointRef& edgeLine,
298 const vector& edgeNormal // (unit or area normal)
299)
300{
301 const vector centreToEdge(edgeLine.centre() - faceCentre);
302
303 vector leVector(edgeLine.vec() ^ edgeNormal);
304
305 scalar s(mag(leVector));
306
307 if (s < ROOTVSMALL)
308 {
309 // The calculated edgeNormal somehow degenerate and thus a
310 // bad cross-product?
311 // Revert to basic centre -> edge
312
313 leVector = centreToEdge;
314 leVector.removeCollinear(edgeLine.unitVec());
315 s = mag(leVector);
316
317 if (s < ROOTVSMALL)
318 {
319 // Unlikely that this should happen
320 return Zero;
321 }
322
323 leVector *= edgeLine.mag()/s;
324 }
325 else
326 {
327 // The additional orientation is probably unnecessary
328 leVector *= edgeLine.mag()/s * sign(leVector & centreToEdge);
329 }
330
331 return leVector;
332}
333
334} // End namespace Foam
335
336
337namespace Foam
339
340// Impose a minimum (edge) vector length
341// - disallow any mag(vec) < SMALL
342static inline void imposeMinVectorLength(vectorField& fld)
343{
344 // If it is small, no orientation information reasonably possible
345 // so use a vector(1,1,1) * sqrt(1/3)*min-length
346
347 // sqrt(1/3) = 0.5773502691896257, but slightly rounded down
348 const vector minVector(vector::uniform(0.57735*SMALL));
349 const scalar minLenSqr(SMALL*SMALL);
350
351 for (vector& v : fld)
352 {
353 if (v.magSqr() < minLenSqr)
354 {
355 v = minVector;
356 }
357 }
358}
359
360} // End namespace Foam
361
362
363// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
364
365Foam::tmp<Foam::vectorField> Foam::faMesh::calcRawEdgeNormals(int order) const
366{
367 // Return edge normals with flat boundary addressing
368 auto tedgeNormals = tmp<vectorField>::New(nEdges_);
369 auto& edgeNormals = tedgeNormals.ref();
370
371 // Need face centres
372 const areaVectorField& fCentres = areaCentres();
373
374 // Also need local points
375 const pointField& localPoints = points();
376
377
378 if (order < 0)
379 {
380 // geometryOrder (-1): no communication
381
382 // Simple (primitive) edge normal calculations.
383 // These are primarly designed to avoid any communication
384 // but are thus necessarily inconsistent across processor boundaries!
385
387 << "Using geometryOrder < 0 : "
388 "simplified edge area-normals, without processor connectivity"
389 << endl;
390
391 // Internal (edge normals) - contributions from owner/neighbour
392 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
393 {
394 const linePointRef edgeLine(edges_[edgei].line(localPoints));
395
396 edgeNormals[edgei] =
397 (
399 (
400 edgeLine,
401 fCentres[edgeOwner()[edgei]]
402 )
403 // NB: reversed sign (edge orientation flipped for neighbour)
405 (
406 edgeLine,
407 fCentres[edgeNeighbour()[edgei]]
408 )
409 );
410 }
411
412 // Boundary (edge normals). Like above, but only has owner
413 for (label edgei = nInternalEdges_; edgei < nEdges_; ++edgei)
414 {
415 const linePointRef edgeLine(edges_[edgei].line(localPoints));
416
417 edgeNormals[edgei] =
418 (
420 (
421 edgeLine,
422 fCentres[edgeOwner()[edgei]]
423 )
424 );
425 }
426 }
427 else
428 {
429 // geometryOrder (0) - no communication
430 // otherwise with communication
431
432 if (order < 1)
433 {
435 << "Using geometryOrder == 0 : "
436 "weighted edge normals, without processor connectivity"
437 << endl;
438 }
439
440 // Internal (edge normals)
441 // - area-weighted contributions from owner/neighbour
442 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
443 {
444 const linePointRef edgeLine(edges_[edgei].line(localPoints));
445
446 edgeNormals[edgei] =
447 (
449 (
450 edgeLine,
451 fCentres[edgeOwner()[edgei]]
452 )
453 // NB: reversed sign (edge orientation flipped for neighbour)
455 (
456 edgeLine,
457 fCentres[edgeNeighbour()[edgei]]
458 )
459 );
460 }
461
462 // Boundary (edge normals). Like above, but only has owner
463 for (label edgei = nInternalEdges_; edgei < nEdges_; ++edgei)
464 {
465 const linePointRef edgeLine(edges_[edgei].line(localPoints));
466
467 edgeNormals[edgei] =
468 (
470 (
471 edgeLine,
472 fCentres[edgeOwner()[edgei]]
473 )
474 );
475 }
476 }
477
478
479 // Boundary edge corrections
480 bitSet nbrBoundaryAdjust;
481
482 // Processor-processor first (for convenience)
483 if (order >= 1)
484 {
486 (
487 2*(boundary().size() - boundary().nNonProcessor())
488 );
489
490 PtrList<vectorField> nbrEdgeNormals(boundary().size());
491
492 // Prefer our own slicing into the raw list (instead of patchSlice).
493 // Although patchSlice does properly handle the start() offset in
494 // the presence of emptyPaPatch, we are slightly paranoia,
495 // and want to avoid kicking off the patchStarts() data...
496
497 label patchOffset = nInternalEdges_;
498
499 forAll(boundary(), patchi)
500 {
501 const faPatch& fap = boundary()[patchi];
502
503 auto edgeNorms = edgeNormals.slice(patchOffset, fap.nEdges());
504 patchOffset += edgeNorms.size();
505
506 const auto* fapp = isA<processorFaPatch>(fap);
507
508 if (fapp)
509 {
510 const label nbrProci = fapp->neighbProcNo();
511
512 if (UPstream::parRun() && !edgeNorms.empty())
513 {
514 nbrEdgeNormals.emplace(patchi, edgeNorms.size());
515
516 // Recv accumulated weighted edge normals
518 (
519 requests.emplace_back(),
520 nbrProci,
521 nbrEdgeNormals[patchi]
522 );
523
524 // Send accumulated weighted edge normals
526 (
527 requests.emplace_back(),
528 nbrProci,
529 edgeNorms
530 );
531 }
532 }
533 else if (isA<wedgeFaPatch>(fap))
534 {
535 // Correct wedge edges
536 const auto& wedgePatch = refCast<const wedgeFaPatch>(fap);
537
538 const vector wedgeNorm
539 (
541 (
542 wedgePatch.edgeT(),
543 wedgePatch.centreNormal()
544 ).normalise()
545 );
546
547 for (vector& e : edgeNorms)
548 {
549 e.removeCollinear(wedgeNorm);
550 }
551 }
552 // TBD:
557 else if (correctPatchPointNormals(patchi) && !fap.coupled())
558 {
559 // Neighbour correction requested
560 nbrBoundaryAdjust.set(patchi);
561 }
562 }
563
564 // Wait for outstanding requests
565 UPstream::waitRequests(requests);
566
567 if (!requests.empty())
568 {
569 // Add in received values
570
571 patchOffset = nInternalEdges_;
572
573 forAll(boundary(), patchi)
574 {
575 const faPatch& fap = boundary()[patchi];
576
577 auto edgeNorms = edgeNormals.slice(patchOffset, fap.nEdges());
578 patchOffset += edgeNorms.size();
579
580 if (nbrEdgeNormals.set(patchi))
581 {
582 const vectorField& nbrNorms = nbrEdgeNormals[patchi];
583
584 forAll(edgeNorms, patchEdgei)
585 {
586 edgeNorms[patchEdgei] += nbrNorms[patchEdgei];
587 }
588 }
589 }
590 }
591 }
592
593
594 // Apply boundary edge corrections
595 if
596 (
597 order >= 1
598 && hasPatchPointNormalsCorrection()
599 && returnReduceOr(nbrBoundaryAdjust.any())
600 )
601 {
603 << "Apply " << nbrBoundaryAdjust.count()
604 << " boundary neighbour corrections" << nl;
605
606 // Collect face normals, per boundary edge
607
608 (void)this->haloFaceNormals();
609
610 // Using our own slicing (instead of patchSlice) - see above
611 label patchOffset = nInternalEdges_;
612
613 for (const label patchi : nbrBoundaryAdjust)
614 {
615 const faPatch& fap = boundary()[patchi];
616
617 auto edgeNorms = edgeNormals.slice(patchOffset, fap.nEdges());
618 patchOffset += edgeNorms.size();
619
620 if (fap.ngbPolyPatchIndex() < 0)
621 {
623 << "Neighbour polyPatch index is not defined "
624 << "for faPatch " << fap.name()
625 << abort(FatalError);
626 }
627
628 // Apply the correction
629
630 // Note from Zeljko Tukovic:
631 //
632 // This posibility is used for free-surface tracking
633 // calculations to enforce 90 deg contact angle between
634 // finite-area mesh and neighbouring polyPatch. It is very
635 // important for curvature calculation to have correct normal
636 // at contact line points.
637
638 vectorField nbrNorms(this->haloFaceNormals(patchi));
639
640 const label nPatchEdges = min(edgeNorms.size(), nbrNorms.size());
641
642 for (label patchEdgei = 0; patchEdgei < nPatchEdges; ++patchEdgei)
643 {
644 edgeNorms[patchEdgei].removeCollinear(nbrNorms[patchEdgei]);
645 }
646 }
647 }
648
649
650 // Remove collinear components and normalise
651
652 forAll(edgeNormals, edgei)
653 {
654 const linePointRef edgeLine(edges_[edgei].line(localPoints));
655
656 edgeNormals[edgei].removeCollinear(edgeLine.unitVec());
657 edgeNormals[edgei].normalise();
658 }
659
660 imposeMinVectorLength(edgeNormals);
661
662 return tedgeNormals;
663}
664
665
666void Foam::faMesh::calcLe() const
667{
669 << "Calculating local edges" << endl;
670
671 if (LePtr_)
672 {
674 << "LePtr_ already allocated"
675 << abort(FatalError);
676 }
677
678 LePtr_ = std::make_unique<edgeVectorField>
679 (
681 (
682 "Le",
683 mesh().pointsInstance(),
689 ),
690 *this,
692 // -> calculatedType()
693 );
694 edgeVectorField& Le = *LePtr_;
695
696 // Need face centres
697 const areaVectorField& fCentres = areaCentres();
698
699 // Also need local points
700 const pointField& localPoints = points();
701
702
703 // The edgeAreaNormals _may_ use communication (depends on geometryOrder)
704
705 {
706 const edgeVectorField& edgeNormals = edgeAreaNormals();
707
708 // Internal (edge vector)
709 {
710 vectorField& fld = Le.primitiveFieldRef();
711 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
712 {
713 fld[edgei] = calcLeVector
714 (
715 fCentres[edgeOwner()[edgei]],
716 edges_[edgei].line(localPoints),
717 edgeNormals[edgei]
718 );
719 }
720 }
721
722 // Boundary (edge vector)
723 forAll(boundary(), patchi)
724 {
725 const faPatch& fap = boundary()[patchi];
726 vectorField& pfld = Le.boundaryFieldRef()[patchi];
727
728 const vectorField& bndEdgeNormals =
729 edgeNormals.boundaryField()[patchi];
730
731 label edgei = fap.start();
732
733 forAll(pfld, patchEdgei)
734 {
735 pfld[patchEdgei] = calcLeVector
736 (
737 fCentres[edgeOwner()[edgei]],
738 edges_[edgei].line(localPoints),
739 bndEdgeNormals[patchEdgei]
740 );
741
742 ++edgei;
743 }
744 }
745 }
746
747
748 // Impose a minimum (edge) vector length
749
750 // Internal (edge vector)
751 {
752 imposeMinVectorLength(Le.primitiveFieldRef());
753 }
754
755 // Boundary (edge vector)
756 for (vectorField& pfld : Le.boundaryFieldRef())
757 {
759 }
760}
761
762
763void Foam::faMesh::calcMagLe() const
764{
766 << "Calculating local edge magnitudes" << endl;
767
768 if (magLePtr_)
769 {
771 << "magLe() already allocated"
772 << abort(FatalError);
773 }
774
775 magLePtr_ = std::make_unique<edgeScalarField>
776 (
778 (
779 "magLe",
780 mesh().pointsInstance(),
786 ),
787 *this,
789 );
790 edgeScalarField& magLe = *magLePtr_;
791
792 const pointField& localPoints = points();
793
794 // Internal (edge length)
795 {
796 auto iter = magLe.primitiveFieldRef().begin();
797
798 for (const edge& e : internalEdges())
799 {
800 *iter = e.mag(localPoints);
801
802 // Do not allow any mag(val) < SMALL
803 if (mag(*iter) < SMALL)
804 {
805 *iter = SMALL;
806 }
807
808 ++iter;
809 }
810 }
811
812 // Boundary (edge length)
813 {
814 auto& bfld = magLe.boundaryFieldRef();
815
816 forAll(boundary(), patchi)
817 {
818 auto iter = bfld[patchi].begin();
819
820 for (const edge& e : boundary()[patchi].patchSlice(edges_))
821 {
822 *iter = e.mag(localPoints);
823
824 // Do not allow any mag(val) < SMALL
825 if (mag(*iter) < SMALL)
826 {
827 *iter = SMALL;
828 }
829
830 ++iter;
831 }
832 }
833 }
834}
835
836
837void Foam::faMesh::calcFaceCentres() const
838{
840 << "Calculating face centres" << endl;
841
842 if (faceCentresPtr_)
843 {
845 << "areaCentres already allocated"
846 << abort(FatalError);
847 }
848
849 faceCentresPtr_ = std::make_unique<areaVectorField>
850 (
852 (
853 "centres",
854 mesh().pointsInstance(),
860 ),
861 *this,
863 // -> calculatedType()
864 );
865 areaVectorField& centres = *faceCentresPtr_;
866
867 // Need local points
868 const pointField& localPoints = points();
869
870
871 // Internal (face centres)
872 {
873 if (mesh().hasFaceCentres())
874 {
875 // The volume mesh has faceCentres, can reuse them
876
877 centres.primitiveFieldRef()
878 = UIndirectList<vector>(mesh().faceCentres(), faceLabels());
879 }
880 else
881 {
882 // Calculate manually
883 auto iter = centres.primitiveFieldRef().begin();
884
885 for (const face& f : faces())
886 {
887 *iter = f.centre(localPoints);
888 ++iter;
889 }
890 }
891 }
892
893 // Boundary (edge centres or neighbour face centres)
894 {
895 auto& bfld = centres.boundaryFieldRef();
896
897 forAll(boundary(), patchi)
898 {
899 auto iter = bfld[patchi].begin();
900
901 for (const edge& e : boundary()[patchi].patchSlice(edges_))
902 {
903 *iter = e.centre(localPoints);
904 ++iter;
905 }
906 }
907 }
908
909 // Parallel consistency, exchange on processor patches
910 if (UPstream::parRun())
911 {
912 centres.boundaryFieldRef().evaluateCoupled<processorFaPatch>();
913 }
914}
915
916
917void Foam::faMesh::calcEdgeCentres() const
918{
920 << "Calculating edge centres" << endl;
921
922 if (edgeCentresPtr_)
923 {
925 << "edgeCentres already allocated"
926 << abort(FatalError);
927 }
928
929 edgeCentresPtr_ = std::make_unique<edgeVectorField>
930 (
932 (
933 "edgeCentres",
934 mesh().pointsInstance(),
940 ),
941 *this,
943 // -> calculatedType()
944 );
945 edgeVectorField& centres = *edgeCentresPtr_;
946
947 // Need local points
948 const pointField& localPoints = points();
949
950
951 // Internal (edge centres)
952 {
953 auto iter = centres.primitiveFieldRef().begin();
954
955 for (const edge& e : internalEdges())
956 {
957 *iter = e.centre(localPoints);
958 ++iter;
959 }
960 }
961
962 // Boundary (edge centres)
963 {
964 auto& bfld = centres.boundaryFieldRef();
965
966 forAll(boundary(), patchi)
967 {
968 auto iter = bfld[patchi].begin();
969
970 for (const edge& e : boundary()[patchi].patchSlice(edges_))
971 {
972 *iter = e.centre(localPoints);
973 ++iter;
974 }
975 }
976 }
977}
978
979
980void Foam::faMesh::calcS() const
981{
983 << "Calculating areas" << endl;
984
985 if (SPtr_)
986 {
988 << "S() already allocated"
989 << abort(FatalError);
990 }
991
992 SPtr_ = std::make_unique<DimensionedField<scalar, areaMesh>>
993 (
995 (
996 "S",
997 time().timeName(),
1002 ),
1003 *this,
1004 dimArea
1005 );
1006 auto& areas = *SPtr_;
1007
1008
1009 // No access to fvMesh::magSf(), only polyMesh::faceAreas()
1010 if (mesh().hasFaceAreas())
1011 {
1012 // The volume mesh has faceAreas, can reuse them
1013 UIndirectList<vector> meshFaceAreas(mesh().faceAreas(), faceLabels());
1014
1015 auto& fld = areas.field();
1016
1017 forAll(fld, facei)
1018 {
1019 fld[facei] = Foam::mag(meshFaceAreas[facei]);
1020
1021 // Do not allow any mag(val) < SMALL
1022 if (mag(fld[facei]) < SMALL)
1023 {
1024 fld[facei] = SMALL;
1025 }
1026 }
1027 }
1028 else
1029 {
1030 // Calculate manually
1031
1032 const pointField& localPoints = points();
1033
1034 auto iter = areas.field().begin();
1035
1036 for (const face& f : faces())
1037 {
1038 *iter = f.mag(localPoints);
1039
1040 // Do not allow any mag(val) < SMALL
1041 if (mag(*iter) < SMALL)
1042 {
1043 *iter = SMALL;
1044 }
1045
1046 ++iter;
1047 }
1048 }
1049}
1050
1051
1052void Foam::faMesh::calcFaceAreaNormals() const
1053{
1055 << "Calculating face area normals" << endl;
1056
1057 if (faceAreaNormalsPtr_)
1058 {
1060 << "faceAreaNormals already allocated"
1061 << abort(FatalError);
1062 }
1063
1064 faceAreaNormalsPtr_ = std::make_unique<areaVectorField>
1065 (
1066 IOobject
1067 (
1068 "faceAreaNormals",
1069 mesh().pointsInstance(),
1075 ),
1076 *this,
1077 dimless
1078 );
1079 areaVectorField& faceNormals = *faceAreaNormalsPtr_;
1080
1081 const pointField& localPoints = points();
1082
1083 // Internal
1084 {
1085 auto& fld = faceNormals.primitiveFieldRef();
1086
1087 if (mesh().hasFaceAreas())
1088 {
1089 // The volume mesh has faceAreas, can reuse them
1090 fld = UIndirectList<vector>(mesh().faceAreas(), faceLabels());
1091 }
1092 else
1093 {
1094 // Calculate manually
1095
1096 auto iter = fld.begin();
1097
1098 for (const face& f : faces())
1099 {
1100 *iter = f.areaNormal(localPoints);
1101 ++iter;
1102 }
1103 }
1104
1105 // Make unit normals
1106 fld.normalise();
1107
1109 }
1110
1111
1112 // Boundary - copy from edges
1113 {
1114 const auto& edgeNormalsBoundary = edgeAreaNormals().boundaryField();
1115
1116 forAll(boundary(), patchi)
1117 {
1118 faceNormals.boundaryFieldRef()[patchi]
1119 = edgeNormalsBoundary[patchi];
1120 }
1121 }
1122
1123 // Parallel consistency, exchange on processor patches
1124 if (UPstream::parRun())
1125 {
1126 faceNormals.boundaryFieldRef().evaluateCoupled<processorFaPatch>();
1127 }
1128}
1129
1130
1131void Foam::faMesh::calcEdgeAreaNormals() const
1132{
1134 << "Calculating edge area normals" << endl;
1135
1136 if (edgeAreaNormalsPtr_)
1137 {
1139 << "edgeAreaNormalsPtr_ already allocated"
1140 << abort(FatalError);
1141 }
1142
1143 edgeAreaNormalsPtr_ = std::make_unique<edgeVectorField>
1144 (
1145 IOobject
1146 (
1147 "edgeAreaNormals",
1148 mesh().pointsInstance(),
1154 ),
1155 *this,
1156 dimless
1157 // -> calculatedType()
1158 );
1159 edgeVectorField& edgeAreaNormals = *edgeAreaNormalsPtr_;
1160
1161
1162 if (faMesh::geometryOrder() < 2)
1163 {
1164 // The edge normals with flat boundary addressing
1165 // (which _may_ use communication)
1166 vectorField edgeNormals
1167 (
1168 calcRawEdgeNormals(faMesh::geometryOrder())
1169 );
1170
1171 // Copy internal field
1172 edgeAreaNormals.primitiveFieldRef()
1173 = vectorField::subList(edgeNormals, nInternalEdges_);
1174
1175 // Using our own slicing (instead of patchSlice) - see above
1176
1177 auto& bfld = edgeAreaNormals.boundaryFieldRef();
1178
1179 label patchOffset = nInternalEdges_;
1180
1181 forAll(boundary(), patchi)
1182 {
1183 const faPatch& fap = boundary()[patchi];
1184
1185 bfld[patchi] = vectorField::subList
1186 (
1187 edgeNormals,
1188 bfld[patchi].size(),
1189 patchOffset
1190 );
1191
1192 patchOffset += fap.nEdges();
1193 }
1194
1195 return;
1196 }
1197
1198
1199 // ------------------------------------------------------------------------
1200
1201 // This is the original approach using an average of the
1202 // point normals. May be removed in the future (2022-09)
1203
1204 // Starting from point area normals
1205 const vectorField& pointNormals = pointAreaNormals();
1206
1207 // Also need local points
1208 const pointField& localPoints = points();
1209
1210 // Internal edges
1211 {
1212 auto& fld = edgeAreaNormals.primitiveFieldRef();
1213
1214 forAll(fld, edgei)
1215 {
1216 const edge& e = edges_[edgei];
1217 const linePointRef edgeLine(e.line(localPoints));
1218
1219 // Average of both ends
1220 fld[edgei] = (pointNormals[e.first()] + pointNormals[e.second()]);
1221
1222 fld[edgei].removeCollinear(edgeLine.unitVec());
1223 fld[edgei].normalise();
1224 }
1225
1227 }
1228
1229 // Boundary
1230 {
1231 auto& bfld = edgeAreaNormals.boundaryFieldRef();
1232
1233 forAll(boundary(), patchi)
1234 {
1235 const faPatch& fap = boundary()[patchi];
1236
1237 auto& pfld = bfld[patchi];
1238
1239 const edgeList::subList bndEdges = fap.patchSlice(edges_);
1240
1241 forAll(bndEdges, patchEdgei)
1242 {
1243 const edge& e = bndEdges[patchEdgei];
1244 const linePointRef edgeLine(e.line(localPoints));
1245
1246 // Average of both ends
1247 pfld[patchEdgei] =
1248 (pointNormals[e.first()] + pointNormals[e.second()]);
1249
1250 pfld[patchEdgei].removeCollinear(edgeLine.unitVec());
1251 pfld[patchEdgei].normalise();
1252 }
1253
1255 }
1256 }
1257}
1258
1259
1260void Foam::faMesh::calcFaceCurvatures() const
1261{
1263 << "Calculating face curvatures" << endl;
1264
1265 if (faceCurvaturesPtr_)
1266 {
1268 << "faceCurvaturesPtr_ already allocated"
1269 << abort(FatalError);
1270 }
1271
1272 faceCurvaturesPtr_ = std::make_unique<areaScalarField>
1273 (
1274 IOobject
1275 (
1276 "faceCurvatures",
1277 mesh().pointsInstance(),
1283 ),
1284 *this,
1286 );
1287 areaScalarField& faceCurvatures = *faceCurvaturesPtr_;
1288
1289
1290// faceCurvatures =
1291// fac::edgeIntegrate(Le()*edgeLengthCorrection())
1292// &faceAreaNormals();
1293
1294 areaVectorField kN(fac::edgeIntegrate(Le()*edgeLengthCorrection()));
1295
1296 faceCurvatures = sign(kN&faceAreaNormals())*mag(kN);
1297}
1298
1299
1300void Foam::faMesh::calcEdgeTransformTensors() const
1301{
1303 << "Calculating edge transformation tensors" << endl;
1304
1305 if (edgeTransformTensorsPtr_)
1306 {
1308 << "edgeTransformTensorsPtr_ already allocated"
1309 << abort(FatalError);
1310 }
1311
1312 edgeTransformTensorsPtr_ =
1313 std::make_unique<FieldField<Field, tensor>>(nEdges_);
1314 auto& edgeTransformTensors = *edgeTransformTensorsPtr_;
1315
1316 // Initialize all transformation tensors
1317 for (label edgei = 0; edgei < nEdges_; ++edgei)
1318 {
1319 edgeTransformTensors.set(edgei, new Field<tensor>(3, tensor::I));
1320 }
1321
1322 const areaVectorField& Nf = faceAreaNormals();
1323 const areaVectorField& Cf = areaCentres();
1324
1325 const edgeVectorField& Ne = edgeAreaNormals();
1326 const edgeVectorField& Ce = edgeCentres();
1327
1328 // Internal edges transformation tensors
1329 for (label edgei = 0; edgei < nInternalEdges_; ++edgei)
1330 {
1331 const label ownFacei = owner()[edgei];
1332 const label neiFacei = neighbour()[edgei];
1333 auto& tensors = edgeTransformTensors[edgei];
1334
1335 vector edgeCtr = Ce.internalField()[edgei];
1336
1337 if (skew())
1338 {
1339 edgeCtr -= skewCorrectionVectors().internalField()[edgei];
1340 }
1341
1342 // Edge transformation tensor
1343 tensors[0] =
1345 (
1346 Ne.internalField()[edgei],
1347 (edgeCtr - Cf.internalField()[ownFacei])
1348 );
1349
1350 // Owner transformation tensor
1351 tensors[1] =
1353 (
1354 Nf.internalField()[ownFacei],
1355 (edgeCtr - Cf.internalField()[ownFacei])
1356 );
1357
1358 // Neighbour transformation tensor
1359 tensors[2] =
1361 (
1362 Nf.internalField()[neiFacei],
1363 (Cf.internalField()[neiFacei] - edgeCtr)
1364 );
1365 }
1366
1367 // Boundary edges transformation tensors
1368 forAll(boundary(), patchi)
1369 {
1370 const labelUList& edgeFaces = boundary()[patchi].edgeFaces();
1371
1372 if (boundary()[patchi].coupled())
1373 {
1374 vectorField nbrCf(Cf.boundaryField()[patchi].patchNeighbourField());
1375 vectorField nbrNf(Nf.boundaryField()[patchi].patchNeighbourField());
1376
1377 forAll(edgeFaces, bndEdgei)
1378 {
1379 const label ownFacei = edgeFaces[bndEdgei];
1380 const label meshEdgei(boundary()[patchi].start() + bndEdgei);
1381
1382 auto& tensors = edgeTransformTensors[meshEdgei];
1383
1384 vector edgeCtr = Ce.boundaryField()[patchi][bndEdgei];
1385
1386 if (skew())
1387 {
1388 edgeCtr -= skewCorrectionVectors()
1389 .boundaryField()[patchi][bndEdgei];
1390 }
1391
1392 // Edge transformation tensor
1393 tensors[0] =
1395 (
1396 Ne.boundaryField()[patchi][bndEdgei],
1397 (edgeCtr - Cf.internalField()[ownFacei])
1398 );
1399
1400 // Owner transformation tensor
1401 tensors[1] =
1403 (
1404 Nf.internalField()[ownFacei],
1405 (edgeCtr - Cf.internalField()[ownFacei])
1406 );
1407
1408 // Neighbour transformation tensor
1409 tensors[2] =
1411 (
1412 nbrNf[bndEdgei],
1413 (nbrCf[bndEdgei] - edgeCtr)
1414 );
1415 }
1416 }
1417 else
1418 {
1419 forAll(edgeFaces, bndEdgei)
1420 {
1421 const label ownFacei = edgeFaces[bndEdgei];
1422 const label meshEdgei(boundary()[patchi].start() + bndEdgei);
1423
1424 auto& tensors = edgeTransformTensors[meshEdgei];
1425
1426 vector edgeCtr = Ce.boundaryField()[patchi][bndEdgei];
1427
1428 if (skew())
1429 {
1430 edgeCtr -= skewCorrectionVectors()
1431 .boundaryField()[patchi][bndEdgei];
1432 }
1433
1434 // Edge transformation tensor
1435 tensors[0] =
1437 (
1438 Ne.boundaryField()[patchi][bndEdgei],
1439 (edgeCtr - Cf.internalField()[ownFacei])
1440 );
1441
1442 // Owner transformation tensor
1443 tensors[1] =
1445 (
1446 Nf.internalField()[ownFacei],
1447 (edgeCtr - Cf.internalField()[ownFacei])
1448 );
1449
1450 // Neighbour transformation tensor
1451 tensors[2] = tensor::I;
1452 }
1453 }
1455}
1456
1457
1459{
1461 << "Calculating internal points" << endl;
1462
1463 bitSet markPoints(markupBoundaryPoints(this->patch()));
1464 markPoints.flip();
1465
1466 return markPoints.sortedToc();
1467}
1468
1469
1471{
1473 << "Calculating boundary points" << endl;
1474
1475 bitSet markPoints(markupBoundaryPoints(this->patch()));
1476
1477 return markPoints.sortedToc();
1478}
1479
1480
1481// ~~~~~~~~~~~~~~~~~~~~~~~~~
1482// Point normal calculations
1483// ~~~~~~~~~~~~~~~~~~~~~~~~~
1484
1485// Revised method (general)
1486// ------------------------
1487//
1488// - For each patch face obtain a centre point (mathematical avg)
1489// and use that to define the face dual as a pair of triangles:
1490// - tri1: base-point / mid-side of right edge / face centre
1491// - tri2: base-point / face centre / mid-side of left edge
1492//
1493// - Walk all face points, inserting directly into the corresponding
1494// locations. No distinction between internal or boundary points (yet).
1495//
1496// Revised method (boundary correction)
1497// ------------------------------------
1498//
1499// - correct wedge directly, use processor patch information to exchange
1500// the current summed values. [No change from original].
1501//
1502// - explicit correction of other boundaries.
1503// Use the new boundary halo information for the face normals.
1504// Calculate the equivalent face-point normals locally and apply
1505// correction as before.
1506
1507void Foam::faMesh::calcPointAreaNormals(vectorField& result) const
1508{
1510 << "Calculating pointAreaNormals : face dual method" << endl;
1511
1512 result.resize_nocopy(nPoints());
1513 result = Zero;
1514
1515 const pointField& points = patch().localPoints();
1516 const faceList& faces = patch().localFaces();
1517
1518
1519 // Loop over all faces
1520
1521 for (const face& f : faces)
1522 {
1523 const label nVerts(f.size());
1524
1525 point centrePoint(Zero);
1526 for (const label fp : f)
1527 {
1528 centrePoint += points[fp];
1529 }
1530 centrePoint /= nVerts;
1531
1532 for (label i = 0; i < nVerts; ++i)
1533 {
1534 const label pt0 = f.thisLabel(i); // base
1535
1536 result[pt0] +=
1538 (
1539 points[pt0], // base
1540 points[f.nextLabel(i)], // right
1541 points[f.prevLabel(i)], // left
1542 centrePoint
1543 );
1544 }
1545 }
1546
1547
1548 // Boundary edge corrections
1549 bitSet nbrBoundaryAdjust;
1550
1551 forAll(boundary(), patchi)
1552 {
1553 const faPatch& fap = boundary()[patchi];
1554
1555 if (isA<wedgeFaPatch>(fap))
1556 {
1557 // Correct wedge points
1558
1559 const auto& wedgePatch = refCast<const wedgeFaPatch>(fap);
1560
1561 const labelList& patchPoints = wedgePatch.pointLabels();
1562
1563 const vector N
1564 (
1565 transform
1566 (
1567 wedgePatch.edgeT(),
1568 wedgePatch.centreNormal()
1569 ).normalise()
1570 );
1571
1572 for (const label pti : patchPoints)
1573 {
1574 result[pti].removeCollinear(N);
1575 }
1576
1577 // Axis point correction
1578 if (wedgePatch.axisPoint() > -1)
1579 {
1580 result[wedgePatch.axisPoint()] =
1581 wedgePatch.axis()
1582 *(
1583 wedgePatch.axis()
1584 &result[wedgePatch.axisPoint()]
1585 );
1586 }
1587 }
1588 else if (Pstream::parRun() && isA<processorFaPatch>(fap))
1589 {
1590 // Correct processor patch points
1591 const auto& procPatch = refCast<const processorFaPatch>(fap);
1592
1593 const labelList& patchPoints = procPatch.pointLabels();
1594 const labelList& nbrPatchPoints = procPatch.neighbPoints();
1595
1596 const labelList& nonGlobalPatchPoints =
1597 procPatch.nonGlobalPatchPoints();
1598
1599 // Send my values
1600
1601 vectorField patchPointNormals
1602 (
1603 UIndirectList<vector>(result, patchPoints)
1604 );
1605
1606 {
1608 (
1610 procPatch.neighbProcNo(),
1611 patchPointNormals
1612 );
1613 }
1614
1615 // Receive neighbour values
1616 patchPointNormals.resize_nocopy(nbrPatchPoints.size());
1617
1618 {
1620 (
1622 procPatch.neighbProcNo(),
1623 patchPointNormals
1624 );
1625 }
1626
1627 for (const label pti : nonGlobalPatchPoints)
1628 {
1629 result[patchPoints[pti]] +=
1630 patchPointNormals[nbrPatchPoints[pti]];
1631 }
1632 }
1633 // TBD:
1638 else if (correctPatchPointNormals(patchi) && !fap.coupled())
1639 {
1640 // Neighbour correction requested
1641 nbrBoundaryAdjust.set(patchi);
1642 }
1643 }
1644
1645
1646 // Correct global points
1647 if (globalData().nGlobalPoints())
1648 {
1649 const labelList& spLabels = globalData().sharedPointLabels();
1650 const labelList& addr = globalData().sharedPointAddr();
1651
1652 vectorField spNormals
1653 (
1654 UIndirectList<vector>(result, spLabels)
1655 );
1656
1657 vectorField gpNormals
1658 (
1659 globalData().nGlobalPoints(),
1660 Zero
1661 );
1662
1663 forAll(addr, i)
1664 {
1665 gpNormals[addr[i]] += spNormals[i];
1666 }
1667
1669
1670 // Extract local data
1671 forAll(addr, i)
1672 {
1673 spNormals[i] = gpNormals[addr[i]];
1674 }
1675
1676 forAll(spNormals, pointI)
1677 {
1678 result[spLabels[pointI]] = spNormals[pointI];
1679 }
1680 }
1681
1682
1683 if
1684 (
1685 hasPatchPointNormalsCorrection()
1686 && returnReduceOr(nbrBoundaryAdjust.any())
1687 )
1688 {
1690 << "Apply " << nbrBoundaryAdjust.count()
1691 << " boundary neighbour corrections" << nl;
1692
1693 // Apply boundary points correction
1694
1695 // Collect face normals as point normals
1696
1697 const auto& haloNormals = this->haloFaceNormals();
1698
1699 Map<vector> fpNormals(4*nBoundaryEdges());
1700
1701 for (const label patchi : nbrBoundaryAdjust)
1702 {
1703 const faPatch& fap = boundary()[patchi];
1704
1705 if (fap.ngbPolyPatchIndex() < 0)
1706 {
1708 << "Neighbour polyPatch index is not defined "
1709 << "for faPatch " << fap.name()
1710 << abort(FatalError);
1711 }
1712
1713 // NB: haloFaceNormals uses primitivePatch edge indexing
1714 for (const label edgei : fap.edgeLabels())
1715 {
1716 const edge& e = patch().edges()[edgei];
1717
1718 // Halo face unitNormal at boundary edge (starts as 0)
1719 const vector& fnorm = haloNormals[edgei - nInternalEdges_];
1720
1721 fpNormals(e.first()) += fnorm;
1722 fpNormals(e.second()) += fnorm;
1723 }
1724 }
1725
1726 // Apply the correction
1727
1728 // Note from Zeljko Tukovic:
1729 //
1730 // This posibility is used for free-surface tracking
1731 // calculations to enforce 90 deg contact angle between
1732 // finite-area mesh and neighbouring polyPatch. It is very
1733 // important for curvature calculation to have correct normal
1734 // at contact line points.
1735
1736 forAllConstIters(fpNormals, iter)
1737 {
1738 const label pointi = iter.key();
1739 result[pointi].removeCollinear(normalised(iter.val()));
1740 }
1741 }
1742
1743 result.normalise();
1744}
1745
1746
1747void Foam::faMesh::calcPointAreaNormalsByQuadricsFit(vectorField& result) const
1748{
1749 const labelList intPoints(internalPoints());
1750 const labelList bndPoints(boundaryPoints());
1751
1752 const pointField& points = patch().localPoints();
1753 const faceList& faces = patch().localFaces();
1754 const labelListList& pointFaces = patch().pointFaces();
1755
1756 forAll(intPoints, pointI)
1757 {
1758 label curPoint = intPoints[pointI];
1759
1760 const labelHashSet faceSet(pointFaces[curPoint]);
1761 const labelList curFaces(faceSet.toc());
1762
1764
1765 for (const label facei : curFaces)
1766 {
1767 const labelList& facePoints = faces[facei];
1768 pointSet.insert(facePoints);
1769 }
1770 pointSet.erase(curPoint);
1771 labelList curPoints(pointSet.toc());
1772
1773 if (pointSet.size() < 5)
1774 {
1775 DebugInfo
1776 << "WARNING: Extending point set for fitting." << endl;
1777
1778 labelHashSet faceSet(pointFaces[curPoint]);
1779 labelList curFaces(faceSet.toc());
1780 for (const label facei : curFaces)
1781 {
1782 const labelList& curFaceFaces = patch().faceFaces()[facei];
1783 faceSet.insert(curFaceFaces);
1784 }
1785 curFaces = faceSet.toc();
1786
1787 pointSet.clear();
1788
1789 for (const label facei : curFaces)
1790 {
1791 const labelList& facePoints = faces[facei];
1792 pointSet.insert(facePoints);
1793 }
1794 pointSet.erase(curPoint);
1795 curPoints = pointSet.toc();
1796 }
1797
1798 pointField allPoints(curPoints.size());
1799 scalarField W(curPoints.size(), 1.0);
1800 for (label i=0; i<curPoints.size(); ++i)
1801 {
1802 allPoints[i] = points[curPoints[i]];
1803 W[i] = 1.0/magSqr(allPoints[i] - points[curPoint]);
1804 }
1805
1806 // Transform points
1808 (
1809 points[curPoint], // origin
1810 result[curPoint], // axis [e3] (normalized by constructor)
1811 allPoints[0] - points[curPoint] // direction [e1]
1812 );
1813
1814 for (point& p : allPoints)
1815 {
1816 p = cs.localPosition(p);
1817 }
1818
1820 (
1821 allPoints.size(),
1822 5,
1823 0.0
1824 );
1825
1826 for (label i = 0; i < allPoints.size(); ++i)
1827 {
1828 M[i][0] = sqr(allPoints[i].x());
1829 M[i][1] = sqr(allPoints[i].y());
1830 M[i][2] = allPoints[i].x()*allPoints[i].y();
1831 M[i][3] = allPoints[i].x();
1832 M[i][4] = allPoints[i].y();
1833 }
1834
1835 scalarSquareMatrix MtM(5, Zero);
1836
1837 for (label i = 0; i < MtM.n(); ++i)
1838 {
1839 for (label j = 0; j < MtM.m(); ++j)
1840 {
1841 for (label k = 0; k < M.n(); ++k)
1842 {
1843 MtM[i][j] += M[k][i]*M[k][j]*W[k];
1844 }
1845 }
1846 }
1847
1848 scalarField MtR(5, Zero);
1849
1850 for (label i=0; i<MtR.size(); ++i)
1851 {
1852 for (label j=0; j<M.n(); ++j)
1853 {
1854 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1855 }
1856 }
1857
1858 LUsolve(MtM, MtR);
1859
1860 vector curNormal = vector(MtR[3], MtR[4], -1);
1861
1862 curNormal = cs.globalVector(curNormal);
1863
1864 curNormal *= sign(curNormal&result[curPoint]);
1865
1866 result[curPoint] = curNormal;
1867 }
1868
1869
1870 forAll(boundary(), patchI)
1871 {
1872 const faPatch& fap = boundary()[patchI];
1873
1875 {
1876 const processorFaPatch& procPatch =
1878
1879 const labelList& patchPointLabels = procPatch.pointLabels();
1880
1881 labelList toNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1882 vectorField toNgbProcLsPoints
1883 (
1884 10*patchPointLabels.size(),
1885 Zero
1886 );
1887 label nPoints = 0;
1888
1889 for (label pointI=0; pointI<patchPointLabels.size(); ++pointI)
1890 {
1891 label curPoint = patchPointLabels[pointI];
1892
1893 toNgbProcLsPointStarts[pointI] = nPoints;
1894
1895 const labelHashSet faceSet(pointFaces[curPoint]);
1896 const labelList curFaces(faceSet.toc());
1897
1899
1900 for (const label facei : curFaces)
1901 {
1902 const labelList& facePoints = faces[facei];
1903 pointSet.insert(facePoints);
1904 }
1905 pointSet.erase(curPoint);
1906 labelList curPoints = pointSet.toc();
1907
1908 for (label i=0; i<curPoints.size(); ++i)
1909 {
1910 toNgbProcLsPoints[nPoints++] = points[curPoints[i]];
1911 }
1912 }
1913
1914 toNgbProcLsPoints.setSize(nPoints);
1915
1916 {
1917 OPstream toNeighbProc
1918 (
1920 procPatch.neighbProcNo(),
1921 toNgbProcLsPoints.size_bytes()
1922 + toNgbProcLsPointStarts.size_bytes()
1923 + 10*sizeof(label)
1924 );
1925
1926 toNeighbProc
1927 << toNgbProcLsPoints
1928 << toNgbProcLsPointStarts;
1929 }
1930 }
1931 }
1932
1933 for (const faPatch& fap : boundary())
1934 {
1936 {
1937 const processorFaPatch& procPatch =
1939
1940 const labelList& patchPointLabels = procPatch.pointLabels();
1941
1942 labelList fromNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1943 vectorField fromNgbProcLsPoints;
1944
1945 {
1946 IPstream fromNeighbProc
1947 (
1949 procPatch.neighbProcNo(),
1950 10*patchPointLabels.size()*sizeof(vector)
1951 + fromNgbProcLsPointStarts.size_bytes()
1952 + 10*sizeof(label)
1953 );
1954
1955 fromNeighbProc
1956 >> fromNgbProcLsPoints
1957 >> fromNgbProcLsPointStarts;
1958 }
1959
1960 const labelList& nonGlobalPatchPoints =
1961 procPatch.nonGlobalPatchPoints();
1962
1963 forAll(nonGlobalPatchPoints, pointI)
1964 {
1965 label curPoint =
1966 patchPointLabels[nonGlobalPatchPoints[pointI]];
1967 label curNgbPoint =
1968 procPatch.neighbPoints()[nonGlobalPatchPoints[pointI]];
1969
1971 faceSet.insert(pointFaces[curPoint]);
1972
1973 labelList curFaces = faceSet.toc();
1974
1976
1977 for (const label facei : curFaces)
1978 {
1979 const labelList& facePoints = faces[facei];
1980 pointSet.insert(facePoints);
1981 }
1982 pointSet.erase(curPoint);
1983 labelList curPoints = pointSet.toc();
1984
1985 label nAllPoints = curPoints.size();
1986
1987 if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
1988 {
1989 nAllPoints +=
1990 fromNgbProcLsPoints.size()
1991 - fromNgbProcLsPointStarts[curNgbPoint];
1992 }
1993 else
1994 {
1995 nAllPoints +=
1996 fromNgbProcLsPointStarts[curNgbPoint + 1]
1997 - fromNgbProcLsPointStarts[curNgbPoint];
1998 }
1999
2000 vectorField allPointsExt(nAllPoints);
2001 label counter = 0;
2002 for (label i=0; i<curPoints.size(); ++i)
2003 {
2004 allPointsExt[counter++] = points[curPoints[i]];
2005 }
2006
2007 if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
2008 {
2009 for
2010 (
2011 label i=fromNgbProcLsPointStarts[curNgbPoint];
2012 i<fromNgbProcLsPoints.size();
2013 ++i
2014 )
2015 {
2016 allPointsExt[counter++] = fromNgbProcLsPoints[i];
2017 }
2018 }
2019 else
2020 {
2021 for
2022 (
2023 label i=fromNgbProcLsPointStarts[curNgbPoint];
2024 i<fromNgbProcLsPointStarts[curNgbPoint+1];
2025 ++i
2026 )
2027 {
2028 allPointsExt[counter++] = fromNgbProcLsPoints[i];
2029 }
2030 }
2031
2032 // Remove duplicate points
2033 vectorField allPoints(nAllPoints, Zero);
2034 const scalar tol = 0.001*treeBoundBox(allPointsExt).mag();
2035
2036 nAllPoints = 0;
2037 for (const point& pt : allPointsExt)
2038 {
2039 bool duplicate = false;
2040 for (label i = 0; i < nAllPoints; ++i)
2041 {
2042 if (pt.dist(allPoints[i]) < tol)
2043 {
2044 duplicate = true;
2045 break;
2046 }
2047 }
2048
2049 if (!duplicate)
2050 {
2051 allPoints[nAllPoints++] = pt;
2052 }
2053 }
2054
2055 allPoints.setSize(nAllPoints);
2056
2057 if (nAllPoints < 5)
2058 {
2060 << "There are no enough points for quadrics "
2061 << "fitting for a point at processor patch"
2062 << abort(FatalError);
2063 }
2064
2065 // Transform points
2066 const vector& origin = points[curPoint];
2067 const vector axis = normalised(result[curPoint]);
2068 vector dir(allPoints[0] - points[curPoint]);
2069 dir.removeCollinear(axis);
2070 dir.normalise();
2071
2072 const coordinateSystem cs("cs", origin, axis, dir);
2073
2074 scalarField W(allPoints.size(), 1.0);
2075
2076 forAll(allPoints, pI)
2077 {
2078 W[pI] = 1.0/magSqr(allPoints[pI] - points[curPoint]);
2079
2080 allPoints[pI] = cs.localPosition(allPoints[pI]);
2081 }
2082
2084 (
2085 allPoints.size(),
2086 5,
2087 0.0
2088 );
2089
2090 for (label i=0; i<allPoints.size(); ++i)
2091 {
2092 M[i][0] = sqr(allPoints[i].x());
2093 M[i][1] = sqr(allPoints[i].y());
2094 M[i][2] = allPoints[i].x()*allPoints[i].y();
2095 M[i][3] = allPoints[i].x();
2096 M[i][4] = allPoints[i].y();
2097 }
2098
2099 scalarSquareMatrix MtM(5, Zero);
2100
2101 for (label i = 0; i < MtM.n(); ++i)
2102 {
2103 for (label j = 0; j < MtM.m(); ++j)
2104 {
2105 for (label k = 0; k < M.n(); ++k)
2106 {
2107 MtM[i][j] += M[k][i]*M[k][j]*W[k];
2108 }
2109 }
2110 }
2111
2112 scalarField MtR(5, Zero);
2113
2114 for (label i = 0; i < MtR.size(); ++i)
2115 {
2116 for (label j = 0; j < M.n(); ++j)
2117 {
2118 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
2119 }
2120 }
2121
2122 LUsolve(MtM, MtR);
2123
2124 vector curNormal = vector(MtR[3], MtR[4], -1);
2125
2126 curNormal = cs.globalVector(curNormal);
2127
2128 curNormal *= sign(curNormal&result[curPoint]);
2129
2130 result[curPoint] = curNormal;
2131 }
2132 }
2133 }
2134
2135 // Correct global points
2136 if (globalData().nGlobalPoints() > 0)
2137 {
2138 const labelList& spLabels = globalData().sharedPointLabels();
2139
2140 const labelList& addr = globalData().sharedPointAddr();
2141
2142 for (label k=0; k<globalData().nGlobalPoints(); ++k)
2143 {
2144 List<List<vector>> procLsPoints(Pstream::nProcs());
2145
2146 const label curSharedPointIndex = addr.find(k);
2147
2148 scalar tol = 0.0;
2149
2150 if (curSharedPointIndex != -1)
2151 {
2152 label curPoint = spLabels[curSharedPointIndex];
2153
2154 const labelHashSet faceSet(pointFaces[curPoint]);
2155 const labelList curFaces(faceSet.toc());
2156
2158 for (const label facei : curFaces)
2159 {
2160 const labelList& facePoints = faces[facei];
2161 pointSet.insert(facePoints);
2162 }
2163 pointSet.erase(curPoint);
2164 labelList curPoints = pointSet.toc();
2165
2166 vectorField locPoints(points, curPoints);
2167
2168 procLsPoints[Pstream::myProcNo()] = locPoints;
2169
2170 tol = 0.001*treeBoundBox(locPoints).mag();
2171 }
2172
2173 Pstream::allGatherList(procLsPoints);
2174
2175 if (curSharedPointIndex != -1)
2176 {
2177 label curPoint = spLabels[curSharedPointIndex];
2178
2179 label nAllPoints = 0;
2180 forAll(procLsPoints, procI)
2181 {
2182 nAllPoints += procLsPoints[procI].size();
2183 }
2184
2185 vectorField allPoints(nAllPoints, Zero);
2186
2187 nAllPoints = 0;
2188 forAll(procLsPoints, procI)
2189 {
2190 forAll(procLsPoints[procI], pointI)
2191 {
2192 bool duplicate = false;
2193 for (label i=0; i<nAllPoints; ++i)
2194 {
2195 if
2196 (
2197 mag
2198 (
2199 allPoints[i]
2200 - procLsPoints[procI][pointI]
2201 )
2202 < tol
2203 )
2204 {
2205 duplicate = true;
2206 break;
2207 }
2208 }
2209
2210 if (!duplicate)
2211 {
2212 allPoints[nAllPoints++] =
2213 procLsPoints[procI][pointI];
2214 }
2215 }
2216 }
2217
2218 allPoints.setSize(nAllPoints);
2219
2220 if (nAllPoints < 5)
2221 {
2223 << "There are no enough points for quadratic "
2224 << "fitting for a global processor point "
2225 << abort(FatalError);
2226 }
2227
2228 // Transform points
2229 const vector& origin = points[curPoint];
2230 const vector axis = normalised(result[curPoint]);
2231 vector dir(allPoints[0] - points[curPoint]);
2232 dir.removeCollinear(axis);
2233 dir.normalise();
2234
2235 coordinateSystem cs("cs", origin, axis, dir);
2236
2237 scalarField W(allPoints.size(), 1.0);
2238
2239 forAll(allPoints, pointI)
2240 {
2241 W[pointI]=
2242 1.0/magSqr(allPoints[pointI] - points[curPoint]);
2243
2244 allPoints[pointI] = cs.localPosition(allPoints[pointI]);
2245 }
2246
2248 (
2249 allPoints.size(),
2250 5,
2251 0.0
2252 );
2253
2254 for (label i=0; i<allPoints.size(); ++i)
2255 {
2256 M[i][0] = sqr(allPoints[i].x());
2257 M[i][1] = sqr(allPoints[i].y());
2258 M[i][2] = allPoints[i].x()*allPoints[i].y();
2259 M[i][3] = allPoints[i].x();
2260 M[i][4] = allPoints[i].y();
2261 }
2262
2263 scalarSquareMatrix MtM(5, Zero);
2264 for (label i = 0; i < MtM.n(); ++i)
2265 {
2266 for (label j = 0; j < MtM.m(); ++j)
2267 {
2268 for (label k = 0; k < M.n(); ++k)
2269 {
2270 MtM[i][j] += M[k][i]*M[k][j]*W[k];
2271 }
2272 }
2273 }
2274
2275 scalarField MtR(5, Zero);
2276 for (label i = 0; i < MtR.size(); ++i)
2277 {
2278 for (label j = 0; j < M.n(); ++j)
2279 {
2280 MtR[i] += M[j][i]*allPoints[j].z()*W[j];
2281 }
2282 }
2283
2284 LUsolve(MtM, MtR);
2285
2286 vector curNormal = vector(MtR[3], MtR[4], -1);
2287
2288 curNormal = cs.globalVector(curNormal);
2289
2290 curNormal *= sign(curNormal&result[curPoint]);
2291
2292 result[curPoint] = curNormal;
2293 }
2294 }
2295 }
2296
2297 for (vector& n : result)
2298 {
2299 n.normalise();
2301}
2302
2303
2305{
2307 << "Calculating edge length correction" << endl;
2308
2309 auto tcorrection = tmp<edgeScalarField>::New
2310 (
2311 IOobject
2312 (
2313 "edgeLengthCorrection",
2314 mesh().pointsInstance(),
2320 ),
2321 *this,
2322 dimless
2323 );
2324 auto& correction = tcorrection.ref();
2325
2326 const vectorField& pointNormals = pointAreaNormals();
2327
2328 const auto angleCorrection =
2329 [](const vector& a, const vector& b) -> scalar
2330 {
2331 return Foam::cos(0.5*Foam::asin(Foam::mag(a ^ b)));
2332 };
2333
2334
2335 // Internal
2336 {
2337 auto& fld = correction.primitiveFieldRef();
2338
2339 forAll(fld, edgei)
2340 {
2341 fld[edgei] = angleCorrection
2342 (
2343 pointNormals[edges_[edgei].start()],
2344 pointNormals[edges_[edgei].end()]
2345 );
2346 }
2347 }
2348
2349 // Boundary
2350 {
2351 auto& bfld = correction.boundaryFieldRef();
2352
2353 forAll(boundary(), patchi)
2354 {
2355 const faPatch& fap = boundary()[patchi];
2356 scalarField& pfld = bfld[patchi];
2357
2358 label edgei = fap.start();
2359
2360 forAll(pfld, patchEdgei)
2361 {
2362 pfld[patchEdgei] = angleCorrection
2363 (
2364 pointNormals[edges_[edgei].start()],
2365 pointNormals[edges_[edgei].end()]
2366 );
2367
2368 ++edgei;
2369 }
2370 }
2371 }
2372
2373 return tcorrection;
2374}
2375
2376
2378{
2379 auto tunitVectors = tmp<edgeVectorField>::New
2380 (
2381 IOobject
2382 (
2383 "unit(Le)",
2384 mesh().pointsInstance(),
2390 ),
2391 *this,
2392 dimless,
2393 (this->Le() / this->magLe())
2394 );
2395
2396 // The above is not quite correct when a min-length limiter
2397 // has been imposed on both Le() and magLe() fields
2398
2399 // tunitVectors.ref().oriented() = this->Le().oriented();
2400 return tunitVectors;
2401}
2402
2403
2404// ************************************************************************* //
scalar y
label k
#define M(I)
label n
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
Info<< " "<< writer.output().name()<< nl;}{ const Field< vector > edgeCentres(faMeshTools::flattenEdgeField(aMesh.edgeCentres(), true))
labelList faceLabels(nFaceLabels)
const polyBoundaryMesh & pbm
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
Generic templated field type that is much like a Foam::List except that it is expected to hold numeri...
Definition Field.H:172
void normalise()
Inplace normalise this field. Generally a no-op except for vector fields.
Definition Field.C:600
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition HashTable.C:141
label size() const noexcept
The number of elements in table.
Definition HashTable.H:358
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition HashTable.C:489
void clear()
Remove all entries from table.
Definition HashTable.C:742
@ NO_REGISTER
Do not request registration (bool: false).
@ NO_READ
Nothing to be read.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
Input inter-processor communications stream.
Definition IPstream.H:53
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
SubList< vector > subList
Definition List.H:129
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
Output inter-processor communications stream.
Definition OPstream.H:53
static void combineReduce(T &value, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors.
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
static const Tensor I
Definition Tensor.H:81
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr)
Receive buffer contents (contiguous types) from given processor.
A List with indirect addressing. Like IndirectList but does not store addressing.
T & first()
Access first element of the list, position [0].
Definition UList.H:957
SubList< T > slice(const label pos, label len=-1)
Return SubList slice (non-const access) - no range checking.
Definition SubList.H:258
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents (contiguous types only) to given processor.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
@ buffered
"buffered" : (MPI_Bsend, MPI_Recv)
Definition UPstream.H:82
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static int & msgType() noexcept
Message tag of standard messages.
Definition UPstream.H:1926
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
Definition UPstream.H:1697
static void waitRequests()
Wait for all requests to finish.
Definition UPstream.H:2497
static Form uniform(const Cmpt &s)
Return a VectorSpace with all elements = s.
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition VectorI.H:114
Vector< Cmpt > & removeCollinear(const Vector< Cmpt > &unitVec)
Inplace removal of components that are collinear to the given unit vector.
Definition VectorI.H:136
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
void flip()
Invert all bits in the addressable region.
Definition bitSetI.H:546
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition bitSetI.H:441
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
scalar mag() const
The magnitude/length of the bounding box diagonal.
Definition boundBoxI.H:198
A Cartesian coordinate system.
Definition cartesianCS.H:68
Base class for coordinate system specification, the default coordinate system type is cartesian .
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
labelList internalPoints() const
Return internal point labels.
virtual const objectRegistry & thisDb() const
Reference to the mesh database.
Definition faMesh.H:1209
static int geometryOrder() noexcept
Return the current geometry treatment.
Definition faMesh.H:944
tmp< edgeVectorField > unitLe() const
Return normalised edge length vectors.
const uindirectPrimitivePatch & patch() const
Return constant reference to primitive patch.
Definition faMeshI.H:102
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition faMesh.C:1034
tmp< edgeScalarField > edgeLengthCorrection() const
Return edge length correction.
const vectorField & pointAreaNormals() const
Return point area normals.
Definition faMesh.C:1211
static word meshSubDir
The mesh sub-directory name (usually "faMesh").
Definition faMesh.H:750
labelList boundaryPoints() const
Return boundary point labels.
Finite area patch class. Used for 2-D non-Euclidian finite area method.
Definition faPatch.H:76
label start() const
Patch start in edge list.
Definition faPatch.C:191
A list of face labels.
Definition faceSet.H:50
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
A line primitive.
Definition line.H:180
PointRef a() const noexcept
The first point.
Definition line.H:227
Point centre() const
Return centre (centroid).
Definition lineI.H:83
scalar mag() const
The magnitude (length) of the line.
Definition lineI.H:96
Point unitVec() const
Return the unit vector (start-to-end).
Definition lineI.H:135
PointRef b() const noexcept
The second point.
Definition line.H:232
Point vec() const
Return start-to-end vector.
Definition lineI.H:122
A set of point labels.
Definition pointSet.H:50
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
labelPair whichPatchFace(const label meshFacei) const
Lookup mesh face index and return (patchi, patchFacei) tuple or (-1, meshFacei) for internal faces.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
Skew-correction vectors for the skewness-corrected interpolation scheme.
A class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
Standard boundBox with extra functionality for use in octree.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
volScalarField & p
faceListList boundary
bool coupled
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
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))
word timeName
Definition getTimeIndex.H:3
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugInFunction
Report an information message using Foam::Info.
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
const char * end
Definition SVGTools.H:223
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.
static vector calcLeVector(const point &faceCentre, const linePointRef &edgeLine, const vector &edgeNormal)
Calculate the 'Le' vector from faceCentre to edge centre.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
dimensionedScalar asin(const dimensionedScalar &ds)
GeometricField< vector, faePatchField, edgeMesh > edgeVectorField
const dimensionSet dimless
Dimensionless.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
static void imposeMinVectorLength(vectorField &fld)
dimensionedScalar sign(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition List.H:62
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.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
static vector areaInvDistSqrWeightedNormalFaceTriangle(const linePointRef &edgeLine, const point &faceCentre)
const dimensionSet dimArea(sqr(dimLength))
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
List< face > faceList
List of faces.
Definition faceListFwd.H:41
static vector areaInvDistSqrWeightedNormalDualEdge(const point &basePoint, const point &rightPoint, const point &leftPoint, const point &centrePoint)
Tensor< scalar > tensor
Definition symmTensor.H:57
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
static Foam::bitSet markupBoundaryPoints(const uindirectPrimitivePatch &p)
GeometricField< vector, faPatchField, areaMesh > areaVectorField
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
line< point, const point & > linePointRef
A line using referred points.
Definition line.H:66
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
static tensor rotation_e3e1(const vector &unitAxis1, vector dirn)
errorManip< error > abort(error &err)
Definition errorManip.H:139
Field< vector > vectorField
Specialisation of Field<T> for vector.
SquareMatrix< scalar > scalarSquareMatrix
vector point
Point is a vector.
Definition point.H:37
static vector areaNormalFaceTriangle(const linePointRef &edgeLine, const point &faceCentre)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
void LUsolve(scalarSquareMatrix &matrix, List< Type > &source)
Solve the matrix using LU decomposition with pivoting returning the LU form of the matrix and the sol...
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
UList< label > labelUList
A UList of labels.
Definition UList.H:75
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:50
labelList f(nPoints)
volScalarField & b
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
const Vector< label > N(dict.get< Vector< label > >("N"))