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