1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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 Utility to refine cells in multiple directions.
28 Either supply -all option to refine all cells (3D refinement for 3D
29 cases; 2D for 2D cases) or reads a refineMeshDict with
31 - directions to refine
33 \*---------------------------------------------------------------------------*/
38 #include "undoableMeshCutter.H"
39 #include "hexCellLooper.H"
41 #include "twoDPointCorrector.H"
42 #include "directions.H"
44 #include "multiDirRefinement.H"
45 #include "labelIOList.H"
46 #include "wedgePolyPatch.H"
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
54 // Max cos angle for edges to be considered aligned with axis.
55 static const scalar edgeTol = 1E-3;
58 // Calculate some edge statistics on mesh.
59 void printEdgeStats(const primitiveMesh& mesh)
77 scalar minOther = GREAT;
78 scalar maxOther = -GREAT;
80 const edgeList& edges = mesh.edges();
84 const edge& e = edges[edgeI];
86 vector eVec(e.vec(mesh.points()));
88 scalar eMag = mag(eVec);
92 if (mag(eVec & x) > 1-edgeTol)
94 minX = min(minX, eMag);
95 maxX = max(maxX, eMag);
98 else if (mag(eVec & y) > 1-edgeTol)
100 minY = min(minY, eMag);
101 maxY = max(maxY, eMag);
104 else if (mag(eVec & z) > 1-edgeTol)
106 minZ = min(minZ, eMag);
107 maxZ = max(maxZ, eMag);
112 minOther = min(minOther, eMag);
113 maxOther = max(maxOther, eMag);
117 Pout<< "Mesh edge statistics:" << endl
118 << " x aligned : number:" << nX << "\tminLen:" << minX
119 << "\tmaxLen:" << maxX << endl
120 << " y aligned : number:" << nY << "\tminLen:" << minY
121 << "\tmaxLen:" << maxY << endl
122 << " z aligned : number:" << nZ << "\tminLen:" << minZ
123 << "\tmaxLen:" << maxZ << endl
124 << " other : number:" << mesh.nEdges() - nX - nY - nZ
125 << "\tminLen:" << minOther
126 << "\tmaxLen:" << maxOther << endl << endl;
130 // Return index of coordinate axis.
131 label axis(const vector& normal)
133 label axisIndex = -1;
135 if (mag(normal & point(1, 0, 0)) > (1-edgeTol))
139 else if (mag(normal & point(0, 1, 0)) > (1-edgeTol))
143 else if (mag(normal & point(0, 0, 1)) > (1-edgeTol))
152 //- Returns -1 or cartesian coordinate component (0=x, 1=y, 2=z) of normal
153 // in case of 2D mesh
154 label twoDNess(const polyMesh& mesh)
156 const pointField& ctrs = mesh.cellCentres();
165 // 1. All cell centres on single plane aligned with x, y or z
168 // Determine 3 points to base plane on.
169 vector vec10 = ctrs[1] - ctrs[0];
172 label otherCellI = -1;
174 for (label cellI = 2; cellI < ctrs.size(); cellI++)
176 vector vec(ctrs[cellI] - ctrs[0]);
179 if (mag(vec & vec10) < 0.9)
181 // ctrs[cellI] not in line with n
188 if (otherCellI == -1)
190 // Cannot find cell to make decent angle with cell0-cell1 vector.
191 // Note: what to do here? All cells (almost) in one line. Maybe 1D case?
195 plane cellPlane(ctrs[0], ctrs[1], ctrs[otherCellI]);
200 const labelList& cEdges = mesh.cellEdges()[cellI];
202 scalar minLen = GREAT;
206 minLen = min(minLen, mesh.edges()[cEdges[i]].mag(mesh.points()));
209 if (cellPlane.distance(ctrs[cellI]) > 1E-6*minLen)
211 // Centres not in plane
216 label axisIndex = axis(cellPlane.normal());
224 const polyBoundaryMesh& patches = mesh.boundaryMesh();
228 // 2. No edges without points on boundary
231 // Mark boundary points
232 boolList boundaryPoint(mesh.allPoints().size(), false);
234 forAll(patches, patchI)
236 const polyPatch& patch = patches[patchI];
238 forAll(patch, patchFaceI)
240 const face& f = patch[patchFaceI];
244 boundaryPoint[f[fp]] = true;
250 const edgeList& edges = mesh.edges();
254 const edge& e = edges[edgeI];
256 if (!boundaryPoint[e.start()] && !boundaryPoint[e.end()])
258 // Edge has no point on boundary.
264 // 3. For all non-wedge patches: all faces either perp or aligned with
265 // cell-plane normal. (wedge patches already checked upon construction)
267 forAll(patches, patchI)
269 const polyPatch& patch = patches[patchI];
271 if (!isA<wedgePolyPatch>(patch))
273 const vectorField& n = patch.faceAreas();
275 scalarField cosAngle = mag(n/mag(n) & cellPlane.normal());
277 if (mag(min(cosAngle) - max(cosAngle)) > 1E-6)
279 // cosAngle should be either ~1 over all faces (2D front and
280 // back) or ~0 (all other patches perp to 2D)
292 int main(int argc, char *argv[])
294 Foam::argList::validOptions.insert("dict", "");
295 Foam::argList::validOptions.insert("overwrite", "");
297 # include "setRootCase.H"
298 # include "createTime.H"
299 runTime.functionObjects().off();
300 # include "createPolyMesh.H"
301 const word oldInstance = mesh.pointsInstance();
303 printEdgeStats(mesh);
307 // Read/construct control dictionary
310 bool readDict = args.optionFound("dict");
311 bool overwrite = args.optionFound("overwrite");
313 // List of cells to refine
316 // Dictionary to control refinement
317 dictionary refineDict;
321 Info<< "Refining according to refineMeshDict" << nl << endl;
336 word setName(refineDict.lookup("set"));
338 cellSet cells(mesh, setName);
340 Pout<< "Read " << cells.size() << " cells from cellSet "
341 << cells.instance()/cells.local()/cells.name()
344 refCells = cells.toc();
348 Info<< "Refining all cells" << nl << endl;
351 refCells.setSize(mesh.nCells());
353 forAll(mesh.cells(), cellI)
355 refCells[cellI] = cellI;
359 // Set refinement directions based on 2D/3D
360 label axisIndex = twoDNess(mesh);
364 Info<< "3D case; refining all directions" << nl << endl;
366 wordList directions(3);
367 directions[0] = "tan1";
368 directions[1] = "tan2";
369 directions[2] = "normal";
370 refineDict.add("directions", directions);
373 refineDict.add("useHexTopology", "true");
377 wordList directions(2);
381 Info<< "2D case; refining in directions y,z\n" << endl;
382 directions[0] = "tan2";
383 directions[1] = "normal";
385 else if (axisIndex == 1)
387 Info<< "2D case; refining in directions x,z\n" << endl;
388 directions[0] = "tan1";
389 directions[1] = "normal";
393 Info<< "2D case; refining in directions x,y\n" << endl;
394 directions[0] = "tan1";
395 directions[1] = "tan2";
398 refineDict.add("directions", directions);
400 // Use standard cutter
401 refineDict.add("useHexTopology", "false");
404 refineDict.add("coordinateSystem", "global");
406 dictionary coeffsDict;
407 coeffsDict.add("tan1", vector(1, 0, 0));
408 coeffsDict.add("tan2", vector(0, 1, 0));
409 refineDict.add("globalCoeffs", coeffsDict);
411 refineDict.add("geometricCut", "false");
412 refineDict.add("writeMesh", "false");
416 string oldTimeName(runTime.timeName());
424 // Multi-directional refinement (does multiple iterations)
425 multiDirRefinement multiRef(mesh, refCells, refineDict);
428 // Write resulting mesh
431 mesh.setInstance(oldInstance);
436 // Get list of cell splits.
437 // (is for every cell in old mesh the cells they have been split into)
438 const labelListList& oldToNew = multiRef.addedCells();
441 // Create cellSet with added cells for easy inspection
442 cellSet newCells(mesh, "refinedCells", refCells.size());
444 forAll(oldToNew, oldCellI)
446 const labelList& added = oldToNew[oldCellI];
450 newCells.insert(added[i]);
454 Pout<< "Writing refined cells (" << newCells.size() << ") to cellSet "
455 << newCells.instance()/newCells.local()/newCells.name()
464 // Invert cell split to construct map from new to old
473 polyMesh::meshSubDir,
481 "From cells in mesh at "
483 + " to cells in mesh at "
487 forAll(oldToNew, oldCellI)
489 const labelList& added = oldToNew[oldCellI];
495 newToOld[added[i]] = oldCellI;
501 newToOld[oldCellI] = oldCellI;
505 Info<< "Writing map from new to old cell to "
506 << newToOld.objectPath() << nl << endl;
513 printEdgeStats(mesh);
515 Info<< "End\n" << endl;
521 // ************************************************************************* //