1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2010 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "layerAdditionRemoval.H"
28 #include "primitiveMesh.H"
29 #include "polyTopoChange.H"
30 #include "polyTopoChanger.H"
31 #include "polyAddPoint.H"
32 #include "polyAddCell.H"
33 #include "polyAddFace.H"
34 #include "polyModifyFace.H"
36 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 //- Calculate the offset to the next layer
39 Foam::tmp<Foam::vectorField> Foam::layerAdditionRemoval::extrusionDir() const
41 const polyMesh& mesh = topoChanger().mesh();
42 const primitiveFacePatch& masterFaceLayer =
43 mesh.faceZones()[faceZoneID_.index()]();
45 const pointField& points = mesh.points();
46 const labelList& mp = masterFaceLayer.meshPoints();
48 tmp<vectorField> textrusionDir(new vectorField(mp.size()));
49 vectorField& extrusionDir = textrusionDir();
51 if (setLayerPairing())
55 Pout<< "void layerAdditionRemoval::extrusionDir() const "
56 << " for object " << name() << " : "
57 << "Using edges for point insertion" << endl;
60 // Detected a valid layer. Grab the point and face collapse mapping
61 const labelList& ptc = pointsPairing();
63 forAll(extrusionDir, mpI)
65 extrusionDir[mpI] = points[ptc[mpI]] - points[mp[mpI]];
72 Pout<< "void layerAdditionRemoval::extrusionDir() const "
73 << " for object " << name() << " : "
74 << "A valid layer could not be found in front of "
75 << "the addition face layer. Using face-based "
76 << "point normals for point addition"
80 extrusionDir = minLayerThickness_*masterFaceLayer.pointNormals();
86 void Foam::layerAdditionRemoval::addCellLayer
91 // Insert the layer addition instructions into the topological change
94 // 1. For every point in the master zone add a new point
95 // 2. For every face in the master zone add a cell
96 // 3. Go through all the edges of the master zone. For all internal edges,
97 // add a face with the correct orientation and make it internal.
98 // For all boundary edges, find the patch it belongs to and add the face
100 // 4. Create a set of new faces on the patch image and assign them to be
101 // between the old master cells and the newly created cells
102 // 5. Modify all the faces in the patch such that they are located
103 // between the old slave cells and newly created cells
107 Pout<< "void layerAdditionRemoval::addCellLayer("
108 << "polyTopoChange& ref) const for object " << name() << " : "
109 << "Adding cell layer" << endl;
114 const polyMesh& mesh = topoChanger().mesh();
115 const primitiveFacePatch& masterFaceLayer =
116 mesh.faceZones()[faceZoneID_.index()]();
118 const pointField& points = mesh.points();
119 const labelList& mp = masterFaceLayer.meshPoints();
121 // Get the extrusion direction for the added points
123 tmp<vectorField> tpointOffsets = extrusionDir();
125 // Add the new points
126 labelList addedPoints(mp.size());
130 // Add the point nominal thickness away from the master zone point
131 // and grab the label
132 addedPoints[pointI] =
137 points[mp[pointI]] // point
138 + addDelta_*tpointOffsets()[pointI],
139 mp[pointI], // master point
140 -1, // zone for point
141 true // supports a cell
146 // Pout<< "mp: " << mp << " addedPoints: " << addedPoints << endl;
149 const labelList& mc =
150 mesh.faceZones()[faceZoneID_.index()].masterCells();
151 const labelList& sc =
152 mesh.faceZones()[faceZoneID_.index()].slaveCells();
153 // Pout<< "mc: " << mc << " sc: " << sc << endl;
154 const labelList& mf = mesh.faceZones()[faceZoneID_.index()];
155 const boolList& mfFlip = mesh.faceZones()[faceZoneID_.index()].flipMap();
157 const labelList& own = mesh.faceOwner();
158 const labelList& nei = mesh.faceNeighbour();
160 labelList addedCells(mf.size());
171 mf[faceI], // master face
178 // Create the new faces
180 // Grab the local faces from the master zone
181 const faceList& zoneFaces = masterFaceLayer.localFaces();
183 // Create the new faces by copying the master zone. All the added
184 // faces need to point into the newly created cells, which means
185 // all the faces from the master layer are flipped. The flux flip
186 // is determined from the original master layer face and the face
187 // owner: if the master cell is equal to the face owner the flux
188 // remains the same; otherwise it is flipped
190 forAll(zoneFaces, faceI)
192 const face oldFace = zoneFaces[faceI].reverseFace();
194 face newFace(oldFace.size());
196 forAll(oldFace, pointI)
198 newFace[pointI] = addedPoints[oldFace[pointI]];
201 bool flipFaceFlux = false;
203 // Flip the face as necessary
206 mc[faceI] == nei[mf[faceI]]
207 || !mesh.isInternalFace(mf[faceI])
220 addedCells[faceI], // neighbour
223 mf[faceI], // master face for addition
224 flipFaceFlux, // flux flip
225 -1, // patch for face
227 false // face zone flip
231 // Pout<< "adding face: " << newFace
232 // << " own: " << mc[faceI]
233 // << " nei: " << addedCells[faceI]
237 // Modify the faces from the master zone for the new neighbour
239 const faceList& faces = mesh.faces();
241 // Pout<< "mfFlip: " << mfFlip << endl;
245 const label curfaceID = mf[faceI];
247 // If the face is internal, modify its owner to be the newly
248 // created cell. No flip is necessary
249 if (!mesh.isInternalFace(curfaceID))
255 faces[curfaceID], // modified face
256 curfaceID, // label of face being modified
257 addedCells[faceI], // owner
260 mesh.boundaryMesh().whichPatch(curfaceID),// patch for face
261 false, // remove from zone
262 faceZoneID_.index(), // zone for face
263 mfFlip[faceI] // face flip in zone
267 // Pout<< "Modifying a boundary face. Face: " << curfaceID
268 // << " flip: " << mfFlip[faceI]
271 // If slave cell is owner, the face remains the same (but with
272 // a new neighbour - the newly created cell). Otherwise, the
274 else if (sc[faceI] == own[curfaceID])
276 // Orientation is good, just change neighbour
281 faces[curfaceID], // modified face
282 curfaceID, // label of face being modified
283 own[curfaceID], // owner
284 addedCells[faceI], // neighbour
286 mesh.boundaryMesh().whichPatch(curfaceID),// patch for face
287 false, // remove from zone
288 faceZoneID_.index(), // zone for face
289 mfFlip[faceI] // face flip in zone
293 // Pout<< "modify face, no flip " << curfaceID
294 // << " own: " << own[curfaceID]
295 // << " nei: " << addedCells[faceI]
300 // Change in orientation; flip face
305 faces[curfaceID].reverseFace(), // modified face
306 curfaceID, // label of face being modified
307 nei[curfaceID], // owner
308 addedCells[faceI], // neighbour
310 mesh.boundaryMesh().whichPatch(curfaceID), // patch for face
311 false, // remove from zone
312 faceZoneID_.index(), // zone for face
313 !mfFlip[faceI] // face flip in zone
317 // Pout<< "modify face, with flip " << curfaceID
318 // << " own: " << own[curfaceID]
319 // << " nei: " << addedCells[faceI]
324 // Create new faces from edges
326 const edgeList& zoneLocalEdges = masterFaceLayer.edges();
328 const labelListList& edgeFaces = masterFaceLayer.edgeFaces();
330 label nInternalEdges = masterFaceLayer.nInternalEdges();
332 const labelList& meshEdges =
333 mesh.faceZones()[faceZoneID_.index()].meshEdges();
335 // Do all internal edges
336 for (label curEdgeID = 0; curEdgeID < nInternalEdges; curEdgeID++)
340 newFace[0] = mp[zoneLocalEdges[curEdgeID].start()];
341 newFace[1] = mp[zoneLocalEdges[curEdgeID].end()];
342 newFace[2] = addedPoints[zoneLocalEdges[curEdgeID].end()];
343 newFace[3] = addedPoints[zoneLocalEdges[curEdgeID].start()];
350 addedCells[edgeFaces[curEdgeID][0]], // owner
351 addedCells[edgeFaces[curEdgeID][1]], // neighbour
353 meshEdges[curEdgeID], // master edge
356 -1, // patch for face
358 false // face zone flip
362 // Pout<< "Add internal face off edge: " << newFace
363 // << " own: " << addedCells[edgeFaces[curEdgeID][0]]
364 // << " nei: " << addedCells[edgeFaces[curEdgeID][1]]
368 // Prepare creation of faces from boundary edges.
370 // A tricky part of the algorithm is finding the patch into which the
371 // newly created face will be added. For this purpose, take the edge
372 // and grab all the faces coming from it. From the set of faces
373 // eliminate the internal faces and find the boundary face from the rest.
374 // If there is more than one boundary face (excluding the ones in
375 // the master zone), the patch with the lower label is selected.
377 const labelListList& meshEdgeFaces = mesh.edgeFaces();
379 const faceZoneMesh& zoneMesh = mesh.faceZones();
381 // Do all boundary edges
385 label curEdgeID = nInternalEdges;
386 curEdgeID < zoneLocalEdges.size();
391 newFace[0] = mp[zoneLocalEdges[curEdgeID].start()];
392 newFace[1] = mp[zoneLocalEdges[curEdgeID].end()];
393 newFace[2] = addedPoints[zoneLocalEdges[curEdgeID].end()];
394 newFace[3] = addedPoints[zoneLocalEdges[curEdgeID].start()];
396 // Determine the patch for insertion
397 const labelList& curFaces = meshEdgeFaces[meshEdges[curEdgeID]];
402 forAll(curFaces, faceI)
404 const label cf = curFaces[faceI];
406 if (!mesh.isInternalFace(cf))
408 // Face not internal. Check if it is in the zone
409 if (zoneMesh.whichZone(cf) != faceZoneID_.index())
411 // Found the face in a boundary patch which is not in zone
412 patchID = mesh.boundaryMesh().whichPatch(cf);
413 zoneID = mesh.faceZones().whichZone(cf);
424 "void Foam::layerAdditionRemoval::setRefinement("
425 "polyTopoChange& ref)"
426 ) << "Cannot find patch for edge " << meshEdges[curEdgeID]
427 << ". Edge: " << mesh.edges()[meshEdges[curEdgeID]]
428 << abort(FatalError);
436 addedCells[edgeFaces[curEdgeID][0]], // owner
439 meshEdges[curEdgeID], // master edge
442 patchID, // patch for face
444 false // zone face flip
448 // Pout<< "add boundary face: " << newFace
449 // << " into patch " << patchID
450 // << " own: " << addedCells[edgeFaces[curEdgeID][0]]
454 // Modify the remaining faces of the master cells to reconnect to the new
456 // Algorithm: Go through all the cells of the master zone and make
457 // a map of faces to avoid duplicates. Do not insert the faces in
458 // the master patch (as they have already been dealt with). Make
459 // a master layer point renumbering map, which for every point in
460 // the master layer gives its new label. Loop through all faces in
461 // the map and attempt to renumber them using the master layer
462 // point renumbering map. Once the face is renumbered, compare it
463 // with the original face; if they are the same, the face has not
464 // changed; if not, modify the face but keep all of its old
465 // attributes (apart from the vertex numbers).
467 // Create the map of faces in the master cell layer
468 labelHashSet masterCellFaceMap(primitiveMesh::facesPerCell_*mc.size());
470 const cellList& cells = mesh.cells();
474 const labelList& curFaces = cells[mc[cellI]];
476 forAll(curFaces, faceI)
478 // Check if the face belongs to the master zone; if not add it
479 if (zoneMesh.whichZone(curFaces[faceI]) != faceZoneID_.index())
481 masterCellFaceMap.insert(curFaces[faceI]);
486 // Create the master layer point map
487 Map<label> masterLayerPointMap(2*mp.size());
491 masterLayerPointMap.insert
498 // Grab the list of faces of the master layer
499 const labelList masterCellFaces = masterCellFaceMap.toc();
501 forAll(masterCellFaces, faceI)
503 // Attempt to renumber the face using the masterLayerPointMap.
504 // Missing point remain the same
506 const label curFaceID = masterCellFaces[faceI];
508 const face& oldFace = faces[curFaceID];
510 face newFace(oldFace.size());
512 bool changed = false;
514 forAll(oldFace, pointI)
516 if (masterLayerPointMap.found(oldFace[pointI]))
520 newFace[pointI] = masterLayerPointMap.find(oldFace[pointI])();
524 newFace[pointI] = oldFace[pointI];
528 // If the face has changed, create a modification entry
531 // Get face zone and its flip
532 label modifiedFaceZone = mesh.faceZones().whichZone(curFaceID);
533 bool modifiedFaceZoneFlip = false;
535 if (modifiedFaceZone >= 0)
537 modifiedFaceZoneFlip =
538 mesh.faceZones()[modifiedFaceZone].flipMap()
540 mesh.faceZones()[modifiedFaceZone].whichFace(curFaceID)
544 if (mesh.isInternalFace(curFaceID))
550 newFace, // modified face
551 curFaceID, // label of face being modified
552 own[curFaceID], // owner
553 nei[curFaceID], // neighbour
555 -1, // patch for face
556 false, // remove from zone
557 modifiedFaceZone, // zone for face
558 modifiedFaceZoneFlip // face flip in zone
562 // Pout<< "modifying stick-out face. Internal Old face: "
564 // << " new face: " << newFace
565 // << " own: " << own[curFaceID]
566 // << " nei: " << nei[curFaceID]
575 newFace, // modified face
576 curFaceID, // label of face being modified
577 own[curFaceID], // owner
580 mesh.boundaryMesh().whichPatch(curFaceID),
582 false, // remove from zone
583 modifiedFaceZone, // zone for face
584 modifiedFaceZoneFlip // face flip in zone
588 // Pout<< "modifying stick-out face. Boundary Old face: "
590 // << " new face: " << newFace
591 // << " own: " << own[curFaceID]
593 // << mesh.boundaryMesh().whichPatch(curFaceID)
601 Pout<< "void layerAdditionRemoval::addCellLayer("
602 << "polyTopoChange& ref) const "
603 << " for object " << name() << " : "
604 << "Finished adding cell layer" << endl;
609 // ************************************************************************* //