isoSurfacePoint.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2020 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 "isoSurfacePoint.H"
30 #include "mergePoints.H"
31 #include "slicedVolFields.H"
32 #include "volFields.H"
33 #include "triSurfaceTools.H"
34 #include "triSurface.H"
35 #include "triPoints.H"
36 
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 
39 #include "isoSurfaceBaseMethods.H"
41 
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
48 }
49 
50 
51 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
52 
53 namespace Foam
54 {
55 
56 // Helper class for slicing triangles
57 struct storeOp
58 {
60 
62  :
63  list(tris)
64  {}
65 
66  void operator()(const triPoints& tri)
67  {
68  list.append(tri);
69  }
70 
71  void operator()(triPoints&& tri)
72  {
73  list.append(std::move(tri));
74  }
75 };
76 
77 
78 // Is patch co-located (i.e. non-separated) coupled patch?
79 static inline bool collocatedPatch(const polyPatch& pp)
80 {
81  const auto* cpp = isA<coupledPolyPatch>(pp);
82  return bool(cpp) && cpp->parallel() && !cpp->separated();
83 }
84 
85 
86 // Collocated patch, with extra checks
87 #if 0
88 static bool isCollocatedPatch(const coupledPolyPatch& pp)
89 {
90  if (isA<processorPolyPatch>(pp) || isA<cyclicPolyPatch>(pp))
91  {
92  return collocatedPatch(pp);
93  }
94 
96  << "Unhandled coupledPolyPatch type " << pp.type() << nl
97  << abort(FatalError);
98 
99  return false;
100 }
101 #endif
102 
103 } // End namespace Foam
104 
105 
106 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
107 
108 bool Foam::isoSurfacePoint::noTransform(const tensor& tt) const
109 {
110  return
111  (mag(tt.xx()-1) < mergeDistance_)
112  && (mag(tt.yy()-1) < mergeDistance_)
113  && (mag(tt.zz()-1) < mergeDistance_)
114  && (mag(tt.xy()) < mergeDistance_)
115  && (mag(tt.xz()) < mergeDistance_)
116  && (mag(tt.yx()) < mergeDistance_)
117  && (mag(tt.yz()) < mergeDistance_)
118  && (mag(tt.zx()) < mergeDistance_)
119  && (mag(tt.zy()) < mergeDistance_);
120 }
121 
122 
123 Foam::bitSet Foam::isoSurfacePoint::collocatedFaces
124 (
125  const coupledPolyPatch& pp
126 )
127 {
128  // Initialise to false
129  bitSet collocated(pp.size());
130 
131  if (isA<processorPolyPatch>(pp) || isA<cyclicPolyPatch>(pp))
132  {
133  if (collocatedPatch(pp))
134  {
135  // All on
136  collocated = true;
137  }
138  }
139  else
140  {
142  << "Unhandled coupledPolyPatch type " << pp.type()
143  << abort(FatalError);
144  }
145  return collocated;
146 }
147 
148 
149 void Foam::isoSurfacePoint::syncUnseparatedPoints
150 (
151  pointField& pointValues,
152  const point& nullValue
153 ) const
154 {
155  // Until syncPointList handles separated coupled patches with multiple
156  // transforms do our own synchronisation of non-separated patches only
157  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
158 
159  if (Pstream::parRun())
160  {
161  // Send
162  for (const polyPatch& p : patches)
163  {
164  if
165  (
166  isA<processorPolyPatch>(p)
167  && p.nPoints() > 0
168  && collocatedPatch(p)
169  )
170  {
171  const processorPolyPatch& pp =
172  refCast<const processorPolyPatch>(p);
173 
174  const labelList& meshPts = pp.meshPoints();
175  const labelList& nbrPts = pp.neighbPoints();
176 
177  pointField patchInfo(meshPts.size());
178 
179  forAll(nbrPts, pointi)
180  {
181  const label nbrPointi = nbrPts[pointi];
182  patchInfo[nbrPointi] = pointValues[meshPts[pointi]];
183  }
184 
185  OPstream toNbr
186  (
188  pp.neighbProcNo()
189  );
190  toNbr << patchInfo;
191  }
192  }
193 
194  // Receive and combine.
195  for (const polyPatch& p : patches)
196  {
197  if
198  (
199  isA<processorPolyPatch>(p)
200  && p.nPoints() > 0
201  && collocatedPatch(p)
202  )
203  {
204  const processorPolyPatch& pp =
205  refCast<const processorPolyPatch>(p);
206 
207  pointField nbrPatchInfo(pp.nPoints());
208  {
209  // We do not know the number of points on the other side
210  // so cannot use Pstream::read.
211  IPstream fromNbr
212  (
214  pp.neighbProcNo()
215  );
216  fromNbr >> nbrPatchInfo;
217  }
218 
219  const labelList& meshPts = pp.meshPoints();
220 
221  forAll(meshPts, pointi)
222  {
223  const label meshPointi = meshPts[pointi];
224  minEqOp<point>()
225  (
226  pointValues[meshPointi],
227  nbrPatchInfo[pointi]
228  );
229  }
230  }
231  }
232  }
233 
234  // Do the cyclics.
235  for (const polyPatch& p : patches)
236  {
237  if (isA<cyclicPolyPatch>(p))
238  {
239  const cyclicPolyPatch& cycPatch =
240  refCast<const cyclicPolyPatch>(p);
241 
242  if (cycPatch.owner() && collocatedPatch(cycPatch))
243  {
244  // Owner does all.
245 
246  const edgeList& coupledPoints = cycPatch.coupledPoints();
247  const labelList& meshPts = cycPatch.meshPoints();
248  const cyclicPolyPatch& nbrPatch = cycPatch.neighbPatch();
249  const labelList& nbrMeshPoints = nbrPatch.meshPoints();
250 
251  pointField half0Values(coupledPoints.size());
252  pointField half1Values(coupledPoints.size());
253 
254  forAll(coupledPoints, i)
255  {
256  const edge& e = coupledPoints[i];
257  half0Values[i] = pointValues[meshPts[e[0]]];
258  half1Values[i] = pointValues[nbrMeshPoints[e[1]]];
259  }
260 
261  forAll(coupledPoints, i)
262  {
263  const edge& e = coupledPoints[i];
264  const label p0 = meshPts[e[0]];
265  const label p1 = nbrMeshPoints[e[1]];
266 
267  minEqOp<point>()(pointValues[p0], half1Values[i]);
268  minEqOp<point>()(pointValues[p1], half0Values[i]);
269  }
270  }
271  }
272  }
273 
274  // Synchronize multiple shared points.
275  const globalMeshData& pd = mesh_.globalData();
276 
277  if (pd.nGlobalPoints() > 0)
278  {
279  // Values on shared points.
280  pointField sharedPts(pd.nGlobalPoints(), nullValue);
281 
282  forAll(pd.sharedPointLabels(), i)
283  {
284  const label meshPointi = pd.sharedPointLabels()[i];
285  // Fill my entries in the shared points
286  sharedPts[pd.sharedPointAddr()[i]] = pointValues[meshPointi];
287  }
288 
289  // Combine on master.
290  Pstream::listCombineGather(sharedPts, minEqOp<point>());
291  Pstream::listCombineScatter(sharedPts);
292 
293  // Now we will all have the same information. Merge it back with
294  // my local information.
295  forAll(pd.sharedPointLabels(), i)
296  {
297  const label meshPointi = pd.sharedPointLabels()[i];
298  pointValues[meshPointi] = sharedPts[pd.sharedPointAddr()[i]];
299  }
300  }
301 }
302 
303 
304 Foam::scalar Foam::isoSurfacePoint::isoFraction
305 (
306  const scalar s0,
307  const scalar s1
308 ) const
309 {
310  const scalar d = s1-s0;
311 
312  if (mag(d) > VSMALL)
313  {
314  return (iso_-s0)/d;
315  }
316 
317  return -1.0;
318 }
319 
320 
321 bool Foam::isoSurfacePoint::isEdgeOfFaceCut
322 (
323  const scalarField& pVals,
324  const face& f,
325  const bool ownLower,
326  const bool neiLower
327 ) const
328 {
329  forAll(f, fp)
330  {
331  const bool fpLower = (pVals[f[fp]] < iso_);
332 
333  if
334  (
335  fpLower != ownLower
336  || fpLower != neiLower
337  || fpLower != (pVals[f[f.fcIndex(fp)]] < iso_)
338  )
339  {
340  return true;
341  }
342  }
343 
344  return false;
345 }
346 
347 
348 void Foam::isoSurfacePoint::getNeighbour
349 (
350  const labelList& boundaryRegion,
351  const volVectorField& meshC,
352  const volScalarField& cVals,
353  const label celli,
354  const label facei,
355  scalar& nbrValue,
356  point& nbrPoint
357 ) const
358 {
359  const labelList& own = mesh_.faceOwner();
360  const labelList& nei = mesh_.faceNeighbour();
361 
362  if (mesh_.isInternalFace(facei))
363  {
364  const label nbr = (own[facei] == celli ? nei[facei] : own[facei]);
365  nbrValue = cVals[nbr];
366  nbrPoint = meshC[nbr];
367  }
368  else
369  {
370  const label bFacei = facei-mesh_.nInternalFaces();
371  const label patchi = boundaryRegion[bFacei];
372  const polyPatch& pp = mesh_.boundaryMesh()[patchi];
373  const label patchFacei = facei-pp.start();
374 
375  nbrValue = cVals.boundaryField()[patchi][patchFacei];
376  nbrPoint = meshC.boundaryField()[patchi][patchFacei];
377  }
378 }
379 
380 
381 void Foam::isoSurfacePoint::calcCutTypes
382 (
383  const labelList& boundaryRegion,
384  const volVectorField& meshC,
385  const volScalarField& cVals,
386  const scalarField& pVals
387 )
388 {
389  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
390  const labelList& own = mesh_.faceOwner();
391  const labelList& nei = mesh_.faceNeighbour();
392 
393  faceCutType_.resize(mesh_.nFaces());
394  faceCutType_ = cutType::NOTCUT;
395 
396  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
397  {
398  const scalar ownValue = cVals[own[facei]];
399  const bool ownLower = (ownValue < iso_);
400 
401  scalar nbrValue;
402  point nbrPoint;
403  getNeighbour
404  (
405  boundaryRegion,
406  meshC,
407  cVals,
408  own[facei],
409  facei,
410  nbrValue,
411  nbrPoint
412  );
413 
414  const bool neiLower = (nbrValue < iso_);
415 
416  if (ownLower != neiLower)
417  {
418  faceCutType_[facei] = cutType::CUT;
419  }
420  else
421  {
422  // Is mesh edge cut?
423  // - by looping over all the edges of the face.
424  const face& f = mesh_.faces()[facei];
425 
426  if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
427  {
428  faceCutType_[facei] = cutType::CUT;
429  }
430  }
431  }
432 
433  for (const polyPatch& pp : patches)
434  {
435  for (const label facei : pp.range())
436  {
437  const scalar ownValue = cVals[own[facei]];
438  const bool ownLower = (ownValue < iso_);
439 
440  scalar nbrValue;
441  point nbrPoint;
442  getNeighbour
443  (
444  boundaryRegion,
445  meshC,
446  cVals,
447  own[facei],
448  facei,
449  nbrValue,
450  nbrPoint
451  );
452 
453  const bool neiLower = (nbrValue < iso_);
454 
455  if (ownLower != neiLower)
456  {
457  faceCutType_[facei] = cutType::CUT;
458  }
459  else
460  {
461  // Is mesh edge cut?
462  // - by looping over all the edges of the face.
463  const face& f = mesh_.faces()[facei];
464 
465  if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
466  {
467  faceCutType_[facei] = cutType::CUT;
468  }
469  }
470  }
471  }
472 
473  nCutCells_ = 0;
474  cellCutType_.resize(mesh_.nCells());
475  cellCutType_ = cutType::NOTCUT;
476 
477 
478  // Propagate internal face cuts into the cells.
479 
480  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
481  {
482  if (faceCutType_[facei] == cutType::NOTCUT)
483  {
484  continue;
485  }
486 
487  if (cellCutType_[own[facei]] == cutType::NOTCUT)
488  {
489  cellCutType_[own[facei]] = cutType::CUT;
490  ++nCutCells_;
491  }
492  if (cellCutType_[nei[facei]] == cutType::NOTCUT)
493  {
494  cellCutType_[nei[facei]] = cutType::CUT;
495  ++nCutCells_;
496  }
497  }
498 
499 
500  // Propagate boundary face cuts into the cells.
501 
502  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); ++facei)
503  {
504  if (faceCutType_[facei] == cutType::NOTCUT)
505  {
506  continue;
507  }
508 
509  if (cellCutType_[own[facei]] == cutType::NOTCUT)
510  {
511  cellCutType_[own[facei]] = cutType::CUT;
512  ++nCutCells_;
513  }
514  }
515 
516  if (debug)
517  {
518  Pout<< "isoSurfacePoint : candidate cut cells "
519  << nCutCells_ << " / " << mesh_.nCells() << endl;
520  }
521 }
522 
523 
524 Foam::point Foam::isoSurfacePoint::calcCentre(const triSurface& s)
525 {
526  // Calculate centre of surface.
527 
528  vector sum = Zero;
529 
530  forAll(s, i)
531  {
532  sum += s[i].centre(s.points());
533  }
534  return sum/s.size();
535 }
536 
537 
538 void Foam::isoSurfacePoint::calcSnappedCc
539 (
540  const labelList& boundaryRegion,
541  const volVectorField& meshC,
542  const volScalarField& cVals,
543  const scalarField& pVals,
544 
545  DynamicList<point>& snappedPoints,
546  labelList& snappedCc
547 ) const
548 {
549  const pointField& pts = mesh_.points();
550  const pointField& cc = mesh_.cellCentres();
551 
552  snappedCc.setSize(mesh_.nCells());
553  snappedCc = -1;
554 
555  // Work arrays
556  DynamicList<point, 64> localTriPoints(64);
557 
558  forAll(mesh_.cells(), celli)
559  {
560  if (cellCutType_[celli] == cutType::CUT)
561  {
562  const scalar cVal = cVals[celli];
563 
564  localTriPoints.clear();
565  label nOther = 0;
566  point otherPointSum = Zero;
567 
568  // Create points for all intersections close to cell centre
569  // (i.e. from pyramid edges)
570 
571  for (const label facei : mesh_.cells()[celli])
572  {
573  const face& f = mesh_.faces()[facei];
574 
575  scalar nbrValue;
576  point nbrPoint;
577  getNeighbour
578  (
579  boundaryRegion,
580  meshC,
581  cVals,
582  celli,
583  facei,
584  nbrValue,
585  nbrPoint
586  );
587 
588  // Calculate intersection points of edges to cell centre
589  FixedList<scalar, 3> s;
590  FixedList<point, 3> pt;
591 
592  // From cc to neighbour cc.
593  s[2] = isoFraction(cVal, nbrValue);
594  pt[2] = (1.0-s[2])*cc[celli] + s[2]*nbrPoint;
595 
596  forAll(f, fp)
597  {
598  // From cc to fp
599  label p0 = f[fp];
600  s[0] = isoFraction(cVal, pVals[p0]);
601  pt[0] = (1.0-s[0])*cc[celli] + s[0]*pts[p0];
602 
603  // From cc to fp+1
604  label p1 = f[f.fcIndex(fp)];
605  s[1] = isoFraction(cVal, pVals[p1]);
606  pt[1] = (1.0-s[1])*cc[celli] + s[1]*pts[p1];
607 
608  if
609  (
610  (s[0] >= 0.0 && s[0] <= 0.5)
611  && (s[1] >= 0.0 && s[1] <= 0.5)
612  && (s[2] >= 0.0 && s[2] <= 0.5)
613  )
614  {
615  localTriPoints.append(pt[0]);
616  localTriPoints.append(pt[1]);
617  localTriPoints.append(pt[2]);
618  }
619  else
620  {
621  // Get average of all other points
622  forAll(s, i)
623  {
624  if (s[i] >= 0.0 && s[i] <= 0.5)
625  {
626  otherPointSum += pt[i];
627  ++nOther;
628  }
629  }
630  }
631  }
632  }
633 
634  if (localTriPoints.size() == 0)
635  {
636  // No complete triangles. Get average of all intersection
637  // points.
638  if (nOther > 0)
639  {
640  snappedCc[celli] = snappedPoints.size();
641  snappedPoints.append(otherPointSum/nOther);
642 
643  //Pout<< " point:" << pointi
644  // << " replacing coord:" << mesh_.points()[pointi]
645  // << " by average:" << collapsedPoint[pointi] << endl;
646  }
647  }
648  else if (localTriPoints.size() == 3)
649  {
650  // Single triangle. No need for any analysis. Average points.
651  snappedCc[celli] = snappedPoints.size();
652  snappedPoints.append(sum(localTriPoints)/3);
653  localTriPoints.clear();
654 
655  //Pout<< " point:" << pointi
656  // << " replacing coord:" << mesh_.points()[pointi]
657  // << " by average:" << collapsedPoint[pointi] << endl;
658  }
659  else
660  {
661  // Convert points into triSurface.
662 
663  // Merge points and compact out non-valid triangles
664  labelList triMap; // merged to unmerged triangle
665  labelList triPointReverseMap; // unmerged to merged point
666  triSurface surf
667  (
668  stitchTriPoints
669  (
670  false, // do not check for duplicate tris
671  localTriPoints,
672  triPointReverseMap,
673  triMap
674  )
675  );
676 
677  labelList faceZone;
678  label nZones = surf.markZones
679  (
680  boolList(surf.nEdges(), false),
681  faceZone
682  );
683 
684  if (nZones == 1)
685  {
686  snappedCc[celli] = snappedPoints.size();
687  snappedPoints.append(calcCentre(surf));
688  //Pout<< " point:" << pointi << " nZones:" << nZones
689  // << " replacing coord:" << mesh_.points()[pointi]
690  // << " by average:" << collapsedPoint[pointi] << endl;
691  }
692  }
693  }
694  }
695 }
696 
697 
698 void Foam::isoSurfacePoint::calcSnappedPoint
699 (
700  const bitSet& isBoundaryPoint,
701  const labelList& boundaryRegion,
702  const volVectorField& meshC,
703  const volScalarField& cVals,
704  const scalarField& pVals,
705 
706  DynamicList<point>& snappedPoints,
707  labelList& snappedPoint
708 ) const
709 {
710  const pointField& pts = mesh_.points();
711  const pointField& cc = mesh_.cellCentres();
712 
713  pointField collapsedPoint(mesh_.nPoints(), point::max);
714 
715  // Work arrays
716  DynamicList<point, 64> localTriPoints(100);
717 
718  forAll(mesh_.pointFaces(), pointi)
719  {
720  if (isBoundaryPoint.test(pointi))
721  {
722  continue;
723  }
724 
725  const labelList& pFaces = mesh_.pointFaces()[pointi];
726 
727  bool anyCut = false;
728 
729  for (const label facei : pFaces)
730  {
731  if (faceCutType_[facei] == cutType::CUT)
732  {
733  anyCut = true;
734  break;
735  }
736  }
737 
738  if (!anyCut)
739  {
740  continue;
741  }
742 
743 
744  localTriPoints.clear();
745  label nOther = 0;
746  point otherPointSum = Zero;
747 
748  for (const label facei : pFaces)
749  {
750  // Create points for all intersections close to point
751  // (i.e. from pyramid edges)
752  const face& f = mesh_.faces()[facei];
753  const label own = mesh_.faceOwner()[facei];
754 
755  // Get neighbour value
756  scalar nbrValue;
757  point nbrPoint;
758  getNeighbour
759  (
760  boundaryRegion,
761  meshC,
762  cVals,
763  own,
764  facei,
765  nbrValue,
766  nbrPoint
767  );
768 
769  // Calculate intersection points of edges emanating from point
770  FixedList<scalar, 4> s;
771  FixedList<point, 4> pt;
772 
773  label fp = f.find(pointi);
774  s[0] = isoFraction(pVals[pointi], cVals[own]);
775  pt[0] = (1.0-s[0])*pts[pointi] + s[0]*cc[own];
776 
777  s[1] = isoFraction(pVals[pointi], nbrValue);
778  pt[1] = (1.0-s[1])*pts[pointi] + s[1]*nbrPoint;
779 
780  label nextPointi = f[f.fcIndex(fp)];
781  s[2] = isoFraction(pVals[pointi], pVals[nextPointi]);
782  pt[2] = (1.0-s[2])*pts[pointi] + s[2]*pts[nextPointi];
783 
784  label prevPointi = f[f.rcIndex(fp)];
785  s[3] = isoFraction(pVals[pointi], pVals[prevPointi]);
786  pt[3] = (1.0-s[3])*pts[pointi] + s[3]*pts[prevPointi];
787 
788  if
789  (
790  (s[0] >= 0.0 && s[0] <= 0.5)
791  && (s[1] >= 0.0 && s[1] <= 0.5)
792  && (s[2] >= 0.0 && s[2] <= 0.5)
793  )
794  {
795  localTriPoints.append(pt[0]);
796  localTriPoints.append(pt[1]);
797  localTriPoints.append(pt[2]);
798  }
799  if
800  (
801  (s[0] >= 0.0 && s[0] <= 0.5)
802  && (s[1] >= 0.0 && s[1] <= 0.5)
803  && (s[3] >= 0.0 && s[3] <= 0.5)
804  )
805  {
806  localTriPoints.append(pt[3]);
807  localTriPoints.append(pt[0]);
808  localTriPoints.append(pt[1]);
809  }
810 
811  // Get average of points as fallback
812  forAll(s, i)
813  {
814  if (s[i] >= 0.0 && s[i] <= 0.5)
815  {
816  otherPointSum += pt[i];
817  ++nOther;
818  }
819  }
820  }
821 
822  if (localTriPoints.size() == 0)
823  {
824  // No complete triangles. Get average of all intersection
825  // points.
826  if (nOther > 0)
827  {
828  collapsedPoint[pointi] = otherPointSum/nOther;
829  }
830  }
831  else if (localTriPoints.size() == 3)
832  {
833  // Single triangle. No need for any analysis. Average points.
835  points.transfer(localTriPoints);
836  collapsedPoint[pointi] = sum(points)/points.size();
837  }
838  else
839  {
840  // Convert points into triSurface.
841 
842  // Merge points and compact out non-valid triangles
843  labelList triMap; // merged to unmerged triangle
844  labelList triPointReverseMap; // unmerged to merged point
845  triSurface surf
846  (
847  stitchTriPoints
848  (
849  false, // do not check for duplicate tris
850  localTriPoints,
851  triPointReverseMap,
852  triMap
853  )
854  );
855 
856  labelList faceZone;
857  label nZones = surf.markZones
858  (
859  boolList(surf.nEdges(), false),
860  faceZone
861  );
862 
863  if (nZones == 1)
864  {
865  collapsedPoint[pointi] = calcCentre(surf);
866  }
867  }
868  }
869 
870 
871  // Synchronise snap location
872  syncUnseparatedPoints(collapsedPoint, point::max);
873 
874 
875  snappedPoint.setSize(mesh_.nPoints());
876  snappedPoint = -1;
877 
878  forAll(collapsedPoint, pointi)
879  {
880  if (collapsedPoint[pointi] != point::max)
881  {
882  snappedPoint[pointi] = snappedPoints.size();
883  snappedPoints.append(collapsedPoint[pointi]);
884  }
885  }
886 }
887 
888 
889 Foam::triSurface Foam::isoSurfacePoint::stitchTriPoints
890 (
891  const bool checkDuplicates,
892  const List<point>& triPoints,
893  labelList& triPointReverseMap, // unmerged to merged point
894  labelList& triMap // merged to unmerged triangle
895 ) const
896 {
897  label nTris = triPoints.size()/3;
898 
899  if ((triPoints.size() % 3) != 0)
900  {
902  << "Problem: number of points " << triPoints.size()
903  << " not a multiple of 3." << abort(FatalError);
904  }
905 
906  pointField newPoints;
908  (
909  triPoints,
910  mergeDistance_,
911  false,
912  triPointReverseMap,
913  newPoints
914  );
915 
916  // Check that enough merged.
917  if (debug)
918  {
919  Pout<< "isoSurfacePoint : merged from " << triPoints.size()
920  << " down to " << newPoints.size() << " unique points." << endl;
921 
922  pointField newNewPoints;
923  labelList oldToNew;
924  bool hasMerged = mergePoints
925  (
926  newPoints,
927  mergeDistance_,
928  true,
929  oldToNew,
930  newNewPoints
931  );
932 
933  if (hasMerged)
934  {
936  << "Merged points contain duplicates"
937  << " when merging with distance " << mergeDistance_ << endl
938  << "merged:" << newPoints.size() << " re-merged:"
939  << newNewPoints.size()
940  << abort(FatalError);
941  }
942  }
943 
944 
945  List<labelledTri> tris;
946  {
947  DynamicList<labelledTri> dynTris(nTris);
948  label rawPointi = 0;
949  DynamicList<label> newToOldTri(nTris);
950 
951  for (label oldTriI = 0; oldTriI < nTris; oldTriI++)
952  {
953  labelledTri tri
954  (
955  triPointReverseMap[rawPointi],
956  triPointReverseMap[rawPointi+1],
957  triPointReverseMap[rawPointi+2],
958  0
959  );
960  rawPointi += 3;
961 
962  if ((tri[0] != tri[1]) && (tri[0] != tri[2]) && (tri[1] != tri[2]))
963  {
964  newToOldTri.append(oldTriI);
965  dynTris.append(tri);
966  }
967  }
968 
969  triMap.transfer(newToOldTri);
970  tris.transfer(dynTris);
971  }
972 
973 
974 
975  // Determine 'flat hole' situation (see RMT paper).
976  // Two unconnected triangles get connected because (some of) the edges
977  // separating them get collapsed. Below only checks for duplicate triangles,
978  // not non-manifold edge connectivity.
979  if (checkDuplicates)
980  {
981  labelListList pointFaces;
982  invertManyToMany(newPoints.size(), tris, pointFaces);
983 
984  // Filter out duplicates.
985  DynamicList<label> newToOldTri(tris.size());
986 
987  forAll(tris, triI)
988  {
989  const labelledTri& tri = tris[triI];
990  const labelList& pFaces = pointFaces[tri[0]];
991 
992  // Find the maximum of any duplicates. Maximum since the tris
993  // below triI
994  // get overwritten so we cannot use them in a comparison.
995  label dupTriI = -1;
996  forAll(pFaces, i)
997  {
998  label nbrTriI = pFaces[i];
999 
1000  if (nbrTriI > triI && (tris[nbrTriI] == tri))
1001  {
1002  //Pout<< "Duplicate : " << triI << " verts:" << tri
1003  // << " to " << nbrTriI << " verts:" << tris[nbrTriI]
1004  // << endl;
1005  dupTriI = nbrTriI;
1006  break;
1007  }
1008  }
1009 
1010  if (dupTriI == -1)
1011  {
1012  // There is no (higher numbered) duplicate triangle
1013  label newTriI = newToOldTri.size();
1014  newToOldTri.append(triMap[triI]);
1015  tris[newTriI] = tris[triI];
1016  }
1017  }
1018 
1019  triMap.transfer(newToOldTri);
1020  tris.setSize(triMap.size());
1021 
1022  if (debug)
1023  {
1024  Pout<< "isoSurfacePoint : merged from " << nTris
1025  << " down to " << tris.size() << " unique triangles." << endl;
1026  }
1027 
1028 
1029  if (debug)
1030  {
1031  triSurface surf(tris, geometricSurfacePatchList(), newPoints);
1032 
1033  forAll(surf, facei)
1034  {
1035  const labelledTri& f = surf[facei];
1036  const labelList& fFaces = surf.faceFaces()[facei];
1037 
1038  forAll(fFaces, i)
1039  {
1040  label nbrFacei = fFaces[i];
1041 
1042  if (nbrFacei <= facei)
1043  {
1044  // lower numbered faces already checked
1045  continue;
1046  }
1047 
1048  const labelledTri& nbrF = surf[nbrFacei];
1049 
1050  if (f == nbrF)
1051  {
1053  << "Check : "
1054  << " triangle " << facei << " vertices " << f
1055  << " fc:" << f.centre(surf.points())
1056  << " has the same vertices as triangle " << nbrFacei
1057  << " vertices " << nbrF
1058  << " fc:" << nbrF.centre(surf.points())
1059  << abort(FatalError);
1060  }
1061  }
1062  }
1063  }
1064  }
1065 
1066  return triSurface(tris, geometricSurfacePatchList(), newPoints, true);
1067 }
1068 
1069 
1070 void Foam::isoSurfacePoint::trimToPlanes
1071 (
1072  const PtrList<plane>& planes,
1073  const triPointRef& tri,
1074  DynamicList<point>& newTriPoints
1075 )
1076 {
1077  // Buffer for generated triangles
1078  DynamicList<triPoints> insideTrisA;
1079  storeOp insideOpA(insideTrisA);
1080 
1081  // Buffer for generated triangles
1082  DynamicList<triPoints> insideTrisB;
1083  storeOp insideOpB(insideTrisB);
1084 
1085  triPointRef::dummyOp dop;
1086 
1087  // Store starting triangle in insideTrisA
1088  insideOpA(triPoints(tri.a(), tri.b(), tri.c()));
1089 
1090 
1091  bool useA = true;
1092 
1093  forAll(planes, faceI)
1094  {
1095  const plane& pln = planes[faceI];
1096 
1097  if (useA)
1098  {
1099  insideTrisB.clear();
1100  for (const triPoints& tri : insideTrisA)
1101  {
1102  triPointRef(tri).sliceWithPlane(pln, insideOpB, dop);
1103  }
1104  }
1105  else
1106  {
1107  insideTrisA.clear();
1108  for (const triPoints& tri : insideTrisB)
1109  {
1110  triPointRef(tri).sliceWithPlane(pln, insideOpA, dop);
1111  }
1112  }
1113  useA = !useA;
1114  }
1115 
1116 
1117  DynamicList<triPoints>& newTris = (useA ? insideTrisA : insideTrisB);
1118 
1119  newTriPoints.reserve(newTriPoints.size() + 3*newTris.size());
1120 
1121  // Transfer
1122  for (const triPoints& tri : newTris)
1123  {
1124  newTriPoints.append(tri[0]);
1125  newTriPoints.append(tri[1]);
1126  newTriPoints.append(tri[2]);
1127  }
1128 }
1129 
1130 
1131 void Foam::isoSurfacePoint::trimToBox
1132 (
1133  const treeBoundBox& bb,
1134  DynamicList<point>& triPoints,
1135  DynamicList<label>& triMap // trimmed to original tris
1136 )
1137 {
1138  if (debug)
1139  {
1140  Pout<< "isoSurfacePoint : trimming to " << bb << endl;
1141  }
1142 
1143  // Generate inwards pointing planes
1144  PtrList<plane> planes(treeBoundBox::faceNormals.size());
1146  {
1147  const vector& n = treeBoundBox::faceNormals[faceI];
1148  planes.set(faceI, new plane(bb.faceCentre(faceI), -n));
1149  }
1150 
1151  label nTris = triPoints.size()/3;
1152 
1153  DynamicList<point> newTriPoints(triPoints.size()/16);
1154  triMap.setCapacity(nTris/16);
1155 
1156  label vertI = 0;
1157  for (label triI = 0; triI < nTris; triI++)
1158  {
1159  const point& p0 = triPoints[vertI++];
1160  const point& p1 = triPoints[vertI++];
1161  const point& p2 = triPoints[vertI++];
1162 
1163  label oldNPoints = newTriPoints.size();
1164  trimToPlanes
1165  (
1166  planes,
1167  triPointRef(p0, p1, p2),
1168  newTriPoints
1169  );
1170 
1171  label nCells = (newTriPoints.size()-oldNPoints)/3;
1172  for (label i = 0; i < nCells; i++)
1173  {
1174  triMap.append(triI);
1175  }
1176  }
1177 
1178  if (debug)
1179  {
1180  Pout<< "isoSurfacePoint : trimmed from " << nTris
1181  << " down to " << triMap.size()
1182  << " triangles." << endl;
1183  }
1184 
1185  triPoints.transfer(newTriPoints);
1186 }
1187 
1188 
1189 void Foam::isoSurfacePoint::trimToBox
1190 (
1191  const treeBoundBox& bb,
1192  DynamicList<point>& triPoints, // new points
1193  DynamicList<label>& triMap, // map from (new) triangle to original
1194  labelList& triPointMap, // map from (new) point to original
1195  labelList& interpolatedPoints, // labels of newly introduced points
1196  List<FixedList<label, 3>>& interpolatedOldPoints,// and their interpolation
1197  List<FixedList<scalar, 3>>& interpolationWeights
1198 )
1199 {
1200  const List<point> oldTriPoints(triPoints);
1201 
1202  // Trim triPoints, return map
1203  trimToBox(bb, triPoints, triMap);
1204 
1205 
1206  // Find point correspondence:
1207  // - one-to-one for preserved original points (triPointMap)
1208  // - interpolation for newly introduced points
1209  // (interpolatedOldPoints)
1210  label sz = oldTriPoints.size()/100;
1211  DynamicList<label> dynInterpolatedPoints(sz);
1212  DynamicList<FixedList<label, 3>> dynInterpolatedOldPoints(sz);
1213  DynamicList<FixedList<scalar, 3>> dynInterpolationWeights(sz);
1214 
1215 
1216  triPointMap.setSize(triPoints.size());
1217  forAll(triMap, triI)
1218  {
1219  label oldTriI = triMap[triI];
1220 
1221  // Find point correspondence. Assumes coordinate is bit-copy.
1222  for (label i = 0; i < 3; i++)
1223  {
1224  label pointI = 3*triI+i;
1225  const point& pt = triPoints[pointI];
1226 
1227  // Compare to old-triangle's points
1228  label matchPointI = -1;
1229  for (label j = 0; j < 3; j++)
1230  {
1231  label oldPointI = 3*oldTriI+j;
1232  if (pt == oldTriPoints[oldPointI])
1233  {
1234  matchPointI = oldPointI;
1235  break;
1236  }
1237  }
1238 
1239  triPointMap[pointI] = matchPointI;
1240 
1241  // If new point: calculate and store interpolation
1242  if (matchPointI == -1)
1243  {
1244  dynInterpolatedPoints.append(pointI);
1245 
1246  FixedList<label, 3> oldPoints
1247  (
1248  {3*oldTriI, 3*oldTriI+1, 3*oldTriI+2}
1249  );
1250  dynInterpolatedOldPoints.append(oldPoints);
1251 
1252  triPointRef tri(oldTriPoints, oldPoints);
1253  barycentric2D bary = tri.pointToBarycentric(pt);
1254  FixedList<scalar, 3> weights({bary.a(), bary.b(), bary.c()});
1255 
1256  dynInterpolationWeights.append(weights);
1257  }
1258  }
1259  }
1260 
1261  interpolatedPoints.transfer(dynInterpolatedPoints);
1262  interpolatedOldPoints.transfer(dynInterpolatedOldPoints);
1263  interpolationWeights.transfer(dynInterpolationWeights);
1264 }
1265 
1266 
1267 Foam::triSurface Foam::isoSurfacePoint::subsetMesh
1268 (
1269  const triSurface& s,
1270  const labelList& newToOldFaces,
1271  labelList& oldToNewPoints,
1272  labelList& newToOldPoints
1273 )
1274 {
1275  const boolList include
1276  (
1277  ListOps::createWithValue<bool>(s.size(), newToOldFaces, true, false)
1278  );
1279 
1280  newToOldPoints.setSize(s.points().size());
1281  oldToNewPoints.setSize(s.points().size());
1282  oldToNewPoints = -1;
1283  {
1284  label pointi = 0;
1285 
1286  forAll(include, oldFacei)
1287  {
1288  if (include[oldFacei])
1289  {
1290  // Renumber labels for triangle
1291  const labelledTri& tri = s[oldFacei];
1292 
1293  forAll(tri, fp)
1294  {
1295  label oldPointi = tri[fp];
1296 
1297  if (oldToNewPoints[oldPointi] == -1)
1298  {
1299  oldToNewPoints[oldPointi] = pointi;
1300  newToOldPoints[pointi++] = oldPointi;
1301  }
1302  }
1303  }
1304  }
1305  newToOldPoints.setSize(pointi);
1306  }
1307 
1308  // Extract points
1309  pointField newPoints(newToOldPoints.size());
1310  forAll(newToOldPoints, i)
1311  {
1312  newPoints[i] = s.points()[newToOldPoints[i]];
1313  }
1314  // Extract faces
1315  List<labelledTri> newTriangles(newToOldFaces.size());
1316 
1317  forAll(newToOldFaces, i)
1318  {
1319  // Get old vertex labels
1320  const labelledTri& tri = s[newToOldFaces[i]];
1321 
1322  newTriangles[i][0] = oldToNewPoints[tri[0]];
1323  newTriangles[i][1] = oldToNewPoints[tri[1]];
1324  newTriangles[i][2] = oldToNewPoints[tri[2]];
1325  newTriangles[i].region() = tri.region();
1326  }
1327 
1328  // Reuse storage.
1329  return triSurface(newTriangles, s.patches(), newPoints, true);
1330 }
1331 
1332 
1333 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1334 
1337  const volScalarField& cellValues,
1338  const scalarField& pointValues,
1339  const scalar iso,
1340  const isoSurfaceParams& params,
1341  const bitSet& /*unused*/
1342 )
1343 :
1345  (
1346  cellValues.mesh(),
1347  cellValues.primitiveField(),
1348  pointValues,
1349  iso,
1350  params
1351  ),
1352  cValsPtr_(nullptr),
1353  mergeDistance_(params.mergeTol()*mesh_.bounds().mag())
1354 {
1355  const bool regularise = (params.filter() != filterType::NONE);
1356  const fvMesh& fvmesh = cellValues.mesh();
1357 
1358  if (debug)
1359  {
1360  Pout<< "isoSurfacePoint:" << nl
1361  << " isoField : " << cellValues.name() << nl
1362  << " cell min/max : " << minMax(cVals_) << nl
1363  << " point min/max : " << minMax(pVals_) << nl
1364  << " isoValue : " << iso << nl
1365  << " filter : " << Switch(regularise) << nl
1366  << " mergeTol : " << params.mergeTol() << nl
1367  << endl;
1368  }
1369 
1370  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1371 
1372  // Rewrite input field
1373  // ~~~~~~~~~~~~~~~~~~~
1374  // Rewrite input volScalarField to have interpolated values
1375  // on separated patches.
1376 
1377  cValsPtr_.reset(adaptPatchFields(cellValues).ptr());
1378 
1379 
1380  // Construct cell centres field consistent with cVals
1381  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1382  // Generate field to interpolate. This is identical to the mesh.C()
1383  // except on separated coupled patches and on empty patches.
1384 
1385  slicedVolVectorField meshC
1386  (
1387  IOobject
1388  (
1389  "C",
1390  fvmesh.pointsInstance(),
1391  fvmesh.meshSubDir,
1392  fvmesh,
1395  false
1396  ),
1397  fvmesh,
1398  dimLength,
1399  fvmesh.cellCentres(),
1400  fvmesh.faceCentres()
1401  );
1402  forAll(patches, patchi)
1403  {
1404  const polyPatch& pp = patches[patchi];
1405 
1406  // Adapt separated coupled (proc and cyclic) patches
1407  if (pp.coupled())
1408  {
1409  auto& pfld = const_cast<fvPatchVectorField&>
1410  (
1411  meshC.boundaryField()[patchi]
1412  );
1413 
1414  bitSet isCollocated
1415  (
1416  collocatedFaces(refCast<const coupledPolyPatch>(pp))
1417  );
1418 
1419  forAll(isCollocated, i)
1420  {
1421  if (!isCollocated[i])
1422  {
1423  pfld[i] = mesh_.faceCentres()[pp.start()+i];
1424  }
1425  }
1426  }
1427  else if (isA<emptyPolyPatch>(pp))
1428  {
1429  auto& bfld = const_cast<slicedVolVectorField::Boundary&>
1430  (
1431  meshC.boundaryField()
1432  );
1433 
1434  // Clear old value. Cannot resize it since is a slice.
1435  bfld.set(patchi, nullptr);
1436 
1437  // Set new value we can change
1438  bfld.set
1439  (
1440  patchi,
1442  (
1443  fvmesh.boundary()[patchi],
1444  meshC
1445  )
1446  );
1447 
1448  // Change to face centres
1449  bfld[patchi] = pp.patchSlice(mesh_.faceCentres());
1450  }
1451  }
1452 
1453 
1454  // Pre-calculate patch-per-face to avoid whichPatch call.
1455  labelList boundaryRegion(mesh_.nBoundaryFaces());
1456 
1457  for (const polyPatch& pp : patches)
1458  {
1459  SubList<label>(boundaryRegion, pp.size(), pp.offset()) = pp.index();
1460  }
1461 
1462 
1463  // Determine if any cut through face/cell
1464  calcCutTypes(boundaryRegion, meshC, cValsPtr_(), pVals_);
1465 
1466  if (debug)
1467  {
1468  volScalarField debugField
1469  (
1470  IOobject
1471  (
1472  "isoSurfacePoint.cutType",
1473  fvmesh.time().timeName(),
1474  fvmesh.time(),
1477  false
1478  ),
1479  fvmesh,
1481  );
1482 
1483  auto& debugFld = debugField.primitiveFieldRef();
1484 
1485  forAll(cellCutType_, celli)
1486  {
1487  debugFld[celli] = cellCutType_[celli];
1488  }
1489 
1490  Pout<< "Writing cut types:"
1491  << debugField.objectPath() << endl;
1492 
1493  debugField.write();
1494  }
1495 
1496 
1497  DynamicList<point> snappedPoints(nCutCells_);
1498 
1499  // Per cc -1 or a point inside snappedPoints.
1500  labelList snappedCc;
1501  if (regularise)
1502  {
1503  calcSnappedCc
1504  (
1506  meshC,
1507  cValsPtr_(),
1508  pVals_,
1509 
1510  snappedPoints,
1511  snappedCc
1512  );
1513  }
1514  else
1515  {
1516  snappedCc.setSize(mesh_.nCells());
1517  snappedCc = -1;
1518  }
1519 
1520 
1521 
1522  if (debug)
1523  {
1524  Pout<< "isoSurfacePoint : shifted " << snappedPoints.size()
1525  << " cell centres to intersection." << endl;
1526  }
1527 
1528  label nCellSnaps = snappedPoints.size();
1529 
1530 
1531  // Per point -1 or a point inside snappedPoints.
1532  labelList snappedPoint;
1533  if (regularise)
1534  {
1535  // Determine if point is on boundary.
1536  bitSet isBoundaryPoint(mesh_.nPoints());
1537 
1538  for (const polyPatch& pp : patches)
1539  {
1540  // Mark all boundary points that are not physically coupled
1541  // (so anything but collocated coupled patches)
1542 
1543  if (pp.coupled())
1544  {
1545  const coupledPolyPatch& cpp =
1546  refCast<const coupledPolyPatch>(pp);
1547 
1548  bitSet isCollocated(collocatedFaces(cpp));
1549 
1550  forAll(isCollocated, i)
1551  {
1552  if (!isCollocated[i])
1553  {
1554  const face& f = mesh_.faces()[cpp.start()+i];
1555 
1556  isBoundaryPoint.set(f);
1557  }
1558  }
1559  }
1560  else
1561  {
1562  forAll(pp, i)
1563  {
1564  const face& f = mesh_.faces()[pp.start()+i];
1565 
1566  isBoundaryPoint.set(f);
1567  }
1568  }
1569  }
1570 
1571  calcSnappedPoint
1572  (
1573  isBoundaryPoint,
1575  meshC,
1576  cValsPtr_(),
1577  pVals_,
1578 
1579  snappedPoints,
1580  snappedPoint
1581  );
1582  }
1583  else
1584  {
1585  snappedPoint.setSize(mesh_.nPoints());
1586  snappedPoint = -1;
1587  }
1588 
1589  if (debug)
1590  {
1591  Pout<< "isoSurfacePoint : shifted " << snappedPoints.size()-nCellSnaps
1592  << " vertices to intersection." << endl;
1593  }
1594 
1595 
1596  // Use a triSurface as a temporary for various operations
1597  triSurface tmpsurf;
1598 
1599  {
1600  DynamicList<point> triPoints(3*nCutCells_);
1601  DynamicList<label> triMeshCells(nCutCells_);
1602 
1603  generateTriPoints
1604  (
1605  cValsPtr_(),
1606  pVals_,
1607 
1608  meshC,
1609  mesh_.points(),
1610 
1611  snappedPoints,
1612  snappedCc,
1613  snappedPoint,
1614 
1615  triPoints, // 3 points of the triangle
1616  triMeshCells // per triangle the originating cell
1617  );
1618 
1619  if (debug)
1620  {
1621  Pout<< "isoSurfacePoint : generated " << triMeshCells.size()
1622  << " unmerged triangles from " << triPoints.size()
1623  << " unmerged points." << endl;
1624  }
1625 
1626  label nOldPoints = triPoints.size();
1627 
1628  // Trimmed to original triangle
1629  DynamicList<label> trimTriMap;
1630  // Trimmed to original point
1631  labelList trimTriPointMap;
1632  if (getClipBounds().valid())
1633  {
1634  trimToBox
1635  (
1636  treeBoundBox(getClipBounds()),
1637  triPoints, // new points
1638  trimTriMap, // map from (new) triangle to original
1639  trimTriPointMap, // map from (new) point to original
1640  interpolatedPoints_, // labels of newly introduced points
1641  interpolatedOldPoints_, // and their interpolation
1642  interpolationWeights_
1643  );
1644  triMeshCells = labelField(triMeshCells, trimTriMap);
1645  }
1646 
1647 
1648  // Merge points and compact out non-valid triangles
1649  labelList triMap; // merged to unmerged triangle
1650  tmpsurf = stitchTriPoints
1651  (
1652  true, // check for duplicate tris
1653  triPoints,
1654  triPointMergeMap_, // unmerged to merged point
1655  triMap
1656  );
1657 
1658  if (debug)
1659  {
1660  Pout<< "isoSurfacePoint : generated " << triMap.size()
1661  << " merged triangles." << endl;
1662  }
1663 
1664 
1665  if (getClipBounds().valid())
1666  {
1667  // Adjust interpolatedPoints_
1668  inplaceRenumber(triPointMergeMap_, interpolatedPoints_);
1669 
1670  // Adjust triPointMergeMap_
1671  labelList newTriPointMergeMap(nOldPoints, -1);
1672  forAll(trimTriPointMap, trimPointI)
1673  {
1674  label oldPointI = trimTriPointMap[trimPointI];
1675  if (oldPointI >= 0)
1676  {
1677  label pointI = triPointMergeMap_[trimPointI];
1678  if (pointI >= 0)
1679  {
1680  newTriPointMergeMap[oldPointI] = pointI;
1681  }
1682  }
1683  }
1684  triPointMergeMap_.transfer(newTriPointMergeMap);
1685  }
1686 
1687  meshCells_.setSize(triMap.size());
1688  forAll(triMap, i)
1689  {
1690  meshCells_[i] = triMeshCells[triMap[i]];
1691  }
1692  }
1693 
1694  if (debug)
1695  {
1696  Pout<< "isoSurfacePoint : checking " << tmpsurf.size()
1697  << " triangles for validity." << endl;
1698 
1699  forAll(tmpsurf, facei)
1700  {
1701  triSurfaceTools::validTri(tmpsurf, facei);
1702  }
1703 
1704  fileName stlFile = mesh_.time().path() + ".stl";
1705  Pout<< "Dumping surface to " << stlFile << endl;
1706  tmpsurf.write(stlFile);
1707  }
1708 
1709 
1710  // Transfer to mesh storage. Note, an iso-surface has no zones
1711  {
1712  // Recover the pointField
1713  pointField pts;
1714  tmpsurf.swapPoints(pts);
1715 
1716  // Transcribe from triFace to face
1717  faceList faces;
1718  tmpsurf.triFaceFaces(faces);
1719 
1720  tmpsurf.clearOut();
1721 
1722  Mesh updated(std::move(pts), std::move(faces), surfZoneList());
1723 
1724  this->Mesh::transfer(updated);
1725  }
1726 }
1727 
1728 
1729 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::fvPatchField< vector >
nZones
label nZones
Definition: interpolatedFaces.H:24
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
volFields.H
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::storeOp
Definition: isoSurfacePoint.C:57
Foam::UPstream::commsTypes::blocking
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:104
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::Switch
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:77
Foam::dimless
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
Dimensionless.
Definition: dimensionSets.H:50
Foam::isoSurfacePoint::isoSurfacePoint
isoSurfacePoint(const volScalarField &cellValues, const scalarField &pointValues, const scalar iso, const isoSurfaceParams &params=isoSurfaceParams(), const bitSet &ignoreCells=bitSet())
Construct from cell values and point values.
Definition: isoSurfacePoint.C:1336
Foam::triSurface::clearOut
void clearOut()
Definition: triSurface.C:566
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::isoSurfaceBase
Low-level components common to various iso-surface algorithms.
Definition: isoSurfaceBase.H:66
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
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::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:53
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:186
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
slicedVolFields.H
Foam::triSurface::triFaceFaces
void triFaceFaces(List< face > &plainFaceList) const
Create a list of faces from the triFaces.
Definition: triSurface.C:684
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:53
Foam::GeometricField::primitiveField
const Internal::FieldType & primitiveField() const
Return a const-reference to the internal field.
Definition: GeometricFieldI.H:53
Foam::treeBoundBox
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:86
Foam::polyPatch::coupled
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:329
Foam::polyMesh::meshSubDir
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:321
Foam::UPstream::parRun
static bool & parRun()
Test if this a parallel run, or allow modify access.
Definition: UPstream.H:434
Foam::Time::timeName
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
Foam::boundaryRegion
The boundaryRegion persistent data saved as a Map<dictionary>.
Definition: boundaryRegion.H:72
Foam::FixedList::size
static constexpr label size() noexcept
Return the number of elements in the FixedList.
Definition: FixedList.H:393
Foam::barycentric2D
Barycentric2D< scalar > barycentric2D
A scalar version of the templated Barycentric2D.
Definition: barycentric2D.H:47
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:69
triPoints.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::coupledPolyPatch
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
Definition: coupledPolyPatch.H:53
defineIsoSurfaceInterpolateMethods
#define defineIsoSurfaceInterpolateMethods(ThisClass)
Definition: isoSurfaceBaseMethods.H:54
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
triSurface.H
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::invertManyToMany
void invertManyToMany(const label len, const UList< InputIntListType > &input, List< OutputIntListType > &output)
Invert many-to-many.
Definition: ListOpsTemplates.C:727
isoSurfaceBaseMethods.H
Convenience macros for instantiating iso-surface interpolate methods.
Foam::geometricSurfacePatchList
List< geometricSurfacePatch > geometricSurfacePatchList
A List of geometricSurfacePatch.
Definition: geometricSurfacePatchList.H:47
Foam::isoSurfacePoint
A surface formed by the iso value. After "Regularised Marching Tetrahedra: improved iso-surface extra...
Definition: isoSurfacePoint.H:87
Foam::isoSurfaceParams::filter
filterType filter() const noexcept
Get current filter type.
Definition: isoSurfaceParams.H:202
Foam::polyMesh::pointsInstance
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:846
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::triPoints
Triangle storage. Null constructable (unfortunately triangle<point, point> is not)
Definition: triPoints.H:52
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
Foam::Field< scalar >
isoSurfacePoint.H
Foam::labelField
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:52
Foam::triSurface::write
void write(Ostream &os) const
Write to Ostream in simple OpenFOAM format.
Definition: triSurfaceIO.C:336
Foam::triSurface
Triangulated surface description with patch information.
Definition: triSurface.H:76
Foam::triSurface::swapPoints
virtual void swapPoints(pointField &pts)
Swap points. Similar to movePoints, but returns the old points.
Definition: triSurface.C:625
Foam::collocatedPatch
static bool collocatedPatch(const polyPatch &pp)
Definition: isoSurfacePoint.C:79
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::storeOp::list
DynamicList< triPoints > & list
Definition: isoSurfacePoint.C:59
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:459
Foam::dimensionedScalar
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Definition: dimensionedScalarFwd.H:43
Foam::volScalarField
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:57
Foam::List::resize
void resize(const label newSize)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::storeOp::operator()
void operator()(const triPoints &tri)
Definition: isoSurfacePoint.C:66
Foam::FatalError
error FatalError
Foam::isoSurfaceParams
Preferences for controlling iso-surface algorithms.
Definition: isoSurfaceParams.H:91
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:83
Foam::calculatedFvPatchField
This boundary condition is not designed to be evaluated; it is assmued that the value is assigned via...
Definition: calculatedFvPatchField.H:66
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
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::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:313
Foam::mergePoints
label mergePoints(const PointList &points, const scalar mergeTol, const bool verbose, labelList &pointMap, typename PointList::const_reference origin=PointList::value_type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
Foam::GeometricField::primitiveFieldRef
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field.
Definition: GeometricField.C:766
Foam::volVectorField
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:62
Foam::Pstream::listCombineGather
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
Definition: combineGatherScatter.C:290
Foam::fvMesh::boundary
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:679
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::primitiveMesh::cellCentres
const vectorField & cellCentres() const
Definition: primitiveMeshCellCentresAndVols.C:84
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::polyPatch::patchSlice
const List< T >::subList patchSlice(const UList< T > &l) const
Slice list to patch.
Definition: polyPatch.H:352
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::VectorSpace< Vector< Cmpt >, Cmpt, 3 >::max
static const Vector< Cmpt > max
Definition: VectorSpace.H:117
f
labelList f(nPoints)
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::storeOp::storeOp
storeOp(DynamicList< triPoints > &tris)
Definition: isoSurfacePoint.C:61
Foam::List< label >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:77
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::storeOp::operator()
void operator()(triPoints &&tri)
Definition: isoSurfacePoint.C:71
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
bool
bool
Definition: EEqn.H:20
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::surfZoneList
List< surfZone > surfZoneList
Definition: surfZoneList.H:47
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:325
mergePoints.H
Merge points. See below.
Foam::boundBox::faceNormals
static const FixedList< vector, 6 > faceNormals
The unit normal per face.
Definition: boundBox.H:92
Foam::SlicedGeometricField
Specialization of GeometricField which holds slices of given complete fields in a form that they act ...
Definition: slicedSurfaceFieldsFwd.H:58
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:275
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::minMax
MinMax< label > minMax(const labelHashSet &set)
Find the min/max values of labelHashSet.
Definition: hashSets.C:61
p0
const volScalarField & p0
Definition: EEqn.H:36
Foam::VectorSpace::size
static constexpr direction size() noexcept
The number of elements in the VectorSpace = Ncmpts.
Definition: VectorSpace.H:176
Foam::Pstream::listCombineScatter
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
Definition: combineGatherScatter.C:432
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::triSurfaceTools::validTri
static bool validTri(const triSurface &, const label facei, const bool verbose=true)
Check single triangle for (topological) validity.
Definition: triSurfaceTools.C:2699
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::isoSurfaceParams::mergeTol
scalar mergeTol() const noexcept
Get current merge tolerance.
Definition: isoSurfaceParams.H:214
Foam::GeometricField< scalar, fvPatchField, volMesh >
Foam::MeshedSurface< face >
Foam::IOobject::NO_READ
Definition: IOobject.H:123
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
triSurfaceTools.H
Foam::tensor
Tensor< scalar > tensor
Tensor of scalars, i.e. Tensor<scalar>.
Definition: symmTensor.H:61
Foam::triPointRef
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangle.H:73