1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
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
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/>.
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"
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
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_;
66 (octree.returnLeaf(leafI).procNo() != Pstream::myProcNo())
70 if( cType[leafI] & meshOctreeAddressing::MESHCELL )
72 leafCellLabel[leafI] = nCells++;
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));
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)
98 const label own = owner[faceI];
99 const label nei = neighbour[faceI];
101 const label ownLabel = leafCellLabel[own];
104 neiLabel = leafCellLabel[nei];
106 if( (ownLabel != -1) && (neiLabel != -1) )
109 ++nFacesInCell[ownLabel];
110 ++nFacesInCell[neiLabel];
112 else if( ownLabel != -1 )
115 ++nFacesInCell[ownLabel];
117 if( (nei != -1) && (cType[nei] & meshOctreeAddressing::MESHCELL) )
119 const label procNo = octree.returnLeaf(nei).procNo();
121 procFaces[procNo].append(faceI);
124 else if( neiLabel != -1 )
127 ++nFacesInCell[neiLabel];
129 if( (own != -1) && (cType[own] & meshOctreeAddressing::MESHCELL) )
131 const label procNo = octree.returnLeaf(own).procNo();
133 procFaces[procNo].append(faceI);
138 //- case is a serial run
139 faces.setSize(nFaces);
141 cells[cI].setSize(nFacesInCell[cI]);
144 //- calculate faces in processor patches
145 if( Pstream::parRun() )
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)
161 const label procI = iter->first;
163 std::ostringstream ssNei;
168 new processorBoundaryPatch
179 nProcBoundaries -= iter->second.size();
183 //- create processor faces
184 //- they need to be created here because of the correct ordering
186 for(iter=procFaces.begin();iter!=procFaces.end();++iter)
188 procBoundaries[patchI].patchStart() = nProcBoundaries;
190 const labelLongList& patchFaces = iter->second;
192 forAll(patchFaces, pfI)
194 const label fLabel = patchFaces[pfI];
195 const label own = owner[fLabel];
196 const label nei = neighbour[fLabel];
198 const label curCell = leafCellLabel[own];
201 neiCell = leafCellLabel[nei];
203 //- create a processor 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++;
212 else if( curCell == -1 )
214 //- add a reversed face
215 faces[nProcBoundaries].setSize(octreeFaces[fLabel].size());
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++;
226 "void cartesianMeshExtractor::createPolyMesh()"
227 ) << "Face " << octreeFaces[fLabel] << " causes problems!"
228 << abort(FatalError);
232 if( procBoundaries[patchI].patchSize() !=
233 (nProcBoundaries - procBoundaries[patchI].patchStart())
237 "cartesianMeshExtractor::createPolyMesh()"
238 ) << "Invalid patch size!" << Pstream::myProcNo()
239 << abort(FatalError);
247 forAll(octreeFaces, faceI)
249 const label own = owner[faceI];
250 const label nei = neighbour[faceI];
252 const label ownLabel = leafCellLabel[own];
255 neiLabel = leafCellLabel[nei];
257 if( (ownLabel != -1) && (neiLabel != -1) )
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;
268 else if( ownLabel != -1 )
270 if( (nei != -1) && (cType[nei] & meshOctreeAddressing::MESHCELL) )
272 //- face at a parallel boundary
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;
284 else if( neiLabel != -1 )
286 if( (own != -1) && (cType[own] & meshOctreeAddressing::MESHCELL) )
288 //- face at a parallel boundary
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;
305 label nProcBoundaries(0);
306 forAll(procBoundaries, patchI)
307 nProcBoundaries += procBoundaries[patchI].patchSize();
309 if( faces.size() != (nProcBoundaries + nFaces) )
311 Serr << "Number of faces " << faces.size() << endl;
312 Serr << "Number of processor boundaries " << nProcBoundaries << endl;
313 Serr << "Number of domain faces " << nFaces << endl;
316 "void cartesianMeshExtractor::createPolyMesh()"
317 ) << Pstream::myProcNo() << "This mesh is invalid!"
318 << abort(FatalError);
321 vectorField closedness(cells.size(), vector::zero);
322 const labelList& owner = mesh_.owner();
323 const labelList& neighbour = mesh_.neighbour();
325 if( owner[faceI] == -1 )
327 Info << "faces " << faces << endl;
330 "void cartesianMeshExtractor::createPolyMesh"
332 "pointFieldPMG& points,"
333 "faceListPMG& faces,"
336 ) << "Face " << faceI
337 << " has no owner and neighbour!!" << abort(FatalError);
342 const vector area = faces[faceI].normal(mesh_.points());
343 closedness[owner[faceI]] += area;
344 if( neighbour[faceI] != -1 )
345 closedness[neighbour[faceI]] -= area;
348 forAll(closedness, cellI)
349 if( mag(closedness[cellI]) > 1e-10 )
350 Info << "Cell " << cellI << " is not closed by "
351 << closedness[cellI] << endl;
355 meshModifier.reorderBoundaryFaces();
357 if( octree.isQuadtree() )
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)
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()) )
390 if( Foam::mag(fCentres[bfI].z() - bb.min().z()) < tZ )
392 newFacePatch.append(1);
394 else if( Foam::mag(fCentres[bfI].z() - bb.max().z()) < tZ )
396 newFacePatch.append(2);
402 "void cartesianMeshExtractor::createPolyMesh()"
403 ) << "Cannot distribute the face!!" << exit(FatalError);
408 newFacePatch.append(0);
412 //- replace the boundary with faces in correct patches
413 meshModifier.replaceBoundary
421 meshModifier.boundariesAccess()[1].patchType() = "patch";
422 meshModifier.boundariesAccess()[2].patchType() = "patch";
425 Info << "Finished creating polyMesh" << endl;
428 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
430 } // End namespace Foam
432 // ************************************************************************* //