1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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/>.
25 All to do with adding cell layers
27 \*----------------------------------------------------------------------------*/
29 #include "autoLayerDriver.H"
32 #include "meshRefinement.H"
33 #include "removePoints.H"
34 #include "pointFields.H"
35 #include "motionSmoother.H"
36 #include "unitConversion.H"
40 #include "polyTopoChange.H"
41 #include "mapPolyMesh.H"
42 #include "addPatchCellLayer.H"
43 #include "mapDistributePolyMesh.H"
45 #include "layerParameters.H"
46 #include "combineFaces.H"
48 #include "globalIndex.H"
49 #include "DynamicField.H"
51 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
56 defineTypeNameAndDebug(autoLayerDriver, 0);
58 } // End namespace Foam
61 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
63 // For debugging: Dump displacement to .obj files
64 void Foam::autoLayerDriver::dumpDisplacement
66 const fileName& prefix,
67 const indirectPrimitivePatch& pp,
68 const vectorField& patchDisp,
69 const List<extrudeMode>& extrudeStatus
72 OFstream dispStr(prefix + "_disp.obj");
73 Info<< "Writing all displacements to " << dispStr.name() << nl << endl;
77 forAll(patchDisp, patchPointI)
79 const point& pt = pp.localPoints()[patchPointI];
81 meshTools::writeOBJ(dispStr, pt); vertI++;
82 meshTools::writeOBJ(dispStr, pt + patchDisp[patchPointI]); vertI++;
84 dispStr << "l " << vertI-1 << ' ' << vertI << nl;
88 OFstream illStr(prefix + "_illegal.obj");
89 Info<< "Writing invalid displacements to " << illStr.name() << nl << endl;
93 forAll(patchDisp, patchPointI)
95 if (extrudeStatus[patchPointI] != EXTRUDE)
97 const point& pt = pp.localPoints()[patchPointI];
99 meshTools::writeOBJ(illStr, pt); vertI++;
100 meshTools::writeOBJ(illStr, pt + patchDisp[patchPointI]); vertI++;
102 illStr << "l " << vertI-1 << ' ' << vertI << nl;
108 // Check that primitivePatch is not multiply connected. Collect non-manifold
109 // points in pointSet.
110 void Foam::autoLayerDriver::checkManifold
112 const indirectPrimitivePatch& fp,
113 pointSet& nonManifoldPoints
116 // Check for non-manifold points (surface pinched at point)
117 fp.checkPointManifold(false, &nonManifoldPoints);
119 // Check for edge-faces (surface pinched at edge)
120 const labelListList& edgeFaces = fp.edgeFaces();
122 forAll(edgeFaces, edgeI)
124 const labelList& eFaces = edgeFaces[edgeI];
126 if (eFaces.size() > 2)
128 const edge& e = fp.edges()[edgeI];
130 nonManifoldPoints.insert(fp.meshPoints()[e[0]]);
131 nonManifoldPoints.insert(fp.meshPoints()[e[1]]);
137 void Foam::autoLayerDriver::checkMeshManifold() const
139 const fvMesh& mesh = meshRefiner_.mesh();
141 Info<< nl << "Checking mesh manifoldness ..." << endl;
143 // Get all outside faces
144 labelList outsideFaces(mesh.nFaces() - mesh.nInternalFaces());
146 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
148 outsideFaces[faceI - mesh.nInternalFaces()] = faceI;
151 pointSet nonManifoldPoints
158 // Build primitivePatch out of faces and check it for problems.
161 indirectPrimitivePatch
163 IndirectList<face>(mesh.faces(), outsideFaces),
169 label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
173 Info<< "Outside of mesh is multiply connected across edges or"
175 << "This is not a fatal error but might cause some unexpected"
176 << " behaviour." << nl
177 << "Writing " << nNonManif
178 << " points where this happens to pointSet "
179 << nonManifoldPoints.name() << endl;
181 nonManifoldPoints.instance() = meshRefiner_.timeName();
182 nonManifoldPoints.write();
189 // Unset extrusion on point. Returns true if anything unset.
190 bool Foam::autoLayerDriver::unmarkExtrusion
192 const label patchPointI,
193 pointField& patchDisp,
194 labelList& patchNLayers,
195 List<extrudeMode>& extrudeStatus
198 if (extrudeStatus[patchPointI] == EXTRUDE)
200 extrudeStatus[patchPointI] = NOEXTRUDE;
201 patchNLayers[patchPointI] = 0;
202 patchDisp[patchPointI] = vector::zero;
205 else if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
207 extrudeStatus[patchPointI] = NOEXTRUDE;
208 patchNLayers[patchPointI] = 0;
209 patchDisp[patchPointI] = vector::zero;
219 // Unset extrusion on face. Returns true if anything unset.
220 bool Foam::autoLayerDriver::unmarkExtrusion
222 const face& localFace,
223 pointField& patchDisp,
224 labelList& patchNLayers,
225 List<extrudeMode>& extrudeStatus
228 bool unextruded = false;
230 forAll(localFace, fp)
250 // No extrusion at non-manifold points.
251 void Foam::autoLayerDriver::handleNonManifolds
253 const indirectPrimitivePatch& pp,
254 const labelList& meshEdges,
255 const labelListList& edgeGlobalFaces,
256 pointField& patchDisp,
257 labelList& patchNLayers,
258 List<extrudeMode>& extrudeStatus
261 const fvMesh& mesh = meshRefiner_.mesh();
263 Info<< nl << "Handling non-manifold points ..." << endl;
265 // Detect non-manifold points
266 Info<< nl << "Checking patch manifoldness ..." << endl;
268 pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints());
271 checkManifold(pp, nonManifoldPoints);
273 // 2. Remote check for boundary edges on coupled boundaries
274 forAll(edgeGlobalFaces, edgeI)
278 pp.edgeFaces()[edgeI].size() == 1
279 && edgeGlobalFaces[edgeI].size() > 2
282 // So boundary edges that are connected to more than 2 processors
283 // i.e. a non-manifold edge which is exactly on a processor
285 const edge& e = pp.edges()[edgeI];
286 nonManifoldPoints.insert(pp.meshPoints()[e[0]]);
287 nonManifoldPoints.insert(pp.meshPoints()[e[1]]);
292 label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
294 Info<< "Outside of local patch is multiply connected across edges or"
295 << " points at " << nNonManif << " points." << endl;
299 const labelList& meshPoints = pp.meshPoints();
301 forAll(meshPoints, patchPointI)
303 if (nonManifoldPoints.found(meshPoints[patchPointI]))
317 Info<< "Set displacement to zero for all " << nNonManif
318 << " non-manifold points" << endl;
322 // Parallel feature edge detection. Assumes non-manifold edges already handled.
323 void Foam::autoLayerDriver::handleFeatureAngle
325 const indirectPrimitivePatch& pp,
326 const labelList& meshEdges,
328 pointField& patchDisp,
329 labelList& patchNLayers,
330 List<extrudeMode>& extrudeStatus
333 const fvMesh& mesh = meshRefiner_.mesh();
335 Info<< nl << "Handling feature edges ..." << endl;
337 if (minCos < 1-SMALL)
339 // Normal component of normals of connected faces.
340 vectorField edgeNormal(mesh.nEdges(), point::max);
342 const labelListList& edgeFaces = pp.edgeFaces();
344 forAll(edgeFaces, edgeI)
346 const labelList& eFaces = pp.edgeFaces()[edgeI];
348 label meshEdgeI = meshEdges[edgeI];
354 edgeNormal[meshEdgeI],
355 pp.faceNormals()[eFaces[i]]
360 syncTools::syncEdgeList
365 point::max // null value
369 autoPtr<OFstream> str;
372 str.reset(new OFstream(mesh.time().path()/"featureEdges.obj"));
373 Info<< "Writing feature edges to " << str().name() << endl;
378 // Now on coupled edges the edgeNormal will have been truncated and
379 // only be still be the old value where two faces have the same normal
380 forAll(edgeFaces, edgeI)
382 const labelList& eFaces = pp.edgeFaces()[edgeI];
384 label meshEdgeI = meshEdges[edgeI];
386 const vector& n = edgeNormal[meshEdgeI];
390 scalar cos = n & pp.faceNormals()[eFaces[0]];
394 const edge& e = pp.edges()[edgeI];
415 meshTools::writeOBJ(str(), pp.localPoints()[e[0]]);
417 meshTools::writeOBJ(str(), pp.localPoints()[e[1]]);
419 str()<< "l " << vertI-1 << ' ' << vertI << nl;
425 Info<< "Set displacement to zero for points on "
426 << returnReduce(nFeats, sumOp<label>())
427 << " feature edges" << endl;
432 // No extrusion on cells with warped faces. Calculates the thickness of the
433 // layer and compares it to the space the warped face takes up. Disables
434 // extrusion if layer thickness is more than faceRatio of the thickness of
436 void Foam::autoLayerDriver::handleWarpedFaces
438 const indirectPrimitivePatch& pp,
439 const scalar faceRatio,
440 const scalar edge0Len,
441 const labelList& cellLevel,
442 pointField& patchDisp,
443 labelList& patchNLayers,
444 List<extrudeMode>& extrudeStatus
447 const fvMesh& mesh = meshRefiner_.mesh();
449 Info<< nl << "Handling cells with warped patch faces ..." << nl;
451 const pointField& points = mesh.points();
453 label nWarpedFaces = 0;
457 const face& f = pp[i];
461 label faceI = pp.addressing()[i];
463 label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
464 scalar edgeLen = edge0Len/(1<<ownLevel);
466 // Normal distance to face centre plane
467 const point& fc = mesh.faceCentres()[faceI];
468 const vector& fn = pp.faceNormals()[i];
470 scalarField vProj(f.size());
474 vector n = points[f[fp]] - fc;
475 vProj[fp] = (n & fn);
478 // Get normal 'span' of face
479 scalar minVal = min(vProj);
480 scalar maxVal = max(vProj);
482 if ((maxVal - minVal) > faceRatio * edgeLen)
501 Info<< "Set displacement to zero on "
502 << returnReduce(nWarpedFaces, sumOp<label>())
503 << " warped faces since layer would be > " << faceRatio
504 << " of the size of the bounding box." << endl;
508 //// No extrusion on cells with multiple patch faces. There ususally is a reason
509 //// why combinePatchFaces hasn't succeeded.
510 //void Foam::autoLayerDriver::handleMultiplePatchFaces
512 // const indirectPrimitivePatch& pp,
513 // pointField& patchDisp,
514 // labelList& patchNLayers,
515 // List<extrudeMode>& extrudeStatus
518 // const fvMesh& mesh = meshRefiner_.mesh();
520 // Info<< nl << "Handling cells with multiple patch faces ..." << nl;
522 // const labelListList& pointFaces = pp.pointFaces();
524 // // Cells that should not get an extrusion layer
525 // cellSet multiPatchCells(mesh, "multiPatchCells", pp.size());
527 // // Detect points that use multiple faces on same cell.
528 // forAll(pointFaces, patchPointI)
530 // const labelList& pFaces = pointFaces[patchPointI];
532 // labelHashSet pointCells(pFaces.size());
536 // label cellI = mesh.faceOwner()[pp.addressing()[pFaces[i]]];
538 // if (!pointCells.insert(cellI))
540 // // Second or more occurrence of cell so cell has two or more
541 // // pp faces connected to this point.
542 // multiPatchCells.insert(cellI);
547 // label nMultiPatchCells = returnReduce
549 // multiPatchCells.size(),
553 // Info<< "Detected " << nMultiPatchCells
554 // << " cells with multiple (connected) patch faces." << endl;
556 // label nChanged = 0;
558 // if (nMultiPatchCells > 0)
560 // multiPatchCells.instance() = meshRefiner_.timeName();
561 // Info<< "Writing " << nMultiPatchCells
562 // << " cells with multiple (connected) patch faces to cellSet "
563 // << multiPatchCells.objectPath() << endl;
564 // multiPatchCells.write();
567 // // Go through all points and remove extrusion on any cell in
568 // // multiPatchCells
569 // // (has to be done in separate loop since having one point on
570 // // multipatches has to reset extrusion on all points of cell)
572 // forAll(pointFaces, patchPointI)
574 // if (extrudeStatus[patchPointI] != NOEXTRUDE)
576 // const labelList& pFaces = pointFaces[patchPointI];
581 // mesh.faceOwner()[pp.addressing()[pFaces[i]]];
583 // if (multiPatchCells.found(cellI))
603 // reduce(nChanged, sumOp<label>());
606 // Info<< "Prevented extrusion on " << nChanged
607 // << " points due to multiple patch faces." << nl << endl;
611 // No extrusion on faces with differing number of layers for points
612 void Foam::autoLayerDriver::setNumLayers
614 const labelList& patchToNLayers,
615 const labelList& patchIDs,
616 const indirectPrimitivePatch& pp,
617 pointField& patchDisp,
618 labelList& patchNLayers,
619 List<extrudeMode>& extrudeStatus
622 const fvMesh& mesh = meshRefiner_.mesh();
624 Info<< nl << "Handling points with inconsistent layer specification ..."
627 // Get for every point (really only nessecary on patch external points)
628 // the max and min of any patch faces using it.
629 labelList maxLayers(patchNLayers.size(), labelMin);
630 labelList minLayers(patchNLayers.size(), labelMax);
634 label patchI = patchIDs[i];
636 const labelList& meshPoints = mesh.boundaryMesh()[patchI].meshPoints();
638 label wantedLayers = patchToNLayers[patchI];
640 forAll(meshPoints, patchPointI)
642 label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
644 maxLayers[ppPointI] = max(wantedLayers, maxLayers[ppPointI]);
645 minLayers[ppPointI] = min(wantedLayers, minLayers[ppPointI]);
649 syncTools::syncPointList
655 labelMin // null value
657 syncTools::syncPointList
663 labelMax // null value
666 // Unmark any point with different min and max
667 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
669 //label nConflicts = 0;
673 if (maxLayers[i] == labelMin || minLayers[i] == labelMax)
675 FatalErrorIn("setNumLayers(..)")
676 << "Patchpoint:" << i << " coord:" << pp.localPoints()[i]
677 << " maxLayers:" << maxLayers
678 << " minLayers:" << minLayers
679 << abort(FatalError);
681 else if (maxLayers[i] == minLayers[i])
684 patchNLayers[i] = maxLayers[i];
688 // Inconsistent num layers between patch faces using point
702 patchNLayers[i] = maxLayers[i];
706 //reduce(nConflicts, sumOp<label>());
708 //Info<< "Set displacement to zero for " << nConflicts
709 // << " points due to points being on multiple regions"
710 // << " with inconsistent nLayers specification." << endl;
714 void Foam::autoLayerDriver::growNoExtrusion
716 const indirectPrimitivePatch& pp,
717 pointField& patchDisp,
718 labelList& patchNLayers,
719 List<extrudeMode>& extrudeStatus
722 Info<< nl << "Growing non-extrusion points by one layer ..." << endl;
724 List<extrudeMode> grownExtrudeStatus(extrudeStatus);
726 const faceList& localFaces = pp.localFaces();
730 forAll(localFaces, faceI)
732 const face& f = localFaces[faceI];
734 bool hasSqueeze = false;
737 if (extrudeStatus[f[fp]] == NOEXTRUDE)
746 // Squeeze all points of face
751 extrudeStatus[f[fp]] == EXTRUDE
752 && grownExtrudeStatus[f[fp]] != NOEXTRUDE
755 grownExtrudeStatus[f[fp]] = NOEXTRUDE;
762 extrudeStatus.transfer(grownExtrudeStatus);
765 // Synchronise since might get called multiple times.
766 // Use the fact that NOEXTRUDE is the minimum value.
768 labelList status(extrudeStatus.size());
771 status[i] = extrudeStatus[i];
773 syncTools::syncPointList
779 labelMax // null value
783 extrudeStatus[i] = extrudeMode(status[i]);
788 forAll(extrudeStatus, patchPointI)
790 if (extrudeStatus[patchPointI] == NOEXTRUDE)
792 patchDisp[patchPointI] = vector::zero;
793 patchNLayers[patchPointI] = 0;
797 reduce(nGrown, sumOp<label>());
799 Info<< "Set displacement to zero for an additional " << nGrown
800 << " points." << endl;
804 void Foam::autoLayerDriver::determineSidePatches
806 const globalIndex& globalFaces,
807 const labelListList& edgeGlobalFaces,
808 const indirectPrimitivePatch& pp,
810 labelList& sidePatchID
813 // Sometimes edges-to-be-extruded are on more than 2 processors.
814 // Work out which 2 hold the faces to be extruded and thus which procpatch
815 // the side-face should be in. As an additional complication this might
816 // mean that 2 procesors that were only edge-connected now suddenly need
817 // to become face-connected i.e. have a processor patch between them.
819 fvMesh& mesh = meshRefiner_.mesh();
821 // Determine sidePatchID. Any additional processor boundary gets added to
822 // patchToNbrProc,nbrProcToPatch and nPatches gets set to the new number
825 Map<label> nbrProcToPatch;
826 Map<label> patchToNbrProc;
827 addPatchCellLayer::calcSidePatch
840 label nOldPatches = mesh.boundaryMesh().size();
841 label nAdded = returnReduce(nPatches-nOldPatches, sumOp<label>());
842 Info<< nl << "Adding in total " << nAdded/2 << " inter-processor patches to"
843 << " handle extrusion of non-manifold processor boundaries."
848 // We might not add patches in same order as in patchToNbrProc
849 // so prepare to renumber sidePatchID
850 Map<label> wantedToAddedPatch;
852 for (label patchI = nOldPatches; patchI < nPatches; patchI++)
854 label nbrProcI = patchToNbrProc[patchI];
857 + Foam::name(Pstream::myProcNo())
859 + Foam::name(nbrProcI);
861 dictionary patchDict;
862 patchDict.add("type", processorPolyPatch::typeName);
863 patchDict.add("myProcNo", Pstream::myProcNo());
864 patchDict.add("neighbProcNo", nbrProcI);
865 patchDict.add("nFaces", 0);
866 patchDict.add("startFace", mesh.nFaces());
868 Pout<< "Adding patch " << patchI
870 << " between " << Pstream::myProcNo()
871 << " and " << nbrProcI
874 label procPatchI = meshRefiner_.appendPatch
877 mesh.boundaryMesh().size(), // new patch index
881 wantedToAddedPatch.insert(patchI, procPatchI);
884 // Renumber sidePatchID
885 forAll(sidePatchID, i)
887 label patchI = sidePatchID[i];
888 Map<label>::const_iterator fnd = wantedToAddedPatch.find(patchI);
889 if (fnd != wantedToAddedPatch.end())
891 sidePatchID[i] = fnd();
896 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh()).updateMesh();
901 void Foam::autoLayerDriver::calculateLayerThickness
903 const indirectPrimitivePatch& pp,
904 const labelList& patchIDs,
905 const scalarField& patchExpansionRatio,
907 const bool relativeSizes,
908 const scalarField& patchFinalLayerThickness,
909 const scalarField& patchMinThickness,
911 const labelList& cellLevel,
912 const labelList& patchNLayers,
913 const scalar edge0Len,
915 scalarField& thickness,
916 scalarField& minThickness,
917 scalarField& expansionRatio
920 const fvMesh& mesh = meshRefiner_.mesh();
921 const polyBoundaryMesh& patches = mesh.boundaryMesh();
924 // Rework patch-wise layer parameters into minimum per point
925 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
927 // Reuse input fields
928 expansionRatio.setSize(pp.nPoints());
929 expansionRatio = GREAT;
930 thickness.setSize(pp.nPoints());
932 minThickness.setSize(pp.nPoints());
933 minThickness = GREAT;
937 label patchI = patchIDs[i];
939 const labelList& meshPoints = patches[patchI].meshPoints();
941 forAll(meshPoints, patchPointI)
943 label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
945 expansionRatio[ppPointI] = min
947 expansionRatio[ppPointI],
948 patchExpansionRatio[patchI]
950 thickness[ppPointI] = min
953 patchFinalLayerThickness[patchI]
955 minThickness[ppPointI] = min
957 minThickness[ppPointI],
958 patchMinThickness[patchI]
963 syncTools::syncPointList
971 syncTools::syncPointList
979 syncTools::syncPointList
989 // Now the thicknesses are set according to the minimum of connected
993 // Rework relative thickness into absolute
994 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
995 // by multiplying with the internal cell size.
999 if (min(patchMinThickness) < 0 || max(patchMinThickness) > 2)
1001 FatalErrorIn("calculateLayerThickness(..)")
1002 << "Thickness should be factor of local undistorted cell size."
1003 << " Valid values are [0..2]." << nl
1004 << " minThickness:" << patchMinThickness
1005 << exit(FatalError);
1009 // Determine per point the max cell level of connected cells
1010 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1012 labelList maxPointLevel(pp.nPoints(), labelMin);
1016 label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1018 const face& f = pp.localFaces()[i];
1022 maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1026 syncTools::syncPointList
1032 labelMin // null value
1036 forAll(maxPointLevel, pointI)
1038 // Find undistorted edge size for this level.
1039 scalar edgeLen = edge0Len/(1<<maxPointLevel[pointI]);
1040 thickness[pointI] *= edgeLen;
1041 minThickness[pointI] *= edgeLen;
1047 // Rework thickness (of final layer) into overall thickness of all layers
1048 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1050 forAll(thickness, pointI)
1052 // Calculate layer thickness based on expansion ratio
1053 // and final layer height
1054 if (expansionRatio[pointI] == 1)
1056 thickness[pointI] *= patchNLayers[pointI];
1061 scalar invExpansion = 1.0 / expansionRatio[pointI];
1062 label nLay = patchNLayers[pointI];
1063 thickness[pointI] *=
1064 (1.0 - pow(invExpansion, nLay))
1065 / (1.0 - invExpansion);
1070 //Info<< "calculateLayerThickness : min:" << gMin(thickness)
1071 // << " max:" << gMax(thickness) << endl;
1075 // Synchronize displacement among coupled patches.
1076 void Foam::autoLayerDriver::syncPatchDisplacement
1078 const motionSmoother& meshMover,
1079 const scalarField& minThickness,
1080 pointField& patchDisp,
1081 labelList& patchNLayers,
1082 List<extrudeMode>& extrudeStatus
1085 const fvMesh& mesh = meshRefiner_.mesh();
1086 const labelList& meshPoints = meshMover.patch().meshPoints();
1088 label nChangedTotal = 0;
1094 // Sync displacement (by taking min)
1095 syncTools::syncPointList
1101 point::max // null value
1104 // Unmark if displacement too small
1105 forAll(patchDisp, i)
1107 if (mag(patchDisp[i]) < minThickness[i])
1125 labelList syncPatchNLayers(patchNLayers);
1127 syncTools::syncPointList
1133 labelMax // null value
1138 forAll(syncPatchNLayers, i)
1140 if (syncPatchNLayers[i] != patchNLayers[i])
1158 syncTools::syncPointList
1164 labelMin // null value
1169 forAll(syncPatchNLayers, i)
1171 if (syncPatchNLayers[i] != patchNLayers[i])
1188 nChangedTotal += nChanged;
1190 if (!returnReduce(nChanged, sumOp<label>()))
1196 Info<< "Prevented extrusion on "
1197 << returnReduce(nChangedTotal, sumOp<label>())
1198 << " coupled patch points during syncPatchDisplacement." << endl;
1202 // Calculate displacement vector for all patch points. Uses pointNormal.
1203 // Checks that displaced patch point would be visible from all centres
1204 // of the faces using it.
1205 // extrudeStatus is both input and output and gives the status of each
1207 void Foam::autoLayerDriver::getPatchDisplacement
1209 const motionSmoother& meshMover,
1210 const scalarField& thickness,
1211 const scalarField& minThickness,
1212 pointField& patchDisp,
1213 labelList& patchNLayers,
1214 List<extrudeMode>& extrudeStatus
1217 Info<< nl << "Determining displacement for added points"
1218 << " according to pointNormal ..." << endl;
1220 const fvMesh& mesh = meshRefiner_.mesh();
1221 const indirectPrimitivePatch& pp = meshMover.patch();
1222 const vectorField& faceNormals = pp.faceNormals();
1223 const labelListList& pointFaces = pp.pointFaces();
1224 const pointField& localPoints = pp.localPoints();
1225 const labelList& meshPoints = pp.meshPoints();
1227 // Determine pointNormal
1228 // ~~~~~~~~~~~~~~~~~~~~~
1230 pointField pointNormals(pp.nPoints(), vector::zero);
1232 labelList nPointFaces(pp.nPoints(), 0);
1234 forAll(faceNormals, faceI)
1236 const face& f = pp.localFaces()[faceI];
1240 pointNormals[f[fp]] += faceNormals[faceI];
1241 nPointFaces[f[fp]] ++;
1245 syncTools::syncPointList
1251 vector::zero // null value
1254 syncTools::syncPointList
1263 forAll(pointNormals, i)
1265 pointNormals[i] /= nPointFaces[i];
1270 // Determine local length scale on patch
1271 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1273 // Start off from same thickness everywhere (except where no extrusion)
1274 patchDisp = thickness*pointNormals;
1276 // Check if no extrude possible.
1277 forAll(pointNormals, patchPointI)
1279 label meshPointI = pp.meshPoints()[patchPointI];
1281 if (extrudeStatus[patchPointI] == NOEXTRUDE)
1283 // Do not use unmarkExtrusion; forcibly set to zero extrusion.
1284 patchNLayers[patchPointI] = 0;
1285 patchDisp[patchPointI] = vector::zero;
1290 const vector& n = pointNormals[patchPointI];
1292 if (!meshTools::visNormal(n, faceNormals, pointFaces[patchPointI]))
1294 Pout<< "No valid normal for point " << meshPointI
1295 << ' ' << pp.points()[meshPointI]
1296 << "; setting displacement to " << patchDisp[patchPointI]
1299 extrudeStatus[patchPointI] = EXTRUDEREMOVE;
1304 // At illegal points make displacement average of new neighbour positions
1305 forAll(extrudeStatus, patchPointI)
1307 if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
1309 point avg(vector::zero);
1312 const labelList& pEdges = pp.pointEdges()[patchPointI];
1316 label edgeI = pEdges[i];
1318 label otherPointI = pp.edges()[edgeI].otherVertex(patchPointI);
1320 if (extrudeStatus[otherPointI] != NOEXTRUDE)
1322 avg += localPoints[otherPointI] + patchDisp[otherPointI];
1329 Pout<< "Displacement at illegal point "
1330 << localPoints[patchPointI]
1331 << " set to " << (avg / nPoints - localPoints[patchPointI])
1334 patchDisp[patchPointI] =
1336 - localPoints[patchPointI];
1341 // Make sure displacement is equal on both sides of coupled patches.
1342 syncPatchDisplacement
1355 bool Foam::autoLayerDriver::sameEdgeNeighbour
1357 const labelListList& globalEdgeFaces,
1358 const label myGlobalFaceI,
1359 const label nbrGlobFaceI,
1363 const labelList& eFaces = globalEdgeFaces[edgeI];
1364 if (eFaces.size() == 2)
1366 return edge(myGlobalFaceI, nbrGlobFaceI) == edge(eFaces[0], eFaces[1]);
1375 void Foam::autoLayerDriver::getVertexString
1377 const indirectPrimitivePatch& pp,
1378 const labelListList& globalEdgeFaces,
1381 const label myGlobFaceI,
1382 const label nbrGlobFaceI,
1383 DynamicList<label>& vertices
1386 const labelList& fEdges = pp.faceEdges()[faceI];
1387 label fp = findIndex(fEdges, edgeI);
1391 FatalErrorIn("autoLayerDriver::getVertexString(..)")
1392 << "problem." << abort(FatalError);
1400 label prevFp = fEdges.rcIndex(startFp);
1420 label nextFp = fEdges.fcIndex(endFp);
1437 const face& f = pp.localFaces()[faceI];
1442 vertices.append(f[fp]);
1445 vertices.append(f[fp]);
1447 vertices.append(f[fp]);
1451 // Truncates displacement
1452 // - for all patchFaces in the faceset displacement gets set to zero
1453 // - all displacement < minThickness gets set to zero
1454 Foam::label Foam::autoLayerDriver::truncateDisplacement
1456 const globalIndex& globalFaces,
1457 const labelListList& edgeGlobalFaces,
1458 const motionSmoother& meshMover,
1459 const scalarField& minThickness,
1460 const faceSet& illegalPatchFaces,
1461 pointField& patchDisp,
1462 labelList& patchNLayers,
1463 List<extrudeMode>& extrudeStatus
1466 const polyMesh& mesh = meshMover.mesh();
1467 const indirectPrimitivePatch& pp = meshMover.patch();
1471 const Map<label>& meshPointMap = pp.meshPointMap();
1473 forAllConstIter(faceSet, illegalPatchFaces, iter)
1475 label faceI = iter.key();
1477 if (mesh.isInternalFace(faceI))
1479 FatalErrorIn("truncateDisplacement(..)")
1480 << "Faceset " << illegalPatchFaces.name()
1481 << " contains internal face " << faceI << nl
1482 << "It should only contain patch faces" << abort(FatalError);
1485 const face& f = mesh.faces()[faceI];
1490 if (meshPointMap.found(f[fp]))
1492 label patchPointI = meshPointMap[f[fp]];
1494 if (extrudeStatus[patchPointI] != NOEXTRUDE)
1509 forAll(patchDisp, patchPointI)
1511 if (mag(patchDisp[patchPointI]) < minThickness[patchPointI])
1527 else if (extrudeStatus[patchPointI] == NOEXTRUDE)
1529 // Make sure displacement is 0. Should already be so but ...
1530 patchDisp[patchPointI] = vector::zero;
1531 patchNLayers[patchPointI] = 0;
1536 const faceList& localFaces = pp.localFaces();
1540 syncPatchDisplacement
1553 // Make sure that a face doesn't have two non-consecutive areas
1554 // not extruded (e.g. quad where vertex 0 and 2 are not extruded
1555 // but 1 and 3 are) since this gives topological errors.
1559 forAll(localFaces, i)
1561 const face& localF = localFaces[i];
1563 // Count number of transitions from unsnapped to snapped.
1566 extrudeMode prevMode = extrudeStatus[localF.prevLabel(0)];
1570 extrudeMode fpMode = extrudeStatus[localF[fp]];
1572 if (prevMode == NOEXTRUDE && fpMode != NOEXTRUDE)
1581 // Multiple pinches. Reset whole face as unextruded.
1599 reduce(nPinched, sumOp<label>());
1601 Info<< "truncateDisplacement : Unextruded " << nPinched
1602 << " faces due to non-consecutive vertices being extruded." << endl;
1608 // Make sure that a string of edges becomes a single face so
1609 // not a butterfly. Occassionally an 'edge' will have a single dangling
1610 // vertex due to face combining. These get extruded as a single face
1611 // (with a dangling vertex) so make sure this extrusion forms a single
1613 // - continuous i.e. no butterfly:
1618 // - extrudes from all but the endpoints i.e. no partial
1624 // The common error topology is a pinch somewhere in the middle
1625 label nButterFly = 0;
1627 DynamicList<label> stringedVerts;
1628 forAll(pp.edges(), edgeI)
1630 const labelList& globFaces = edgeGlobalFaces[edgeI];
1632 if (globFaces.size() == 2)
1634 label myFaceI = pp.edgeFaces()[edgeI][0];
1635 label myGlobalFaceI = globalFaces.toGlobal
1637 pp.addressing()[myFaceI]
1639 label nbrGlobalFaceI =
1641 globFaces[0] != myGlobalFaceI
1658 extrudeStatus[stringedVerts[0]] != NOEXTRUDE
1659 || extrudeStatus[stringedVerts.last()] != NOEXTRUDE
1662 // Any pinch in the middle
1664 for (label i = 1; i < stringedVerts.size()-1; i++)
1668 extrudeStatus[stringedVerts[i]] == NOEXTRUDE
1677 forAll(stringedVerts, i)
1700 reduce(nButterFly, sumOp<label>());
1702 Info<< "truncateDisplacement : Unextruded " << nButterFly
1703 << " faces due to stringed edges with inconsistent extrusion."
1708 // Consistent number of layers
1709 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1711 // Make sure that a face has consistent number of layers for all
1714 label nDiffering = 0;
1716 //forAll(localFaces, i)
1718 // const face& localF = localFaces[i];
1720 // label numLayers = -1;
1722 // forAll(localF, fp)
1724 // if (patchNLayers[localF[fp]] > 0)
1726 // if (numLayers == -1)
1728 // numLayers = patchNLayers[localF[fp]];
1730 // else if (numLayers != patchNLayers[localF[fp]])
1732 // // Differing number of layers
1753 //reduce(nDiffering, sumOp<label>());
1755 //Info<< "truncateDisplacement : Unextruded " << nDiffering
1756 // << " faces due to having differing number of layers." << endl;
1758 if (nPinched+nButterFly+nDiffering == 0)
1768 // Setup layer information (at points and faces) to modify mesh topology in
1769 // regions where layer mesh terminates.
1770 void Foam::autoLayerDriver::setupLayerInfoTruncation
1772 const motionSmoother& meshMover,
1773 const labelList& patchNLayers,
1774 const List<extrudeMode>& extrudeStatus,
1775 const label nBufferCellsNoExtrude,
1776 labelList& nPatchPointLayers,
1777 labelList& nPatchFaceLayers
1780 Info<< nl << "Setting up information for layer truncation ..." << endl;
1782 const indirectPrimitivePatch& pp = meshMover.patch();
1783 const polyMesh& mesh = meshMover.mesh();
1785 if (nBufferCellsNoExtrude < 0)
1787 Info<< nl << "Performing no layer truncation."
1788 << " nBufferCellsNoExtrude set to less than 0 ..." << endl;
1790 // Face layers if any point gets extruded
1791 forAll(pp.localFaces(), patchFaceI)
1793 const face& f = pp.localFaces()[patchFaceI];
1797 if (patchNLayers[f[fp]] > 0)
1799 nPatchFaceLayers[patchFaceI] = patchNLayers[f[fp]];
1804 nPatchPointLayers = patchNLayers;
1808 // Determine max point layers per face.
1809 labelList maxLevel(pp.size(), 0);
1811 forAll(pp.localFaces(), patchFaceI)
1813 const face& f = pp.localFaces()[patchFaceI];
1815 // find patch faces where layer terminates (i.e contains extrude
1816 // and noextrude points).
1818 bool noExtrude = false;
1823 if (extrudeStatus[f[fp]] == NOEXTRUDE)
1827 mLevel = max(mLevel, patchNLayers[f[fp]]);
1832 // So one of the points is extruded. Check if all are extruded
1837 nPatchFaceLayers[patchFaceI] = 1;
1838 maxLevel[patchFaceI] = mLevel;
1842 maxLevel[patchFaceI] = mLevel;
1847 // We have the seed faces (faces with nPatchFaceLayers != maxLevel)
1848 // Now do a meshwave across the patch where we pick up neighbours
1850 // Note: quite inefficient. Could probably be coded better.
1852 const labelListList& pointFaces = pp.pointFaces();
1854 label nLevels = gMax(patchNLayers);
1856 // flag neighbouring patch faces with number of layers to grow
1857 for (label ilevel = 1; ilevel < nLevels; ilevel++)
1863 nBuffer = nBufferCellsNoExtrude - 1;
1867 nBuffer = nBufferCellsNoExtrude;
1870 for (label ibuffer = 0; ibuffer < nBuffer + 1; ibuffer++)
1872 labelList tempCounter(nPatchFaceLayers);
1874 boolList foundNeighbour(pp.nPoints(), false);
1876 forAll(pp.meshPoints(), patchPointI)
1878 forAll(pointFaces[patchPointI], pointFaceI)
1880 label faceI = pointFaces[patchPointI][pointFaceI];
1884 nPatchFaceLayers[faceI] != -1
1885 && maxLevel[faceI] > 0
1888 foundNeighbour[patchPointI] = true;
1894 syncTools::syncPointList
1903 forAll(pp.meshPoints(), patchPointI)
1905 if (foundNeighbour[patchPointI])
1907 forAll(pointFaces[patchPointI], pointFaceI)
1909 label faceI = pointFaces[patchPointI][pointFaceI];
1912 nPatchFaceLayers[faceI] == -1
1913 && maxLevel[faceI] > 0
1914 && ilevel < maxLevel[faceI]
1917 tempCounter[faceI] = ilevel;
1922 nPatchFaceLayers = tempCounter;
1926 forAll(pp.localFaces(), patchFaceI)
1928 if (nPatchFaceLayers[patchFaceI] == -1)
1930 nPatchFaceLayers[patchFaceI] = maxLevel[patchFaceI];
1934 forAll(pp.meshPoints(), patchPointI)
1936 if (extrudeStatus[patchPointI] != NOEXTRUDE)
1938 forAll(pointFaces[patchPointI], pointFaceI)
1940 label face = pointFaces[patchPointI][pointFaceI];
1941 nPatchPointLayers[patchPointI] = max
1943 nPatchPointLayers[patchPointI],
1944 nPatchFaceLayers[face]
1950 nPatchPointLayers[patchPointI] = 0;
1953 syncTools::syncPointList
1965 // Does any of the cells use a face from faces?
1966 bool Foam::autoLayerDriver::cellsUseFace
1968 const polyMesh& mesh,
1969 const labelList& cellLabels,
1970 const labelHashSet& faces
1973 forAll(cellLabels, i)
1975 const cell& cFaces = mesh.cells()[cellLabels[i]];
1977 forAll(cFaces, cFaceI)
1979 if (faces.found(cFaces[cFaceI]))
1989 // Checks the newly added cells and locally unmarks points so they
1990 // will not get extruded next time round. Returns global number of unmarked
1991 // points (0 if all was fine)
1992 Foam::label Foam::autoLayerDriver::checkAndUnmark
1994 const addPatchCellLayer& addLayer,
1995 const dictionary& meshQualityDict,
1996 const bool additionalReporting,
1997 const List<labelPair>& baffles,
1998 const indirectPrimitivePatch& pp,
1999 const fvMesh& newMesh,
2001 pointField& patchDisp,
2002 labelList& patchNLayers,
2003 List<extrudeMode>& extrudeStatus
2006 // Check the resulting mesh for errors
2007 Info<< nl << "Checking mesh with layer ..." << endl;
2008 faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
2009 motionSmoother::checkMesh
2014 identity(newMesh.nFaces()),
2018 Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
2020 << " (concave, zero area or negative cell pyramid volume)"
2023 // Undo local extrusion if
2024 // - any of the added cells in error
2028 // Get all cells in the layer.
2029 labelListList addedCells
2031 addPatchCellLayer::addedCells
2034 addLayer.layerFaces()
2038 // Check if any of the faces in error uses any face of an added cell
2039 // - if additionalReporting print the few remaining areas for ease of
2040 // finding out where the problems are.
2042 const label nReportMax = 10;
2043 DynamicField<point> disabledFaceCentres(nReportMax);
2045 forAll(addedCells, oldPatchFaceI)
2047 // Get the cells (in newMesh labels) per old patch face (in mesh
2049 const labelList& fCells = addedCells[oldPatchFaceI];
2051 if (cellsUseFace(newMesh, fCells, wrongFaces))
2053 // Unmark points on old mesh
2058 pp.localFaces()[oldPatchFaceI],
2065 if (additionalReporting && (nChanged < nReportMax))
2067 disabledFaceCentres.append
2069 pp.faceCentres()[oldPatchFaceI]
2079 label nChangedTotal = returnReduce(nChanged, sumOp<label>());
2081 if (additionalReporting)
2083 // Limit the number of points to be printed so that
2084 // not too many points are reported when running in parallel
2085 // Not accurate, i.e. not always nReportMax points are written,
2086 // but this estimation avoid some communication here.
2087 // The important thing, however, is that when only a few faces
2088 // are disabled, their coordinates are printed, and this should be
2090 label nReportLocal = nChanged;
2091 if (nChangedTotal > nReportMax)
2095 max(nChangedTotal / Pstream::nProcs(), 1),
2099 max(nReportMax / Pstream::nProcs(), 1)
2106 Pout<< "Checked mesh with layers. Disabled extrusion at " << endl;
2107 for (label i=0; i < nReportLocal; i++)
2109 Pout<< " " << disabledFaceCentres[i] << endl;
2113 label nReportTotal = returnReduce(nReportLocal, sumOp<label>());
2115 if (nReportTotal < nChangedTotal)
2117 Info<< "Suppressed disabled extrusion message for other "
2118 << nChangedTotal - nReportTotal << " faces." << endl;
2122 return nChangedTotal;
2126 //- Count global number of extruded faces
2127 Foam::label Foam::autoLayerDriver::countExtrusion
2129 const indirectPrimitivePatch& pp,
2130 const List<extrudeMode>& extrudeStatus
2133 // Count number of extruded patch faces
2134 label nExtruded = 0;
2136 const faceList& localFaces = pp.localFaces();
2138 forAll(localFaces, i)
2140 const face& localFace = localFaces[i];
2142 forAll(localFace, fp)
2144 if (extrudeStatus[localFace[fp]] != NOEXTRUDE)
2153 return returnReduce(nExtruded, sumOp<label>());
2157 // Collect layer faces and layer cells into bools for ease of handling
2158 void Foam::autoLayerDriver::getLayerCellsFaces
2160 const polyMesh& mesh,
2161 const addPatchCellLayer& addLayer,
2162 boolList& flaggedCells,
2163 boolList& flaggedFaces
2166 flaggedCells.setSize(mesh.nCells());
2167 flaggedCells = false;
2168 flaggedFaces.setSize(mesh.nFaces());
2169 flaggedFaces = false;
2171 // Mark all faces in the layer
2172 const labelListList& layerFaces = addLayer.layerFaces();
2174 // Mark all cells in the layer.
2175 labelListList addedCells(addPatchCellLayer::addedCells(mesh, layerFaces));
2177 forAll(addedCells, oldPatchFaceI)
2179 const labelList& added = addedCells[oldPatchFaceI];
2183 flaggedCells[added[i]] = true;
2187 forAll(layerFaces, oldPatchFaceI)
2189 const labelList& layer = layerFaces[oldPatchFaceI];
2193 for (label i = 1; i < layer.size()-1; i++)
2195 flaggedFaces[layer[i]] = true;
2202 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2204 Foam::autoLayerDriver::autoLayerDriver
2206 meshRefinement& meshRefiner,
2207 const labelList& globalToPatch
2210 meshRefiner_(meshRefiner),
2211 globalToPatch_(globalToPatch)
2215 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2217 void Foam::autoLayerDriver::mergePatchFacesUndo
2219 const layerParameters& layerParams,
2220 const dictionary& motionDict
2224 Foam::cos(degToRad(layerParams.featureAngle()));
2227 Foam::cos(degToRad(layerParams.concaveAngle()));
2230 << "Merging all faces of a cell" << nl
2231 << "---------------------------" << nl
2232 << " - which are on the same patch" << nl
2233 << " - which make an angle < " << layerParams.featureAngle()
2236 << " (cos:" << minCos << ')' << nl
2237 << " - as long as the resulting face doesn't become concave"
2239 << layerParams.concaveAngle() << " degrees" << nl
2240 << " (0=straight, 180=fully concave)" << nl
2243 label nChanged = meshRefiner_.mergePatchFacesUndo
2247 meshRefiner_.meshedPatches(),
2251 nChanged += meshRefiner_.mergeEdgesUndo(minCos, motionDict);
2255 void Foam::autoLayerDriver::addLayers
2257 const layerParameters& layerParams,
2258 const dictionary& motionDict,
2259 const labelList& patchIDs,
2260 const label nAllowableErrors,
2261 decompositionMethod& decomposer,
2262 fvMeshDistribute& distributor
2265 fvMesh& mesh = meshRefiner_.mesh();
2267 // Create baffles (pairs of faces that share the same points)
2268 // Baffles stored as owner and neighbour face that have been created.
2269 List<labelPair> baffles;
2270 meshRefiner_.createZoneBaffles(globalToPatch_, baffles);
2275 const_cast<Time&>(mesh.time())++;
2276 Info<< "Writing baffled mesh to " << meshRefiner_.timeName() << endl;
2280 mesh.time().path()/meshRefiner_.timeName()
2285 autoPtr<indirectPrimitivePatch> pp
2287 meshRefinement::makePatch
2295 // Global face indices engine
2296 const globalIndex globalFaces(mesh.nFaces());
2298 // Determine extrudePatch.edgeFaces in global numbering (so across
2299 // coupled patches). This is used only to string up edges between coupled
2300 // faces (all edges between same (global)face indices get extruded).
2301 labelListList edgeGlobalFaces
2303 addPatchCellLayer::globalEdgeFaces
2311 // Determine patches for extruded boundary edges. Calculates if any
2312 // additional processor patches need to be constructed.
2314 labelList sidePatchID;
2315 determineSidePatches
2325 // Construct iterative mesh mover.
2326 Info<< "Constructing mesh displacer ..." << endl;
2328 autoPtr<motionSmoother> meshMover
2335 meshRefinement::makeDisplacementField
2337 pointMesh::New(mesh),
2345 // Point-wise extrusion data
2346 // ~~~~~~~~~~~~~~~~~~~~~~~~~
2348 // Displacement for all pp.localPoints.
2349 vectorField patchDisp(pp().nPoints(), vector::one);
2351 // Number of layers for all pp.localPoints. Note: only valid if
2352 // extrudeStatus = EXTRUDE.
2353 labelList patchNLayers(pp().nPoints(), 0);
2355 // Whether to add edge for all pp.localPoints.
2356 List<extrudeMode> extrudeStatus(pp().nPoints(), EXTRUDE);
2359 // Get number of layer per point from number of layers per patch
2360 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2364 layerParams.numLayers(), // per patch the num layers
2365 meshMover().adaptPatchIDs(),// patches that are being moved
2366 pp, // indirectpatch for all faces moving
2373 // Precalculate mesh edge labels for patch edges
2374 labelList meshEdges(pp().meshEdges(mesh.edges(), mesh.pointEdges()));
2376 // Disable extrusion on non-manifold points
2377 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2390 // Disable extrusion on feature angles
2391 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2397 degToRad(layerParams.featureAngle()),
2404 // Disable extrusion on warped faces
2405 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2407 // Undistorted edge length
2408 const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
2409 const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
2414 layerParams.maxFaceThicknessRatio(),
2423 //// Disable extrusion on cells with multiple patch faces
2424 //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2426 //handleMultiplePatchFaces
2436 // Grow out region of non-extrusion
2437 for (label i = 0; i < layerParams.nGrow(); i++)
2450 // Undistorted edge length
2451 const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
2452 const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
2454 // Determine (wanted) point-wise layer thickness and expansion ratio
2455 scalarField thickness(pp().nPoints());
2456 scalarField minThickness(pp().nPoints());
2457 scalarField expansionRatio(pp().nPoints());
2458 calculateLayerThickness
2461 meshMover().adaptPatchIDs(),
2462 layerParams.expansionRatio(),
2464 layerParams.relativeSizes(), // thickness relative to cellsize?
2465 layerParams.finalLayerThickness(), // wanted thicknes
2466 layerParams.minThickness(), // minimum thickness
2480 const polyBoundaryMesh& patches = mesh.boundaryMesh();
2482 // Find maximum length of a patch name, for a nicer output
2483 label maxPatchNameLen = 0;
2484 forAll(meshMover().adaptPatchIDs(), i)
2486 label patchI = meshMover().adaptPatchIDs()[i];
2487 word patchName = patches[patchI].name();
2488 maxPatchNameLen = max(maxPatchNameLen, label(patchName.size()));
2492 << setf(ios_base::left) << setw(maxPatchNameLen) << "patch"
2493 << setw(0) << " faces layers avg thickness[m]" << nl
2494 << setf(ios_base::left) << setw(maxPatchNameLen) << " "
2495 << setw(0) << " near-wall overall" << nl
2496 << setf(ios_base::left) << setw(maxPatchNameLen) << "-----"
2497 << setw(0) << " ----- ------ --------- -------" << endl;
2499 forAll(meshMover().adaptPatchIDs(), i)
2501 label patchI = meshMover().adaptPatchIDs()[i];
2503 const labelList& meshPoints = patches[patchI].meshPoints();
2505 scalar sumThickness = 0;
2506 scalar sumNearWallThickness = 0;
2508 forAll(meshPoints, patchPointI)
2510 label ppPointI = pp().meshPointMap()[meshPoints[patchPointI]];
2512 sumThickness += thickness[ppPointI];
2514 label nLay = patchNLayers[ppPointI];
2517 if (expansionRatio[ppPointI] == 1)
2519 sumNearWallThickness += thickness[ppPointI]/nLay;
2524 (1.0-pow(expansionRatio[ppPointI], nLay))
2525 / (1.0-expansionRatio[ppPointI]);
2526 sumNearWallThickness += thickness[ppPointI]/s;
2531 label totNPoints = returnReduce(meshPoints.size(), sumOp<label>());
2533 // For empty patches, totNPoints is 0.
2534 scalar avgThickness = 0;
2535 scalar avgNearWallThickness = 0;
2540 returnReduce(sumThickness, sumOp<scalar>())
2542 avgNearWallThickness =
2543 returnReduce(sumNearWallThickness, sumOp<scalar>())
2547 Info<< setf(ios_base::left) << setw(maxPatchNameLen)
2548 << patches[patchI].name() << setprecision(3)
2550 << returnReduce(patches[patchI].size(), sumOp<scalar>())
2551 << " " << setw(6) << layerParams.numLayers()[patchI]
2552 << " " << setw(8) << avgNearWallThickness
2553 << " " << setw(8) << avgThickness
2560 // Calculate wall to medial axis distance for smoothing displacement
2561 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2563 pointScalarField pointMedialDist
2568 meshRefiner_.timeName(),
2574 meshMover().pMesh(),
2575 dimensionedScalar("pointMedialDist", dimless, 0.0)
2578 pointVectorField dispVec
2583 meshRefiner_.timeName(),
2589 meshMover().pMesh(),
2590 dimensionedVector("dispVec", dimless, vector::zero)
2593 pointScalarField medialRatio
2598 meshRefiner_.timeName(),
2604 meshMover().pMesh(),
2605 dimensionedScalar("medialRatio", dimless, 0.0)
2608 // Setup information for medial axis smoothing. Calculates medial axis
2609 // and a smoothed displacement direction.
2610 // - pointMedialDist : distance to medial axis
2611 // - dispVec : normalised direction of nearest displacement
2612 // - medialRatio : ratio of medial distance to wall distance.
2613 // (1 at wall, 0 at medial axis)
2614 medialAxisSmoothingInfo
2617 layerParams.nSmoothNormals(),
2618 layerParams.nSmoothSurfaceNormals(),
2619 layerParams.minMedianAxisAngleCos(),
2629 pointField oldPoints(mesh.points());
2631 // Last set of topology changes. (changing mesh clears out polyTopoChange)
2632 polyTopoChange savedMeshMod(mesh.boundaryMesh().size());
2634 boolList flaggedCells;
2635 boolList flaggedFaces;
2637 for (label iteration = 0; iteration < layerParams.nLayerIter(); iteration++)
2640 << "Layer addition iteration " << iteration << nl
2641 << "--------------------------" << endl;
2644 // Unset the extrusion at the pp.
2645 const dictionary& meshQualityDict =
2647 iteration < layerParams.nRelaxedIter()
2649 : motionDict.subDict("relaxed")
2652 if (iteration >= layerParams.nRelaxedIter())
2654 Info<< "Switched to relaxed meshQuality constraints." << endl;
2659 // Make sure displacement is equal on both sides of coupled patches.
2660 syncPatchDisplacement
2669 // Displacement acc. to pointnormals
2670 getPatchDisplacement
2680 // Shrink mesh by displacement value first.
2681 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2684 pointField oldPatchPos(pp().localPoints());
2686 //// Laplacian displacement shrinking.
2687 //shrinkMeshDistance
2691 // -patchDisp, // Shrink in opposite direction of addedPoints
2692 // layerParams.nSmoothDisp(),
2693 // layerParams.nSnap()
2696 // Medial axis based shrinking
2697 shrinkMeshMedialDistance
2703 layerParams.nSmoothThickness(),
2704 layerParams.maxThicknessToMedialRatio(),
2706 layerParams.nSnap(),
2707 layerParams.layerTerminationCos(),
2721 // Update patchDisp (since not all might have been honoured)
2722 patchDisp = oldPatchPos - pp().localPoints();
2725 // Truncate displacements that are too small (this will do internal
2726 // ones, coupled ones have already been truncated by
2727 // syncPatchDisplacement)
2728 faceSet dummySet(mesh, "wrongPatchFaces", 0);
2729 truncateDisplacement
2742 // Dump to .obj file for debugging.
2747 mesh.time().path()/"layer",
2753 const_cast<Time&>(mesh.time())++;
2754 Info<< "Writing shrunk mesh to " << meshRefiner_.timeName() << endl;
2756 // See comment in autoSnapDriver why we should not remove meshPhi
2757 // using mesh.clearOut().
2762 mesh.time().path()/meshRefiner_.timeName()
2767 // Mesh topo change engine
2768 polyTopoChange meshMod(mesh);
2770 // Grow layer of cells on to patch. Handles zero sized displacement.
2771 addPatchCellLayer addLayer(mesh);
2773 // Determine per point/per face number of layers to extrude. Also
2774 // handles the slow termination of layers when going switching layers
2776 labelList nPatchPointLayers(pp().nPoints(),-1);
2777 labelList nPatchFaceLayers(pp().localFaces().size(),-1);
2778 setupLayerInfoTruncation
2783 layerParams.nBufferCellsNoExtrude(),
2788 // Calculate displacement for first layer for addPatchLayer.
2789 // (first layer = layer of cells next to the original mesh)
2790 vectorField firstDisp(patchNLayers.size(), vector::zero);
2792 forAll(nPatchPointLayers, i)
2794 if (nPatchPointLayers[i] > 0)
2796 if (expansionRatio[i] == 1.0)
2798 firstDisp[i] = patchDisp[i]/nPatchPointLayers[i];
2802 label nLay = nPatchPointLayers[i];
2804 pow(expansionRatio[i], nLay - 1)
2805 * (1.0 - expansionRatio[i])
2806 / (1.0 - pow(expansionRatio[i], nLay));
2807 firstDisp[i] = h*patchDisp[i];
2812 const scalarField invExpansionRatio(1.0 / expansionRatio);
2814 // Add topo regardless of whether extrudeStatus is extruderemove.
2815 // Not add layer if patchDisp is zero.
2816 addLayer.setRefinement
2823 sidePatchID, // boundary patch for extruded boundary edges
2824 labelList(0), // exposed patchIDs, not used for adding layers
2825 nPatchFaceLayers, // layers per face
2826 nPatchPointLayers, // layers per point
2827 firstDisp, // thickness of layer nearest internal mesh
2833 const_cast<Time&>(mesh.time())++;
2836 // Store mesh changes for if mesh is correct.
2837 savedMeshMod = meshMod;
2840 // With the stored topo changes we create a new mesh so we can
2841 // undo if neccesary.
2843 autoPtr<fvMesh> newMeshPtr;
2844 autoPtr<mapPolyMesh> map = meshMod.makeMesh
2849 //mesh.name()+"_layer",
2851 static_cast<polyMesh&>(mesh).instance(),
2852 mesh.time(), // register with runTime
2853 static_cast<polyMesh&>(mesh).readOpt(),
2854 static_cast<polyMesh&>(mesh).writeOpt()
2855 ), // io params from original mesh but new name
2856 mesh, // original mesh
2857 true // parallel sync
2859 fvMesh& newMesh = newMeshPtr();
2861 //?neccesary? Update fields
2862 newMesh.updateMesh(map);
2864 newMesh.setInstance(meshRefiner_.timeName());
2866 // Update numbering on addLayer:
2867 // - cell/point labels to be newMesh.
2868 // - patchFaces to remain in oldMesh order.
2872 identity(pp().size()),
2873 identity(pp().nPoints())
2876 // Update numbering of baffles
2877 List<labelPair> newMeshBaffles(baffles.size());
2880 const labelPair& p = baffles[i];
2881 newMeshBaffles[i][0] = map().reverseFaceMap()[p[0]];
2882 newMeshBaffles[i][1] = map().reverseFaceMap()[p[1]];
2885 // Collect layer faces and cells for outside loop.
2897 Info<< "Writing layer mesh to " << meshRefiner_.timeName() << endl;
2899 cellSet addedCellSet
2903 findIndices(flaggedCells, true)
2905 addedCellSet.instance() = meshRefiner_.timeName();
2907 << returnReduce(addedCellSet.size(), sumOp<label>())
2908 << " added cells to cellSet "
2909 << addedCellSet.name() << endl;
2910 addedCellSet.write();
2912 faceSet layerFacesSet
2916 findIndices(flaggedCells, true)
2918 layerFacesSet.instance() = meshRefiner_.timeName();
2920 << returnReduce(layerFacesSet.size(), sumOp<label>())
2921 << " faces inside added layer to faceSet "
2922 << layerFacesSet.name() << endl;
2923 layerFacesSet.write();
2927 label nTotChanged = checkAndUnmark
2931 layerParams.additionalReporting(),
2941 label nExtruded = countExtrusion(pp, extrudeStatus);
2942 label nTotFaces = returnReduce(pp().size(), sumOp<label>());
2943 Info<< "Extruding " << nExtruded
2944 << " out of " << nTotFaces
2945 << " faces (" << 100.0*nExtruded/nTotFaces << "%)."
2946 << " Removed extrusion at " << nTotChanged << " faces."
2949 if (nTotChanged == 0)
2954 // Reset mesh points and start again
2955 meshMover().movePoints(oldPoints);
2956 meshMover().correct();
2959 // Grow out region of non-extrusion
2960 for (label i = 0; i < layerParams.nGrow(); i++)
2975 // At this point we have a (shrunk) mesh and a set of topology changes
2976 // which will make a valid mesh with layer. Apply these changes to the
2979 // Apply the stored topo changes to the current mesh.
2980 autoPtr<mapPolyMesh> map = savedMeshMod.changeMesh(mesh, false);
2982 // Hack to remove meshPhi - mapped incorrectly. TBD.
2986 mesh.updateMesh(map);
2988 // Move mesh (since morphing does not do this)
2989 if (map().hasMotionPoints())
2991 mesh.movePoints(map().preMotionPoints());
2995 // Delete mesh volumes.
2999 // Reset the instance for if in overwrite mode
3000 mesh.setInstance(meshRefiner_.timeName());
3002 meshRefiner_.updateMesh(map, labelList(0));
3005 // Update numbering on baffles
3008 labelPair& p = baffles[i];
3009 p[0] = map().reverseFaceMap()[p[0]];
3010 p[1] = map().reverseFaceMap()[p[1]];
3014 label nBaffles = returnReduce(baffles.size(), sumOp<label>());
3017 // Merge any baffles
3018 Info<< "Converting " << nBaffles
3019 << " baffles back into zoned faces ..."
3022 autoPtr<mapPolyMesh> map = meshRefiner_.mergeBaffles(baffles);
3024 inplaceReorder(map().reverseCellMap(), flaggedCells);
3025 inplaceReorder(map().reverseFaceMap(), flaggedFaces);
3027 Info<< "Converted baffles in = "
3028 << meshRefiner_.mesh().time().cpuTimeIncrement()
3029 << " s\n" << nl << endl;
3033 // Do final balancing
3034 // ~~~~~~~~~~~~~~~~~~
3036 if (Pstream::parRun())
3039 << "Doing final balancing" << nl
3040 << "---------------------" << nl
3045 const_cast<Time&>(mesh.time())++;
3048 // Balance. No restriction on face zones and baffles.
3049 autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
3053 scalarField(mesh.nCells(), 1.0),
3058 // Re-distribute flag of layer faces and cells
3059 map().distributeCellData(flaggedCells);
3060 map().distributeFaceData(flaggedFaces);
3067 cellSet addedCellSet(mesh, "addedCells", findIndices(flaggedCells, true));
3068 addedCellSet.instance() = meshRefiner_.timeName();
3070 << returnReduce(addedCellSet.size(), sumOp<label>())
3071 << " added cells to cellSet "
3072 << addedCellSet.name() << endl;
3073 addedCellSet.write();
3075 faceSet layerFacesSet(mesh, "layerFaces", findIndices(flaggedFaces, true));
3076 layerFacesSet.instance() = meshRefiner_.timeName();
3078 << returnReduce(layerFacesSet.size(), sumOp<label>())
3079 << " faces inside added layer to faceSet "
3080 << layerFacesSet.name() << endl;
3081 layerFacesSet.write();
3085 void Foam::autoLayerDriver::doLayers
3087 const dictionary& shrinkDict,
3088 const dictionary& motionDict,
3089 const layerParameters& layerParams,
3090 const bool preBalance,
3091 decompositionMethod& decomposer,
3092 fvMeshDistribute& distributor
3095 const fvMesh& mesh = meshRefiner_.mesh();
3098 << "Shrinking and layer addition phase" << nl
3099 << "----------------------------------" << nl
3102 Info<< "Using mesh parameters " << motionDict << nl << endl;
3104 // Merge coplanar boundary faces
3105 mergePatchFacesUndo(layerParams, motionDict);
3107 // Per patch the number of layers (0 if no layer)
3108 const labelList& numLayers = layerParams.numLayers();
3110 // Patches that need to get a layer
3111 DynamicList<label> patchIDs(numLayers.size());
3112 label nFacesWithLayers = 0;
3113 forAll(numLayers, patchI)
3115 if (numLayers[patchI] > 0)
3117 const polyPatch& pp = mesh.boundaryMesh()[patchI];
3119 if (!polyPatch::constraintType(pp.type()))
3121 patchIDs.append(patchI);
3122 nFacesWithLayers += mesh.boundaryMesh()[patchI].size();
3126 WarningIn("autoLayerDriver::doLayers(..)")
3127 << "Ignoring layers on constraint patch " << pp.name()
3134 if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0)
3136 Info<< nl << "No layers to generate ..." << endl;
3140 // Check that outside of mesh is not multiply connected.
3141 checkMeshManifold();
3143 // Check initial mesh
3144 Info<< "Checking initial mesh ..." << endl;
3145 labelHashSet wrongFaces(mesh.nFaces()/100);
3146 motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces);
3147 const label nInitErrors = returnReduce
3153 Info<< "Detected " << nInitErrors << " illegal faces"
3154 << " (concave, zero area or negative cell pyramid volume)"
3159 if (Pstream::parRun() && preBalance)
3162 << "Doing initial balancing" << nl
3163 << "-----------------------" << nl
3166 scalarField cellWeights(mesh.nCells(), 1);
3167 forAll(numLayers, patchI)
3169 if (numLayers[patchI] > 0)
3171 const polyPatch& pp = mesh.boundaryMesh()[patchI];
3172 forAll(pp.faceCells(), i)
3174 cellWeights[pp.faceCells()[i]] += numLayers[patchI];
3179 // Balance mesh (and meshRefinement). Restrict faceZones to
3180 // be on internal faces only since they will be converted into
3182 autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
3184 true, //false, // keepZoneFaces
3193 // Do all topo changes
3207 // ************************************************************************* //