meshDualiser.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-2016 OpenFOAM Foundation
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "meshDualiser.H"
29 #include "meshTools.H"
30 #include "polyMesh.H"
31 #include "polyTopoChange.H"
32 #include "mapPolyMesh.H"
33 #include "edgeFaceCirculator.H"
34 #include "mergePoints.H"
35 #include "OFstream.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(meshDualiser, 0);
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 void Foam::meshDualiser::checkPolyTopoChange(const polyTopoChange& meshMod)
48 {
49  // Assume no removed points
50  pointField points(meshMod.points().size());
51  forAll(meshMod.points(), i)
52  {
53  points[i] = meshMod.points()[i];
54  }
55 
56  labelList oldToNew;
57  label nUnique = mergePoints
58  (
59  points,
60  1e-6,
61  false,
62  oldToNew
63  );
64 
65  if (nUnique < points.size())
66  {
67  labelListList newToOld(invertOneToMany(nUnique, oldToNew));
68 
69  forAll(newToOld, newI)
70  {
71  if (newToOld[newI].size() != 1)
72  {
74  << "duplicate verts:" << newToOld[newI]
75  << " coords:"
76  << UIndirectList<point>(points, newToOld[newI])
77  << abort(FatalError);
78  }
79  }
80  }
81 }
82 
83 
84 // Dump state so far.
85 void Foam::meshDualiser::dumpPolyTopoChange
86 (
87  const polyTopoChange& meshMod,
88  const fileName& prefix
89 )
90 {
91  OFstream str1(prefix + "Faces.obj");
92  OFstream str2(prefix + "Edges.obj");
93 
94  Info<< "Dumping current polyTopoChange. Faces to " << str1.name()
95  << " , points and edges to " << str2.name() << endl;
96 
97  const DynamicList<point>& points = meshMod.points();
98 
99  forAll(points, pointi)
100  {
101  meshTools::writeOBJ(str1, points[pointi]);
102  meshTools::writeOBJ(str2, points[pointi]);
103  }
104 
105  const DynamicList<face>& faces = meshMod.faces();
106 
107  forAll(faces, facei)
108  {
109  const face& f = faces[facei];
110 
111  str1<< 'f';
112  forAll(f, fp)
113  {
114  str1<< ' ' << f[fp]+1;
115  }
116  str1<< nl;
117 
118  str2<< 'l';
119  forAll(f, fp)
120  {
121  str2<< ' ' << f[fp]+1;
122  }
123  str2<< ' ' << f[0]+1 << nl;
124  }
125 }
126 
127 
128 Foam::label Foam::meshDualiser::findDualCell
129 (
130  const label celli,
131  const label pointi
132 ) const
133 {
134  const labelList& dualCells = pointToDualCells_[pointi];
135 
136  if (dualCells.size() == 1)
137  {
138  return dualCells[0];
139  }
140  else
141  {
142  label index = mesh_.pointCells()[pointi].find(celli);
143 
144  return dualCells[index];
145  }
146 }
147 
148 
149 void Foam::meshDualiser::generateDualBoundaryEdges
150 (
151  const bitSet& isBoundaryEdge,
152  const label pointi,
153  polyTopoChange& meshMod
154 )
155 {
156  const labelList& pEdges = mesh_.pointEdges()[pointi];
157 
158  forAll(pEdges, pEdgeI)
159  {
160  label edgeI = pEdges[pEdgeI];
161 
162  if (edgeToDualPoint_[edgeI] == -1 && isBoundaryEdge.test(edgeI))
163  {
164  const edge& e = mesh_.edges()[edgeI];
165 
166  edgeToDualPoint_[edgeI] = meshMod.addPoint
167  (
168  e.centre(mesh_.points()),
169  pointi, // masterPoint
170  -1, // zoneID
171  true // inCell
172  );
173  }
174  }
175 }
176 
177 
178 // Return true if point on face has same dual cells on both owner and neighbour
179 // sides.
180 bool Foam::meshDualiser::sameDualCell
181 (
182  const label facei,
183  const label pointi
184 ) const
185 {
186  if (!mesh_.isInternalFace(facei))
187  {
189  << "face:" << facei << " is not internal face."
190  << abort(FatalError);
191  }
192 
193  label own = mesh_.faceOwner()[facei];
194  label nei = mesh_.faceNeighbour()[facei];
195 
196  return findDualCell(own, pointi) == findDualCell(nei, pointi);
197 }
198 
199 
200 Foam::label Foam::meshDualiser::addInternalFace
201 (
202  const label masterPointi,
203  const label masterEdgeI,
204  const label masterFacei,
205 
206  const bool edgeOrder,
207  const label dualCell0,
208  const label dualCell1,
209  const DynamicList<label>& verts,
210  polyTopoChange& meshMod
211 ) const
212 {
213  face newFace(verts);
214 
215  if (edgeOrder != (dualCell0 < dualCell1))
216  {
217  reverse(newFace);
218  }
219 
220  if (debug)
221  {
222  pointField facePoints(meshMod.points(), newFace);
223 
224  labelList oldToNew;
225  label nUnique = mergePoints
226  (
227  facePoints,
228  1e-6,
229  false,
230  oldToNew
231  );
232 
233  if (nUnique < facePoints.size())
234  {
236  << "verts:" << verts << " newFace:" << newFace
237  << " face points:" << facePoints
238  << abort(FatalError);
239  }
240  }
241 
242 
243  label zoneID = -1;
244  bool zoneFlip = false;
245  if (masterFacei != -1)
246  {
247  zoneID = mesh_.faceZones().whichZone(masterFacei);
248 
249  if (zoneID != -1)
250  {
251  const faceZone& fZone = mesh_.faceZones()[zoneID];
252 
253  zoneFlip = fZone.flipMap()[fZone.whichFace(masterFacei)];
254  }
255  }
256 
257  label dualFacei;
258 
259  if (dualCell0 < dualCell1)
260  {
261  dualFacei = meshMod.addFace
262  (
263  newFace,
264  dualCell0, // own
265  dualCell1, // nei
266  masterPointi, // masterPointID
267  masterEdgeI, // masterEdgeID
268  masterFacei, // masterFaceID
269  false, // flipFaceFlux
270  -1, // patchID
271  zoneID, // zoneID
272  zoneFlip // zoneFlip
273  );
274 
275  //pointField dualPoints(meshMod.points());
276  //const vector n(newFace.unitNormal(dualPoints));
277  //
278  //Pout<< "Generated internal dualFace:" << dualFacei
279  // << " verts:" << newFace
280  // << " points:" << UIndirectList<point>(meshMod.points(), newFace)
281  // << " n:" << n
282  // << " between dualowner:" << dualCell0
283  // << " dualneighbour:" << dualCell1
284  // << endl;
285  }
286  else
287  {
288  dualFacei = meshMod.addFace
289  (
290  newFace,
291  dualCell1, // own
292  dualCell0, // nei
293  masterPointi, // masterPointID
294  masterEdgeI, // masterEdgeID
295  masterFacei, // masterFaceID
296  false, // flipFaceFlux
297  -1, // patchID
298  zoneID, // zoneID
299  zoneFlip // zoneFlip
300  );
301 
302  //pointField dualPoints(meshMod.points());
303  //const vector n(newFace.unitNormal(dualPoints));
304  //
305  //Pout<< "Generated internal dualFace:" << dualFacei
306  // << " verts:" << newFace
307  // << " points:" << UIndirectList<point>(meshMod.points(), newFace)
308  // << " n:" << n
309  // << " between dualowner:" << dualCell1
310  // << " dualneighbour:" << dualCell0
311  // << endl;
312  }
313  return dualFacei;
314 }
315 
316 
317 Foam::label Foam::meshDualiser::addBoundaryFace
318 (
319  const label masterPointi,
320  const label masterEdgeI,
321  const label masterFacei,
322 
323  const label dualCelli,
324  const label patchi,
325  const DynamicList<label>& verts,
326  polyTopoChange& meshMod
327 ) const
328 {
329  face newFace(verts);
330 
331  label zoneID = -1;
332  bool zoneFlip = false;
333  if (masterFacei != -1)
334  {
335  zoneID = mesh_.faceZones().whichZone(masterFacei);
336 
337  if (zoneID != -1)
338  {
339  const faceZone& fZone = mesh_.faceZones()[zoneID];
340 
341  zoneFlip = fZone.flipMap()[fZone.whichFace(masterFacei)];
342  }
343  }
344 
345  label dualFacei = meshMod.addFace
346  (
347  newFace,
348  dualCelli, // own
349  -1, // nei
350  masterPointi, // masterPointID
351  masterEdgeI, // masterEdgeID
352  masterFacei, // masterFaceID
353  false, // flipFaceFlux
354  patchi, // patchID
355  zoneID, // zoneID
356  zoneFlip // zoneFlip
357  );
358 
359  //pointField dualPoints(meshMod.points());
360  //const vector n(newFace.unitNormal(dualPoints));
361  //
362  //Pout<< "Generated boundary dualFace:" << dualFacei
363  // << " verts:" << newFace
364  // << " points:" << UIndirectList<point>(meshMod.points(), newFace)
365  // << " n:" << n
366  // << " on dualowner:" << dualCelli
367  // << endl;
368  return dualFacei;
369 }
370 
371 
372 // Walks around edgeI.
373 // splitFace=true : creates multiple faces
374 // splitFace=false: creates single face if same dual cells on both sides,
375 // multiple faces otherwise.
376 void Foam::meshDualiser::createFacesAroundEdge
377 (
378  const bool splitFace,
379  const bitSet& isBoundaryEdge,
380  const label edgeI,
381  const label startFacei,
382  polyTopoChange& meshMod,
383  boolList& doneEFaces
384 ) const
385 {
386  const edge& e = mesh_.edges()[edgeI];
387  const labelList& eFaces = mesh_.edgeFaces()[edgeI];
388 
390  (
391  mesh_.faces()[startFacei],
392  e[0],
393  e[1]
394  );
395 
396  edgeFaceCirculator ie
397  (
398  mesh_,
399  startFacei, // face
400  true, // ownerSide
401  fp, // fp
402  isBoundaryEdge.test(edgeI) // isBoundaryEdge
403  );
404  ie.setCanonical();
405 
406  bool edgeOrder = ie.sameOrder(e[0], e[1]);
407  label startFaceLabel = ie.faceLabel();
408 
409  //Pout<< "At edge:" << edgeI << " verts:" << e
410  // << " points:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
411  // << " started walking at face:" << ie.faceLabel()
412  // << " verts:" << mesh_.faces()[ie.faceLabel()]
413  // << " edgeOrder:" << edgeOrder
414  // << " in direction of cell:" << ie.cellLabel()
415  // << endl;
416 
417  // Walk and collect face.
418  DynamicList<label> verts(100);
419 
420  if (edgeToDualPoint_[edgeI] != -1)
421  {
422  verts.append(edgeToDualPoint_[edgeI]);
423  }
424  if (faceToDualPoint_[ie.faceLabel()] != -1)
425  {
426  doneEFaces[eFaces.find(ie.faceLabel())] = true;
427  verts.append(faceToDualPoint_[ie.faceLabel()]);
428  }
429  if (cellToDualPoint_[ie.cellLabel()] != -1)
430  {
431  verts.append(cellToDualPoint_[ie.cellLabel()]);
432  }
433 
434  label currentDualCell0 = findDualCell(ie.cellLabel(), e[0]);
435  label currentDualCell1 = findDualCell(ie.cellLabel(), e[1]);
436 
437  ++ie;
438 
439  while (true)
440  {
441  label facei = ie.faceLabel();
442 
443  // Mark face as visited.
444  doneEFaces[eFaces.find(facei)] = true;
445 
446  if (faceToDualPoint_[facei] != -1)
447  {
448  verts.append(faceToDualPoint_[facei]);
449  }
450 
451  label celli = ie.cellLabel();
452 
453  if (celli == -1)
454  {
455  // At ending boundary face. We've stored the face point above
456  // so this is the whole face.
457  break;
458  }
459 
460 
461  label dualCell0 = findDualCell(celli, e[0]);
462  label dualCell1 = findDualCell(celli, e[1]);
463 
464  // Generate face. (always if splitFace=true; only if needed to
465  // separate cells otherwise)
466  if
467  (
468  splitFace
469  || (
470  dualCell0 != currentDualCell0
471  || dualCell1 != currentDualCell1
472  )
473  )
474  {
475  // Close current face.
476  addInternalFace
477  (
478  -1, // masterPointi
479  edgeI, // masterEdgeI
480  -1, // masterFacei
481  edgeOrder,
482  currentDualCell0,
483  currentDualCell1,
484  verts.shrink(),
485  meshMod
486  );
487 
488  // Restart
489  currentDualCell0 = dualCell0;
490  currentDualCell1 = dualCell1;
491 
492  verts.clear();
493  if (edgeToDualPoint_[edgeI] != -1)
494  {
495  verts.append(edgeToDualPoint_[edgeI]);
496  }
497  if (faceToDualPoint_[facei] != -1)
498  {
499  verts.append(faceToDualPoint_[facei]);
500  }
501  }
502 
503  if (cellToDualPoint_[celli] != -1)
504  {
505  verts.append(cellToDualPoint_[celli]);
506  }
507 
508  ++ie;
509 
510  if (ie == ie.end())
511  {
512  // Back at start face (for internal edge only). See if this needs
513  // adding.
514  if (!isBoundaryEdge.test(edgeI))
515  {
516  label startDual = faceToDualPoint_[startFaceLabel];
517 
518  if (startDual != -1 && !verts.found(startDual))
519  {
520  verts.append(startDual);
521  }
522  }
523  break;
524  }
525  }
526 
527  verts.shrink();
528  addInternalFace
529  (
530  -1, // masterPointi
531  edgeI, // masterEdgeI
532  -1, // masterFacei
533  edgeOrder,
534  currentDualCell0,
535  currentDualCell1,
536  verts,
537  meshMod
538  );
539 }
540 
541 
542 // Walks around circumference of facei. Creates single face. Gets given
543 // starting (feature) edge to start from. Returns ending edge. (all edges
544 // in form of index in faceEdges)
545 void Foam::meshDualiser::createFaceFromInternalFace
546 (
547  const label facei,
548  label& fp,
549  polyTopoChange& meshMod
550 ) const
551 {
552  const face& f = mesh_.faces()[facei];
553  const labelList& fEdges = mesh_.faceEdges()[facei];
554  label own = mesh_.faceOwner()[facei];
555  label nei = mesh_.faceNeighbour()[facei];
556 
557  //Pout<< "createFaceFromInternalFace : At face:" << facei
558  // << " verts:" << f
559  // << " points:" << UIndirectList<point>(mesh_.points(), f)
560  // << " started walking at edge:" << fEdges[fp]
561  // << " verts:" << mesh_.edges()[fEdges[fp]]
562  // << endl;
563 
564 
565  // Walk and collect face.
566  DynamicList<label> verts(100);
567 
568  verts.append(faceToDualPoint_[facei]);
569  verts.append(edgeToDualPoint_[fEdges[fp]]);
570 
571  // Step to vertex after edge mid
572  fp = f.fcIndex(fp);
573 
574  // Get cells on either side of face at that point
575  label currentDualCell0 = findDualCell(own, f[fp]);
576  label currentDualCell1 = findDualCell(nei, f[fp]);
577 
578  forAll(f, i)
579  {
580  // Check vertex
581  if (pointToDualPoint_[f[fp]] != -1)
582  {
583  verts.append(pointToDualPoint_[f[fp]]);
584  }
585 
586  // Edge between fp and fp+1
587  label edgeI = fEdges[fp];
588 
589  if (edgeToDualPoint_[edgeI] != -1)
590  {
591  verts.append(edgeToDualPoint_[edgeI]);
592  }
593 
594  // Next vertex on edge
595  label nextFp = f.fcIndex(fp);
596 
597  // Get dual cells on nextFp to check whether face needs closing.
598  label dualCell0 = findDualCell(own, f[nextFp]);
599  label dualCell1 = findDualCell(nei, f[nextFp]);
600 
601  if (dualCell0 != currentDualCell0 || dualCell1 != currentDualCell1)
602  {
603  // Check: make sure that there is a midpoint on the edge.
604  if (edgeToDualPoint_[edgeI] == -1)
605  {
607  << "face:" << facei << " verts:" << f
608  << " points:" << UIndirectList<point>(mesh_.points(), f)
609  << " no feature edge between " << f[fp]
610  << " and " << f[nextFp] << " although have different"
611  << " dual cells." << endl
612  << "point " << f[fp] << " has dual cells "
613  << currentDualCell0 << " and " << currentDualCell1
614  << " ; point "<< f[nextFp] << " has dual cells "
615  << dualCell0 << " and " << dualCell1
616  << abort(FatalError);
617  }
618 
619 
620  // Close current face.
621  verts.shrink();
622  addInternalFace
623  (
624  -1, // masterPointi
625  -1, // masterEdgeI
626  facei, // masterFacei
627  true, // edgeOrder,
628  currentDualCell0,
629  currentDualCell1,
630  verts,
631  meshMod
632  );
633  break;
634  }
635 
636  fp = nextFp;
637  }
638 }
639 
640 
641 // Given a point on a face converts the faces around the point.
642 // (pointFaces()). Gets starting face and marks off visited faces in donePFaces.
643 void Foam::meshDualiser::createFacesAroundBoundaryPoint
644 (
645  const label patchi,
646  const label patchPointi,
647  const label startFacei,
648  polyTopoChange& meshMod,
649  boolList& donePFaces // pFaces visited
650 ) const
651 {
652  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
653  const polyPatch& pp = patches[patchi];
654  const labelList& pFaces = pp.pointFaces()[patchPointi];
655  const labelList& own = mesh_.faceOwner();
656 
657  label pointi = pp.meshPoints()[patchPointi];
658 
659  if (pointToDualPoint_[pointi] == -1)
660  {
661  // Not a feature point. Loop over all connected
662  // pointFaces.
663 
664  // Starting face
665  label facei = startFacei;
666 
667  DynamicList<label> verts(4);
668 
669  while (true)
670  {
671  label index = pFaces.find(facei-pp.start());
672 
673  // Has face been visited already?
674  if (donePFaces[index])
675  {
676  break;
677  }
678  donePFaces[index] = true;
679 
680  // Insert face centre
681  verts.append(faceToDualPoint_[facei]);
682 
683  label dualCelli = findDualCell(own[facei], pointi);
684 
685  // Get the edge before the patchPointi
686  const face& f = mesh_.faces()[facei];
687  label fp = f.find(pointi);
688  label prevFp = f.rcIndex(fp);
689  label edgeI = mesh_.faceEdges()[facei][prevFp];
690 
691  if (edgeToDualPoint_[edgeI] != -1)
692  {
693  verts.append(edgeToDualPoint_[edgeI]);
694  }
695 
696  // Get next boundary face (whilst staying on edge).
697  edgeFaceCirculator circ
698  (
699  mesh_,
700  facei,
701  true, // ownerSide
702  prevFp, // index of edge in face
703  true // isBoundaryEdge
704  );
705 
706  do
707  {
708  ++circ;
709  }
710  while (mesh_.isInternalFace(circ.faceLabel()));
711 
712  // Step to next face
713  facei = circ.faceLabel();
714 
715  if (facei < pp.start() || facei >= pp.start()+pp.size())
716  {
718  << "Walked from face on patch:" << patchi
719  << " to face:" << facei
720  << " fc:" << mesh_.faceCentres()[facei]
721  << " on patch:" << patches.whichPatch(facei)
722  << abort(FatalError);
723  }
724 
725  // Check if different cell.
726  if (dualCelli != findDualCell(own[facei], pointi))
727  {
729  << "Different dual cells but no feature edge"
730  << " inbetween point:" << pointi
731  << " coord:" << mesh_.points()[pointi]
732  << abort(FatalError);
733  }
734  }
735 
736  verts.shrink();
737 
738  label dualCelli = findDualCell(own[facei], pointi);
739 
740  //Bit dodgy: create dualface from the last face (instead of from
741  // the central point). This will also use the original faceZone to
742  // put the new face (which might span multiple original faces) in.
743 
744  addBoundaryFace
745  (
746  //pointi, // masterPointi
747  -1, // masterPointi
748  -1, // masterEdgeI
749  facei, // masterFacei
750  dualCelli,
751  patchi,
752  verts,
753  meshMod
754  );
755  }
756  else
757  {
758  label facei = startFacei;
759 
760  // Storage for face
761  DynamicList<label> verts(mesh_.faces()[facei].size());
762 
763  // Starting point.
764  verts.append(pointToDualPoint_[pointi]);
765 
766  // Find edge between pointi and next point on face.
767  const labelList& fEdges = mesh_.faceEdges()[facei];
768  label nextEdgeI = fEdges[mesh_.faces()[facei].find(pointi)];
769  if (edgeToDualPoint_[nextEdgeI] != -1)
770  {
771  verts.append(edgeToDualPoint_[nextEdgeI]);
772  }
773 
774  do
775  {
776  label index = pFaces.find(facei-pp.start());
777 
778  // Has face been visited already?
779  if (donePFaces[index])
780  {
781  break;
782  }
783  donePFaces[index] = true;
784 
785  // Face centre
786  verts.append(faceToDualPoint_[facei]);
787 
788  // Find edge before pointi on facei
789  const labelList& fEdges = mesh_.faceEdges()[facei];
790  const face& f = mesh_.faces()[facei];
791  label prevFp = f.rcIndex(f.find(pointi));
792  label edgeI = fEdges[prevFp];
793 
794  if (edgeToDualPoint_[edgeI] != -1)
795  {
796  // Feature edge. Close any face so far. Note: uses face to
797  // create dualFace from. Could use pointi instead.
798  verts.append(edgeToDualPoint_[edgeI]);
799  addBoundaryFace
800  (
801  -1, // masterPointi
802  -1, // masterEdgeI
803  facei, // masterFacei
804  findDualCell(own[facei], pointi),
805  patchi,
806  verts.shrink(),
807  meshMod
808  );
809  verts.clear();
810 
811  verts.append(pointToDualPoint_[pointi]);
812  verts.append(edgeToDualPoint_[edgeI]);
813  }
814 
815  // Cross edgeI to next boundary face
816  edgeFaceCirculator circ
817  (
818  mesh_,
819  facei,
820  true, // ownerSide
821  prevFp, // index of edge in face
822  true // isBoundaryEdge
823  );
824 
825  do
826  {
827  ++circ;
828  }
829  while (mesh_.isInternalFace(circ.faceLabel()));
830 
831  // Step to next face. Quit if not on same patch.
832  facei = circ.faceLabel();
833  }
834  while
835  (
836  facei != startFacei
837  && facei >= pp.start()
838  && facei < pp.start()+pp.size()
839  );
840 
841  if (verts.size() > 2)
842  {
843  // Note: face created from face, not from pointi
844  addBoundaryFace
845  (
846  -1, // masterPointi
847  -1, // masterEdgeI
848  startFacei, // masterFacei
849  findDualCell(own[facei], pointi),
850  patchi,
851  verts.shrink(),
852  meshMod
853  );
854  }
855  }
856 }
857 
858 
859 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
860 
861 Foam::meshDualiser::meshDualiser(const polyMesh& mesh)
862 :
863  mesh_(mesh),
864  pointToDualCells_(mesh_.nPoints()),
865  pointToDualPoint_(mesh_.nPoints(), -1),
866  cellToDualPoint_(mesh_.nCells()),
867  faceToDualPoint_(mesh_.nFaces(), -1),
868  edgeToDualPoint_(mesh_.nEdges(), -1)
869 {}
870 
871 
872 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
873 
875 (
876  const bool splitFace,
877  const labelList& featureFaces,
878  const labelList& featureEdges,
879  const labelList& singleCellFeaturePoints,
880  const labelList& multiCellFeaturePoints,
881  polyTopoChange& meshMod
882 )
883 {
884  const labelList& own = mesh_.faceOwner();
885  const labelList& nei = mesh_.faceNeighbour();
886  const vectorField& cellCentres = mesh_.cellCentres();
887 
888  // Mark boundary edges and points.
889  // (Note: in 1.4.2 we can use the built-in mesh point ordering
890  // facility instead)
891  bitSet isBoundaryEdge(mesh_.nEdges());
892  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
893  {
894  const labelList& fEdges = mesh_.faceEdges()[facei];
895 
896  isBoundaryEdge.set(fEdges);
897  }
898 
899 
900  if (splitFace)
901  {
902  // This is a special mode where whenever we are walking around an edge
903  // every area through a cell becomes a separate dualface. So two
904  // dual cells will probably have more than one dualface between them!
905  // This mode implies that
906  // - all faces have to be feature faces since there has to be a
907  // dualpoint at the face centre.
908  // - all edges have to be feature edges ,,
909  boolList featureFaceSet(mesh_.nFaces(), false);
910  forAll(featureFaces, i)
911  {
912  featureFaceSet[featureFaces[i]] = true;
913  }
914  label facei = featureFaceSet.find(false);
915 
916  if (facei != -1)
917  {
919  << "In split-face-mode (splitFace=true) but not all faces"
920  << " marked as feature faces." << endl
921  << "First conflicting face:" << facei
922  << " centre:" << mesh_.faceCentres()[facei]
923  << abort(FatalError);
924  }
925 
926  boolList featureEdgeSet(mesh_.nEdges(), false);
927  forAll(featureEdges, i)
928  {
929  featureEdgeSet[featureEdges[i]] = true;
930  }
931  label edgeI = featureEdgeSet.find(false);
932 
933  if (edgeI != -1)
934  {
935  const edge& e = mesh_.edges()[edgeI];
937  << "In split-face-mode (splitFace=true) but not all edges"
938  << " marked as feature edges." << endl
939  << "First conflicting edge:" << edgeI
940  << " verts:" << e
941  << " coords:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
942  << abort(FatalError);
943  }
944  }
945  else
946  {
947  // Check that all boundary faces are feature faces.
948 
949  boolList featureFaceSet(mesh_.nFaces(), false);
950  forAll(featureFaces, i)
951  {
952  featureFaceSet[featureFaces[i]] = true;
953  }
954  for
955  (
956  label facei = mesh_.nInternalFaces();
957  facei < mesh_.nFaces();
958  facei++
959  )
960  {
961  if (!featureFaceSet[facei])
962  {
964  << "Not all boundary faces marked as feature faces."
965  << endl
966  << "First conflicting face:" << facei
967  << " centre:" << mesh_.faceCentres()[facei]
968  << abort(FatalError);
969  }
970  }
971  }
972 
973 
974 
975 
976  // Start creating cells, points, and faces (in that order)
977 
978 
979  // 1. Mark which cells to create
980  // Mostly every point becomes one cell but sometimes (for feature points)
981  // all cells surrounding a feature point become cells. Also a non-manifold
982  // point can create two cells! So a dual cell is uniquely defined by a
983  // mesh point + cell (as in pointCells index)
984 
985  // 2. Mark which face centres to create
986 
987  // 3. Internal faces can now consist of
988  // - only cell centres of walk around edge
989  // - cell centres + face centres of walk around edge
990  // - same but now other side is not a single cell
991 
992  // 4. Boundary faces (or internal faces between cell zones!) now consist of
993  // - walk around boundary point.
994 
995 
996 
997  autoPtr<OFstream> dualCcStr;
998  if (debug)
999  {
1000  dualCcStr.reset(new OFstream("dualCc.obj"));
1001  Pout<< "Dumping centres of dual cells to " << dualCcStr().name()
1002  << endl;
1003  }
1004 
1005 
1006  // Dual cells (from points)
1007  // ~~~~~~~~~~~~~~~~~~~~~~~~
1008 
1009  // pointToDualCells_[pointi]
1010  // - single entry : all cells surrounding point all become the same
1011  // cell.
1012  // - multiple entries: in order of pointCells.
1013 
1014 
1015  // feature points that become single cell
1016  forAll(singleCellFeaturePoints, i)
1017  {
1018  label pointi = singleCellFeaturePoints[i];
1019 
1020  pointToDualPoint_[pointi] = meshMod.addPoint
1021  (
1022  mesh_.points()[pointi],
1023  pointi, // masterPoint
1024  mesh_.pointZones().whichZone(pointi), // zoneID
1025  true // inCell
1026  );
1027 
1028  // Generate single cell
1029  pointToDualCells_[pointi].setSize(1);
1030  pointToDualCells_[pointi][0] = meshMod.addCell
1031  (
1032  pointi, //masterPointID,
1033  -1, //masterEdgeID,
1034  -1, //masterFaceID,
1035  -1, //masterCellID,
1036  -1 //zoneID
1037  );
1038  if (dualCcStr.valid())
1039  {
1040  meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointi]);
1041  }
1042  }
1043 
1044  // feature points that become multiple cells
1045  forAll(multiCellFeaturePoints, i)
1046  {
1047  label pointi = multiCellFeaturePoints[i];
1048 
1049  if (pointToDualCells_[pointi].size() > 0)
1050  {
1052  << "Point " << pointi << " at:" << mesh_.points()[pointi]
1053  << " is both in singleCellFeaturePoints"
1054  << " and multiCellFeaturePoints."
1055  << abort(FatalError);
1056  }
1057 
1058  pointToDualPoint_[pointi] = meshMod.addPoint
1059  (
1060  mesh_.points()[pointi],
1061  pointi, // masterPoint
1062  mesh_.pointZones().whichZone(pointi), // zoneID
1063  true // inCell
1064  );
1065 
1066  // Create dualcell for every cell connected to dual point
1067 
1068  const labelList& pCells = mesh_.pointCells()[pointi];
1069 
1070  pointToDualCells_[pointi].setSize(pCells.size());
1071 
1072  forAll(pCells, pCelli)
1073  {
1074  pointToDualCells_[pointi][pCelli] = meshMod.addCell
1075  (
1076  pointi, //masterPointID
1077  -1, //masterEdgeID
1078  -1, //masterFaceID
1079  -1, //masterCellID
1080  mesh_.cellZones().whichZone(pCells[pCelli]) //zoneID
1081  );
1082  if (dualCcStr.valid())
1083  {
1085  (
1086  dualCcStr(),
1087  0.5*(mesh_.points()[pointi]+cellCentres[pCells[pCelli]])
1088  );
1089  }
1090  }
1091  }
1092  // Normal points
1093  forAll(mesh_.points(), pointi)
1094  {
1095  if (pointToDualCells_[pointi].empty())
1096  {
1097  pointToDualCells_[pointi].setSize(1);
1098  pointToDualCells_[pointi][0] = meshMod.addCell
1099  (
1100  pointi, //masterPointID,
1101  -1, //masterEdgeID,
1102  -1, //masterFaceID,
1103  -1, //masterCellID,
1104  -1 //zoneID
1105  );
1106 
1107  if (dualCcStr.valid())
1108  {
1109  meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointi]);
1110  }
1111  }
1112  }
1113 
1114 
1115  // Dual points (from cell centres, feature faces, feature edges)
1116  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1117 
1118  forAll(cellToDualPoint_, celli)
1119  {
1120  cellToDualPoint_[celli] = meshMod.addPoint
1121  (
1122  cellCentres[celli],
1123  mesh_.faces()[mesh_.cells()[celli][0]][0], // masterPoint
1124  -1, // zoneID
1125  true // inCell
1126  );
1127  }
1128 
1129  // From face to dual point
1130 
1131  forAll(featureFaces, i)
1132  {
1133  label facei = featureFaces[i];
1134 
1135  faceToDualPoint_[facei] = meshMod.addPoint
1136  (
1137  mesh_.faceCentres()[facei],
1138  mesh_.faces()[facei][0], // masterPoint
1139  -1, // zoneID
1140  true // inCell
1141  );
1142  }
1143  // Detect whether different dual cells on either side of a face. This
1144  // would necessitate having a dual face built from the face and thus a
1145  // dual point at the face centre.
1146  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1147  {
1148  if (faceToDualPoint_[facei] == -1)
1149  {
1150  const face& f = mesh_.faces()[facei];
1151 
1152  forAll(f, fp)
1153  {
1154  label ownDualCell = findDualCell(own[facei], f[fp]);
1155  label neiDualCell = findDualCell(nei[facei], f[fp]);
1156 
1157  if (ownDualCell != neiDualCell)
1158  {
1159  faceToDualPoint_[facei] = meshMod.addPoint
1160  (
1161  mesh_.faceCentres()[facei],
1162  f[fp], // masterPoint
1163  -1, // zoneID
1164  true // inCell
1165  );
1166 
1167  break;
1168  }
1169  }
1170  }
1171  }
1172 
1173  // From edge to dual point
1174 
1175  forAll(featureEdges, i)
1176  {
1177  label edgeI = featureEdges[i];
1178 
1179  const edge& e = mesh_.edges()[edgeI];
1180 
1181  edgeToDualPoint_[edgeI] = meshMod.addPoint
1182  (
1183  e.centre(mesh_.points()),
1184  e[0], // masterPoint
1185  -1, // zoneID
1186  true // inCell
1187  );
1188  }
1189 
1190  // Detect whether different dual cells on either side of an edge. This
1191  // would neccesitate having a dual face built perpendicular to the edge
1192  // and thus a dual point at the mid of the edge.
1193  // Note: not really true - the face can be built without the edge centre!
1194  const labelListList& edgeCells = mesh_.edgeCells();
1195 
1196  forAll(edgeCells, edgeI)
1197  {
1198  if (edgeToDualPoint_[edgeI] == -1)
1199  {
1200  const edge& e = mesh_.edges()[edgeI];
1201 
1202  // We need a point on the edge if not all cells on both sides
1203  // are the same.
1204 
1205  const labelList& eCells = mesh_.edgeCells()[edgeI];
1206 
1207  label dualE0 = findDualCell(eCells[0], e[0]);
1208  label dualE1 = findDualCell(eCells[0], e[1]);
1209 
1210  for (label i = 1; i < eCells.size(); i++)
1211  {
1212  label newDualE0 = findDualCell(eCells[i], e[0]);
1213 
1214  if (dualE0 != newDualE0)
1215  {
1216  edgeToDualPoint_[edgeI] = meshMod.addPoint
1217  (
1218  e.centre(mesh_.points()),
1219  e[0], // masterPoint
1220  mesh_.pointZones().whichZone(e[0]), // zoneID
1221  true // inCell
1222  );
1223 
1224  break;
1225  }
1226 
1227  label newDualE1 = findDualCell(eCells[i], e[1]);
1228 
1229  if (dualE1 != newDualE1)
1230  {
1231  edgeToDualPoint_[edgeI] = meshMod.addPoint
1232  (
1233  e.centre(mesh_.points()),
1234  e[1], // masterPoint
1235  mesh_.pointZones().whichZone(e[1]), // zoneID
1236  true // inCell
1237  );
1238 
1239  break;
1240  }
1241  }
1242  }
1243  }
1244 
1245  // Make sure all boundary edges emanating from feature points are
1246  // feature edges as well.
1247  forAll(singleCellFeaturePoints, i)
1248  {
1249  generateDualBoundaryEdges
1250  (
1251  isBoundaryEdge,
1252  singleCellFeaturePoints[i],
1253  meshMod
1254  );
1255  }
1256  forAll(multiCellFeaturePoints, i)
1257  {
1258  generateDualBoundaryEdges
1259  (
1260  isBoundaryEdge,
1261  multiCellFeaturePoints[i],
1262  meshMod
1263  );
1264  }
1265 
1266 
1267  // Check for duplicate points
1268  if (debug)
1269  {
1270  dumpPolyTopoChange(meshMod, "generatedPoints_");
1271  checkPolyTopoChange(meshMod);
1272  }
1273 
1274 
1275  // Now we have all points and cells
1276  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1277  // - pointToDualCells_ : per point a single dualCell or multiple dualCells
1278  // - pointToDualPoint_ : per point -1 or the dual point at the coordinate
1279  // - edgeToDualPoint_ : per edge -1 or the edge centre
1280  // - faceToDualPoint_ : per face -1 or the face centre
1281  // - cellToDualPoint_ : per cell the cell centre
1282  // Now we have to walk all edges and construct faces. Either single face
1283  // per edge or multiple (-if nonmanifold edge -if different dualcells)
1284 
1285  const edgeList& edges = mesh_.edges();
1286 
1287  forAll(edges, edgeI)
1288  {
1289  const labelList& eFaces = mesh_.edgeFaces()[edgeI];
1290 
1291  boolList doneEFaces(eFaces.size(), false);
1292 
1293  forAll(eFaces, i)
1294  {
1295  if (!doneEFaces[i])
1296  {
1297  // We found a face that hasn't yet been visited. This might
1298  // happen for non-manifold edges where a single edge can
1299  // become multiple faces.
1300 
1301  label startFacei = eFaces[i];
1302 
1303  //Pout<< "Walking edge:" << edgeI
1304  // << " points:" << mesh_.points()[e[0]]
1305  // << mesh_.points()[e[1]]
1306  // << " startFace:" << startFacei
1307  // << " at:" << mesh_.faceCentres()[startFacei]
1308  // << endl;
1309 
1310  createFacesAroundEdge
1311  (
1312  splitFace,
1313  isBoundaryEdge,
1314  edgeI,
1315  startFacei,
1316  meshMod,
1317  doneEFaces
1318  );
1319  }
1320  }
1321  }
1322 
1323  if (debug)
1324  {
1325  dumpPolyTopoChange(meshMod, "generatedFacesFromEdges_");
1326  }
1327 
1328  // Create faces from feature faces. These can be internal or external faces.
1329  // - feature face : centre needs to be included.
1330  // - single cells on either side: triangulate
1331  // - multiple cells: create single face between unique cell pair. Only
1332  // create face where cells differ on either side.
1333  // - non-feature face : inbetween cell zones.
1334  forAll(faceToDualPoint_, facei)
1335  {
1336  if (faceToDualPoint_[facei] != -1 && mesh_.isInternalFace(facei))
1337  {
1338  const face& f = mesh_.faces()[facei];
1339  const labelList& fEdges = mesh_.faceEdges()[facei];
1340 
1341  // Starting edge
1342  label fp = 0;
1343 
1344  do
1345  {
1346  // Find edge that is in dual mesh and where the
1347  // next point (fp+1) has different dual cells on either side.
1348  bool foundStart = false;
1349 
1350  do
1351  {
1352  if
1353  (
1354  edgeToDualPoint_[fEdges[fp]] != -1
1355  && !sameDualCell(facei, f.nextLabel(fp))
1356  )
1357  {
1358  foundStart = true;
1359  break;
1360  }
1361  fp = f.fcIndex(fp);
1362  }
1363  while (fp != 0);
1364 
1365  if (!foundStart)
1366  {
1367  break;
1368  }
1369 
1370  // Walk from edge fp and generate a face.
1371  createFaceFromInternalFace
1372  (
1373  facei,
1374  fp,
1375  meshMod
1376  );
1377  }
1378  while (fp != 0);
1379  }
1380  }
1381 
1382  if (debug)
1383  {
1384  dumpPolyTopoChange(meshMod, "generatedFacesFromFeatFaces_");
1385  }
1386 
1387 
1388  // Create boundary faces. Every boundary point has one or more dualcells.
1389  // These need to be closed.
1390  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1391 
1392  forAll(patches, patchi)
1393  {
1394  const polyPatch& pp = patches[patchi];
1395 
1396  const labelListList& pointFaces = pp.pointFaces();
1397 
1398  forAll(pointFaces, patchPointi)
1399  {
1400  const labelList& pFaces = pointFaces[patchPointi];
1401 
1402  boolList donePFaces(pFaces.size(), false);
1403 
1404  forAll(pFaces, i)
1405  {
1406  if (!donePFaces[i])
1407  {
1408  // Starting face
1409  label startFacei = pp.start()+pFaces[i];
1410 
1411  //Pout<< "Walking around point:" << pointi
1412  // << " coord:" << mesh_.points()[pointi]
1413  // << " on patch:" << patchi
1414  // << " startFace:" << startFacei
1415  // << " at:" << mesh_.faceCentres()[startFacei]
1416  // << endl;
1417 
1418  createFacesAroundBoundaryPoint
1419  (
1420  patchi,
1421  patchPointi,
1422  startFacei,
1423  meshMod,
1424  donePFaces // pFaces visited
1425  );
1426  }
1427  }
1428  }
1429  }
1430 
1431  if (debug)
1432  {
1433  dumpPolyTopoChange(meshMod, "generatedFacesFromBndFaces_");
1434  }
1435 }
1436 
1437 
1438 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::reverse
void reverse(UList< T > &list, const label n)
Definition: UListI.H:396
meshTools.H
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
edgeFaceCirculator.H
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
mapPolyMesh.H
polyTopoChange.H
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:69
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
polyMesh.H
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
OFstream.H
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::edgeFaceCirculator::getMinIndex
static label getMinIndex(const face &f, const label v0, const label v1)
Helper: find index in face of edge or -1. Index is such that edge is.
Definition: edgeFaceCirculatorI.H:143
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::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:107
Foam::meshDualiser::setRefinement
void setRefinement(const bool splitFace, const labelList &featureFaces, const labelList &featureEdges, const labelList &singleCellFeaturePoints, const labelList &multiCellFeaturePoints, polyTopoChange &meshMod)
Insert all changes into meshMod to convert the polyMesh into.
Foam::polyBoundaryMesh::whichPatch
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Definition: polyBoundaryMesh.C:805
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
zoneID
const labelIOList & zoneID
Definition: interpolatedFaces.H:22
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
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::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
meshDualiser.H
Foam::nl
constexpr char nl
Definition: Ostream.H:385
f
labelList f(nPoints)
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:325
mergePoints.H
Merge points. See below.
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::invertOneToMany
labelListList invertOneToMany(const label len, const labelUList &map)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:114
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)