Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / src / mesh / cfMesh / cartesianMesh / cartesianMeshExtractor / cartesianMeshExtractorPolyMesh.C
bloba2172b4d608124df43f2e77055b2651b91c59456
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 "cartesianMeshExtractor.H"
29 #include "demandDrivenData.H"
30 #include "meshOctree.H"
31 #include "labelledPair.H"
33 #include "meshSurfaceEngine.H"
34 #include "helperFunctions.H"
35 #include "helperFunctionsPar.H"
36 #include "decomposeFaces.H"
37 #include "decomposeCells.H"
39 #include <map>
40 #include <sstream>
42 //#define DEBUGMesh
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
46 namespace Foam
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 void cartesianMeshExtractor::createPolyMesh()
53     Info << "Creating polyMesh from octree" << endl;
55     const meshOctree& octree = octreeCheck_.octree();
57     //- give labels to cubes which will be used as mesh cells
58     const List<direction>& cType = octreeCheck_.boxType();
60     labelList& leafCellLabel = *leafCellLabelPtr_;
61     label nCells(0);
62     forAll(cType, leafI)
63     {
64         if(
65             Pstream::parRun() &&
66             (octree.returnLeaf(leafI).procNo() != Pstream::myProcNo())
67         )
68             continue;
70         if( cType[leafI] & meshOctreeAddressing::MESHCELL )
71         {
72             leafCellLabel[leafI] = nCells++;
73         }
74     }
76     //- access to mesh data
77     polyMeshGenModifier meshModifier(mesh_);
78     faceListPMG& faces = meshModifier.facesAccess();
79     cellListPMG& cells = meshModifier.cellsAccess();
81     //- start creating octree mesh
82     cells.setSize(nCells);
83     List<direction> nFacesInCell(nCells, direction(0));
84     label nFaces(0);
86     const VRWGraph& octreeFaces = octreeCheck_.octreeFaces();
87     const labelLongList& owner = octreeCheck_.octreeFaceOwner();
88     const labelLongList& neighbour = octreeCheck_.octreeFaceNeighbour();
90     //- map storing box label and a direction for each processor face
91     //- The map stores data in the same order on both sides of processor
92     //- boundaries. This is a consequence of Morton ordering of
93     //- leaf boxes in the octree.
94     std::map<label, labelLongList> procFaces;
96     forAll(octreeFaces, faceI)
97     {
98         const label own = owner[faceI];
99         const label nei = neighbour[faceI];
101         const label ownLabel = leafCellLabel[own];
102         label neiLabel(-1);
103         if( nei != -1 )
104             neiLabel = leafCellLabel[nei];
106         if( (ownLabel != -1) && (neiLabel != -1) )
107         {
108             ++nFaces;
109             ++nFacesInCell[ownLabel];
110             ++nFacesInCell[neiLabel];
111         }
112         else if( ownLabel != -1 )
113         {
114             ++nFaces;
115             ++nFacesInCell[ownLabel];
117             if( (nei != -1) && (cType[nei] & meshOctreeAddressing::MESHCELL) )
118             {
119                 const label procNo = octree.returnLeaf(nei).procNo();
121                 procFaces[procNo].append(faceI);
122             }
123         }
124         else if( neiLabel != -1 )
125         {
126             ++nFaces;
127             ++nFacesInCell[neiLabel];
129             if( (own != -1) && (cType[own] & meshOctreeAddressing::MESHCELL) )
130             {
131                 const label procNo = octree.returnLeaf(own).procNo();
133                 procFaces[procNo].append(faceI);
134             }
135         }
136     }
138     //- case is a serial run
139     faces.setSize(nFaces);
140     forAll(cells, cI)
141         cells[cI].setSize(nFacesInCell[cI]);
142     nFacesInCell = 0;
144     //- calculate faces in processor patches
145     if( Pstream::parRun() )
146     {
147         PtrList<processorBoundaryPatch>& procBoundaries =
148             meshModifier.procBoundariesAccess();
150         //- set the number of procBoundaries
151         procBoundaries.setSize(procFaces.size());
152         std::ostringstream ss;
153         ss << Pstream::myProcNo();
154         const word name("processor"+ss.str()+"to");
155         label nProcBoundaries(nFaces), patchI(0);
157         //- allocate memory for processor patches
158         std::map<label, labelLongList>::const_iterator iter;
159         for(iter=procFaces.begin();iter!=procFaces.end();++iter)
160         {
161             const label procI = iter->first;
163             std::ostringstream ssNei;
164             ssNei << procI;
165             procBoundaries.set
166             (
167                 patchI,
168                 new processorBoundaryPatch
169                 (
170                     name+ssNei.str(),
171                     "processor",
172                     iter->second.size(),
173                     0,
174                     Pstream::myProcNo(),
175                     procI
176                 )
177             );
179             nProcBoundaries -= iter->second.size();
180             ++patchI;
181         }
183         //- create processor faces
184         //- they need to be created here because of the correct ordering
185         patchI = 0;
186         for(iter=procFaces.begin();iter!=procFaces.end();++iter)
187         {
188             procBoundaries[patchI].patchStart() = nProcBoundaries;
190             const labelLongList& patchFaces = iter->second;
192             forAll(patchFaces, pfI)
193             {
194                 const label fLabel = patchFaces[pfI];
195                 const label own = owner[fLabel];
196                 const label nei = neighbour[fLabel];
198                 const label curCell = leafCellLabel[own];
199                 label neiCell(-1);
200                 if( nei != -1 )
201                     neiCell = leafCellLabel[nei];
203                 //- create a processor face
204                 if( neiCell == -1 )
205                 {
206                     //- add a face
207                     faces[nProcBoundaries].setSize(octreeFaces[fLabel].size());
208                     forAllRow(octreeFaces, fLabel, pI)
209                         faces[nProcBoundaries][pI] = octreeFaces(fLabel, pI);
210                     cells[curCell][nFacesInCell[curCell]++] = nProcBoundaries++;
211                 }
212                 else if( curCell == -1 )
213                 {
214                     //- add a reversed face
215                     faces[nProcBoundaries].setSize(octreeFaces[fLabel].size());
216                     label i(0);
217                     faces[nProcBoundaries][i++] = octreeFaces(fLabel, 0);
218                     for(label pI=octreeFaces.sizeOfRow(fLabel)-1;pI>0;--pI)
219                         faces[nProcBoundaries][i++] = octreeFaces(fLabel, pI);
220                     cells[neiCell][nFacesInCell[neiCell]++] = nProcBoundaries++;
221                 }
222                 else
223                 {
224                     FatalErrorIn
225                     (
226                         "void cartesianMeshExtractor::createPolyMesh()"
227                     ) << "Face " << octreeFaces[fLabel] << " causes problems!"
228                         << abort(FatalError);
229                 }
230             }
232             if( procBoundaries[patchI].patchSize() !=
233                 (nProcBoundaries - procBoundaries[patchI].patchStart())
234             )
235                 FatalErrorIn
236                 (
237                     "cartesianMeshExtractor::createPolyMesh()"
238                 ) << "Invalid patch size!" << Pstream::myProcNo()
239                     << abort(FatalError);
241             ++patchI;
242         }
243     }
245     nFaces = 0;
247     forAll(octreeFaces, faceI)
248     {
249         const label own = owner[faceI];
250         const label nei = neighbour[faceI];
252         const label ownLabel = leafCellLabel[own];
253         label neiLabel(-1);
254         if( nei != -1 )
255             neiLabel = leafCellLabel[nei];
257         if( (ownLabel != -1) && (neiLabel != -1) )
258         {
259             //- internal face
260             faces[nFaces].setSize(octreeFaces.sizeOfRow(faceI));
261             forAllRow(octreeFaces, faceI, pI)
262                 faces[nFaces][pI] = octreeFaces(faceI, pI);
264             cells[ownLabel][nFacesInCell[ownLabel]++] = nFaces;
265             cells[neiLabel][nFacesInCell[neiLabel]++] = nFaces;
266             ++nFaces;
267         }
268         else if( ownLabel != -1 )
269         {
270             if( (nei != -1) && (cType[nei] & meshOctreeAddressing::MESHCELL) )
271             {
272                 //- face at a parallel boundary
273                 continue;
274             }
276             //- boundary face
277             faces[nFaces].setSize(octreeFaces.sizeOfRow(faceI));
278             forAllRow(octreeFaces, faceI, pI)
279                 faces[nFaces][pI] = octreeFaces(faceI, pI);
281             cells[ownLabel][nFacesInCell[ownLabel]++] = nFaces;
282             ++nFaces;
283         }
284         else if( neiLabel != -1 )
285         {
286             if( (own != -1) && (cType[own] & meshOctreeAddressing::MESHCELL) )
287             {
288                 //- face at a parallel boundary
289                 continue;
290             }
292             //- boundary face
293             faces[nFaces].setSize(octreeFaces.sizeOfRow(faceI));
294             faces[nFaces][0] = octreeFaces(faceI, 0);
295             for(label pI=octreeFaces.sizeOfRow(faceI)-1;pI>0;--pI)
296                 faces[nFaces][octreeFaces.sizeOfRow(faceI)-pI] =
297                     octreeFaces(faceI, pI);
299             cells[neiLabel][nFacesInCell[neiLabel]++] = nFaces;
300             ++nFaces;
301         }
302     }
304     # ifdef DEBUGMesh
305     label nProcBoundaries(0);
306     forAll(procBoundaries, patchI)
307         nProcBoundaries += procBoundaries[patchI].patchSize();
309     if( faces.size() != (nProcBoundaries + nFaces) )
310     {
311         Serr << "Number of faces " << faces.size() << endl;
312         Serr << "Number of processor boundaries " << nProcBoundaries << endl;
313         Serr << "Number of domain faces " << nFaces << endl;
314         FatalErrorIn
315         (
316             "void cartesianMeshExtractor::createPolyMesh()"
317         ) << Pstream::myProcNo() << "This mesh is invalid!"
318             << abort(FatalError);
319     }
321     vectorField closedness(cells.size(), vector::zero);
322     const labelList& owner = mesh_.owner();
323     const labelList& neighbour = mesh_.neighbour();
324     forAll(owner, faceI)
325         if( owner[faceI] == -1 )
326         {
327             Info << "faces " << faces << endl;
328             FatalErrorIn
329             (
330                 "void cartesianMeshExtractor::createPolyMesh"
331                 "("
332                 "pointFieldPMG& points,"
333                 "faceListPMG& faces,"
334                 "cellListPMG& cells"
335                 ")"
336             ) << "Face " << faceI
337                 << " has no owner and neighbour!!" << abort(FatalError);
338         }
340     forAll(faces, faceI)
341     {
342         const vector area = faces[faceI].normal(mesh_.points());
343         closedness[owner[faceI]] += area;
344         if( neighbour[faceI] != -1 )
345             closedness[neighbour[faceI]] -= area;
346     }
348     forAll(closedness, cellI)
349         if( mag(closedness[cellI]) > 1e-10 )
350             Info << "Cell " << cellI << " is not closed by "
351                 << closedness[cellI] << endl;
353     # endif
355     meshModifier.reorderBoundaryFaces();
357     if( octree.isQuadtree() )
358     {
359         //- generate empty patches
360         //- search for faces with a dominant z coordinate and store them
361         //- into an empty patch
362         meshSurfaceEngine mse(mesh_);
363         const vectorField& fNormals = mse.faceNormals();
364         const faceList::subList& bFaces = mse.boundaryFaces();
365         const labelList& fOwner = mse.faceOwners();
366         const vectorField& fCentres = mse.faceCentres();
368         const boundBox& bb = octree.rootBox();
369         const scalar tZ = 0.05 * (bb.max().z() - bb.min().z());
371         wordList patchNames(3);
372         patchNames[0] = "defaultFaces";
373         patchNames[1] = "unusedFacesBottom";
374         patchNames[2] = "unusedFacesTop";
376         VRWGraph boundaryFaces;
377         labelLongList newFaceOwner;
378         labelLongList newFacePatch;
380         forAll(fNormals, bfI)
381         {
382             //- store the face and its owner
383             boundaryFaces.appendList(bFaces[bfI]);
384             newFaceOwner.append(fOwner[bfI]);
386             const vector& fNormal = fNormals[bfI];
388             if( Foam::mag(fNormal.z()) > Foam::mag(fNormal.x() + fNormal.y()) )
389             {
390                 if( Foam::mag(fCentres[bfI].z() - bb.min().z()) < tZ )
391                 {
392                     newFacePatch.append(1);
393                 }
394                 else if( Foam::mag(fCentres[bfI].z() - bb.max().z()) < tZ )
395                 {
396                     newFacePatch.append(2);
397                 }
398                 else
399                 {
400                     FatalErrorIn
401                     (
402                         "void cartesianMeshExtractor::createPolyMesh()"
403                     ) << "Cannot distribute the face!!" << exit(FatalError);
404                 }
405             }
406             else
407             {
408                 newFacePatch.append(0);
409             }
410         }
412         //- replace the boundary with faces in correct patches
413         meshModifier.replaceBoundary
414         (
415             patchNames,
416             boundaryFaces,
417             newFaceOwner,
418             newFacePatch
419         );
421         meshModifier.boundariesAccess()[1].patchType() = "patch";
422         meshModifier.boundariesAccess()[2].patchType() = "patch";
423     }
425     Info << "Finished creating polyMesh" << endl;
428 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
430 } // End namespace Foam
432 // ************************************************************************* //