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 Utility to refine cells in multiple directions.
27 Either supply -all option to refine all cells (3D refinement for 3D
28 cases; 2D for 2D cases) or reads a refineMeshDict with
30 - directions to refine
32 \*---------------------------------------------------------------------------*/
37 #include "undoableMeshCutter.H"
38 #include "hexCellLooper.H"
40 #include "twoDPointCorrector.H"
41 #include "directions.H"
43 #include "multiDirRefinement.H"
44 #include "labelIOList.H"
45 #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.points().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 const 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[])
296 "refine cells in multiple directions"
299 #include "addOverwriteOption.H"
300 #include "addRegionOption.H"
301 argList::addBoolOption
304 "refine according to system/refineMeshDict"
307 #include "setRootCase.H"
308 #include "createTime.H"
309 runTime.functionObjects().off();
310 #include "createNamedPolyMesh.H"
311 const word oldInstance = mesh.pointsInstance();
313 printEdgeStats(mesh);
316 // Read/construct control dictionary
319 const bool readDict = args.optionFound("dict");
320 const bool overwrite = args.optionFound("overwrite");
322 // List of cells to refine
325 // Dictionary to control refinement
326 dictionary refineDict;
330 Info<< "Refining according to refineMeshDict" << nl << endl;
332 refineDict = IOdictionary
339 IOobject::MUST_READ_IF_MODIFIED,
344 const word setName(refineDict.lookup("set"));
346 cellSet cells(mesh, setName);
348 Pout<< "Read " << cells.size() << " cells from cellSet "
349 << cells.instance()/cells.local()/cells.name()
352 refCells = cells.toc();
356 Info<< "Refining all cells" << nl << endl;
359 refCells.setSize(mesh.nCells());
361 forAll(mesh.cells(), cellI)
363 refCells[cellI] = cellI;
367 // Set refinement directions based on 2D/3D
368 label axisIndex = twoDNess(mesh);
372 Info<< "3D case; refining all directions" << nl << endl;
374 wordList directions(3);
375 directions[0] = "tan1";
376 directions[1] = "tan2";
377 directions[2] = "normal";
378 refineDict.add("directions", directions);
381 refineDict.add("useHexTopology", "true");
385 wordList directions(2);
389 Info<< "2D case; refining in directions y,z\n" << endl;
390 directions[0] = "tan2";
391 directions[1] = "normal";
393 else if (axisIndex == 1)
395 Info<< "2D case; refining in directions x,z\n" << endl;
396 directions[0] = "tan1";
397 directions[1] = "normal";
401 Info<< "2D case; refining in directions x,y\n" << endl;
402 directions[0] = "tan1";
403 directions[1] = "tan2";
406 refineDict.add("directions", directions);
408 // Use standard cutter
409 refineDict.add("useHexTopology", "false");
412 refineDict.add("coordinateSystem", "global");
414 dictionary coeffsDict;
415 coeffsDict.add("tan1", vector(1, 0, 0));
416 coeffsDict.add("tan2", vector(0, 1, 0));
417 refineDict.add("globalCoeffs", coeffsDict);
419 refineDict.add("geometricCut", "false");
420 refineDict.add("writeMesh", "false");
424 string oldTimeName(runTime.timeName());
432 // Multi-directional refinement (does multiple iterations)
433 multiDirRefinement multiRef(mesh, refCells, refineDict);
436 // Write resulting mesh
439 mesh.setInstance(oldInstance);
444 // Get list of cell splits.
445 // (is for every cell in old mesh the cells they have been split into)
446 const labelListList& oldToNew = multiRef.addedCells();
449 // Create cellSet with added cells for easy inspection
450 cellSet newCells(mesh, "refinedCells", refCells.size());
452 forAll(oldToNew, oldCellI)
454 const labelList& added = oldToNew[oldCellI];
458 newCells.insert(added[i]);
462 Pout<< "Writing refined cells (" << newCells.size() << ") to cellSet "
463 << newCells.instance()/newCells.local()/newCells.name()
472 // Invert cell split to construct map from new to old
481 polyMesh::meshSubDir,
489 "From cells in mesh at "
491 + " to cells in mesh at "
495 forAll(oldToNew, oldCellI)
497 const labelList& added = oldToNew[oldCellI];
503 newToOld[added[i]] = oldCellI;
509 newToOld[oldCellI] = oldCellI;
513 Info<< "Writing map from new to old cell to "
514 << newToOld.objectPath() << nl << endl;
521 printEdgeStats(mesh);
523 Info<< "End\n" << endl;
529 // ************************************************************************* //