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 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "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"
37 #include "processorFaPatchFields.H"
38 #include "emptyFaPatchFields.H"
39 #include "wedgeFaPatch.H"
40 #include "triangle.H"
41 
42 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
43 
44 namespace 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;
75 }
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
133  )
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
140 static 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 
154 namespace Foam
155 {
156 
157 // Calculate transform tensor with reference vector (unitAxis1)
158 // and direction vector (axis2).
159 //
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
166 static 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 
189 namespace 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 
213 void 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 
229 void 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 
245 void 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 
255  const polyBoundaryMesh& pbm = mesh().boundaryMesh();
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,
276  bitOrOp<labelHashSet>(),
278  this->comm()
279  );
280 
281  polyPatchIdsPtr_ = std::make_unique<labelList>(ids.sortedToc());
282 }
283 
284 
285 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
286 
287 namespace 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
294 static 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 
337 namespace Foam
338 {
339 
340 // Impose a minimum (edge) vector length
341 // - disallow any mag(vec) < SMALL
342 static 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 
365 Foam::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  {
485  DynamicList<UPstream::Request> requests
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  (
540  transform
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 
666 void 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  (
680  IOobject
681  (
682  "Le",
683  mesh().pointsInstance(),
685  faMesh::thisDb(),
689  ),
690  *this,
691  dimLength
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  {
758  imposeMinVectorLength(pfld);
759  }
760 }
761 
762 
763 void 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  (
777  IOobject
778  (
779  "magLe",
780  mesh().pointsInstance(),
782  faMesh::thisDb(),
786  ),
787  *this,
788  dimLength
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 
837 void 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  (
851  IOobject
852  (
853  "centres",
854  mesh().pointsInstance(),
856  faMesh::thisDb(),
860  ),
861  *this,
862  dimLength
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 
917 void 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  (
931  IOobject
932  (
933  "edgeCentres",
934  mesh().pointsInstance(),
936  faMesh::thisDb(),
940  ),
941  *this,
942  dimLength
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 
980 void 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  (
994  IOobject
995  (
996  "S",
997  time().timeName(),
998  faMesh::thisDb(),
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 
1052 void 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(),
1071  faMesh::thisDb(),
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 
1131 void 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(),
1150  faMesh::thisDb(),
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 
1254  imposeMinVectorLength(pfld);
1255  }
1256  }
1257 }
1258 
1259 
1260 void 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(),
1279  faMesh::thisDb(),
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 
1300 void 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  }
1454  }
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 
1507 void 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 
1668  Pstream::combineReduce(gpNormals, plusEqOp<vectorField>());
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 
1747 void 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 
1763  labelHashSet pointSet;
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
1807  coordSystem::cartesian cs
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 
1874  if (Pstream::parRun() && isA<processorFaPatch>(fap))
1875  {
1876  const processorFaPatch& procPatch =
1877  refCast<const processorFaPatch>(boundary()[patchI]);
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 
1898  labelHashSet pointSet;
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  {
1935  if (Pstream::parRun() && isA<processorFaPatch>(fap))
1936  {
1937  const processorFaPatch& procPatch =
1938  refCast<const processorFaPatch>(fap);
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 
1970  labelHashSet faceSet;
1971  faceSet.insert(pointFaces[curPoint]);
1972 
1973  labelList curFaces = faceSet.toc();
1974 
1975  labelHashSet pointSet;
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 
2157  labelHashSet pointSet;
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();
2300  }
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(),
2316  faMesh::thisDb(),
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(),
2386  faMesh::thisDb(),
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 // ************************************************************************* //
faceListList boundary
dimensionedScalar sign(const dimensionedScalar &ds)
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
labelList internalPoints() const
Return internal point labels.
Point unitVec() const
Return the unit vector (start-to-end)
Definition: lineI.H:122
const polyBoundaryMesh & pbm
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A line primitive.
Definition: line.H:52
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:498
tmp< edgeScalarField > edgeLengthCorrection() const
Return edge length correction.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
scalar mag() const
The magnitude (length) of the line.
Definition: lineI.H:96
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
dimensionedTensor skew(const dimensionedTensor &dt)
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition: bitSetI.H:441
Tensor< scalar > tensor
Definition: symmTensor.H:57
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
labelPair whichPatchFace(const label meshFacei) const
Lookup mesh face index and return (patchi, patchFacei) tuple or (-1, meshFacei) for internal faces...
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1252
SubList< vector > subList
Declare type of subList.
Definition: List.H:144
static vector areaInvDistSqrWeightedNormalFaceTriangle(const linePointRef &edgeLine, const point &faceCentre)
label k
Boltzmann constant.
Ignore writing from objectRegistry::writeObject()
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
const dimensionSet dimless
Dimensionless.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
labelList faceLabels(nFaceLabels)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Namespace of functions to calculate explicit derivatives.
static vector areaNormalFaceTriangle(const linePointRef &edgeLine, const point &faceCentre)
dimensionedScalar asin(const dimensionedScalar &ds)
static void waitRequests()
Wait for all requests to finish.
Definition: UPstream.H:1561
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
static void imposeMinVectorLength(vectorField &fld)
virtual const objectRegistry & thisDb() const
Reference to the mesh database.
Definition: faMesh.H:1203
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static int geometryOrder() noexcept
Return the current geometry treatment.
Definition: faMesh.H:944
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
word timeName
Definition: getTimeIndex.H:3
scalar y
A list of faces which address into the list of points.
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:1077
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
dimensionedScalar cos(const dimensionedScalar &ds)
line< point, const point & > linePointRef
A line using referred points.
Definition: line.H:66
const pointField & points
SubList< T > slice(const label pos, label len=-1)
Return SubList slice (non-const access) - no range checking.
Definition: SubList.H:250
static const Identity< scalar > I
Definition: Identity.H:100
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:59
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Info<< nl<< "Wrote faMesh in vtk format: "<< writer.output().name()<< nl;}{ const Field< vector > edgeCentres(faMeshTools::flattenEdgeField(aMesh.edgeCentres(), true))
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
static void combineReduce(T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
GeometricField< vector, faePatchField, edgeMesh > edgeVectorField
Definition: edgeFieldsFwd.H:60
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
PointRef a() const noexcept
The first point.
Definition: line.H:222
Vector< scalar > vector
Definition: vector.H:57
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
Definition: edgeFieldsFwd.H:43
PointRef b() const noexcept
The second point.
Definition: line.H:227
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
#define DebugInfo
Report an information message using Foam::Info.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
static Foam::bitSet markupBoundaryPoints(const uindirectPrimitivePatch &p)
labelList f(nPoints)
bool hasFaceAreas() const noexcept
tmp< GeometricField< Type, faPatchField, areaMesh > > edgeIntegrate(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
const Vector< label > N(dict.get< Vector< label >>("N"))
Point centre() const
Return centre (centroid)
Definition: lineI.H:83
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;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Point vec() const
Return start-to-end vector.
Definition: lineI.H:109
const vectorField & faceCentres() const
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual linear/tree communicat...
labelList boundaryPoints() const
Return boundary point labels.
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:750
vector point
Point is a vector.
Definition: point.H:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
static vector calcLeVector(const point &faceCentre, const linePointRef &edgeLine, const vector &edgeNormal)
Calculate the &#39;Le&#39; vector from faceCentre to edge centre.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
const vectorField & faceAreas() const
Nothing to be read.
const std::string patch
OpenFOAM patch number as a std::string.
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents to given processor.
label n
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
"buffered" : (MPI_Bsend, MPI_Recv)
bool coupled
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))
Vector< Cmpt > & removeCollinear(const Vector< Cmpt > &unitVec)
Inplace removal of components that are collinear to the given unit vector.
Definition: VectorI.H:136
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Tensor of scalars, i.e. Tensor<scalar>.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
tmp< edgeVectorField > unitLe() const
Return normalised edge length vectors.
SquareMatrix< scalar > scalarSquareMatrix
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:76
static vector areaInvDistSqrWeightedNormalDualEdge(const point &basePoint, const point &rightPoint, const point &leftPoint, const point &centrePoint)
#define M(I)
Do not request registration (bool: false)
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
static tensor rotation_e3e1(const vector &unitAxis1, vector dirn)
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:57
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
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...
RectangularMatrix< scalar > scalarRectangularMatrix
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm, UPstream::Request *req=nullptr)
Read buffer contents from given processor.
Definition: UIPstreamRead.C:35
vector areaNormal() const
The area normal - with magnitude equal to area of triangle.
Definition: triangleI.H:180
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
Definition: areaFieldsFwd.H:72
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
static vector areaInvDistSqrWeightedNormal(const vector &a, const vector &b)