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-2021 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 "primitiveFacePatch.H"
34 #include "fac.H"
35 #include "processorFaPatch.H"
36 #include "wedgeFaPatch.H"
38 #include "cartesianCS.H"
39 #include "scalarMatrices.H"
40 #include "processorFaPatchFields.H"
41 #include "emptyFaPatchFields.H"
42 
43 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47 
48 // Define an area-weighted normal for three points (defining a triangle)
49 // (p0, p1, p2) are the base, first, second points respectively
50 //
51 // From the original Tukovic code:
52 //
53 // vector n = (d1^d2)/mag(d1^d2);
54 // scalar sinAlpha = mag(d1^d2)/(mag(d1)*mag(d2));
55 // scalar w = sinAlpha/(mag(d1)*mag(d2));
56 //
57 // ie, normal weighted by area, sine angle and inverse distance squared.
58 // - area : larger weight for larger areas
59 // - sin : lower weight for narrow angles (eg, shards)
60 // - inv distance squared : lower weights for distant points
61 //
62 // The above refactored, with 0.5 for area:
63 //
64 // (d1 ^ d2) / (2 * magSqr(d1) * magSqr(d2))
65 
67 (
68  const vector& a,
69  const vector& b
70 )
71 {
72  const scalar s(2*magSqr(a)*magSqr(b));
73 
74  return s < VSMALL ? 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 } // End namespace Foam
108 
109 
110 namespace Foam
111 {
112 
113 // A bitSet (size patch nPoints()) with boundary points marked
115 {
116  // Initially all unmarked
117  bitSet markPoints(p.nPoints());
118  for (const edge& e : p.boundaryEdges())
119  {
120  // Mark boundary points
121  markPoints.set(e.first());
122  markPoints.set(e.second());
123  }
124 
125  return markPoints;
126 }
127 
128 
129 } // End namespace Foam
130 
131 
132 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
133 
134 void Foam::faMesh::calcLduAddressing() const
135 {
137  << "Calculating addressing" << endl;
138 
139  if (lduPtr_)
140  {
142  << "lduPtr_ already allocated"
143  << abort(FatalError);
144  }
145 
146  lduPtr_ = new faMeshLduAddressing(*this);
147 }
148 
149 
150 void Foam::faMesh::calcPatchStarts() const
151 {
153  << "Calculating patch starts" << endl;
154 
155  if (patchStartsPtr_)
156  {
158  << "patchStartsPtr_ already allocated"
159  << abort(FatalError);
160  }
161 
162  patchStartsPtr_ = new labelList(boundary().patchStarts());
163 }
164 
165 
166 void Foam::faMesh::calcLe() const
167 {
169  << "Calculating local edges" << endl;
170 
171  if (LePtr_)
172  {
174  << "LePtr_ already allocated"
175  << abort(FatalError);
176  }
177 
178  LePtr_ =
179  new edgeVectorField
180  (
181  IOobject
182  (
183  "Le",
184  mesh().pointsInstance(),
185  meshSubDir,
186  mesh()
187  ),
188  *this,
189  dimLength
190  );
191 
192  edgeVectorField& Le = *LePtr_;
193 
194 
195  const pointField& pPoints = points();
196  const edgeList& pEdges = edges();
197 
198  const edgeVectorField& eCentres = edgeCentres();
199  const areaVectorField& fCentres = areaCentres();
200 
201  const edgeVectorField& edgeNormals = edgeAreaNormals();
202 
203  vectorField& leInternal = Le.ref();
204  const vectorField& edgeNormalsInternal = edgeNormals.internalField();
205  const vectorField& fCentresInternal = fCentres.internalField();
206  const vectorField& eCentresInternal = eCentres.internalField();
207  const scalarField& magLeInternal = magLe().internalField();
208 
209  forAll(leInternal, edgeI)
210  {
211  leInternal[edgeI] =
212  pEdges[edgeI].vec(pPoints) ^ edgeNormalsInternal[edgeI];
213 
214  leInternal[edgeI] *=
215  - sign
216  (
217  leInternal[edgeI] &
218  (
219  fCentresInternal[owner()[edgeI]]
220  - eCentresInternal[edgeI]
221  )
222  );
223 
224  leInternal[edgeI] *=
225  magLeInternal[edgeI]/mag(leInternal[edgeI]);
226  }
227 
228  forAll(boundary(), patchI)
229  {
230  const labelUList& bndEdgeFaces = boundary()[patchI].edgeFaces();
231 
232  const edgeList::subList bndEdges =
233  boundary()[patchI].patchSlice(pEdges);
234 
235  const vectorField& bndEdgeNormals =
236  edgeNormals.boundaryField()[patchI];
237 
238  vectorField& patchLe = Le.boundaryFieldRef()[patchI];
239  const vectorField& patchECentres = eCentres.boundaryField()[patchI];
240 
241  forAll(patchLe, edgeI)
242  {
243  patchLe[edgeI] =
244  bndEdges[edgeI].vec(pPoints) ^ bndEdgeNormals[edgeI];
245 
246  patchLe[edgeI] *=
247  - sign
248  (
249  patchLe[edgeI]&
250  (
251  fCentresInternal[bndEdgeFaces[edgeI]]
252  - patchECentres[edgeI]
253  )
254  );
255 
256  patchLe[edgeI] *=
257  magLe().boundaryField()[patchI][edgeI]
258  /mag(patchLe[edgeI]);
259  }
260  }
261 }
262 
263 
264 void Foam::faMesh::calcMagLe() const
265 {
267  << "Calculating local edge magnitudes" << endl;
268 
269  if (magLePtr_)
270  {
272  << "magLePtr_ already allocated"
273  << abort(FatalError);
274  }
275 
276  magLePtr_ =
277  new edgeScalarField
278  (
279  IOobject
280  (
281  "magLe",
282  mesh().pointsInstance(),
283  meshSubDir,
284  mesh()
285  ),
286  *this,
287  dimLength
288  );
289 
290  edgeScalarField& magLe = *magLePtr_;
291 
292  const pointField& localPoints = points();
293 
294  label edgei = 0;
295  for (const edge& e : patch().internalEdges())
296  {
297  magLe.ref()[edgei] = e.mag(localPoints);
298  ++edgei;
299  }
300 
301 
302  forAll(boundary(), patchI)
303  {
304  const edgeList::subList patchEdges =
305  boundary()[patchI].patchSlice(edges());
306 
307  forAll(patchEdges, edgeI)
308  {
309  magLe.boundaryFieldRef()[patchI][edgeI] =
310  patchEdges[edgeI].mag(localPoints);
311  }
312  }
313 }
314 
315 
316 void Foam::faMesh::calcAreaCentres() const
317 {
319  << "Calculating face centres" << endl;
320 
321  if (centresPtr_)
322  {
324  << "centresPtr_ already allocated"
325  << abort(FatalError);
326  }
327 
328  centresPtr_ =
329  new areaVectorField
330  (
331  IOobject
332  (
333  "centres",
334  mesh().pointsInstance(),
335  meshSubDir,
336  mesh()
337  ),
338  *this,
339  dimLength
340  );
341 
342  areaVectorField& centres = *centresPtr_;
343 
344  const pointField& localPoints = points();
345  const faceList& localFaces = faces();
346 
347  forAll(localFaces, faceI)
348  {
349  centres.ref()[faceI] = localFaces[faceI].centre(localPoints);
350  }
351 
352  forAll(boundary(), patchI)
353  {
354  const edgeList::subList patchEdges =
355  boundary()[patchI].patchSlice(edges());
356 
357  forAll(patchEdges, edgeI)
358  {
359  centres.boundaryFieldRef()[patchI][edgeI] =
360  patchEdges[edgeI].centre(localPoints);
361  }
362  }
363 
364  forAll(centres.boundaryField(), patchI)
365  {
366  //HJ: this is wrong! 5/Aug/2011
367  if
368  (
369  isA<processorFaPatchVectorField>
370  (
371  centres.boundaryField()[patchI]
372  )
373  )
374  {
375  centres.boundaryFieldRef()[patchI].initEvaluate();
376  centres.boundaryFieldRef()[patchI].evaluate();
377  }
378  }
379 }
380 
381 
382 void Foam::faMesh::calcEdgeCentres() const
383 {
385  << "Calculating edge centres" << endl;
386 
387  if (edgeCentresPtr_)
388  {
390  << "edgeCentresPtr_ already allocated"
391  << abort(FatalError);
392  }
393 
394  edgeCentresPtr_ =
395  new edgeVectorField
396  (
397  IOobject
398  (
399  "edgeCentres",
400  mesh().pointsInstance(),
401  meshSubDir,
402  mesh()
403  ),
404  *this,
405  dimLength
406  );
407 
408  edgeVectorField& edgeCentres = *edgeCentresPtr_;
409 
410  const pointField& localPoints = points();
411 
412 
413  label edgei = 0;
414  for (const edge& e : patch().internalEdges())
415  {
416  edgeCentres.ref()[edgei] = e.centre(localPoints);
417  ++edgei;
418  }
419 
420 
421  forAll(boundary(), patchI)
422  {
423  const edgeList::subList patchEdges =
424  boundary()[patchI].patchSlice(edges());
425 
426  forAll(patchEdges, edgeI)
427  {
428  edgeCentres.boundaryFieldRef()[patchI][edgeI] =
429  patchEdges[edgeI].centre(localPoints);
430  }
431  }
432 }
433 
434 
435 void Foam::faMesh::calcS() const
436 {
438  << "Calculating areas" << endl;
439 
440  if (SPtr_)
441  {
443  << "SPtr_ already allocated"
444  << abort(FatalError);
445  }
446 
447  SPtr_ = new DimensionedField<scalar, areaMesh>
448  (
449  IOobject
450  (
451  "S",
452  time().timeName(),
453  mesh(),
456  ),
457  *this,
458  dimArea
459  );
460  DimensionedField<scalar, areaMesh>& S = *SPtr_;
461 
462  const pointField& localPoints = points();
463  const faceList& localFaces = faces();
464 
465  forAll(S, faceI)
466  {
467  S[faceI] = localFaces[faceI].mag(localPoints);
468  }
469 }
470 
471 
472 void Foam::faMesh::calcFaceAreaNormals() const
473 {
475  << "Calculating face area normals" << endl;
476 
477  if (faceAreaNormalsPtr_)
478  {
480  << "faceAreaNormalsPtr_ already allocated"
481  << abort(FatalError);
482  }
483 
484  faceAreaNormalsPtr_ =
485  new areaVectorField
486  (
487  IOobject
488  (
489  "faceAreaNormals",
490  mesh().pointsInstance(),
491  meshSubDir,
492  mesh()
493  ),
494  *this,
495  dimless
496  );
497 
498  areaVectorField& faceAreaNormals = *faceAreaNormalsPtr_;
499 
500  const pointField& localPoints = points();
501  const faceList& localFaces = faces();
502 
503  vectorField& nInternal = faceAreaNormals.ref();
504  forAll(localFaces, faceI)
505  {
506  nInternal[faceI] = localFaces[faceI].unitNormal(localPoints);
507  }
508 
509  forAll(boundary(), patchI)
510  {
511  faceAreaNormals.boundaryFieldRef()[patchI] =
512  edgeAreaNormals().boundaryField()[patchI];
513  }
514 
515  forAll(faceAreaNormals.boundaryField(), patchI)
516  {
517  if
518  (
519  isA<processorFaPatchVectorField>
520  (
521  faceAreaNormals.boundaryField()[patchI]
522  )
523  )
524  {
525  faceAreaNormals.boundaryFieldRef()[patchI].initEvaluate();
526  faceAreaNormals.boundaryFieldRef()[patchI].evaluate();
527  }
528  }
529 }
530 
531 
532 void Foam::faMesh::calcEdgeAreaNormals() const
533 {
535  << "Calculating edge area normals" << endl;
536 
537  if (edgeAreaNormalsPtr_)
538  {
540  << "edgeAreaNormalsPtr_ already allocated"
541  << abort(FatalError);
542  }
543 
544  edgeAreaNormalsPtr_ =
545  new edgeVectorField
546  (
547  IOobject
548  (
549  "edgeAreaNormals",
550  mesh().pointsInstance(),
551  meshSubDir,
552  mesh()
553  ),
554  *this,
555  dimless
556  );
557 
558  edgeVectorField& edgeAreaNormals = *edgeAreaNormalsPtr_;
559 
560 
561  // Point area normals
562  const vectorField& pointNormals = pointAreaNormals();
563 
564  forAll(edgeAreaNormals.internalField(), edgei)
565  {
566  const edge& e = edges()[edgei];
567  const vector edgeVec = e.unitVec(points());
568 
569  vector& n = edgeAreaNormals.ref()[edgei];
570 
571  n = (pointNormals[e.first()] + pointNormals[e.second()]);
572 
573  n -= edgeVec*(edgeVec & n);
574 
575  n.normalise();
576  }
577 
578  forAll(boundary(), patchi)
579  {
580  const edgeList::subList patchEdges =
581  boundary()[patchi].patchSlice(edges());
582 
583  vectorField& edgeNorms = edgeAreaNormals.boundaryFieldRef()[patchi];
584 
585  forAll(patchEdges, edgei)
586  {
587  const edge& e = patchEdges[edgei];
588  const vector edgeVec = e.unitVec(points());
589 
590  vector& n = edgeNorms[edgei];
591 
592  n = (pointNormals[e.first()] + pointNormals[e.second()]);
593 
594  n -= edgeVec*(edgeVec & n);
595 
596  n.normalise();
597  }
598  }
599 }
600 
601 
602 void Foam::faMesh::calcFaceCurvatures() const
603 {
605  << "Calculating face curvatures" << endl;
606 
607  if (faceCurvaturesPtr_)
608  {
610  << "faceCurvaturesPtr_ already allocated"
611  << abort(FatalError);
612  }
613 
614  faceCurvaturesPtr_ =
615  new areaScalarField
616  (
617  IOobject
618  (
619  "faceCurvatures",
620  mesh().pointsInstance(),
621  meshSubDir,
622  mesh()
623  ),
624  *this,
626  );
627 
628  areaScalarField& faceCurvatures = *faceCurvaturesPtr_;
629 
630 
631 // faceCurvatures =
632 // fac::edgeIntegrate(Le()*edgeLengthCorrection())
633 // &faceAreaNormals();
634 
635  areaVectorField kN(fac::edgeIntegrate(Le()*edgeLengthCorrection()));
636 
637  faceCurvatures = sign(kN&faceAreaNormals())*mag(kN);
638 }
639 
640 
641 void Foam::faMesh::calcEdgeTransformTensors() const
642 {
644  << "Calculating edge transformation tensors" << endl;
645 
646  if (edgeTransformTensorsPtr_)
647  {
649  << "edgeTransformTensorsPtr_ already allocated"
650  << abort(FatalError);
651  }
652 
653  edgeTransformTensorsPtr_ = new FieldField<Field, tensor>(nEdges());
654  FieldField<Field, tensor>& edgeTransformTensors =
655  *edgeTransformTensorsPtr_;
656 
657  const areaVectorField& Nf = faceAreaNormals();
658  const areaVectorField& Cf = areaCentres();
659 
660  const edgeVectorField& Ne = edgeAreaNormals();
661  const edgeVectorField& Ce = edgeCentres();
662 
663  // Internal edges transformation tensors
664  for (label edgeI=0; edgeI<nInternalEdges(); ++edgeI)
665  {
666  edgeTransformTensors.set(edgeI, new Field<tensor>(3, I));
667 
668  vector E = Ce.internalField()[edgeI];
669 
670  if (skew())
671  {
672  E -= skewCorrectionVectors().internalField()[edgeI];
673  }
674 
675  // Edge transformation tensor
676  vector il = E - Cf.internalField()[owner()[edgeI]];
677 
678  il -= Ne.internalField()[edgeI]
679  *(Ne.internalField()[edgeI]&il);
680 
681  il /= mag(il);
682 
683  vector kl = Ne.internalField()[edgeI];
684  vector jl = kl^il;
685 
686  edgeTransformTensors[edgeI][0] =
687  tensor
688  (
689  il.x(), il.y(), il.z(),
690  jl.x(), jl.y(), jl.z(),
691  kl.x(), kl.y(), kl.z()
692  );
693 
694  // Owner transformation tensor
695  il = E - Cf.internalField()[owner()[edgeI]];
696 
697  il -= Nf.internalField()[owner()[edgeI]]
698  *(Nf.internalField()[owner()[edgeI]]&il);
699 
700  il /= mag(il);
701 
702  kl = Nf.internalField()[owner()[edgeI]];
703  jl = kl^il;
704 
705  edgeTransformTensors[edgeI][1] =
706  tensor
707  (
708  il.x(), il.y(), il.z(),
709  jl.x(), jl.y(), jl.z(),
710  kl.x(), kl.y(), kl.z()
711  );
712 
713  // Neighbour transformation tensor
714  il = Cf.internalField()[neighbour()[edgeI]] - E;
715 
716  il -= Nf.internalField()[neighbour()[edgeI]]
717  *(Nf.internalField()[neighbour()[edgeI]]&il);
718 
719  il /= mag(il);
720 
721  kl = Nf.internalField()[neighbour()[edgeI]];
722  jl = kl^il;
723 
724  edgeTransformTensors[edgeI][2] =
725  tensor
726  (
727  il.x(), il.y(), il.z(),
728  jl.x(), jl.y(), jl.z(),
729  kl.x(), kl.y(), kl.z()
730  );
731  }
732 
733  // Boundary edges transformation tensors
734  forAll(boundary(), patchI)
735  {
736  if (boundary()[patchI].coupled())
737  {
738  const labelUList& edgeFaces =
739  boundary()[patchI].edgeFaces();
740 
741  vectorField ngbCf(Cf.boundaryField()[patchI].patchNeighbourField());
742 
743  vectorField ngbNf(Nf.boundaryField()[patchI].patchNeighbourField());
744 
745  forAll(edgeFaces, edgeI)
746  {
747  edgeTransformTensors.set
748  (
749  boundary()[patchI].start() + edgeI,
750  new Field<tensor>(3, I)
751  );
752 
753  vector E = Ce.boundaryField()[patchI][edgeI];
754 
755  if (skew())
756  {
757  E -= skewCorrectionVectors()
758  .boundaryField()[patchI][edgeI];
759  }
760 
761  // Edge transformation tensor
762  vector il = E - Cf.internalField()[edgeFaces[edgeI]];
763 
764  il -= Ne.boundaryField()[patchI][edgeI]
765  *(Ne.boundaryField()[patchI][edgeI]&il);
766 
767  il /= mag(il);
768 
769  vector kl = Ne.boundaryField()[patchI][edgeI];
770  vector jl = kl^il;
771 
772  edgeTransformTensors[boundary()[patchI].start() + edgeI][0] =
773  tensor(il, jl, kl);
774 
775  // Owner transformation tensor
776  il = E - Cf.internalField()[edgeFaces[edgeI]];
777 
778  il -= Nf.internalField()[edgeFaces[edgeI]]
779  *(Nf.internalField()[edgeFaces[edgeI]]&il);
780 
781  il /= mag(il);
782 
783  kl = Nf.internalField()[edgeFaces[edgeI]];
784  jl = kl^il;
785 
786  edgeTransformTensors[boundary()[patchI].start() + edgeI][1] =
787  tensor(il, jl, kl);
788 
789  // Neighbour transformation tensor
790  il = ngbCf[edgeI] - E;
791 
792  il -= ngbNf[edgeI]*(ngbNf[edgeI]&il);
793 
794  il /= mag(il);
795 
796  kl = ngbNf[edgeI];
797 
798  jl = kl^il;
799 
800  edgeTransformTensors[boundary()[patchI].start() + edgeI][2] =
801  tensor(il, jl, kl);
802  }
803  }
804  else
805  {
806  const labelUList& edgeFaces = boundary()[patchI].edgeFaces();
807 
808  forAll(edgeFaces, edgeI)
809  {
810  edgeTransformTensors.set
811  (
812  boundary()[patchI].start() + edgeI,
813  new Field<tensor>(3, I)
814  );
815 
816  vector E = Ce.boundaryField()[patchI][edgeI];
817 
818  if (skew())
819  {
820  E -= skewCorrectionVectors()
821  .boundaryField()[patchI][edgeI];
822  }
823 
824  // Edge transformation tensor
825  vector il = E - Cf.internalField()[edgeFaces[edgeI]];
826 
827  il -= Ne.boundaryField()[patchI][edgeI]
828  *(Ne.boundaryField()[patchI][edgeI]&il);
829 
830  il /= mag(il);
831 
832  vector kl = Ne.boundaryField()[patchI][edgeI];
833  vector jl = kl^il;
834 
835  edgeTransformTensors[boundary()[patchI].start() + edgeI][0] =
836  tensor(il, jl, kl);
837 
838  // Owner transformation tensor
839  il = E - Cf.internalField()[edgeFaces[edgeI]];
840 
841  il -= Nf.internalField()[edgeFaces[edgeI]]
842  *(Nf.internalField()[edgeFaces[edgeI]]&il);
843 
844  il /= mag(il);
845 
846  kl = Nf.internalField()[edgeFaces[edgeI]];
847  jl = kl^il;
848 
849  edgeTransformTensors[boundary()[patchI].start() + edgeI][1] =
850  tensor(il, jl, kl);
851  }
852  }
853  }
854 }
855 
856 
858 {
860  << "Calculating internal points" << endl;
861 
862  bitSet markPoints(markupBoundaryPoints(this->patch()));
863  markPoints.flip();
864 
865  return markPoints.sortedToc();
866 }
867 
868 
870 {
872  << "Calculating boundary points" << endl;
873 
874  bitSet markPoints(markupBoundaryPoints(this->patch()));
875 
876  return markPoints.sortedToc();
877 }
878 
879 
880 // ~~~~~~~~~~~~~~~~~~~~~~~~~
881 // Point normal calculations
882 // ~~~~~~~~~~~~~~~~~~~~~~~~~
883 
884 // Original method (general)
885 // -------------------------
886 // - For each point, obtain the list of connected patch faces
887 // (from point-to-face addressing).
888 //
889 // - Create a primitive patch for those faces and use that to obtain the
890 // outer edge loop(s). This is effectively an agglomeration of the patch
891 // faces connected to a point.
892 //
893 // - Perform a pair-wise walk of the edge loop to obtain triangles from
894 // the originating point outwards (fan-like triangulation).
895 // Calculate an area-weighted value for each triangle.
896 //
897 // NOTE: not sure why internal and boundary point agglomeration was
898 // handled separately.
899 //
900 // Problems:
901 // - possibly susceptible to edge-loop errors (issue #2233) that cause
902 // the agglomeration logic to include the current point twice?
903 // - use of outer edge loop makes it more sensitive to face warpage.
904 // - relatively expensive with point-face connectivity,
905 // creation/destruction of a primitive-patch around each point.
906 //
907 // Original method (boundary correction)
908 // -------------------------------------
909 //
910 // - correct wedge directly, use processor patch information to exchange
911 // the current summed values
912 //
913 // - explicit correction of other boundaries.
914 // Polls the patch for the ngbPolyPatchPointNormals(), which internally
915 // calls ngbPolyPatchFaces and can return -1 for unmatched edges.
916 // This occurs when the outside perimeter of the faPatch aligns with
917 // a polyMesh processor. The neighbour face is off-processor and cannot
918 // be found. Accessing the mesh face at -1 == SEGFAULT.
919 
920 void Foam::faMesh::calcPointAreaNormals_orig(vectorField& result) const
921 {
923  << "Calculating pointAreaNormals : original method" << endl;
924 
925  result.resize(nPoints());
926  result = Zero;
927 
928  labelList intPoints(internalPoints());
929  labelList bndPoints(boundaryPoints());
930 
931  const pointField& points = patch().localPoints();
932  const faceList& faces = patch().localFaces();
933  const labelListList& pointFaces = patch().pointFaces();
934 
935  for (const label curPoint : intPoints)
936  {
937  faceList curFaceList(pointFaces[curPoint].size());
938 
939  forAll(curFaceList, faceI)
940  {
941  curFaceList[faceI] = faces[pointFaces[curPoint][faceI]];
942  }
943 
944  primitiveFacePatch curPatch(curFaceList, points);
945 
946  labelList curPointPoints = curPatch.edgeLoops()[0];
947 
948  for (label i = 0; i < curPointPoints.size(); ++i)
949  {
950  vector d1 =
951  points[curPatch.meshPoints()[curPointPoints[i]]]
952  - points[curPoint];
953 
954  label p = i + 1;
955 
956  if (i == (curPointPoints.size() - 1))
957  {
958  p = 0;
959  }
960 
961  vector d2 =
962  points[curPatch.meshPoints()[curPointPoints[p]]]
963  - points[curPoint];
964 
965  vector n = (d1 ^ d2)/(mag(d1 ^ d2) + SMALL);
966 
967  scalar sinAlpha = mag(d1^d2)/(mag(d1)*mag(d2));
968 
969  scalar w = sinAlpha/(mag(d1)*mag(d2));
970 
971  result[curPoint] += w*n;
972  }
973  }
974 
975  for (const label curPoint : bndPoints)
976  {
977  faceList curFaceList(pointFaces[curPoint].size());
978 
979  forAll(curFaceList, faceI)
980  {
981  curFaceList[faceI] = faces[pointFaces[curPoint][faceI]];
982  }
983 
984  primitiveFacePatch curPatch(curFaceList, points);
985 
986  labelList agglomFacePoints = curPatch.edgeLoops()[0];
987 
988  SLList<label> slList;
989 
990  label curPointLabel = -1;
991 
992  for (label i=0; i<agglomFacePoints.size(); ++i)
993  {
994  if (curPatch.meshPoints()[agglomFacePoints[i]] == curPoint)
995  {
996  curPointLabel = i;
997  }
998  else if ( curPointLabel != -1 )
999  {
1000  slList.append(curPatch.meshPoints()[agglomFacePoints[i]]);
1001  }
1002  }
1003 
1004  for (label i=0; i<curPointLabel; ++i)
1005  {
1006  slList.append(curPatch.meshPoints()[agglomFacePoints[i]]);
1007  }
1008 
1009  labelList curPointPoints(slList);
1010 
1011  for (label i=0; i < (curPointPoints.size() - 1); ++i)
1012  {
1013  vector d1 = points[curPointPoints[i]] - points[curPoint];
1014 
1015  vector d2 = points[curPointPoints[i + 1]] - points[curPoint];
1016 
1017  vector n = (d1 ^ d2)/(mag(d1 ^ d2) + SMALL);
1018 
1019  scalar sinAlpha = mag(d1 ^ d2)/(mag(d1)*mag(d2));
1020 
1021  scalar w = sinAlpha/(mag(d1)*mag(d2));
1022 
1023  result[curPoint] += w*n;
1024  }
1025  }
1026 
1027  // Correct wedge points
1028  forAll(boundary(), patchI)
1029  {
1030  const faPatch& fap = boundary()[patchI];
1031 
1032  if (isA<wedgeFaPatch>(fap))
1033  {
1034  const wedgeFaPatch& wedgePatch = refCast<const wedgeFaPatch>(fap);
1035 
1036  const labelList& patchPoints = wedgePatch.pointLabels();
1037 
1038  const vector N
1039  (
1040  transform
1041  (
1042  wedgePatch.edgeT(),
1043  wedgePatch.centreNormal()
1044  ).normalise()
1045  );
1046 
1047  for (const label pti : patchPoints)
1048  {
1049  result[pti] -= N*(N&result[pti]);
1050  }
1051 
1052  // Axis point correction
1053  if (wedgePatch.axisPoint() > -1)
1054  {
1055  result[wedgePatch.axisPoint()] =
1056  wedgePatch.axis()
1057  *(
1058  wedgePatch.axis()
1059  &result[wedgePatch.axisPoint()]
1060  );
1061  }
1062  }
1063  }
1064 
1065 
1066  // Processor patch points correction
1067  for (const faPatch& fap : boundary())
1068  {
1069  if (Pstream::parRun() && isA<processorFaPatch>(fap))
1070  {
1071  const processorFaPatch& procPatch =
1072  refCast<const processorFaPatch>(fap);
1073 
1074  const labelList& patchPointLabels = procPatch.pointLabels();
1075 
1076  vectorField patchPointNormals
1077  (
1078  patchPointLabels.size(),
1079  Zero
1080  );
1081 
1082  forAll(patchPointNormals, pointI)
1083  {
1084  patchPointNormals[pointI] = result[patchPointLabels[pointI]];
1085  }
1086 
1087  {
1089  (
1091  procPatch.neighbProcNo(),
1092  patchPointNormals.cdata_bytes(),
1093  patchPointNormals.byteSize()
1094  );
1095  }
1096 
1097  vectorField ngbPatchPointNormals
1098  (
1099  procPatch.neighbPoints().size(),
1100  Zero
1101  );
1102 
1103  {
1105  (
1107  procPatch.neighbProcNo(),
1108  ngbPatchPointNormals.data_bytes(),
1109  ngbPatchPointNormals.byteSize()
1110  );
1111  }
1112 
1113  const labelList& nonGlobalPatchPoints =
1114  procPatch.nonGlobalPatchPoints();
1115 
1116  for (const label pti : nonGlobalPatchPoints)
1117  {
1118  result[patchPointLabels[pti]] +=
1119  ngbPatchPointNormals[procPatch.neighbPoints()[pti]];
1120  }
1121  }
1122  }
1123 
1124 
1125  // Correct global points
1126  if (globalData().nGlobalPoints() > 0)
1127  {
1128  const labelList& spLabels(globalData().sharedPointLabels());
1129 
1130  vectorField spNormals(spLabels.size(), Zero);
1131  forAll(spNormals, pointI)
1132  {
1133  spNormals[pointI] = result[spLabels[pointI]];
1134  }
1135 
1136  const labelList& addr = globalData().sharedPointAddr();
1137 
1138  vectorField gpNormals
1139  (
1140  globalData().nGlobalPoints(),
1141  Zero
1142  );
1143 
1144  forAll(addr, i)
1145  {
1146  gpNormals[addr[i]] += spNormals[i];
1147  }
1148 
1149  combineReduce(gpNormals, plusEqOp<vectorField>());
1150 
1151  // Extract local data
1152  forAll(addr, i)
1153  {
1154  spNormals[i] = gpNormals[addr[i]];
1155  }
1156 
1157  forAll(spNormals, pointI)
1158  {
1159  result[spLabels[pointI]] = spNormals[pointI];
1160  }
1161  }
1162 
1163 
1164  // Boundary points correction
1165  forAll(boundary(), patchI)
1166  {
1167  const faPatch& fap = boundary()[patchI];
1168 
1169  if (correctPatchPointNormals(patchI) && !fap.coupled())
1170  {
1171  if (fap.ngbPolyPatchIndex() < 0)
1172  {
1174  << "Neighbour polyPatch index is not defined "
1175  << "for faPatch " << fap.name()
1176  << abort(FatalError);
1177  }
1178 
1179  const labelList& patchPoints = fap.pointLabels();
1180 
1181  const vectorField N(fap.ngbPolyPatchPointNormals());
1182 
1183  forAll(patchPoints, pointI)
1184  {
1185  result[patchPoints[pointI]]
1186  -= N[pointI]*(N[pointI]&result[patchPoints[pointI]]);
1187  }
1188  }
1189  }
1190 
1191  for (vector& n : result)
1192  {
1193  n.normalise();
1194  }
1195 }
1196 
1197 
1198 // ~~~~~~~~~~~~~~~~~~~~~~~~~
1199 // Point normal calculations
1200 // ~~~~~~~~~~~~~~~~~~~~~~~~~
1201 
1202 // Revised method (general)
1203 // ------------------------
1204 //
1205 // - For each patch face obtain a centre point (mathematical avg)
1206 // and use that to define the face dual as a pair of triangles:
1207 // - tri1: base-point / mid-side of right edge / face centre
1208 // - tri2: base-point / face centre / mid-side of left edge
1209 //
1210 // - Walk all face points, inserting directly into the corresponding
1211 // locations. No distinction between internal or boundary points (yet).
1212 //
1213 // Revised method (boundary correction)
1214 // ------------------------------------
1215 //
1216 // - correct wedge directly, use processor patch information to exchange
1217 // the current summed values. [No change from original].
1218 //
1219 // - explicit correction of other boundaries.
1220 // Use the new boundary halo information for the face normals.
1221 // Calculate the equivalent face-point normals locally and apply
1222 // correction as before.
1223 
1224 void Foam::faMesh::calcPointAreaNormals(vectorField& result) const
1225 {
1227  << "Calculating pointAreaNormals : face dual method" << endl;
1228 
1229  result.resize(nPoints());
1230  result = Zero;
1231 
1232  const pointField& points = patch().localPoints();
1233  const faceList& faces = patch().localFaces();
1234 
1235 
1236  // Loop over all faces
1237 
1238  for (const face& f : faces)
1239  {
1240  const label nVerts(f.size());
1241 
1242  point centrePoint(Zero);
1243  for (label i = 0; i < nVerts; ++i)
1244  {
1245  centrePoint += points[f[i]];
1246  }
1247  centrePoint /= nVerts;
1248 
1249  for (label i = 0; i < nVerts; ++i)
1250  {
1251  const label pt0 = f.thisLabel(i); // base
1252 
1253  result[pt0] +=
1255  (
1256  points[pt0], // base
1257  points[f.nextLabel(i)], // right
1258  points[f.prevLabel(i)], // left
1259  centrePoint
1260  );
1261  }
1262  }
1263 
1264 
1265  // Handle the boundary edges
1266 
1267  bitSet nbrBoundaryAdjust(boundary().size(), true);
1268 
1269  forAll(boundary(), patchi)
1270  {
1271  const faPatch& fap = boundary()[patchi];
1272 
1273  if (isA<wedgeFaPatch>(fap))
1274  {
1275  // Correct wedge points
1276 
1277  const auto& wedgePatch = refCast<const wedgeFaPatch>(fap);
1278 
1279  const labelList& patchPoints = wedgePatch.pointLabels();
1280 
1281  const vector N
1282  (
1283  transform
1284  (
1285  wedgePatch.edgeT(),
1286  wedgePatch.centreNormal()
1287  ).normalise()
1288  );
1289 
1290  for (const label pti : patchPoints)
1291  {
1292  result[pti] -= N*(N&result[pti]);
1293  }
1294 
1295  // Axis point correction
1296  if (wedgePatch.axisPoint() > -1)
1297  {
1298  result[wedgePatch.axisPoint()] =
1299  wedgePatch.axis()
1300  *(
1301  wedgePatch.axis()
1302  &result[wedgePatch.axisPoint()]
1303  );
1304  }
1305 
1306  // Handled
1307  nbrBoundaryAdjust.unset(patchi);
1308  }
1309  else if (Pstream::parRun() && isA<processorFaPatch>(fap))
1310  {
1311  // Correct processor patch points
1312 
1313  const auto& procPatch = refCast<const processorFaPatch>(fap);
1314 
1315  const labelList& patchPoints = procPatch.pointLabels();
1316  const labelList& nbrPatchPoints = procPatch.neighbPoints();
1317 
1318  const labelList& nonGlobalPatchPoints =
1319  procPatch.nonGlobalPatchPoints();
1320 
1321  // Send my values
1322 
1323  vectorField patchPointNormals
1324  (
1325  UIndirectList<vector>(result, patchPoints)
1326  );
1327 
1328  {
1330  (
1332  procPatch.neighbProcNo(),
1333  reinterpret_cast<const char*>(patchPointNormals.cdata()),
1334  patchPointNormals.size_bytes()
1335  );
1336  }
1337 
1338  // Receive neighbour values
1339  patchPointNormals.resize(nbrPatchPoints.size());
1340 
1341  {
1343  (
1345  procPatch.neighbProcNo(),
1346  reinterpret_cast<char*>(patchPointNormals.data()),
1347  patchPointNormals.size_bytes()
1348  );
1349  }
1350 
1351  for (const label pti : nonGlobalPatchPoints)
1352  {
1353  result[patchPoints[pti]] +=
1354  patchPointNormals[nbrPatchPoints[pti]];
1355  }
1356 
1357  // Handled
1358  nbrBoundaryAdjust.unset(patchi);
1359  }
1360  else if (fap.coupled())
1361  {
1362  // Coupled - no further action for neighbour side
1363  nbrBoundaryAdjust.unset(patchi);
1364  }
1365  // TBD:
1371  else if (!correctPatchPointNormals(patchi))
1372  {
1373  // No corrections
1374  nbrBoundaryAdjust.unset(patchi);
1375  }
1376  }
1377 
1378 
1379  // Correct global points
1380  if (globalData().nGlobalPoints())
1381  {
1382  const labelList& spLabels = globalData().sharedPointLabels();
1383  const labelList& addr = globalData().sharedPointAddr();
1384 
1385  vectorField spNormals
1386  (
1387  UIndirectList<vector>(result, spLabels)
1388  );
1389 
1390  vectorField gpNormals
1391  (
1392  globalData().nGlobalPoints(),
1393  Zero
1394  );
1395 
1396  forAll(addr, i)
1397  {
1398  gpNormals[addr[i]] += spNormals[i];
1399  }
1400 
1401  combineReduce(gpNormals, plusEqOp<vectorField>());
1402 
1403  // Extract local data
1404  forAll(addr, i)
1405  {
1406  spNormals[i] = gpNormals[addr[i]];
1407  }
1408 
1409  forAll(spNormals, pointI)
1410  {
1411  result[spLabels[pointI]] = spNormals[pointI];
1412  }
1413  }
1414 
1415 
1416  if (returnReduce(nbrBoundaryAdjust.any(), orOp<bool>()))
1417  {
1418  if (debug)
1419  {
1421  << "Apply " << nbrBoundaryAdjust.count()
1422  << " boundary neighbour corrections" << nl;
1423  }
1424 
1425  // Apply boundary points correction
1426 
1427  // Collect face normals as point normals
1428 
1429  const auto& haloNormals = this->haloFaceNormals();
1430 
1431  Map<vector> fpNormals(4*nBoundaryEdges());
1432 
1433  for (const label patchi : nbrBoundaryAdjust)
1434  {
1435  const faPatch& fap = boundary()[patchi];
1436  const labelList& edgeLabels = fap.edgeLabels();
1437 
1438  if (fap.ngbPolyPatchIndex() < 0)
1439  {
1441  << "Neighbour polyPatch index is not defined "
1442  << "for faPatch " << fap.name()
1443  << abort(FatalError);
1444  }
1445 
1446  for (const label edgei : edgeLabels)
1447  {
1448  const edge& e = patch().edges()[edgei];
1449 
1450  // Halo face unitNormal at boundary edge (starts as 0)
1451  const vector& fnorm = haloNormals[edgei - nInternalEdges_];
1452 
1453  fpNormals(e.first()) += fnorm;
1454  fpNormals(e.second()) += fnorm;
1455  }
1456  }
1457 
1458  // Apply the correction
1459 
1460  // Note from Zeljko Tukovic:
1461  //
1462  // This posibility is used for free-surface tracking
1463  // calculations to enforce 90 deg contact angle between
1464  // finite-area mesh and neighbouring polyPatch. It is very
1465  // important for curvature calculation to have correct normal
1466  // at contact line points.
1467 
1468  forAllConstIters(fpNormals, iter)
1469  {
1470  const label pointi = iter.key();
1471  vector fpnorm = iter.val();
1472 
1473  fpnorm.normalise();
1474  result[pointi] -= fpnorm*(fpnorm & result[pointi]);
1475  }
1476  }
1477 
1478  for (vector& n : result)
1479  {
1480  n.normalise();
1481  }
1482 }
1483 
1484 
1485 void Foam::faMesh::calcPointAreaNormalsByQuadricsFit(vectorField& result) const
1486 {
1487  const labelList intPoints(internalPoints());
1488  const labelList bndPoints(boundaryPoints());
1489 
1490  const pointField& points = patch().localPoints();
1491  const faceList& faces = patch().localFaces();
1492  const labelListList& pointFaces = patch().pointFaces();
1493 
1494  forAll(intPoints, pointI)
1495  {
1496  label curPoint = intPoints[pointI];
1497 
1498  const labelHashSet faceSet(pointFaces[curPoint]);
1499  const labelList curFaces(faceSet.toc());
1500 
1501  labelHashSet pointSet;
1502 
1503  for (const label facei : curFaces)
1504  {
1505  const labelList& facePoints = faces[facei];
1506  pointSet.insert(facePoints);
1507  }
1508  pointSet.erase(curPoint);
1509  labelList curPoints(pointSet.toc());
1510 
1511  if (pointSet.size() < 5)
1512  {
1513  DebugInfo
1514  << "WARNING: Extending point set for fitting." << endl;
1515 
1516  labelHashSet faceSet(pointFaces[curPoint]);
1517  labelList curFaces(faceSet.toc());
1518  for (const label facei : curFaces)
1519  {
1520  const labelList& curFaceFaces = patch().faceFaces()[facei];
1521  faceSet.insert(curFaceFaces);
1522  }
1523  curFaces = faceSet.toc();
1524 
1525  pointSet.clear();
1526 
1527  for (const label facei : curFaces)
1528  {
1529  const labelList& facePoints = faces[facei];
1530  pointSet.insert(facePoints);
1531  }
1532  pointSet.erase(curPoint);
1533  curPoints = pointSet.toc();
1534  }
1535 
1536  pointField allPoints(curPoints.size());
1537  scalarField W(curPoints.size(), 1.0);
1538  for (label i=0; i<curPoints.size(); ++i)
1539  {
1540  allPoints[i] = points[curPoints[i]];
1541  W[i] = 1.0/magSqr(allPoints[i] - points[curPoint]);
1542  }
1543 
1544  // Transform points
1545  coordSystem::cartesian cs
1546  (
1547  points[curPoint], // origin
1548  result[curPoint], // axis [e3] (normalized by constructor)
1549  allPoints[0] - points[curPoint] // direction [e1]
1550  );
1551 
1552  for (point& p : allPoints)
1553  {
1554  p = cs.localPosition(p);
1555  }
1556 
1558  (
1559  allPoints.size(),
1560  5,
1561  0.0
1562  );
1563 
1564  for (label i = 0; i < allPoints.size(); ++i)
1565  {
1566  M[i][0] = sqr(allPoints[i].x());
1567  M[i][1] = sqr(allPoints[i].y());
1568  M[i][2] = allPoints[i].x()*allPoints[i].y();
1569  M[i][3] = allPoints[i].x();
1570  M[i][4] = allPoints[i].y();
1571  }
1572 
1573  scalarSquareMatrix MtM(5, Zero);
1574 
1575  for (label i = 0; i < MtM.n(); ++i)
1576  {
1577  for (label j = 0; j < MtM.m(); ++j)
1578  {
1579  for (label k = 0; k < M.n(); ++k)
1580  {
1581  MtM[i][j] += M[k][i]*M[k][j]*W[k];
1582  }
1583  }
1584  }
1585 
1586  scalarField MtR(5, Zero);
1587 
1588  for (label i=0; i<MtR.size(); ++i)
1589  {
1590  for (label j=0; j<M.n(); ++j)
1591  {
1592  MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1593  }
1594  }
1595 
1596  LUsolve(MtM, MtR);
1597 
1598  vector curNormal = vector(MtR[3], MtR[4], -1);
1599 
1600  curNormal = cs.globalVector(curNormal);
1601 
1602  curNormal *= sign(curNormal&result[curPoint]);
1603 
1604  result[curPoint] = curNormal;
1605  }
1606 
1607 
1608  forAll(boundary(), patchI)
1609  {
1610  const faPatch& fap = boundary()[patchI];
1611 
1612  if (Pstream::parRun() && isA<processorFaPatch>(fap))
1613  {
1614  const processorFaPatch& procPatch =
1615  refCast<const processorFaPatch>(boundary()[patchI]);
1616 
1617  const labelList& patchPointLabels = procPatch.pointLabels();
1618 
1619  labelList toNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1620  vectorField toNgbProcLsPoints
1621  (
1622  10*patchPointLabels.size(),
1623  Zero
1624  );
1625  label nPoints = 0;
1626 
1627  for (label pointI=0; pointI<patchPointLabels.size(); ++pointI)
1628  {
1629  label curPoint = patchPointLabels[pointI];
1630 
1631  toNgbProcLsPointStarts[pointI] = nPoints;
1632 
1633  const labelHashSet faceSet(pointFaces[curPoint]);
1634  const labelList curFaces(faceSet.toc());
1635 
1636  labelHashSet pointSet;
1637 
1638  for (const label facei : curFaces)
1639  {
1640  const labelList& facePoints = faces[facei];
1641  pointSet.insert(facePoints);
1642  }
1643  pointSet.erase(curPoint);
1644  labelList curPoints = pointSet.toc();
1645 
1646  for (label i=0; i<curPoints.size(); ++i)
1647  {
1648  toNgbProcLsPoints[nPoints++] = points[curPoints[i]];
1649  }
1650  }
1651 
1652  toNgbProcLsPoints.setSize(nPoints);
1653 
1654  {
1655  OPstream toNeighbProc
1656  (
1658  procPatch.neighbProcNo(),
1659  toNgbProcLsPoints.byteSize()
1660  + toNgbProcLsPointStarts.byteSize()
1661  + 10*sizeof(label)
1662  );
1663 
1664  toNeighbProc
1665  << toNgbProcLsPoints
1666  << toNgbProcLsPointStarts;
1667  }
1668  }
1669  }
1670 
1671  for (const faPatch& fap : boundary())
1672  {
1673  if (Pstream::parRun() && isA<processorFaPatch>(fap))
1674  {
1675  const processorFaPatch& procPatch =
1676  refCast<const processorFaPatch>(fap);
1677 
1678  const labelList& patchPointLabels = procPatch.pointLabels();
1679 
1680  labelList fromNgbProcLsPointStarts(patchPointLabels.size(), Zero);
1681  vectorField fromNgbProcLsPoints;
1682 
1683  {
1684  IPstream fromNeighbProc
1685  (
1687  procPatch.neighbProcNo(),
1688  10*patchPointLabels.size()*sizeof(vector)
1689  + fromNgbProcLsPointStarts.byteSize()
1690  + 10*sizeof(label)
1691  );
1692 
1693  fromNeighbProc
1694  >> fromNgbProcLsPoints
1695  >> fromNgbProcLsPointStarts;
1696  }
1697 
1698  const labelList& nonGlobalPatchPoints =
1699  procPatch.nonGlobalPatchPoints();
1700 
1701  forAll(nonGlobalPatchPoints, pointI)
1702  {
1703  label curPoint =
1704  patchPointLabels[nonGlobalPatchPoints[pointI]];
1705  label curNgbPoint =
1706  procPatch.neighbPoints()[nonGlobalPatchPoints[pointI]];
1707 
1708  labelHashSet faceSet;
1709  faceSet.insert(pointFaces[curPoint]);
1710 
1711  labelList curFaces = faceSet.toc();
1712 
1713  labelHashSet pointSet;
1714 
1715  for (const label facei : curFaces)
1716  {
1717  const labelList& facePoints = faces[facei];
1718  pointSet.insert(facePoints);
1719  }
1720  pointSet.erase(curPoint);
1721  labelList curPoints = pointSet.toc();
1722 
1723  label nAllPoints = curPoints.size();
1724 
1725  if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
1726  {
1727  nAllPoints +=
1728  fromNgbProcLsPoints.size()
1729  - fromNgbProcLsPointStarts[curNgbPoint];
1730  }
1731  else
1732  {
1733  nAllPoints +=
1734  fromNgbProcLsPointStarts[curNgbPoint + 1]
1735  - fromNgbProcLsPointStarts[curNgbPoint];
1736  }
1737 
1738  vectorField allPointsExt(nAllPoints);
1739  label counter = 0;
1740  for (label i=0; i<curPoints.size(); ++i)
1741  {
1742  allPointsExt[counter++] = points[curPoints[i]];
1743  }
1744 
1745  if (curNgbPoint == fromNgbProcLsPointStarts.size() - 1)
1746  {
1747  for
1748  (
1749  label i=fromNgbProcLsPointStarts[curNgbPoint];
1750  i<fromNgbProcLsPoints.size();
1751  ++i
1752  )
1753  {
1754  allPointsExt[counter++] = fromNgbProcLsPoints[i];
1755  }
1756  }
1757  else
1758  {
1759  for
1760  (
1761  label i=fromNgbProcLsPointStarts[curNgbPoint];
1762  i<fromNgbProcLsPointStarts[curNgbPoint+1];
1763  ++i
1764  )
1765  {
1766  allPointsExt[counter++] = fromNgbProcLsPoints[i];
1767  }
1768  }
1769 
1770  // Remove duplicate points
1771  vectorField allPoints(nAllPoints, Zero);
1772  boundBox bb(allPointsExt, false);
1773  scalar tol = 0.001*mag(bb.max() - bb.min());
1774 
1775  nAllPoints = 0;
1776  forAll(allPointsExt, pI)
1777  {
1778  bool duplicate = false;
1779  for (label i=0; i<nAllPoints; ++i)
1780  {
1781  if
1782  (
1783  mag
1784  (
1785  allPoints[i]
1786  - allPointsExt[pI]
1787  )
1788  < tol
1789  )
1790  {
1791  duplicate = true;
1792  break;
1793  }
1794  }
1795 
1796  if (!duplicate)
1797  {
1798  allPoints[nAllPoints++] = allPointsExt[pI];
1799  }
1800  }
1801 
1802  allPoints.setSize(nAllPoints);
1803 
1804  if (nAllPoints < 5)
1805  {
1807  << "There are no enough points for quadrics "
1808  << "fitting for a point at processor patch"
1809  << abort(FatalError);
1810  }
1811 
1812  // Transform points
1813  const vector& origin = points[curPoint];
1814  const vector axis = normalised(result[curPoint]);
1815  vector dir(allPoints[0] - points[curPoint]);
1816  dir -= axis*(axis&dir);
1817  dir.normalise();
1818 
1819  const coordinateSystem cs("cs", origin, axis, dir);
1820 
1821  scalarField W(allPoints.size(), 1.0);
1822 
1823  forAll(allPoints, pI)
1824  {
1825  W[pI] = 1.0/magSqr(allPoints[pI] - points[curPoint]);
1826 
1827  allPoints[pI] = cs.localPosition(allPoints[pI]);
1828  }
1829 
1831  (
1832  allPoints.size(),
1833  5,
1834  0.0
1835  );
1836 
1837  for (label i=0; i<allPoints.size(); ++i)
1838  {
1839  M[i][0] = sqr(allPoints[i].x());
1840  M[i][1] = sqr(allPoints[i].y());
1841  M[i][2] = allPoints[i].x()*allPoints[i].y();
1842  M[i][3] = allPoints[i].x();
1843  M[i][4] = allPoints[i].y();
1844  }
1845 
1846  scalarSquareMatrix MtM(5, Zero);
1847 
1848  for (label i = 0; i < MtM.n(); ++i)
1849  {
1850  for (label j = 0; j < MtM.m(); ++j)
1851  {
1852  for (label k = 0; k < M.n(); ++k)
1853  {
1854  MtM[i][j] += M[k][i]*M[k][j]*W[k];
1855  }
1856  }
1857  }
1858 
1859  scalarField MtR(5, Zero);
1860 
1861  for (label i = 0; i < MtR.size(); ++i)
1862  {
1863  for (label j = 0; j < M.n(); ++j)
1864  {
1865  MtR[i] += M[j][i]*allPoints[j].z()*W[j];
1866  }
1867  }
1868 
1869  LUsolve(MtM, MtR);
1870 
1871  vector curNormal = vector(MtR[3], MtR[4], -1);
1872 
1873  curNormal = cs.globalVector(curNormal);
1874 
1875  curNormal *= sign(curNormal&result[curPoint]);
1876 
1877  result[curPoint] = curNormal;
1878  }
1879  }
1880  }
1881 
1882  // Correct global points
1883  if (globalData().nGlobalPoints() > 0)
1884  {
1885  const labelList& spLabels = globalData().sharedPointLabels();
1886 
1887  const labelList& addr = globalData().sharedPointAddr();
1888 
1889  for (label k=0; k<globalData().nGlobalPoints(); ++k)
1890  {
1891  List<List<vector>> procLsPoints(Pstream::nProcs());
1892 
1893  const label curSharedPointIndex = addr.find(k);
1894 
1895  scalar tol = 0.0;
1896 
1897  if (curSharedPointIndex != -1)
1898  {
1899  label curPoint = spLabels[curSharedPointIndex];
1900 
1901  const labelHashSet faceSet(pointFaces[curPoint]);
1902  const labelList curFaces(faceSet.toc());
1903 
1904  labelHashSet pointSet;
1905  for (const label facei : curFaces)
1906  {
1907  const labelList& facePoints = faces[facei];
1908  pointSet.insert(facePoints);
1909  }
1910  pointSet.erase(curPoint);
1911  labelList curPoints = pointSet.toc();
1912 
1913  vectorField locPoints(points, curPoints);
1914 
1915  procLsPoints[Pstream::myProcNo()] = locPoints;
1916 
1917  const boundBox bb(locPoints, false);
1918  tol = 0.001*mag(bb.max() - bb.min());
1919  }
1920 
1921  Pstream::gatherList(procLsPoints);
1922  Pstream::scatterList(procLsPoints);
1923 
1924  if (curSharedPointIndex != -1)
1925  {
1926  label curPoint = spLabels[curSharedPointIndex];
1927 
1928  label nAllPoints = 0;
1929  forAll(procLsPoints, procI)
1930  {
1931  nAllPoints += procLsPoints[procI].size();
1932  }
1933 
1934  vectorField allPoints(nAllPoints, Zero);
1935 
1936  nAllPoints = 0;
1937  forAll(procLsPoints, procI)
1938  {
1939  forAll(procLsPoints[procI], pointI)
1940  {
1941  bool duplicate = false;
1942  for (label i=0; i<nAllPoints; ++i)
1943  {
1944  if
1945  (
1946  mag
1947  (
1948  allPoints[i]
1949  - procLsPoints[procI][pointI]
1950  )
1951  < tol
1952  )
1953  {
1954  duplicate = true;
1955  break;
1956  }
1957  }
1958 
1959  if (!duplicate)
1960  {
1961  allPoints[nAllPoints++] =
1962  procLsPoints[procI][pointI];
1963  }
1964  }
1965  }
1966 
1967  allPoints.setSize(nAllPoints);
1968 
1969  if (nAllPoints < 5)
1970  {
1972  << "There are no enough points for quadratic "
1973  << "fitting for a global processor point "
1974  << abort(FatalError);
1975  }
1976 
1977  // Transform points
1978  const vector& origin = points[curPoint];
1979  const vector axis = normalised(result[curPoint]);
1980  vector dir(allPoints[0] - points[curPoint]);
1981  dir -= axis*(axis&dir);
1982  dir.normalise();
1983 
1984  coordinateSystem cs("cs", origin, axis, dir);
1985 
1986  scalarField W(allPoints.size(), 1.0);
1987 
1988  forAll(allPoints, pointI)
1989  {
1990  W[pointI]=
1991  1.0/magSqr(allPoints[pointI] - points[curPoint]);
1992 
1993  allPoints[pointI] = cs.localPosition(allPoints[pointI]);
1994  }
1995 
1997  (
1998  allPoints.size(),
1999  5,
2000  0.0
2001  );
2002 
2003  for (label i=0; i<allPoints.size(); ++i)
2004  {
2005  M[i][0] = sqr(allPoints[i].x());
2006  M[i][1] = sqr(allPoints[i].y());
2007  M[i][2] = allPoints[i].x()*allPoints[i].y();
2008  M[i][3] = allPoints[i].x();
2009  M[i][4] = allPoints[i].y();
2010  }
2011 
2012  scalarSquareMatrix MtM(5, Zero);
2013  for (label i = 0; i < MtM.n(); ++i)
2014  {
2015  for (label j = 0; j < MtM.m(); ++j)
2016  {
2017  for (label k = 0; k < M.n(); ++k)
2018  {
2019  MtM[i][j] += M[k][i]*M[k][j]*W[k];
2020  }
2021  }
2022  }
2023 
2024  scalarField MtR(5, Zero);
2025  for (label i = 0; i < MtR.size(); ++i)
2026  {
2027  for (label j = 0; j < M.n(); ++j)
2028  {
2029  MtR[i] += M[j][i]*allPoints[j].z()*W[j];
2030  }
2031  }
2032 
2033  LUsolve(MtM, MtR);
2034 
2035  vector curNormal = vector(MtR[3], MtR[4], -1);
2036 
2037  curNormal = cs.globalVector(curNormal);
2038 
2039  curNormal *= sign(curNormal&result[curPoint]);
2040 
2041  result[curPoint] = curNormal;
2042  }
2043  }
2044  }
2045 
2046  for (vector& n : result)
2047  {
2048  n.normalise();
2049  }
2050 }
2051 
2052 
2054 {
2056  << "Calculating edge length correction" << endl;
2057 
2058  tmp<edgeScalarField> tcorrection
2059  (
2060  new edgeScalarField
2061  (
2062  IOobject
2063  (
2064  "edgeLengthCorrection",
2065  mesh().pointsInstance(),
2066  meshSubDir,
2067  mesh()
2068  ),
2069  *this,
2070  dimless
2071  )
2072  );
2073  edgeScalarField& correction = tcorrection.ref();
2074 
2075  const vectorField& pointNormals = pointAreaNormals();
2076 
2077  forAll(correction.internalField(), edgeI)
2078  {
2079  scalar sinAlpha = mag
2080  (
2081  pointNormals[edges()[edgeI].start()]^
2082  pointNormals[edges()[edgeI].end()]
2083  );
2084 
2085  scalar alpha = asin(sinAlpha);
2086 
2087  correction.ref()[edgeI] = cos(0.5*alpha);
2088  }
2089 
2090 
2091  forAll(boundary(), patchI)
2092  {
2093  const edgeList::subList patchEdges
2094  (
2095  boundary()[patchI].patchSlice(edges())
2096  );
2097 
2098  forAll(patchEdges, edgeI)
2099  {
2100  scalar sinAlpha =
2101  mag
2102  (
2103  pointNormals[patchEdges[edgeI].start()]
2104  ^ pointNormals[patchEdges[edgeI].end()]
2105  );
2106 
2107  scalar alpha = asin(sinAlpha);
2108 
2109  correction.boundaryFieldRef()[patchI][edgeI] = cos(0.5*alpha);
2110  }
2111  }
2112 
2113  return tcorrection;
2114 }
2115 
2116 
2117 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::LUsolve
void LUsolve(scalarSquareMatrix &matrix, List< Type > &source)
Definition: scalarMatricesTemplates.C:215
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:169
Foam::areaInvDistSqrWeightedNormal
static vector areaInvDistSqrWeightedNormal(const vector &a, const vector &b)
Definition: faMeshDemandDrivenData.C:67
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::UOPstream::write
static bool write(const commsTypes commsType, const int toProcNo, const char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label communicator=UPstream::worldComm)
Write given buffer to given processor.
Definition: UOPwrite.C:36
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::skew
dimensionedTensor skew(const dimensionedTensor &dt)
Definition: dimensionedTensor.C:138
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:52
Foam::primitiveFacePatch
PrimitivePatch< List< face >, const pointField & > primitiveFacePatch
A PrimitivePatch with List storage for the faces, const reference for the point field.
Definition: primitiveFacePatch.H:51
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
Foam::edgeVectorField
GeometricField< vector, faePatchField, edgeMesh > edgeVectorField
Definition: edgeFieldsFwd.H:57
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::faMesh::edgeLengthCorrection
tmp< edgeScalarField > edgeLengthCorrection() const
Return edge length correction.
Definition: faMeshDemandDrivenData.C:2053
Foam::Pstream::scatterList
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
Definition: gatherScatterList.C:215
Foam::constant::atomic::alpha
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
Definition: readThermalProperties.H:212
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:54
processorFaPatch.H
Foam::faMesh::internalPoints
labelList internalPoints() const
Return internal point labels.
Definition: faMeshDemandDrivenData.C:857
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
primitiveFacePatch.H
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
Foam::combineReduce
void combineReduce(const List< UPstream::commsStruct > &comms, T &Value, const CombineOp &cop, const int tag, const label comm)
Definition: PstreamCombineReduceOps.H:54
emptyFaPatchFields.H
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
faMesh.H
Foam::correction
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Foam::Vector::normalise
Vector< Cmpt > & normalise()
Normalise the vector by its magnitude.
Definition: VectorI.H:123
Foam::sign
dimensionedScalar sign(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:166
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
cartesianCS.H
Foam::UIPstream::read
static label read(const commsTypes commsType, const int fromProcNo, char *buf, const std::streamsize bufSize, const int tag=UPstream::msgType(), const label communicator=UPstream::worldComm)
Read into given buffer from given processor.
Definition: UIPread.C:81
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::markupBoundaryPoints
static Foam::bitSet markupBoundaryPoints(const uindirectPrimitivePatch &p)
Definition: faMeshDemandDrivenData.C:114
PstreamCombineReduceOps.H
Combination-Reduction operation for a parallel run. The information from all nodes is collected on th...
Foam::areaVectorField
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:58
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::tmp::ref
T & ref() const
Definition: tmpI.H:227
Foam::dimArea
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:59
fac.H
Namespace of functions to calculate explicit derivatives.
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::Field< vector >
DebugInFunction
#define DebugInFunction
Report an information message using Foam::Info.
Definition: messageStream.H:388
edgeFields.H
Foam::edgeScalarField
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
Definition: edgeFieldsFwd.H:52
areaFields.H
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::fac::edgeIntegrate
tmp< GeometricField< Type, faPatchField, areaMesh > > edgeIntegrate(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition: facEdgeIntegrate.C:47
Foam::List::subList
SubList< T > subList
Declare type of subList.
Definition: List.H:112
Foam::scalarSquareMatrix
SquareMatrix< scalar > scalarSquareMatrix
Definition: scalarMatrices.H:57
Foam::bitSet::flip
void flip()
Invert all bits in the addressable region.
Definition: bitSetI.H:618
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::areaScalarField
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
Definition: areaFieldsFwd.H:53
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::faMesh::boundaryPoints
labelList boundaryPoints() const
Return boundary point labels.
Definition: faMeshDemandDrivenData.C:869
PoutInFunction
#define PoutInFunction
Report using Foam::Pout with FUNCTION_NAME prefix.
Definition: messageStream.H:357
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:487
processorFaPatchFields.H
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
DebugInfo
#define DebugInfo
Report an information message using Foam::Info.
Definition: messageStream.H:382
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
Foam::nl
constexpr char nl
Definition: Ostream.H:404
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::UPstream::parRun
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Foam::List< label >
faMeshLduAddressing.H
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
M
#define M(I)
points
const pointField & points
Definition: gmvOutputHeader.H:1
k
label k
Boltzmann constant.
Definition: LISASMDCalcMethod2.H:41
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::areaInvDistSqrWeightedNormalDualEdge
static vector areaInvDistSqrWeightedNormalDualEdge(const point &basePoint, const point &rightPoint, const point &leftPoint, const point &centrePoint)
Definition: faMeshDemandDrivenData.C:83
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
x
x
Definition: LISASMDCalcMethod2.H:52
scalarMatrices.H
Foam::DelaunayMeshTools::allPoints
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
coupled
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
N
const Vector< label > N(dict.get< Vector< label >>("N"))
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Foam::GeometricField< scalar, faePatchField, edgeMesh >
Foam::IOobject::NO_READ
Definition: IOobject.H:188
wedgeFaPatch.H
Foam::scalarRectangularMatrix
RectangularMatrix< scalar > scalarRectangularMatrix
Definition: scalarMatrices.H:56
Foam::tensor
Tensor< scalar > tensor
Tensor of scalars, i.e. Tensor<scalar>.
Definition: symmTensor.H:61
Foam::bitSet::sortedToc
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition: bitSetI.H:532
boundary
faceListList boundary
Definition: createBlockMesh.H:4
Foam::asin
dimensionedScalar asin(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:267
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::I
static const Identity< scalar > I
Definition: Identity.H:95
Foam::dimless
const dimensionSet dimless
Dimensionless.
Definition: dimensionSets.C:189
y
scalar y
Definition: LISASMDCalcMethod1.H:14
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:79
Foam::UPstream::commsTypes::blocking
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265