Adding cfMesh-v1.0 into the repository
[foam-extend-3.2.git] / src / meshLibrary / utilities / meshes / polyMeshGenModifier / polyMeshGenModifierZipUpCells.C
blobbde99de060263f7742de5ab9bac28e0956c0ae23
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | cfMesh: A library for mesh generation
4    \\    /   O peration     |
5     \\  /    A nd           | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6      \\/     M anipulation  | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
8 License
9     This file is part of cfMesh.
11     cfMesh is free software; you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation; either version 3 of the License, or (at your
14     option) any later version.
16     cfMesh 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.
21     You should have received a copy of the GNU General Public License
22     along with cfMesh.  If not, see <http://www.gnu.org/licenses/>.
24 Description
26 \*---------------------------------------------------------------------------*/
28 #include "polyMeshGenModifier.H"
29 #include "demandDrivenData.H"
30 #include "HashSet.H"
31 #include "boolList.H"
33 //#define DEBUG_ZIPUP
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 namespace Foam
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 void polyMeshGenModifier::zipUpCells()
44     this->clearOut();
45     
46     Info<< "Zipping up topologically open cells" << endl;
47     
48     const pointFieldPMG& points = mesh_.points();
49     const cellListPMG& cells = mesh_.cells();
50     
51     faceListPMG& faces = mesh_.faces_;
53     // Algorithm:
54     // Take the original mesh and visit all cells.  For every cell
55     // calculate the edges of all faces on the cells.  A cell is
56     // correctly topologically closed when all the edges are reference
57     // by exactly two cells.  If the edges are referenced only by a
58     // single cell, additional vertices need to be inserted into some
59     // of the faces (topological closedness).  If an edge is
60     // referenced by more that two faces, there is an error in
61     // topological closedness.
62     // Point insertion into the faces is done by attempting to create
63     // closed loops and inserting the intermediate points into the
64     // defining edge
65     // Note:
66     // The algorithm is recursive and changes the mesh faces in each
67     // pass.  It is therefore essential to discard the addressing
68     // after every pass.  The algorithm is completed when the mesh
69     // stops changing.
70     // 
72     label nChangedFacesInMesh;
73     label nCycles(0);
75     labelHashSet problemCells;
77     do
78     {
79         nChangedFacesInMesh = 0;
80         
81         //- calculate pointFaces addressing
82         # ifdef DEBUG_ZIPUP
83         Info << "Starting pointFaces addressing " << endl;
84         # endif
86         List<direction> nUsage(points.size(), direction(0));
87         forAll(faces, fI)
88         {
89             const face& f = faces[fI];
90             forAll(f, pI)
91                 ++nUsage[f[pI]];
92         }
93         
94         VRWGraph pFaces(points.size());
95         forAll(nUsage, pI)
96             pFaces.setRowSize(pI, nUsage[pI]);
97         
98         nUsage = 0;
99         
100         forAll(faces, fI)
101         {
102             const face& f = faces[fI];
103             forAll(f, pI)
104                 pFaces(f[pI], nUsage[f[pI]]++) = fI;
105         }
106         
107         nUsage.clear();
109         # ifdef DEBUG_ZIPUP
110         Info << "Starting zipping cells " << endl;
111         # endif
113         forAll (cells, cellI)
114         {
115             const labelList& curFaces = cells[cellI];
116             const edgeList cellEdges = cells[cellI].edges(faces);
117             const labelList cellPoints = cells[cellI].labels(faces);
119             // Find the edges used only once in the cell
121             labelList edgeUsage(cellEdges.size(), 0);
123             forAll (curFaces, faceI)
124             {
125                 edgeList curFaceEdges = faces[curFaces[faceI]].edges();
127                 forAll (curFaceEdges, faceEdgeI)
128                 {
129                     const edge& curEdge = curFaceEdges[faceEdgeI];
131                     forAll (cellEdges, cellEdgeI)
132                     {
133                         if (cellEdges[cellEdgeI] == curEdge)
134                         {
135                             edgeUsage[cellEdgeI]++;
136                             break;
137                         }
138                     }
139                 }
140             }
142             edgeList singleEdges(cellEdges.size());
143             label nSingleEdges = 0;
145             forAll (edgeUsage, edgeI)
146             {
147                 if (edgeUsage[edgeI] == 1)
148                 {
149                     singleEdges[nSingleEdges] = cellEdges[edgeI];
150                     nSingleEdges++;
151                 }
152                 else if (edgeUsage[edgeI] != 2)
153                 {
154                     Warning
155                         << "void polyMesh::zipUpCells() : "
156                         << "edge " << cellEdges[edgeI] << " in cell " << cellI
157                         << " used " << edgeUsage[edgeI] << " times. " << nl
158                         << "Should be 1 or 2 - serious error "
159                         << "in mesh structure. " << endl;
161 #           ifdef DEBUG_ZIPUP
162                     forAll (curFaces, faceI)
163                     {
164                         Info<< "face: " << faces[curFaces[faceI]]
165                             << endl;
166                     }
168                     Info<< "Cell edges: " << cellEdges << nl
169                         << "Edge usage: " << edgeUsage << nl
170                         << "Cell points: " << cellPoints << endl;
172                     forAll (cellPoints, cpI)
173                     {
174                         Info<< "vertex create \"" << cellPoints[cpI]
175                             << "\" coordinates "
176                             << points[cellPoints[cpI]] << endl;
177                     }
178 #           endif
180                     // Gather the problem cell
181                     problemCells.insert(cellI);
182                 }
183             }
185             // Check if the cell is already zipped up
186             if (nSingleEdges == 0) continue;
188             singleEdges.setSize(nSingleEdges);
190 #           ifdef DEBUG_ZIPUP
191             Info << "Cell " << cellI << endl;
193             forAll (curFaces, faceI)
194             {
195                 Info<< "face: " << faces[curFaces[faceI]] << endl;
196             }
198             Info<< "Cell edges: " << cellEdges << nl
199                 << "Edge usage: " << edgeUsage << nl
200                 << "Single edges: " << singleEdges << nl
201                 << "Cell points: " << cellPoints << endl;
203             forAll (cellPoints, cpI)
204             {
205                 Info<< "vertex create \"" << cellPoints[cpI]
206                     << "\" coordinates "
207                     << points[cellPoints[cpI]] << endl;
208             }
209 #           endif
211             // Loop through all single edges and mark the points they use
212             // points marked twice are internal to edge; those marked more than
213             // twice are corners
215             labelList pointUsage(cellPoints.size(), 0);
217             forAll (singleEdges, edgeI)
218             {
219                 const edge& curEdge = singleEdges[edgeI];
221                 forAll (cellPoints, pointI)
222                 {
223                     if
224                     (
225                         cellPoints[pointI] == curEdge.start()
226                      || cellPoints[pointI] == curEdge.end()
227                     )
228                     {
229                         pointUsage[pointI]++;
230                     }
231                 }
232             }
234             boolList singleEdgeUsage(singleEdges.size(), false);
236             // loop through all edges and eliminate the ones that are
237             // blocked out
238             forAll (singleEdges, edgeI)
239             {
240                 bool blockedHead = false;
241                 bool blockedTail = false;
243                 label newEdgeStart = singleEdges[edgeI].start();
244                 label newEdgeEnd = singleEdges[edgeI].end();
246                 // check that the edge has not got all ends blocked
247                 forAll (cellPoints, pointI)
248                 {
249                     if (cellPoints[pointI] == newEdgeStart)
250                     {
251                         if (pointUsage[pointI] > 2)
252                         {
253                             blockedHead = true;
254                         }
255                     }
256                     else if (cellPoints[pointI] == newEdgeEnd)
257                     {
258                         if (pointUsage[pointI] > 2)
259                         {
260                             blockedTail = true;
261                         }
262                     }
263                 }
265                 if (blockedHead && blockedTail)
266                 {
267                     // Eliminating edge singleEdges[edgeI] as blocked
268                     singleEdgeUsage[edgeI] = true;
269                 }
270             }
272             // Go through the points and start from the point used twice
273             // check all the edges to find the edges starting from this point
274             // add the 
276             labelListList edgesToInsert(singleEdges.size());
277             label nEdgesToInsert = 0;
279             // Find a good edge
280             forAll (singleEdges, edgeI)
281             {
282                 SLList<label> pointChain;
284                 bool blockHead = false;
285                 bool blockTail = false;
287                 if (!singleEdgeUsage[edgeI])
288                 {
289                     // found a new edge
290                     singleEdgeUsage[edgeI] = true;
292                     label newEdgeStart = singleEdges[edgeI].start();
293                     label newEdgeEnd = singleEdges[edgeI].end();
295                     pointChain.insert(newEdgeStart);
296                     pointChain.append(newEdgeEnd);
298 #                   ifdef DEBUG_CHAIN
299                     Info<< "found edge to start with: "
300                         << singleEdges[edgeI] << endl;
301 #                   endif
303                     // Check if head or tail are blocked
304                     forAll (cellPoints, pointI)
305                     {
306                         if (cellPoints[pointI] == newEdgeStart)
307                         {
308                             if (pointUsage[pointI] > 2)
309                             {
310 #                               ifdef DEBUG_CHAIN
311                                 Info << "start head blocked" << endl;
312 #                               endif
314                                 blockHead = true;
315                             }
316                         }
317                         else if(cellPoints[pointI] == newEdgeEnd)
318                         {
319                             if (pointUsage[pointI] > 2)
320                             {
321 #                               ifdef DEBUG_CHAIN
322                                 Info << "start tail blocked" << endl;
323 #                               endif
325                                 blockTail = true;
326                             }
327                         }
328                     }
330                     bool stopSearching = false;
332                     // Go through the unused edges and try to chain them up
333                     do
334                     {
335                         stopSearching = false;
337                         forAll (singleEdges, addEdgeI)
338                         {
339                             if (!singleEdgeUsage[addEdgeI])
340                             {
341                                 // Grab start and end of the candidate
342                                 label addStart =
343                                     singleEdges[addEdgeI].start();
345                                 label addEnd =
346                                     singleEdges[addEdgeI].end();
348 #                               ifdef DEBUG_CHAIN
349                                 Info<< "Trying candidate "
350                                     << singleEdges[addEdgeI] << endl;
351 #                               endif
353                                 // Try to add the edge onto the head
354                                 if (!blockHead)
355                                 {
356                                     if (pointChain.first() == addStart)
357                                     {
358                                         // Added at start mark as used
359                                         pointChain.insert(addEnd);
361                                         singleEdgeUsage[addEdgeI] = true;
362                                     }
363                                     else if (pointChain.first() == addEnd)
364                                     {
365                                         pointChain.insert(addStart);
367                                         singleEdgeUsage[addEdgeI] = true;
368                                     }
369                                 }
371                                 // Try the other end only if the first end
372                                 // did not add it
373                                 if (!blockTail && !singleEdgeUsage[addEdgeI])
374                                 {
375                                     if (pointChain.last() == addStart)
376                                     {
377                                         // Added at start mark as used
378                                         pointChain.append(addEnd);
380                                         singleEdgeUsage[addEdgeI] = true;
381                                     }
382                                     else if (pointChain.last() == addEnd)
383                                     {
384                                         pointChain.append(addStart);
386                                         singleEdgeUsage[addEdgeI] = true;
387                                     }
388                                 }
390                                 // check if the new head or tail are blocked
391                                 label curEdgeStart = pointChain.first();
392                                 label curEdgeEnd = pointChain.last();
394 #                               ifdef DEBUG_CHAIN
395                                 Info<< "curEdgeStart: " << curEdgeStart
396                                     << " curEdgeEnd: " << curEdgeEnd << endl;
397 #                               endif
399                                 forAll (cellPoints, pointI)
400                                 {
401                                     if (cellPoints[pointI] == curEdgeStart)
402                                     {
403                                         if (pointUsage[pointI] > 2)
404                                         {
405 #                                           ifdef DEBUG_CHAIN
406                                             Info << "head blocked" << endl;
407 #                                           endif
409                                             blockHead = true;
410                                         }
411                                     }
412                                     else if(cellPoints[pointI] == curEdgeEnd)
413                                     {
414                                         if (pointUsage[pointI] > 2)
415                                         {
416 #                                           ifdef DEBUG_CHAIN
417                                             Info << "tail blocked" << endl;
418 #                                           endif
420                                             blockTail = true;
421                                         }
422                                     }
423                                 }
425                                 // Check if the loop is closed
426                                 if (curEdgeStart == curEdgeEnd)
427                                 {
428 #                                   ifdef DEBUG_CHAIN
429                                     Info << "closed loop" << endl;
430 #                                   endif
432                                     pointChain.removeHead();
434                                     blockHead = true;
435                                     blockTail = true;
437                                     stopSearching = true;
438                                 }
440 #                               ifdef DEBUG_CHAIN
441                                 Info<< "current pointChain: " << pointChain
442                                     << endl;
443 #                               endif
445                                 if (stopSearching) break;
446                             }
447                         }
448                     } while (stopSearching);
449                 }
451 #               ifdef DEBUG_CHAIN
452                 Info << "completed patch chain: " << pointChain << endl;
453 #               endif
455                 if (pointChain.size() > 2)
456                 {
457                     edgesToInsert[nEdgesToInsert] = pointChain;
458                     nEdgesToInsert++;
459                 }
460             }
462             edgesToInsert.setSize(nEdgesToInsert);
464 #           ifdef DEBUG_ZIPUP
465             Info << "edgesToInsert: " << edgesToInsert << endl;
466 #           endif
468             // Insert the edges into a list of faces
469             forAll (edgesToInsert, edgeToInsertI)
470             {
471                 // Order the points of the edge
472                 // Warning: the ordering must be parametric, because in
473                 // the case of multiple point insertion onto the same edge
474                 // it is possible to get non-cyclic loops
475                 // 
477                 const labelList& unorderedEdge = edgesToInsert[edgeToInsertI];
479                 scalarField dist(unorderedEdge.size());
481                 // Calculate distance
482                 point startPoint = points[unorderedEdge[0]];
483                 dist[0] = 0;
485                 vector dir =
486                     points[unorderedEdge[unorderedEdge.size() - 1]]
487                   - startPoint;
489                 for (label i = 1; i < dist.size(); i++)
490                 {
491                     dist[i] = (points[unorderedEdge[i]] - startPoint) & dir;
492                 }
494                 // Sort points
495                 labelList orderedEdge(unorderedEdge.size(), -1);
496                 boolList used(unorderedEdge.size(), false);
498                 forAll (orderedEdge, epI)
499                 {
500                     label nextPoint = -1;
501                     scalar minDist = GREAT;
503                     forAll (dist, i)
504                     {
505                         if (!used[i] && dist[i] < minDist)
506                         {
507                             minDist = dist[i];
508                             nextPoint = i;
509                         }
510                     }
512                     // Insert the next point
513                     orderedEdge[epI] = unorderedEdge[nextPoint];
514                     used[nextPoint] = true;
515                 }
517 #               ifdef DEBUG_ORDER
518                 Info<< "unorderedEdge: " << unorderedEdge << nl
519                     << "orderedEdge: " << orderedEdge << endl;
520 #               endif
522                 // check for duplicate points in the ordered edge
523                 forAll (orderedEdge, checkI)
524                 {
525                     for
526                     (
527                         label checkJ = checkI + 1;
528                         checkJ < orderedEdge.size();
529                         checkJ++
530                     )
531                     {
532                         if (orderedEdge[checkI] == orderedEdge[checkJ])
533                         {
534                             Warning
535                                 << "void polyMesh::zipUpCells() : "
536                                 << "Duplicate point found in edge to insert. "
537                                 << nl << "Point: " << orderedEdge[checkI]
538                                 << " edge: " << orderedEdge << endl;
540                             problemCells.insert(cellI);
541                         }
542                     }
543                 }
545                 edge testEdge
546                 (
547                     orderedEdge[0],
548                     orderedEdge[orderedEdge.size() - 1]
549                 );
551                 // In order to avoid edge-to-edge comparison, get faces using
552                 // point-face addressing in two goes.
553                 const label start = testEdge.start();
554                 const label end = testEdge.end();
555                 
556                 labelList facesSharingEdge
557                 (
558                     pFaces.sizeOfRow(start) +
559                     pFaces.sizeOfRow(end)
560                 );
561                 label nfse = 0;
562                 
563                 forAllRow(pFaces, start, pfI)
564                     facesSharingEdge[nfse++] = pFaces(start, pfI);
565                 
566                 forAllRow(pFaces, end, pfI)
567                     facesSharingEdge[nfse++] = pFaces(end, pfI);
569                 forAll(facesSharingEdge, faceI)
570                 {
571                     bool faceChanges = false;
573                     // Label of the face being analysed
574                     const label currentFaceIndex = facesSharingEdge[faceI];
576                     const edgeList curFaceEdges =
577                         faces[currentFaceIndex].edges();
579                     forAll (curFaceEdges, cfeI)
580                     {
581                         if (curFaceEdges[cfeI] == testEdge)
582                         {
583                             faceChanges = true;
584                             break;
585                         }
586                     }
588                     if (faceChanges)
589                     {
590                         nChangedFacesInMesh++;
591                         // In order to avoid loosing point from multiple
592                         // insertions into the same face, the new face
593                         // will be change incrementally.
594                         // 1) Check if all the internal points of the edge
595                         // to add already exist in the face. If so, the
596                         // edge has already been included 2) Check if the
597                         // point insertion occurs on an edge which is
598                         // still untouched. If so, simply insert
599                         // additional points into the face.  3) If not,
600                         // the edge insertion occurs on an already
601                         // modified edge. ???
603                         face& newFace = faces[currentFaceIndex];
605                         bool allPointsPresent = true;
607                         forAll (orderedEdge, oeI)
608                         {
609                             bool curPointFound = false;
611                             forAll (newFace, nfI)
612                             {
613                                 if (newFace[nfI] == orderedEdge[oeI])
614                                 {
615                                     curPointFound = true;
616                                     break;
617                                 }
618                             }
620                             allPointsPresent =
621                                 allPointsPresent && curPointFound;
622                         }
624 #                       ifdef DEBUG_ZIPUP
625                         if (allPointsPresent)
626                         {
627                             Info << "All points present" << endl;
628                         }
629 #                       endif
631                         if (!allPointsPresent)
632                         {
633                             // Not all points are already present.  The
634                             // new edge will need to be inserted into the
635                             // face.
637                             // Check to see if a new edge fits onto an
638                             // untouched edge of the face.  Make sure the
639                             // edges are grabbed before the face is
640                             // resized.
641                             edgeList newFaceEdges = newFace.edges();
643 #                           ifdef DEBUG_ZIPUP
644                             Info << "Not all points present." << endl;
645 #                           endif
647                             label nNewFacePoints = 0;
649                             bool edgeAdded = false;
651                             forAll (newFaceEdges, curFacEdgI)
652                             {
653                                 // Does the current edge change?
654                                 if (newFaceEdges[curFacEdgI] == testEdge)
655                                 {
656                                     // Found an edge match
657                                     edgeAdded = true;
659                                     // Resize the face to accept additional
660                                     // points
661                                     newFace.setSize
662                                     (
663                                         newFace.size()
664                                       + orderedEdge.size() - 2
665                                     );
667                                     if
668                                     (
669                                         newFaceEdges[curFacEdgI].start()
670                                      == testEdge.start()
671                                     )
672                                     {
673                                         // insertion in ascending order
674                                         for
675                                         (
676                                             label i = 0;
677                                             i < orderedEdge.size() - 1;
678                                             i++
679                                         )
680                                         {
681                                             newFace[nNewFacePoints] =
682                                                 orderedEdge[i];
683                                             nNewFacePoints++;
684                                         }
685                                     }
686                                     else
687                                     {
688                                         // insertion in reverse order
689                                         for
690                                         (
691                                             label i = orderedEdge.size() - 1;
692                                             i > 0;
693                                             i--
694                                         )
695                                         {
696                                             newFace[nNewFacePoints] =
697                                                 orderedEdge[i];
698                                             nNewFacePoints++;
699                                         }
700                                     }
701                                 }
702                                 else
703                                 {
704                                     // Does not fit onto this edge.
705                                     // Copy the next point into the face
706                                     newFace[nNewFacePoints] =
707                                         newFaceEdges[curFacEdgI].start();
708                                     nNewFacePoints++;
709                                 }
710                             }
711                             
712                             forAll(newFace, pI)
713                                 pFaces.appendIfNotIn
714                                 (
715                                     newFace[pI],
716                                     currentFaceIndex
717                                 );
719 #                           ifdef DEBUG_ZIPUP
720                             Info<< "oldFace: "
721                                 << faces[currentFaceIndex] << nl
722                                 << "newFace: " << newFace << endl;
723 #                           endif
725                             // Check for duplicate points in the new face
726                             forAll (newFace, checkI)
727                             {
728                                 for
729                                 (
730                                     label checkJ = checkI + 1;
731                                     checkJ < newFace.size();
732                                     checkJ++
733                                 )
734                                 {
735                                     if (newFace[checkI] == newFace[checkJ])
736                                     {
737                                         Warning
738                                             << "void polyMesh::zipUpCells()"
739                                             << "Duplicate point found "
740                                             << "in the new face. " << nl
741                                             << "Point: "
742                                             << orderedEdge[checkI]
743                                             << " face: "
744                                             << newFace << endl;
746                                         problemCells.insert(cellI);
747                                     }
748                                 }
749                             }
751                             // Check if the edge is added.
752                             // If not, then it comes on top of an already
753                             // modified edge and they need to be
754                             // merged in together.
755                             if (!edgeAdded)
756                             {
757                                 Info<< "This edge modifies an already modified "
758                                     << "edge.  Point insertions skipped."
759                                     << endl;
760                             }
761                         }
762                     }
763                 }
764             }
765         }
767         if (problemCells.size() > 0)
768         {
769             // This cycle has failed.  Print out the problem cells
770             labelList toc(problemCells.toc());
771             sort(toc);
773             FatalErrorIn("void polyMesh::zipUpCells()")
774                 << "Found " << problemCells.size() << " problem cells." << nl
775                 << "Cells: " << toc
776                 << abort(FatalError);
777         }
779         Info<< "Cycle " << ++nCycles
780             << " changed " << nChangedFacesInMesh << " faces." << endl;
781     } while (nChangedFacesInMesh > 0 || nCycles > 100);
783     if (nChangedFacesInMesh > 0)
784     {
785         FatalErrorIn("void polyMesh::zipUpCells()")
786             << "cell zip-up failed after 100 cycles.  Probable problem "
787             << "with the original mesh"
788             << abort(FatalError);
789     }
790     Info << "Finished zipping the mesh." << endl;
793 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
795 } // End namespace Foam
797 // ************************************************************************* //