1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 All to do with adding cell layers
28 \*----------------------------------------------------------------------------*/
30 #include "autoLayerDriver.H"
33 #include "meshRefinement.H"
34 #include "removePoints.H"
35 #include "pointFields.H"
36 #include "motionSmoother.H"
37 #include "mathematicalConstants.H"
41 #include "polyTopoChange.H"
42 #include "mapPolyMesh.H"
43 #include "addPatchCellLayer.H"
44 #include "mapDistributePolyMesh.H"
46 #include "layerParameters.H"
47 #include "combineFaces.H"
49 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
54 defineTypeNameAndDebug(autoLayerDriver, 0);
56 } // End namespace Foam
59 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
61 Foam::label Foam::autoLayerDriver::mergePatchFacesUndo
64 const scalar concaveCos,
65 const dictionary& motionDict
68 fvMesh& mesh = meshRefiner_.mesh();
70 // Patch face merging engine
71 combineFaces faceCombiner(mesh, true);
73 // Pick up all candidate cells on boundary
74 labelHashSet boundaryCells(mesh.nFaces()-mesh.nInternalFaces());
77 labelList patchIDs(meshRefinement::addedPatches(globalToPatch_));
79 const polyBoundaryMesh& patches = mesh.boundaryMesh();
83 label patchI = patchIDs[i];
85 const polyPatch& patch = patches[patchI];
91 boundaryCells.insert(mesh.faceOwner()[patch.start()+i]);
97 // Get all sets of faces that can be merged
98 labelListList allFaceSets
100 faceCombiner.getMergeSets
108 label nFaceSets = returnReduce(allFaceSets.size(), sumOp<label>());
110 Info<< "Merging " << nFaceSets << " sets of faces." << nl << endl;
116 faceSet allSets(mesh, "allFaceSets", allFaceSets.size());
117 forAll(allFaceSets, setI)
119 forAll(allFaceSets[setI], i)
121 allSets.insert(allFaceSets[setI][i]);
124 Pout<< "Writing all faces to be merged to set "
125 << allSets.objectPath() << endl;
130 // Topology changes container
131 polyTopoChange meshMod(mesh);
133 // Merge all faces of a set into the first face of the set.
134 faceCombiner.setRefinement(allFaceSets, meshMod);
136 // Experimental: store data for all the points that have been deleted
137 meshRefiner_.storeData
139 faceCombiner.savedPointLabels(), // points to store
140 labelList(0), // faces to store
141 labelList(0) // cells to store
144 // Change the mesh (no inflation)
145 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
148 mesh.updateMesh(map);
150 // Move mesh (since morphing does not do this)
151 if (map().hasMotionPoints())
153 mesh.movePoints(map().preMotionPoints());
156 faceCombiner.updateMesh(map);
158 meshRefiner_.updateMesh(map, labelList(0));
162 for (label iteration = 0; iteration < 100; iteration++)
165 << "Undo iteration " << iteration << nl
166 << "----------------" << endl;
169 // Check mesh for errors
170 // ~~~~~~~~~~~~~~~~~~~~~
176 mesh.nFaces()-mesh.nInternalFaces()
178 bool hasErrors = motionSmoother::checkMesh
185 //if (checkEdgeConnectivity)
187 // Info<< "Checking edge-face connectivity (duplicate faces"
188 // << " or non-consecutive shared vertices)" << endl;
190 // label nOldSize = errorFaces.size();
193 // mesh.checkFaceFaces
200 // Info<< "Detected additional "
201 // << returnReduce(errorFaces.size()-nOldSize, sumOp<label>())
202 // << " faces with illegal face-face connectivity"
214 Pout<< "Writing all faces in error to faceSet "
215 << errorFaces.objectPath() << nl << endl;
220 // Check any master cells for using any of the error faces
221 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223 DynamicList<label> mastersToRestore(allFaceSets.size());
225 forAll(allFaceSets, setI)
227 label masterFaceI = faceCombiner.masterFace()[setI];
229 if (masterFaceI != -1)
231 label masterCellII = mesh.faceOwner()[masterFaceI];
233 const cell& cFaces = mesh.cells()[masterCellII];
237 if (errorFaces.found(cFaces[i]))
239 mastersToRestore.append(masterFaceI);
245 mastersToRestore.shrink();
247 label nRestore = returnReduce
249 mastersToRestore.size(),
253 Info<< "Masters that need to be restored:"
258 faceSet restoreSet(mesh, "mastersToRestore", mastersToRestore);
259 Pout<< "Writing all " << mastersToRestore.size()
260 << " masterfaces to be restored to set "
261 << restoreSet.objectPath() << endl;
275 // Topology changes container
276 polyTopoChange meshMod(mesh);
278 // Merge all faces of a set into the first face of the set.
279 // Experimental:mark all points/faces/cells that have been restored.
280 Map<label> restoredPoints(0);
281 Map<label> restoredFaces(0);
282 Map<label> restoredCells(0);
284 faceCombiner.setUnrefinement
293 // Change the mesh (no inflation)
294 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
297 mesh.updateMesh(map);
299 // Move mesh (since morphing does not do this)
300 if (map().hasMotionPoints())
302 mesh.movePoints(map().preMotionPoints());
305 faceCombiner.updateMesh(map);
307 // Renumber restore maps
308 inplaceMapKey(map().reversePointMap(), restoredPoints);
309 inplaceMapKey(map().reverseFaceMap(), restoredFaces);
310 inplaceMapKey(map().reverseCellMap(), restoredCells);
312 // Experimental:restore all points/face/cells in maps
313 meshRefiner_.updateMesh
316 labelList(0), // changedFaces
327 Pout<< "Writing merged-faces mesh to time "
328 << mesh.time().timeName() << nl << endl;
334 Info<< "No faces merged ..." << endl;
341 // Remove points. pointCanBeDeleted is parallel synchronised.
342 Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRemovePoints
344 removePoints& pointRemover,
345 const boolList& pointCanBeDeleted
348 fvMesh& mesh = meshRefiner_.mesh();
350 // Topology changes container
351 polyTopoChange meshMod(mesh);
353 pointRemover.setRefinement(pointCanBeDeleted, meshMod);
355 // Change the mesh (no inflation)
356 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
359 mesh.updateMesh(map);
361 // Move mesh (since morphing does not do this)
362 if (map().hasMotionPoints())
364 mesh.movePoints(map().preMotionPoints());
367 pointRemover.updateMesh(map);
368 meshRefiner_.updateMesh(map, labelList(0));
374 // Restore faces (which contain removed points)
375 Foam::autoPtr<Foam::mapPolyMesh> Foam::autoLayerDriver::doRestorePoints
377 removePoints& pointRemover,
378 const labelList& facesToRestore
381 fvMesh& mesh = meshRefiner_.mesh();
383 // Topology changes container
384 polyTopoChange meshMod(mesh);
386 // Determine sets of points and faces to restore
387 labelList localFaces, localPoints;
388 pointRemover.getUnrefimentSet
395 // Undo the changes on the faces that are in error.
396 pointRemover.setUnrefinement
403 // Change the mesh (no inflation)
404 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
407 mesh.updateMesh(map);
409 // Move mesh (since morphing does not do this)
410 if (map().hasMotionPoints())
412 mesh.movePoints(map().preMotionPoints());
415 pointRemover.updateMesh(map);
416 meshRefiner_.updateMesh(map, labelList(0));
422 // Collect all faces that are both in candidateFaces and in the set.
423 // If coupled face also collects the coupled face.
424 Foam::labelList Foam::autoLayerDriver::collectFaces
426 const labelList& candidateFaces,
427 const labelHashSet& set
430 const fvMesh& mesh = meshRefiner_.mesh();
432 // Has face been selected?
433 boolList selected(mesh.nFaces(), false);
435 forAll(candidateFaces, i)
437 label faceI = candidateFaces[i];
439 if (set.found(faceI))
441 selected[faceI] = true;
444 syncTools::syncFaceList
448 orEqOp<bool>(), // combine operator
452 labelList selectedFaces(findIndices(selected, true));
454 return selectedFaces;
458 // Pick up faces of cells of faces in set.
459 Foam::labelList Foam::autoLayerDriver::growFaceCellFace
461 const labelHashSet& set
464 const fvMesh& mesh = meshRefiner_.mesh();
466 boolList selected(mesh.nFaces(), false);
468 forAllConstIter(faceSet, set, iter)
470 label faceI = iter.key();
472 label own = mesh.faceOwner()[faceI];
474 const cell& ownFaces = mesh.cells()[own];
475 forAll(ownFaces, ownFaceI)
477 selected[ownFaces[ownFaceI]] = true;
480 if (mesh.isInternalFace(faceI))
482 label nbr = mesh.faceNeighbour()[faceI];
484 const cell& nbrFaces = mesh.cells()[nbr];
485 forAll(nbrFaces, nbrFaceI)
487 selected[nbrFaces[nbrFaceI]] = true;
491 syncTools::syncFaceList
495 orEqOp<bool>(), // combine operator
498 return findIndices(selected, true);
502 // Remove points not used by any face or points used by only two faces where
503 // the edges are in line
504 Foam::label Foam::autoLayerDriver::mergeEdgesUndo
507 const dictionary& motionDict
510 fvMesh& mesh = meshRefiner_.mesh();
513 << "Merging all points on surface that" << nl
514 << "- are used by only two boundary faces and" << nl
515 << "- make an angle with a cosine of more than " << minCos
516 << "." << nl << endl;
518 // Point removal analysis engine with undo
519 removePoints pointRemover(mesh, true);
521 // Count usage of points
522 boolList pointCanBeDeleted;
523 label nRemove = pointRemover.countPointUsage(minCos, pointCanBeDeleted);
527 Info<< "Removing " << nRemove
528 << " straight edge points ..." << nl << endl;
533 doRemovePoints(pointRemover, pointCanBeDeleted);
536 for (label iteration = 0; iteration < 100; iteration++)
539 << "Undo iteration " << iteration << nl
540 << "----------------" << endl;
543 // Check mesh for errors
544 // ~~~~~~~~~~~~~~~~~~~~~
550 mesh.nFaces()-mesh.nInternalFaces()
552 bool hasErrors = motionSmoother::checkMesh
559 //if (checkEdgeConnectivity)
561 // Info<< "Checking edge-face connectivity (duplicate faces"
562 // << " or non-consecutive shared vertices)" << endl;
564 // label nOldSize = errorFaces.size();
567 // mesh.checkFaceFaces
574 // Info<< "Detected additional "
575 // << returnReduce(errorFaces.size()-nOldSize,sumOp<label>())
576 // << " faces with illegal face-face connectivity"
587 Pout<< "**Writing all faces in error to faceSet "
588 << errorFaces.objectPath() << nl << endl;
592 labelList masterErrorFaces
596 pointRemover.savedFaceLabels(),
601 label n = returnReduce(masterErrorFaces.size(), sumOp<label>());
603 Info<< "Detected " << n
604 << " error faces on boundaries that have been merged."
605 << " These will be restored to their original faces." << nl
613 << returnReduce(errorFaces.size(), sumOp<label>())
614 << " error faces in mesh."
615 << " Restoring neighbours of faces in error." << nl
618 labelList expandedErrorFaces
626 doRestorePoints(pointRemover, expandedErrorFaces);
632 doRestorePoints(pointRemover, masterErrorFaces);
637 Pout<< "Writing merged-edges mesh to time "
638 << mesh.time().timeName() << nl << endl;
644 Info<< "No straight edges simplified and no points removed ..." << endl;
651 // For debugging: Dump displacement to .obj files
652 void Foam::autoLayerDriver::dumpDisplacement
654 const fileName& prefix,
655 const indirectPrimitivePatch& pp,
656 const vectorField& patchDisp,
657 const List<extrudeMode>& extrudeStatus
660 OFstream dispStr(prefix + "_disp.obj");
661 Info<< "Writing all displacements to " << dispStr.name() << nl << endl;
665 forAll(patchDisp, patchPointI)
667 const point& pt = pp.localPoints()[patchPointI];
669 meshTools::writeOBJ(dispStr, pt); vertI++;
670 meshTools::writeOBJ(dispStr, pt + patchDisp[patchPointI]); vertI++;
672 dispStr << "l " << vertI-1 << ' ' << vertI << nl;
676 OFstream illStr(prefix + "_illegal.obj");
677 Info<< "Writing invalid displacements to " << illStr.name() << nl << endl;
681 forAll(patchDisp, patchPointI)
683 if (extrudeStatus[patchPointI] != EXTRUDE)
685 const point& pt = pp.localPoints()[patchPointI];
687 meshTools::writeOBJ(illStr, pt); vertI++;
688 meshTools::writeOBJ(illStr, pt + patchDisp[patchPointI]); vertI++;
690 illStr << "l " << vertI-1 << ' ' << vertI << nl;
696 // Check that primitivePatch is not multiply connected. Collect non-manifold
697 // points in pointSet.
698 void Foam::autoLayerDriver::checkManifold
700 const indirectPrimitivePatch& fp,
701 pointSet& nonManifoldPoints
704 // Check for non-manifold points (surface pinched at point)
705 fp.checkPointManifold(false, &nonManifoldPoints);
707 // Check for edge-faces (surface pinched at edge)
708 const labelListList& edgeFaces = fp.edgeFaces();
710 forAll(edgeFaces, edgeI)
712 const labelList& eFaces = edgeFaces[edgeI];
714 if (eFaces.size() > 2)
716 const edge& e = fp.edges()[edgeI];
718 nonManifoldPoints.insert(fp.meshPoints()[e[0]]);
719 nonManifoldPoints.insert(fp.meshPoints()[e[1]]);
725 void Foam::autoLayerDriver::checkMeshManifold() const
727 const fvMesh& mesh = meshRefiner_.mesh();
729 Info<< nl << "Checking mesh manifoldness ..." << endl;
731 // Get all outside faces
732 labelList outsideFaces(mesh.nFaces() - mesh.nInternalFaces());
734 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
736 outsideFaces[faceI - mesh.nInternalFaces()] = faceI;
739 pointSet nonManifoldPoints
746 // Build primitivePatch out of faces and check it for problems.
749 indirectPrimitivePatch
751 IndirectList<face>(mesh.faces(), outsideFaces),
757 label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
761 Info<< "Outside of mesh is multiply connected across edges or"
763 << "This is not a fatal error but might cause some unexpected"
764 << " behaviour." << nl
765 << "Writing " << nNonManif
766 << " points where this happens to pointSet "
767 << nonManifoldPoints.name() << endl;
769 nonManifoldPoints.write();
776 // Unset extrusion on point. Returns true if anything unset.
777 bool Foam::autoLayerDriver::unmarkExtrusion
779 const label patchPointI,
780 pointField& patchDisp,
781 labelList& patchNLayers,
782 List<extrudeMode>& extrudeStatus
785 if (extrudeStatus[patchPointI] == EXTRUDE)
787 extrudeStatus[patchPointI] = NOEXTRUDE;
788 patchNLayers[patchPointI] = 0;
789 patchDisp[patchPointI] = vector::zero;
792 else if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
794 extrudeStatus[patchPointI] = NOEXTRUDE;
795 patchNLayers[patchPointI] = 0;
796 patchDisp[patchPointI] = vector::zero;
806 // Unset extrusion on face. Returns true if anything unset.
807 bool Foam::autoLayerDriver::unmarkExtrusion
809 const face& localFace,
810 pointField& patchDisp,
811 labelList& patchNLayers,
812 List<extrudeMode>& extrudeStatus
815 bool unextruded = false;
817 forAll(localFace, fp)
837 // No extrusion at non-manifold points.
838 void Foam::autoLayerDriver::handleNonManifolds
840 const indirectPrimitivePatch& pp,
841 const labelList& meshEdges,
842 pointField& patchDisp,
843 labelList& patchNLayers,
844 List<extrudeMode>& extrudeStatus
847 const fvMesh& mesh = meshRefiner_.mesh();
849 Info<< nl << "Handling non-manifold points ..." << endl;
851 // Detect non-manifold points
852 Info<< nl << "Checking patch manifoldness ..." << endl;
854 pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints());
857 checkManifold(pp, nonManifoldPoints);
859 label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
861 Info<< "Outside of local patch is multiply connected across edges or"
862 << " points at " << nNonManif << " points." << endl;
865 const labelList& meshPoints = pp.meshPoints();
869 // For now disable extrusion at any shared edges.
870 const labelHashSet sharedEdgeSet(mesh.globalData().sharedEdgeLabels());
872 forAll(pp.edges(), edgeI)
874 if (sharedEdgeSet.found(meshEdges[edgeI]))
876 const edge& e = mesh.edges()[meshEdges[edgeI]];
878 Pout<< "Disabling extrusion at edge "
879 << mesh.points()[e[0]] << mesh.points()[e[1]]
880 << " since it is non-manifold across coupled patches."
883 nonManifoldPoints.insert(e[0]);
884 nonManifoldPoints.insert(e[1]);
888 // 3b. extrusion can produce multiple faces between 2 cells
889 // across processor boundary
890 // This occurs when a coupled face shares more than 1 edge with a
891 // non-coupled boundary face.
892 // This is now correctly handled by addPatchCellLayer in that it
893 // extrudes a single face from the stringed up edges.
896 nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
900 Info<< "Outside of patches is multiply connected across edges or"
901 << " points at " << nNonManif << " points." << nl
902 << "Writing " << nNonManif
903 << " points where this happens to pointSet "
904 << nonManifoldPoints.name() << nl
905 << "and setting layer thickness to zero on these points."
908 nonManifoldPoints.write();
910 forAll(meshPoints, patchPointI)
912 if (nonManifoldPoints.found(meshPoints[patchPointI]))
925 Info<< "Set displacement to zero for all " << nNonManif
926 << " non-manifold points" << endl;
930 // Parallel feature edge detection. Assumes non-manifold edges already handled.
931 void Foam::autoLayerDriver::handleFeatureAngle
933 const indirectPrimitivePatch& pp,
934 const labelList& meshEdges,
936 pointField& patchDisp,
937 labelList& patchNLayers,
938 List<extrudeMode>& extrudeStatus
941 const fvMesh& mesh = meshRefiner_.mesh();
943 Info<< nl << "Handling feature edges ..." << endl;
945 if (minCos < 1-SMALL)
947 // Normal component of normals of connected faces.
948 vectorField edgeNormal(mesh.nEdges(), wallPoint::greatPoint);
950 const labelListList& edgeFaces = pp.edgeFaces();
952 forAll(edgeFaces, edgeI)
954 const labelList& eFaces = pp.edgeFaces()[edgeI];
956 label meshEdgeI = meshEdges[edgeI];
962 edgeNormal[meshEdgeI],
963 pp.faceNormals()[eFaces[i]]
968 syncTools::syncEdgeList
973 wallPoint::greatPoint, // null value
974 false // no separation
978 autoPtr<OFstream> str;
981 str.reset(new OFstream(mesh.time().path()/"featureEdges.obj"));
982 Info<< "Writing feature edges to " << str().name() << endl;
987 // Now on coupled edges the edgeNormal will have been truncated and
988 // only be still be the old value where two faces have the same normal
989 forAll(edgeFaces, edgeI)
991 const labelList& eFaces = pp.edgeFaces()[edgeI];
993 label meshEdgeI = meshEdges[edgeI];
995 const vector& n = edgeNormal[meshEdgeI];
997 if (n != wallPoint::greatPoint)
999 scalar cos = n & pp.faceNormals()[eFaces[0]];
1003 const edge& e = pp.edges()[edgeI];
1024 meshTools::writeOBJ(str(), pp.localPoints()[e[0]]);
1026 meshTools::writeOBJ(str(), pp.localPoints()[e[1]]);
1028 str()<< "l " << vertI-1 << ' ' << vertI << nl;
1034 Info<< "Set displacement to zero for points on "
1035 << returnReduce(nFeats, sumOp<label>())
1036 << " feature edges" << endl;
1041 // No extrusion on cells with warped faces. Calculates the thickness of the
1042 // layer and compares it to the space the warped face takes up. Disables
1043 // extrusion if layer thickness is more than faceRatio of the thickness of
1045 void Foam::autoLayerDriver::handleWarpedFaces
1047 const indirectPrimitivePatch& pp,
1048 const scalar faceRatio,
1049 const scalar edge0Len,
1050 const labelList& cellLevel,
1051 pointField& patchDisp,
1052 labelList& patchNLayers,
1053 List<extrudeMode>& extrudeStatus
1056 const fvMesh& mesh = meshRefiner_.mesh();
1058 Info<< nl << "Handling cells with warped patch faces ..." << nl;
1060 const pointField& points = mesh.points();
1062 label nWarpedFaces = 0;
1066 const face& f = pp[i];
1070 label faceI = pp.addressing()[i];
1072 label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
1073 scalar edgeLen = edge0Len/(1<<ownLevel);
1075 // Normal distance to face centre plane
1076 const point& fc = mesh.faceCentres()[faceI];
1077 const vector& fn = pp.faceNormals()[i];
1079 scalarField vProj(f.size());
1083 vector n = points[f[fp]] - fc;
1084 vProj[fp] = (n & fn);
1087 // Get normal 'span' of face
1088 scalar minVal = min(vProj);
1089 scalar maxVal = max(vProj);
1091 if ((maxVal - minVal) > faceRatio * edgeLen)
1110 Info<< "Set displacement to zero on "
1111 << returnReduce(nWarpedFaces, sumOp<label>())
1112 << " warped faces since layer would be > " << faceRatio
1113 << " of the size of the bounding box." << endl;
1118 //// No extrusion on cells with multiple patch faces. There ususally is a reason
1119 //// why combinePatchFaces hasn't succeeded.
1120 //void Foam::autoLayerDriver::handleMultiplePatchFaces
1122 // const indirectPrimitivePatch& pp,
1123 // pointField& patchDisp,
1124 // labelList& patchNLayers,
1125 // List<extrudeMode>& extrudeStatus
1128 // const fvMesh& mesh = meshRefiner_.mesh();
1130 // Info<< nl << "Handling cells with multiple patch faces ..." << nl;
1132 // const labelListList& pointFaces = pp.pointFaces();
1134 // // Cells that should not get an extrusion layer
1135 // cellSet multiPatchCells(mesh, "multiPatchCells", pp.size());
1137 // // Detect points that use multiple faces on same cell.
1138 // forAll(pointFaces, patchPointI)
1140 // const labelList& pFaces = pointFaces[patchPointI];
1142 // labelHashSet pointCells(pFaces.size());
1144 // forAll(pFaces, i)
1146 // label cellI = mesh.faceOwner()[pp.addressing()[pFaces[i]]];
1148 // if (!pointCells.insert(cellI))
1150 // // Second or more occurrence of cell so cell has two or more
1151 // // pp faces connected to this point.
1152 // multiPatchCells.insert(cellI);
1157 // label nMultiPatchCells = returnReduce
1159 // multiPatchCells.size(),
1163 // Info<< "Detected " << nMultiPatchCells
1164 // << " cells with multiple (connected) patch faces." << endl;
1166 // label nChanged = 0;
1168 // if (nMultiPatchCells > 0)
1170 // Info<< "Writing " << nMultiPatchCells
1171 // << " cells with multiple (connected) patch faces to cellSet "
1172 // << multiPatchCells.objectPath() << endl;
1173 // multiPatchCells.write();
1176 // // Go through all points and remove extrusion on any cell in
1177 // // multiPatchCells
1178 // // (has to be done in separate loop since having one point on
1179 // // multipatches has to reset extrusion on all points of cell)
1181 // forAll(pointFaces, patchPointI)
1183 // if (extrudeStatus[patchPointI] != NOEXTRUDE)
1185 // const labelList& pFaces = pointFaces[patchPointI];
1187 // forAll(pFaces, i)
1190 // mesh.faceOwner()[pp.addressing()[pFaces[i]]];
1192 // if (multiPatchCells.found(cellI))
1212 // reduce(nChanged, sumOp<label>());
1215 // Info<< "Prevented extrusion on " << nChanged
1216 // << " points due to multiple patch faces." << nl << endl;
1220 // No extrusion on faces with differing number of layers for points
1221 void Foam::autoLayerDriver::setNumLayers
1223 const labelList& patchToNLayers,
1224 const labelList& patchIDs,
1225 const indirectPrimitivePatch& pp,
1226 pointField& patchDisp,
1227 labelList& patchNLayers,
1228 List<extrudeMode>& extrudeStatus
1231 const fvMesh& mesh = meshRefiner_.mesh();
1233 Info<< nl << "Handling points with inconsistent layer specification ..."
1236 // Get for every point (really only nessecary on patch external points)
1237 // the max and min of any patch faces using it.
1238 labelList maxLayers(patchNLayers.size(), labelMin);
1239 labelList minLayers(patchNLayers.size(), labelMax);
1243 label patchI = patchIDs[i];
1245 const labelList& meshPoints = mesh.boundaryMesh()[patchI].meshPoints();
1247 label wantedLayers = patchToNLayers[patchI];
1249 forAll(meshPoints, patchPointI)
1251 label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
1253 maxLayers[ppPointI] = max(wantedLayers, maxLayers[ppPointI]);
1254 minLayers[ppPointI] = min(wantedLayers, minLayers[ppPointI]);
1258 syncTools::syncPointList
1264 labelMin, // null value
1265 false // no separation
1267 syncTools::syncPointList
1273 labelMax, // null value
1274 false // no separation
1277 // Unmark any point with different min and max
1278 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1280 //label nConflicts = 0;
1282 forAll(maxLayers, i)
1284 if (maxLayers[i] == labelMin || minLayers[i] == labelMax)
1286 FatalErrorIn("setNumLayers(..)")
1287 << "Patchpoint:" << i << " coord:" << pp.localPoints()[i]
1288 << " maxLayers:" << maxLayers
1289 << " minLayers:" << minLayers
1290 << abort(FatalError);
1292 else if (maxLayers[i] == minLayers[i])
1295 patchNLayers[i] = maxLayers[i];
1299 // Inconsistent num layers between patch faces using point
1313 patchNLayers[i] = maxLayers[i];
1317 //reduce(nConflicts, sumOp<label>());
1319 //Info<< "Set displacement to zero for " << nConflicts
1320 // << " points due to points being on multiple regions"
1321 // << " with inconsistent nLayers specification." << endl;
1325 // Grow no-extrusion layer
1326 void Foam::autoLayerDriver::growNoExtrusion
1328 const indirectPrimitivePatch& pp,
1329 pointField& patchDisp,
1330 labelList& patchNLayers,
1331 List<extrudeMode>& extrudeStatus
1334 Info<< nl << "Growing non-extrusion points by one layer ..." << endl;
1336 List<extrudeMode> grownExtrudeStatus(extrudeStatus);
1338 const faceList& localFaces = pp.localFaces();
1342 forAll(localFaces, faceI)
1344 const face& f = localFaces[faceI];
1346 bool hasSqueeze = false;
1349 if (extrudeStatus[f[fp]] == NOEXTRUDE)
1358 // Squeeze all points of face
1363 extrudeStatus[f[fp]] == NOEXTRUDE
1364 && grownExtrudeStatus[f[fp]] != NOEXTRUDE
1367 grownExtrudeStatus[f[fp]] = NOEXTRUDE;
1374 extrudeStatus.transfer(grownExtrudeStatus);
1376 forAll(extrudeStatus, patchPointI)
1378 if (extrudeStatus[patchPointI] == NOEXTRUDE)
1380 patchDisp[patchPointI] = vector::zero;
1381 patchNLayers[patchPointI] = 0;
1385 reduce(nGrown, sumOp<label>());
1387 Info<< "Set displacement to zero for an additional " << nGrown
1388 << " points." << endl;
1392 void Foam::autoLayerDriver::calculateLayerThickness
1394 const indirectPrimitivePatch& pp,
1395 const labelList& patchIDs,
1396 const scalarField& patchExpansionRatio,
1397 const scalarField& patchFinalLayerRatio,
1398 const scalarField& patchRelMinThickness,
1399 const labelList& cellLevel,
1400 const labelList& patchNLayers,
1401 const scalar edge0Len,
1403 scalarField& thickness,
1404 scalarField& minThickness,
1405 scalarField& expansionRatio
1408 const fvMesh& mesh = meshRefiner_.mesh();
1409 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1411 if (min(patchRelMinThickness) < 0 || max(patchRelMinThickness) > 2)
1413 FatalErrorIn("calculateLayerThickness(..)")
1414 << "Thickness should be factor of local undistorted cell size."
1415 << " Valid values are [0..2]." << nl
1416 << " minThickness:" << patchRelMinThickness
1417 << exit(FatalError);
1421 // Per point the max cell level of connected cells
1422 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1424 labelList maxPointLevel(pp.nPoints(), labelMin);
1429 label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1431 const face& f = pp.localFaces()[i];
1435 maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1439 syncTools::syncPointList
1445 labelMin, // null value
1446 false // no separation
1451 // Rework patch-wise layer parameters into minimum per point
1452 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1454 expansionRatio.setSize(pp.nPoints());
1455 expansionRatio = GREAT;
1456 scalarField finalLayerRatio(pp.nPoints(), GREAT);
1457 scalarField relMinThickness(pp.nPoints(), GREAT);
1462 label patchI = patchIDs[i];
1464 const labelList& meshPoints = patches[patchI].meshPoints();
1466 forAll(meshPoints, patchPointI)
1468 label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
1470 expansionRatio[ppPointI] = min
1472 expansionRatio[ppPointI],
1473 patchExpansionRatio[patchI]
1475 finalLayerRatio[ppPointI] = min
1477 finalLayerRatio[ppPointI],
1478 patchFinalLayerRatio[patchI]
1480 relMinThickness[ppPointI] = min
1482 relMinThickness[ppPointI],
1483 patchRelMinThickness[patchI]
1488 syncTools::syncPointList
1494 GREAT, // null value
1495 false // no separation
1497 syncTools::syncPointList
1503 GREAT, // null value
1504 false // no separation
1506 syncTools::syncPointList
1512 GREAT, // null value
1513 false // no separation
1519 // Per mesh point the expansion parameters
1520 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1522 thickness.setSize(pp.nPoints());
1523 minThickness.setSize(pp.nPoints());
1525 forAll(maxPointLevel, pointI)
1527 // Find undistorted edge size for this level.
1528 scalar edgeLen = edge0Len/(1<<maxPointLevel[pointI]);
1530 // Calculate layer thickness based on expansion ratio
1531 // and final layer height
1532 if (expansionRatio[pointI] == 1)
1535 finalLayerRatio[pointI]
1536 * patchNLayers[pointI]
1538 minThickness[pointI] = relMinThickness[pointI]*edgeLen;
1542 scalar invExpansion = 1.0 / expansionRatio[pointI];
1543 label nLay = patchNLayers[pointI];
1545 finalLayerRatio[pointI]
1547 * (1.0 - pow(invExpansion, nLay))
1548 / (1.0 - invExpansion);
1549 minThickness[pointI] = relMinThickness[pointI]*edgeLen;
1553 Info<< "calculateLayerThickness : min:" << gMin(thickness)
1554 << " max:" << gMax(thickness) << endl;
1558 // Synchronize displacement among coupled patches.
1559 void Foam::autoLayerDriver::syncPatchDisplacement
1561 const motionSmoother& meshMover,
1562 const scalarField& minThickness,
1563 pointField& patchDisp,
1564 labelList& patchNLayers,
1565 List<extrudeMode>& extrudeStatus
1568 const fvMesh& mesh = meshRefiner_.mesh();
1569 const labelList& meshPoints = meshMover.patch().meshPoints();
1571 label nChangedTotal = 0;
1577 // Sync displacement (by taking min)
1578 syncTools::syncPointList
1584 wallPoint::greatPoint, // null value
1585 false // no separation
1588 // Unmark if displacement too small
1589 forAll(patchDisp, i)
1591 if (mag(patchDisp[i]) < minThickness[i])
1609 labelList syncPatchNLayers(patchNLayers);
1611 syncTools::syncPointList
1617 labelMax, // null value
1618 false // no separation
1622 forAll(syncPatchNLayers, i)
1624 if (syncPatchNLayers[i] != patchNLayers[i])
1642 syncTools::syncPointList
1648 labelMin, // null value
1649 false // no separation
1653 forAll(syncPatchNLayers, i)
1655 if (syncPatchNLayers[i] != patchNLayers[i])
1672 nChangedTotal += nChanged;
1674 if (!returnReduce(nChanged, sumOp<label>()))
1680 Info<< "Prevented extrusion on "
1681 << returnReduce(nChangedTotal, sumOp<label>())
1682 << " coupled patch points during syncPatchDisplacement." << endl;
1686 // Calculate displacement vector for all patch points. Uses pointNormal.
1687 // Checks that displaced patch point would be visible from all centres
1688 // of the faces using it.
1689 // extrudeStatus is both input and output and gives the status of each
1691 void Foam::autoLayerDriver::getPatchDisplacement
1693 const motionSmoother& meshMover,
1694 const scalarField& thickness,
1695 const scalarField& minThickness,
1696 pointField& patchDisp,
1697 labelList& patchNLayers,
1698 List<extrudeMode>& extrudeStatus
1701 Info<< nl << "Determining displacement for added points"
1702 << " according to pointNormal ..." << endl;
1704 const fvMesh& mesh = meshRefiner_.mesh();
1705 const indirectPrimitivePatch& pp = meshMover.patch();
1706 const vectorField& faceNormals = pp.faceNormals();
1707 const labelListList& pointFaces = pp.pointFaces();
1708 const pointField& localPoints = pp.localPoints();
1709 const labelList& meshPoints = pp.meshPoints();
1711 // Determine pointNormal
1712 // ~~~~~~~~~~~~~~~~~~~~~
1714 pointField pointNormals(pp.nPoints(), vector::zero);
1716 labelList nPointFaces(pp.nPoints(), 0);
1718 forAll(faceNormals, faceI)
1720 const face& f = pp.localFaces()[faceI];
1724 pointNormals[f[fp]] += faceNormals[faceI];
1725 nPointFaces[f[fp]] ++;
1729 syncTools::syncPointList
1735 vector::zero, // null value
1736 false // no separation
1739 syncTools::syncPointList
1746 false // no separation
1749 forAll(pointNormals, i)
1751 pointNormals[i] /= nPointFaces[i];
1756 // Determine local length scale on patch
1757 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1759 // Start off from same thickness everywhere (except where no extrusion)
1760 patchDisp = thickness*pointNormals;
1762 // Check if no extrude possible.
1763 forAll(pointNormals, patchPointI)
1765 label meshPointI = pp.meshPoints()[patchPointI];
1767 if (extrudeStatus[patchPointI] == NOEXTRUDE)
1769 // Do not use unmarkExtrusion; forcibly set to zero extrusion.
1770 patchNLayers[patchPointI] = 0;
1771 patchDisp[patchPointI] = vector::zero;
1776 const vector& n = pointNormals[patchPointI];
1778 if (!meshTools::visNormal(n, faceNormals, pointFaces[patchPointI]))
1780 Pout<< "No valid normal for point " << meshPointI
1781 << ' ' << pp.points()[meshPointI]
1782 << "; setting displacement to " << patchDisp[patchPointI]
1785 extrudeStatus[patchPointI] = EXTRUDEREMOVE;
1790 // At illegal points make displacement average of new neighbour positions
1791 forAll(extrudeStatus, patchPointI)
1793 if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
1795 point avg(vector::zero);
1798 const labelList& pEdges = pp.pointEdges()[patchPointI];
1802 label edgeI = pEdges[i];
1804 label otherPointI = pp.edges()[edgeI].otherVertex(patchPointI);
1806 if (extrudeStatus[otherPointI] != NOEXTRUDE)
1808 avg += localPoints[otherPointI] + patchDisp[otherPointI];
1815 Pout<< "Displacement at illegal point "
1816 << localPoints[patchPointI]
1817 << " set to " << (avg / nPoints - localPoints[patchPointI])
1820 patchDisp[patchPointI] =
1822 - localPoints[patchPointI];
1827 // Make sure displacement is equal on both sides of coupled patches.
1828 syncPatchDisplacement
1841 // Truncates displacement
1842 // - for all patchFaces in the faceset displacement gets set to zero
1843 // - all displacement < minThickness gets set to zero
1844 Foam::label Foam::autoLayerDriver::truncateDisplacement
1846 const motionSmoother& meshMover,
1847 const scalarField& minThickness,
1848 const faceSet& illegalPatchFaces,
1849 pointField& patchDisp,
1850 labelList& patchNLayers,
1851 List<extrudeMode>& extrudeStatus
1854 const polyMesh& mesh = meshMover.mesh();
1855 const indirectPrimitivePatch& pp = meshMover.patch();
1859 const Map<label>& meshPointMap = pp.meshPointMap();
1861 forAllConstIter(faceSet, illegalPatchFaces, iter)
1863 label faceI = iter.key();
1865 if (mesh.isInternalFace(faceI))
1867 FatalErrorIn("truncateDisplacement(..)")
1868 << "Faceset " << illegalPatchFaces.name()
1869 << " contains internal face " << faceI << nl
1870 << "It should only contain patch faces" << abort(FatalError);
1873 const face& f = mesh.faces()[faceI];
1878 if (meshPointMap.found(f[fp]))
1880 label patchPointI = meshPointMap[f[fp]];
1882 if (extrudeStatus[patchPointI] != NOEXTRUDE)
1897 forAll(patchDisp, patchPointI)
1899 if (mag(patchDisp[patchPointI]) < minThickness[patchPointI])
1915 else if (extrudeStatus[patchPointI] == NOEXTRUDE)
1917 // Make sure displacement is 0. Should already be so but ...
1918 patchDisp[patchPointI] = vector::zero;
1919 patchNLayers[patchPointI] = 0;
1924 const faceList& localFaces = pp.localFaces();
1928 syncPatchDisplacement
1937 // Make sure that a face doesn't have two non-consecutive areas
1938 // not extruded (e.g. quad where vertex 0 and 2 are not extruded
1939 // but 1 and 3 are) since this gives topological errors.
1943 forAll(localFaces, i)
1945 const face& localF = localFaces[i];
1947 // Count number of transitions from unsnapped to snapped.
1950 extrudeMode prevMode = extrudeStatus[localF.prevLabel(0)];
1954 extrudeMode fpMode = extrudeStatus[localF[fp]];
1956 if (prevMode == NOEXTRUDE && fpMode != NOEXTRUDE)
1965 // Multiple pinches. Reset whole face as unextruded.
1983 reduce(nPinched, sumOp<label>());
1985 Info<< "truncateDisplacement : Unextruded " << nPinched
1986 << " faces due to non-consecutive vertices being extruded." << endl;
1989 // Make sure that a face has consistent number of layers for all
1992 label nDiffering = 0;
1994 //forAll(localFaces, i)
1996 // const face& localF = localFaces[i];
1998 // label numLayers = -1;
2000 // forAll(localF, fp)
2002 // if (patchNLayers[localF[fp]] > 0)
2004 // if (numLayers == -1)
2006 // numLayers = patchNLayers[localF[fp]];
2008 // else if (numLayers != patchNLayers[localF[fp]])
2010 // // Differing number of layers
2031 //reduce(nDiffering, sumOp<label>());
2033 //Info<< "truncateDisplacement : Unextruded " << nDiffering
2034 // << " faces due to having differing number of layers." << endl;
2036 if (nPinched+nDiffering == 0)
2046 // Setup layer information (at points and faces) to modify mesh topology in
2047 // regions where layer mesh terminates.
2048 void Foam::autoLayerDriver::setupLayerInfoTruncation
2050 const motionSmoother& meshMover,
2051 const labelList& patchNLayers,
2052 const List<extrudeMode>& extrudeStatus,
2053 const label nBufferCellsNoExtrude,
2054 labelList& nPatchPointLayers,
2055 labelList& nPatchFaceLayers
2058 Info<< nl << "Setting up information for layer truncation ..." << endl;
2060 const indirectPrimitivePatch& pp = meshMover.patch();
2061 const polyMesh& mesh = meshMover.mesh();
2063 if (nBufferCellsNoExtrude < 0)
2065 Info<< nl << "Performing no layer truncation."
2066 << " nBufferCellsNoExtrude set to less than 0 ..." << endl;
2068 // Face layers if any point get extruded
2069 forAll(pp.localFaces(), patchFaceI)
2071 const face& f = pp.localFaces()[patchFaceI];
2075 if (patchNLayers[f[fp]] > 0)
2077 nPatchFaceLayers[patchFaceI] = patchNLayers[f[fp]];
2082 nPatchPointLayers = patchNLayers;
2086 // Determine max point layers per face.
2087 labelList maxLevel(pp.size(), 0);
2089 forAll(pp.localFaces(), patchFaceI)
2091 const face& f = pp.localFaces()[patchFaceI];
2093 // find patch faces where layer terminates (i.e contains extrude
2094 // and noextrude points).
2096 bool noExtrude = false;
2101 if (extrudeStatus[f[fp]] == NOEXTRUDE)
2105 mLevel = max(mLevel, patchNLayers[f[fp]]);
2110 // So one of the points is extruded. Check if all are extruded
2115 nPatchFaceLayers[patchFaceI] = 1;
2116 maxLevel[patchFaceI] = mLevel;
2120 maxLevel[patchFaceI] = mLevel;
2125 // We have the seed faces (faces with nPatchFaceLayers != maxLevel)
2126 // Now do a meshwave across the patch where we pick up neighbours
2128 // Note: quite inefficient. Could probably be coded better.
2130 const labelListList& pointFaces = pp.pointFaces();
2132 label nLevels = gMax(patchNLayers);
2134 // flag neighbouring patch faces with number of layers to grow
2135 for (label ilevel = 1; ilevel < nLevels; ilevel++)
2141 nBuffer = nBufferCellsNoExtrude - 1;
2145 nBuffer = nBufferCellsNoExtrude;
2148 for (label ibuffer = 0; ibuffer < nBuffer + 1; ibuffer++)
2150 labelList tempCounter(nPatchFaceLayers);
2152 boolList foundNeighbour(pp.nPoints(), false);
2154 forAll(pp.meshPoints(), patchPointI)
2156 forAll(pointFaces[patchPointI], pointFaceI)
2158 label faceI = pointFaces[patchPointI][pointFaceI];
2162 nPatchFaceLayers[faceI] != -1
2163 && maxLevel[faceI] > 0
2166 foundNeighbour[patchPointI] = true;
2172 syncTools::syncPointList
2178 false, // null value
2179 false // no separation
2182 forAll(pp.meshPoints(), patchPointI)
2184 if (foundNeighbour[patchPointI])
2186 forAll(pointFaces[patchPointI], pointFaceI)
2188 label faceI = pointFaces[patchPointI][pointFaceI];
2191 nPatchFaceLayers[faceI] == -1
2192 && maxLevel[faceI] > 0
2193 && ilevel < maxLevel[faceI]
2196 tempCounter[faceI] = ilevel;
2201 nPatchFaceLayers = tempCounter;
2205 forAll(pp.localFaces(), patchFaceI)
2207 if (nPatchFaceLayers[patchFaceI] == -1)
2209 nPatchFaceLayers[patchFaceI] = maxLevel[patchFaceI];
2213 forAll(pp.meshPoints(), patchPointI)
2215 if (extrudeStatus[patchPointI] != NOEXTRUDE)
2217 forAll(pointFaces[patchPointI], pointFaceI)
2219 label face = pointFaces[patchPointI][pointFaceI];
2220 nPatchPointLayers[patchPointI] = max
2222 nPatchPointLayers[patchPointI],
2223 nPatchFaceLayers[face]
2229 nPatchPointLayers[patchPointI] = 0;
2232 syncTools::syncPointList
2239 false // no separation
2245 // Does any of the cells use a face from faces?
2246 bool Foam::autoLayerDriver::cellsUseFace
2248 const polyMesh& mesh,
2249 const labelList& cellLabels,
2250 const labelHashSet& faces
2253 forAll(cellLabels, i)
2255 const cell& cFaces = mesh.cells()[cellLabels[i]];
2257 forAll(cFaces, cFaceI)
2259 if (faces.found(cFaces[cFaceI]))
2269 // Checks the newly added cells and locally unmarks points so they
2270 // will not get extruded next time round. Returns global number of unmarked
2271 // points (0 if all was fine)
2272 Foam::label Foam::autoLayerDriver::checkAndUnmark
2274 const addPatchCellLayer& addLayer,
2275 const dictionary& motionDict,
2276 const indirectPrimitivePatch& pp,
2277 const fvMesh& newMesh,
2279 pointField& patchDisp,
2280 labelList& patchNLayers,
2281 List<extrudeMode>& extrudeStatus
2284 // Check the resulting mesh for errors
2285 Info<< nl << "Checking mesh with layer ..." << endl;
2286 faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
2287 motionSmoother::checkMesh(false, newMesh, motionDict, wrongFaces);
2288 Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
2290 << " (concave, zero area or negative cell pyramid volume)"
2293 // Undo local extrusion if
2294 // - any of the added cells in error
2298 // Get all cells in the layer.
2299 labelListList addedCells
2301 addPatchCellLayer::addedCells
2304 addLayer.layerFaces()
2308 // Check if any of the faces in error uses any face of an added cell
2309 forAll(addedCells, oldPatchFaceI)
2311 // Get the cells (in newMesh labels) per old patch face (in mesh
2313 const labelList& fCells = addedCells[oldPatchFaceI];
2315 if (cellsUseFace(newMesh, fCells, wrongFaces))
2317 // Unmark points on old mesh
2322 pp.localFaces()[oldPatchFaceI],
2334 return returnReduce(nChanged, sumOp<label>());
2338 //- Count global number of extruded faces
2339 Foam::label Foam::autoLayerDriver::countExtrusion
2341 const indirectPrimitivePatch& pp,
2342 const List<extrudeMode>& extrudeStatus
2345 // Count number of extruded patch faces
2346 label nExtruded = 0;
2348 const faceList& localFaces = pp.localFaces();
2350 forAll(localFaces, i)
2352 const face& localFace = localFaces[i];
2354 forAll(localFace, fp)
2356 if (extrudeStatus[localFace[fp]] != NOEXTRUDE)
2365 return returnReduce(nExtruded, sumOp<label>());
2369 // Collect layer faces and layer cells into bools for ease of handling
2370 void Foam::autoLayerDriver::getLayerCellsFaces
2372 const polyMesh& mesh,
2373 const addPatchCellLayer& addLayer,
2374 boolList& flaggedCells,
2375 boolList& flaggedFaces
2378 flaggedCells.setSize(mesh.nCells());
2379 flaggedCells = false;
2380 flaggedFaces.setSize(mesh.nFaces());
2381 flaggedFaces = false;
2383 // Mark all faces in the layer
2384 const labelListList& layerFaces = addLayer.layerFaces();
2386 // Mark all cells in the layer.
2387 labelListList addedCells(addPatchCellLayer::addedCells(mesh, layerFaces));
2389 forAll(addedCells, oldPatchFaceI)
2391 const labelList& added = addedCells[oldPatchFaceI];
2395 flaggedCells[added[i]] = true;
2399 forAll(layerFaces, oldPatchFaceI)
2401 const labelList& layer = layerFaces[oldPatchFaceI];
2403 if (layer.size() > 0)
2405 for (label i = 1; i < layer.size()-1; i++)
2407 flaggedFaces[layer[i]] = true;
2414 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2416 Foam::autoLayerDriver::autoLayerDriver
2418 meshRefinement& meshRefiner,
2419 const labelList& globalToPatch
2422 meshRefiner_(meshRefiner),
2423 globalToPatch_(globalToPatch)
2427 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2429 void Foam::autoLayerDriver::mergePatchFacesUndo
2431 const layerParameters& layerParams,
2432 const dictionary& motionDict
2435 scalar minCos = Foam::cos
2437 layerParams.featureAngle()
2438 * mathematicalConstant::pi/180.0
2441 scalar concaveCos = Foam::cos
2443 layerParams.concaveAngle()
2444 * mathematicalConstant::pi/180.0
2448 << "Merging all faces of a cell" << nl
2449 << "---------------------------" << nl
2450 << " - which are on the same patch" << nl
2451 << " - which make an angle < " << layerParams.featureAngle()
2454 << " (cos:" << minCos << ')' << nl
2455 << " - as long as the resulting face doesn't become concave"
2457 << layerParams.concaveAngle()
2458 << " degrees (0=straight, 180=fully concave)" << nl
2461 label nChanged = mergePatchFacesUndo(minCos, concaveCos, motionDict);
2463 nChanged += mergeEdgesUndo(minCos, motionDict);
2467 void Foam::autoLayerDriver::addLayers
2469 const layerParameters& layerParams,
2470 const dictionary& motionDict,
2471 const label nAllowableErrors,
2472 motionSmoother& meshMover,
2473 decompositionMethod& decomposer,
2474 fvMeshDistribute& distributor
2477 fvMesh& mesh = meshRefiner_.mesh();
2478 const indirectPrimitivePatch& pp = meshMover.patch();
2479 const labelList& meshPoints = pp.meshPoints();
2481 // Precalculate mesh edge labels for patch edges
2482 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2484 labelList meshEdges(pp.nEdges());
2485 forAll(pp.edges(), edgeI)
2487 const edge& ppEdge = pp.edges()[edgeI];
2488 label v0 = meshPoints[ppEdge[0]];
2489 label v1 = meshPoints[ppEdge[1]];
2490 meshEdges[edgeI] = meshTools::findEdge
2493 mesh.pointEdges()[v0],
2499 // Displacement for all pp.localPoints.
2500 vectorField patchDisp(pp.nPoints(), vector::one);
2502 // Number of layers for all pp.localPoints. Note: only valid if
2503 // extrudeStatus = EXTRUDE.
2504 labelList patchNLayers(pp.nPoints(), 0);
2506 // Whether to add edge for all pp.localPoints.
2507 List<extrudeMode> extrudeStatus(pp.nPoints(), EXTRUDE);
2510 // Get number of layer per point from number of layers per patch
2511 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2515 layerParams.numLayers(), // per patch the num layers
2516 meshMover.adaptPatchIDs(), // patches that are being moved
2517 pp, // indirectpatch for all faces moving
2524 // Disable extrusion on non-manifold points
2525 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2537 // Disable extrusion on feature angles
2538 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2544 layerParams.featureAngle()*mathematicalConstant::pi/180.0,
2551 // Disable extrusion on warped faces
2552 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2554 // Undistorted edge length
2555 const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
2556 const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
2561 layerParams.maxFaceThicknessRatio(),
2570 //// Disable extrusion on cells with multiple patch faces
2571 //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2573 //handleMultiplePatchFaces
2583 // Grow out region of non-extrusion
2584 for (label i = 0; i < layerParams.nGrow(); i++)
2595 // Determine (wanted) point-wise layer thickness and expansion ratio
2596 scalarField thickness(pp.nPoints());
2597 scalarField minThickness(pp.nPoints());
2598 scalarField expansionRatio(pp.nPoints());
2599 calculateLayerThickness
2602 meshMover.adaptPatchIDs(),
2603 layerParams.expansionRatio(),
2604 layerParams.finalLayerRatio(),
2605 layerParams.minThickness(),
2615 // Calculate wall to medial axis distance for smoothing displacement
2616 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2618 pointScalarField pointMedialDist
2623 mesh.time().timeName(),
2630 dimensionedScalar("pointMedialDist", dimless, 0.0)
2633 pointVectorField dispVec
2638 mesh.time().timeName(),
2645 dimensionedVector("dispVec", dimless, vector::zero)
2648 pointScalarField medialRatio
2653 mesh.time().timeName(),
2660 dimensionedScalar("medialRatio", dimless, 0.0)
2663 // Setup information for medial axis smoothing. Calculates medial axis
2664 // and a smoothed displacement direction.
2665 // - pointMedialDist : distance to medial axis
2666 // - dispVec : normalised direction of nearest displacement
2667 // - medialRatio : ratio of medial distance to wall distance.
2668 // (1 at wall, 0 at medial axis)
2669 medialAxisSmoothingInfo
2672 layerParams.nSmoothNormals(),
2673 layerParams.nSmoothSurfaceNormals(),
2674 layerParams.minMedianAxisAngleCos(),
2684 pointField oldPoints(mesh.points());
2686 // Last set of topology changes. (changing mesh clears out polyTopoChange)
2687 polyTopoChange savedMeshMod(mesh.boundaryMesh().size());
2689 boolList flaggedCells;
2690 boolList flaggedFaces;
2694 // Make sure displacement is equal on both sides of coupled patches.
2695 syncPatchDisplacement
2704 // Displacement acc. to pointnormals
2705 getPatchDisplacement
2715 // Shrink mesh by displacement value first.
2716 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2719 pointField oldPatchPos(pp.localPoints());
2721 //// Laplacian displacement shrinking.
2722 //shrinkMeshDistance
2726 // -patchDisp, // Shrink in opposite direction of addedPoints
2727 // layerParams.nSmoothDisp(),
2728 // layerParams.nSnap()
2731 // Medial axis based shrinking
2732 shrinkMeshMedialDistance
2736 layerParams.nSmoothThickness(),
2737 layerParams.maxThicknessToMedialRatio(),
2739 layerParams.nSnap(),
2740 layerParams.layerTerminationCos(),
2754 // Update patchDisp (since not all might have been honoured)
2755 patchDisp = oldPatchPos - pp.localPoints();
2758 // Truncate displacements that are too small (this will do internal
2759 // ones, coupled ones have already been truncated by syncPatch)
2760 faceSet dummySet(mesh, "wrongPatchFaces", 0);
2761 truncateDisplacement
2772 // Dump to .obj file for debugging.
2777 mesh.time().path()/"layer",
2783 const_cast<Time&>(mesh.time())++;
2784 Info<< "Writing shrunk mesh to " << mesh.time().timeName() << endl;
2789 // Mesh topo change engine
2790 polyTopoChange meshMod(mesh);
2792 // Grow layer of cells on to patch. Handles zero sized displacement.
2793 addPatchCellLayer addLayer(mesh);
2795 // Determine per point/per face number of layers to extrude. Also
2796 // handles the slow termination of layers when going switching layers
2798 labelList nPatchPointLayers(pp.nPoints(),-1);
2799 labelList nPatchFaceLayers(pp.localFaces().size(),-1);
2800 setupLayerInfoTruncation
2805 layerParams.nBufferCellsNoExtrude(),
2810 // Calculate displacement for first layer for addPatchLayer
2811 vectorField firstDisp(patchNLayers.size(), vector::zero);
2813 forAll(patchNLayers, i)
2815 if (patchNLayers[i] > 0)
2817 if (expansionRatio[i] == 1.0)
2819 firstDisp[i] = patchDisp[i]/nPatchPointLayers[i];
2823 label nLay = nPatchPointLayers[i];
2825 pow(expansionRatio[i], nLay - 1)
2826 * (mag(patchDisp[i])*(1.0 - expansionRatio[i]))
2827 / (1.0 - pow(expansionRatio[i], nLay));
2828 firstDisp[i] = h/mag(patchDisp[i])*patchDisp[i];
2833 scalarField invExpansionRatio = 1.0 / expansionRatio;
2835 // Add topo regardless of whether extrudeStatus is extruderemove.
2836 // Not add layer if patchDisp is zero.
2837 addLayer.setRefinement
2841 nPatchFaceLayers, // layers per face
2842 nPatchPointLayers, // layers per point
2843 firstDisp, // thickness of first layer
2849 const_cast<Time&>(mesh.time())++;
2852 // Store mesh changes for if mesh is correct.
2853 savedMeshMod = meshMod;
2856 // With the stored topo changes we create a new mesh so we can
2857 // undo if neccesary.
2859 autoPtr<fvMesh> newMeshPtr;
2860 autoPtr<mapPolyMesh> map = meshMod.makeMesh
2865 //mesh.name()+"_layer",
2867 static_cast<polyMesh&>(mesh).instance(),
2869 static_cast<polyMesh&>(mesh).readOpt(),
2870 static_cast<polyMesh&>(mesh).writeOpt()
2871 ), // io params from original mesh but new name
2872 mesh, // original mesh
2873 true // parallel sync
2875 fvMesh& newMesh = newMeshPtr();
2877 //?neccesary? Update fields
2878 newMesh.updateMesh(map);
2880 // Update numbering on addLayer:
2881 // - cell/point labels to be newMesh.
2882 // - patchFaces to remain in oldMesh order.
2886 identity(pp.size()),
2887 identity(pp.nPoints())
2890 // Collect layer faces and cells for outside loop.
2902 Info<< "Writing layer mesh to " << mesh.time().timeName() << endl;
2904 cellSet addedCellSet
2908 findIndices(flaggedCells, true)
2911 << returnReduce(addedCellSet.size(), sumOp<label>())
2912 << " added cells to cellSet "
2913 << addedCellSet.name() << endl;
2914 addedCellSet.write();
2916 faceSet layerFacesSet
2920 findIndices(flaggedCells, true)
2923 << returnReduce(layerFacesSet.size(), sumOp<label>())
2924 << " faces inside added layer to faceSet "
2925 << layerFacesSet.name() << endl;
2926 layerFacesSet.write();
2929 // Unset the extrusion at the pp.
2930 label nTotChanged = checkAndUnmark
2942 Info<< "Extruding " << countExtrusion(pp, extrudeStatus)
2943 << " out of " << returnReduce(pp.size(), sumOp<label>())
2944 << " faces. Removed extrusion at " << nTotChanged << " faces."
2947 if (nTotChanged == 0)
2952 // Reset mesh points and start again
2953 meshMover.movePoints(oldPoints);
2954 meshMover.correct();
2958 // At this point we have a (shrunk) mesh and a set of topology changes
2959 // which will make a valid mesh with layer. Apply these changes to the
2962 // Apply the stored topo changes to the current mesh.
2963 autoPtr<mapPolyMesh> map = savedMeshMod.changeMesh(mesh, false);
2966 mesh.updateMesh(map);
2968 // Move mesh (since morphing does not do this)
2969 if (map().hasMotionPoints())
2971 mesh.movePoints(map().preMotionPoints());
2974 meshRefiner_.updateMesh(map, labelList(0));
2977 // Do final balancing
2978 // ~~~~~~~~~~~~~~~~~~
2980 if (Pstream::parRun())
2983 << "Doing final balancing" << nl
2984 << "---------------------" << nl
2989 const_cast<Time&>(mesh.time())++;
2992 // Balance. No restriction on face zones and baffles.
2993 autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
3001 // Re-distribute flag of layer faces and cells
3002 map().distributeCellData(flaggedCells);
3003 map().distributeFaceData(flaggedFaces);
3010 cellSet addedCellSet(mesh, "addedCells", findIndices(flaggedCells, true));
3012 << returnReduce(addedCellSet.size(), sumOp<label>())
3013 << " added cells to cellSet "
3014 << addedCellSet.name() << endl;
3015 addedCellSet.write();
3017 faceSet layerFacesSet(mesh, "layerFaces", findIndices(flaggedFaces, true));
3019 << returnReduce(layerFacesSet.size(), sumOp<label>())
3020 << " faces inside added layer to faceSet "
3021 << layerFacesSet.name() << endl;
3022 layerFacesSet.write();
3026 void Foam::autoLayerDriver::doLayers
3028 const dictionary& shrinkDict,
3029 const dictionary& motionDict,
3030 const layerParameters& layerParams,
3031 decompositionMethod& decomposer,
3032 fvMeshDistribute& distributor
3035 fvMesh& mesh = meshRefiner_.mesh();
3038 << "Shrinking and layer addition phase" << nl
3039 << "----------------------------------" << nl
3042 const_cast<Time&>(mesh.time())++;
3044 Info<< "Using mesh parameters " << motionDict << nl << endl;
3046 // Merge coplanar boundary faces
3047 mergePatchFacesUndo(layerParams, motionDict);
3049 // Per patch the number of layers (0 if no layer)
3050 const labelList& numLayers = layerParams.numLayers();
3052 // Patches that need to get a layer
3053 DynamicList<label> patchIDs(numLayers.size());
3054 label nFacesWithLayers = 0;
3055 forAll(numLayers, patchI)
3057 if (numLayers[patchI] > 0)
3059 patchIDs.append(patchI);
3060 nFacesWithLayers += mesh.boundaryMesh()[patchI].size();
3065 if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0)
3067 Info<< nl << "No layers to generate ..." << endl;
3071 autoPtr<indirectPrimitivePatch> ppPtr
3073 meshRefinement::makePatch
3079 indirectPrimitivePatch& pp = ppPtr();
3081 // Construct iterative mesh mover.
3082 Info<< "Constructing mesh displacer ..." << endl;
3085 pointMesh pMesh(mesh);
3087 motionSmoother meshMover
3092 meshRefinement::makeDisplacementField(pMesh, patchIDs),
3096 // Check that outside of mesh is not multiply connected.
3097 checkMeshManifold();
3099 // Check initial mesh
3100 Info<< "Checking initial mesh ..." << endl;
3101 labelHashSet wrongFaces(mesh.nFaces()/100);
3102 motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces);
3103 const label nInitErrors = returnReduce
3109 Info<< "Detected " << nInitErrors << " illegal faces"
3110 << " (concave, zero area or negative cell pyramid volume)"
3113 // Do all topo changes
3128 // ************************************************************************* //