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