1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
25 Manipulates mesh elements.
32 - split and move introduced point
35 - split(triangulate) and move introduced point
41 - split into polygonal base pyramids around newly introduced mid
44 Is a bit of a loose collection of mesh change drivers.
46 \*---------------------------------------------------------------------------*/
49 #include "objectRegistry.H"
52 #include "directTopoChange.H"
53 #include "mapPolyMesh.H"
54 #include "boundaryCutter.H"
55 #include "cellSplitter.H"
56 #include "edgeCollapser.H"
57 #include "meshTools.H"
62 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
64 // Locate point on patch. Returns (mesh) point label.
65 label findPoint(const primitivePatch& pp, const point& nearPoint)
67 const pointField& points = pp.points();
68 const labelList& meshPoints = pp.meshPoints();
70 // Find nearest and next nearest
71 scalar minDistSqr = GREAT;
74 scalar almostMinDistSqr = GREAT;
75 label almostMinI = -1;
79 label pointI = meshPoints[i];
81 scalar distSqr = magSqr(nearPoint - points[pointI]);
83 if (distSqr < minDistSqr)
85 almostMinDistSqr = minDistSqr;
91 else if (distSqr < almostMinDistSqr)
93 almostMinDistSqr = distSqr;
99 // Decide if nearPoint unique enough.
100 Info<< "Found to point " << nearPoint << nl
101 << " nearest point : " << minI
102 << " distance " << Foam::sqrt(minDistSqr)
103 << " at " << points[minI] << nl
104 << " next nearest point : " << almostMinI
105 << " distance " << Foam::sqrt(almostMinDistSqr)
106 << " at " << points[almostMinI] << endl;
108 if (almostMinDistSqr < 4*minDistSqr)
110 Info<< "Next nearest too close to nearest. Aborting" << endl;
121 // Locate edge on patch. Return mesh edge label.
124 const primitiveMesh& mesh,
125 const primitivePatch& pp,
126 const point& nearPoint
129 const pointField& localPoints = pp.localPoints();
130 const pointField& points = pp.points();
131 const labelList& meshPoints = pp.meshPoints();
132 const edgeList& edges = pp.edges();
134 // Find nearest and next nearest
135 scalar minDist = GREAT;
138 scalar almostMinDist = GREAT;
139 label almostMinI = -1;
143 const edge& e = edges[edgeI];
145 pointHit pHit(e.line(localPoints).nearestDist(nearPoint));
149 if (pHit.distance() < minDist)
151 almostMinDist = minDist;
154 minDist = pHit.distance();
155 minI = meshTools::findEdge
162 else if (pHit.distance() < almostMinDist)
164 almostMinDist = pHit.distance();
165 almostMinI = meshTools::findEdge
177 Info<< "Did not find edge close to point " << nearPoint << endl;
183 // Decide if nearPoint unique enough.
184 Info<< "Found to point " << nearPoint << nl
185 << " nearest edge : " << minI
186 << " distance " << minDist << " endpoints "
187 << mesh.edges()[minI].line(points) << nl
188 << " next nearest edge : " << almostMinI
189 << " distance " << almostMinDist << " endpoints "
190 << mesh.edges()[almostMinI].line(points) << nl
193 if (almostMinDist < 2*minDist)
195 Info<< "Next nearest too close to nearest. Aborting" << endl;
206 // Find face on patch. Return mesh face label.
209 const primitiveMesh& mesh,
210 const primitivePatch& pp,
211 const point& nearPoint
214 const pointField& points = pp.points();
216 // Find nearest and next nearest
217 scalar minDist = GREAT;
220 scalar almostMinDist = GREAT;
221 label almostMinI = -1;
223 forAll(pp, patchFaceI)
225 pointHit pHit(pp[patchFaceI].nearestPoint(nearPoint, points));
229 if (pHit.distance() < minDist)
231 almostMinDist = minDist;
234 minDist = pHit.distance();
235 minI = patchFaceI + mesh.nInternalFaces();
237 else if (pHit.distance() < almostMinDist)
239 almostMinDist = pHit.distance();
240 almostMinI = patchFaceI + mesh.nInternalFaces();
247 Info<< "Did not find face close to point " << nearPoint << endl;
253 // Decide if nearPoint unique enough.
254 Info<< "Found to point " << nearPoint << nl
255 << " nearest face : " << minI
256 << " distance " << minDist
257 << " to face centre " << mesh.faceCentres()[minI] << nl
258 << " next nearest face : " << almostMinI
259 << " distance " << almostMinDist
260 << " to face centre " << mesh.faceCentres()[almostMinI] << nl
263 if (almostMinDist < 2*minDist)
265 Info<< "Next nearest too close to nearest. Aborting" << endl;
276 // Find cell with cell centre close to given point.
277 label findCell(const primitiveMesh& mesh, const point& nearPoint)
279 label cellI = mesh.findCell(nearPoint);
283 scalar distToCcSqr = magSqr(nearPoint - mesh.cellCentres()[cellI]);
285 const labelList& cPoints = mesh.cellPoints()[cellI];
288 scalar minDistSqr = GREAT;
292 label pointI = cPoints[i];
294 scalar distSqr = magSqr(nearPoint - mesh.points()[pointI]);
296 if (distSqr < minDistSqr)
298 minDistSqr = distSqr;
303 // Decide if nearPoint unique enough.
304 Info<< "Found to point " << nearPoint << nl
305 << " nearest cell : " << cellI
306 << " distance " << Foam::sqrt(distToCcSqr)
307 << " to cell centre " << mesh.cellCentres()[cellI] << nl
308 << " nearest mesh point : " << minI
309 << " distance " << Foam::sqrt(minDistSqr)
310 << " to " << mesh.points()[minI] << nl
313 if (minDistSqr < 4*distToCcSqr)
315 Info<< "Mesh point too close to nearest cell centre. Aborting"
329 int main(int argc, char *argv[])
331 argList::validOptions.insert("overwrite", "");
333 # include "setRootCase.H"
334 # include "createTime.H"
335 runTime.functionObjects().off();
336 # include "createPolyMesh.H"
337 const word oldInstance = mesh.pointsInstance();
339 bool overwrite = args.optionFound("overwrite");
341 Info<< "Reading modifyMeshDict\n" << endl;
355 // Read all from the dictionary.
356 List<Pair<point> > pointsToMove(dict.lookup("pointsToMove"));
357 List<Pair<point> > edgesToSplit(dict.lookup("edgesToSplit"));
358 List<Pair<point> > facesToTriangulate
360 dict.lookup("facesToTriangulate")
366 || edgesToSplit.size()
367 || facesToTriangulate.size()
370 List<Pair<point> > edgesToCollapse(dict.lookup("edgesToCollapse"));
372 bool collapseEdge = edgesToCollapse.size();
374 List<Pair<point> > cellsToPyramidise(dict.lookup("cellsToSplit"));
376 bool cellsToSplit = cellsToPyramidise.size();
378 //List<Tuple<pointField,point> >
379 // cellsToCreate(dict.lookup("cellsToCreate"));
381 Info<< "Read from " << dict.name() << nl
382 << " Boundary cutting module:" << nl
383 << " points to move :" << pointsToMove.size() << nl
384 << " edges to split :" << edgesToSplit.size() << nl
385 << " faces to triangulate:" << facesToTriangulate.size() << nl
386 << " Cell splitting module:" << nl
387 << " cells to split :" << cellsToPyramidise.size() << nl
388 << " Edge collapsing module:" << nl
389 << " edges to collapse :" << edgesToCollapse.size() << nl
390 //<< " cells to create :" << cellsToCreate.size() << nl
395 (cutBoundary && collapseEdge)
396 || (cutBoundary && cellsToSplit)
397 || (collapseEdge && cellsToSplit)
400 FatalErrorIn(args.executable())
401 << "Used more than one mesh modifying module "
402 << "(boundary cutting, cell splitting, edge collapsing)" << nl
403 << "Please do them in separate passes." << exit(FatalError);
408 // Get calculating engine for all of outside
409 const SubList<face> outsideFaces
412 mesh.nFaces() - mesh.nInternalFaces(),
413 mesh.nInternalFaces()
416 primitivePatch allBoundary(outsideFaces, mesh.points());
419 // Look up mesh labels and convert to input for boundaryCutter.
421 bool validInputs = true;
424 Info<< nl << "Looking up points to move ..." << nl << endl;
425 Map<point> pointToPos(pointsToMove.size());
426 forAll(pointsToMove, i)
428 const Pair<point>& pts = pointsToMove[i];
430 label pointI = findPoint(allBoundary, pts.first());
432 if (pointI == -1 || !pointToPos.insert(pointI, pts.second()))
434 Info<< "Could not insert mesh point " << pointI
435 << " for input point " << pts.first() << nl
436 << "Perhaps the point is already marked for moving?" << endl;
442 Info<< nl << "Looking up edges to split ..." << nl << endl;
443 Map<List<point> > edgeToCuts(edgesToSplit.size());
444 forAll(edgesToSplit, i)
446 const Pair<point>& pts = edgesToSplit[i];
448 label edgeI = findEdge(mesh, allBoundary, pts.first());
453 || !edgeToCuts.insert(edgeI, List<point>(1, pts.second()))
456 Info<< "Could not insert mesh edge " << edgeI
457 << " for input point " << pts.first() << nl
458 << "Perhaps the edge is already marked for cutting?" << endl;
465 Info<< nl << "Looking up faces to triangulate ..." << nl << endl;
466 Map<point> faceToDecompose(facesToTriangulate.size());
467 forAll(facesToTriangulate, i)
469 const Pair<point>& pts = facesToTriangulate[i];
471 label faceI = findFace(mesh, allBoundary, pts.first());
473 if (faceI == -1 || !faceToDecompose.insert(faceI, pts.second()))
475 Info<< "Could not insert mesh face " << faceI
476 << " for input point " << pts.first() << nl
477 << "Perhaps the face is already marked for splitting?" << endl;
485 Info<< nl << "Looking up cells to convert to pyramids around"
486 << " cell centre ..." << nl << endl;
487 Map<point> cellToPyrCentre(cellsToPyramidise.size());
488 forAll(cellsToPyramidise, i)
490 const Pair<point>& pts = cellsToPyramidise[i];
492 label cellI = findCell(mesh, pts.first());
494 if (cellI == -1 || !cellToPyrCentre.insert(cellI, pts.second()))
496 Info<< "Could not insert mesh cell " << cellI
497 << " for input point " << pts.first() << nl
498 << "Perhaps the cell is already marked for splitting?" << endl;
505 Info<< nl << "Looking up edges to collapse ..." << nl << endl;
506 Map<point> edgeToPos(edgesToCollapse.size());
507 forAll(edgesToCollapse, i)
509 const Pair<point>& pts = edgesToCollapse[i];
511 label edgeI = findEdge(mesh, allBoundary, pts.first());
513 if (edgeI == -1 || !edgeToPos.insert(edgeI, pts.second()))
515 Info<< "Could not insert mesh edge " << edgeI
516 << " for input point " << pts.first() << nl
517 << "Perhaps the edge is already marked for collaping?" << endl;
527 Info<< nl << "There was a problem in one of the inputs in the"
528 << " dictionary. Not modifying mesh." << endl;
530 else if (cellToPyrCentre.size())
532 Info<< nl << "All input cells located. Modifying mesh." << endl;
534 // Mesh change engine
535 cellSplitter cutter(mesh);
537 // Topo change container
538 directTopoChange meshMod(mesh);
540 // Insert commands into meshMod
541 cutter.setRefinement(cellToPyrCentre, meshMod);
544 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
546 if (morphMap().hasMotionPoints())
548 mesh.movePoints(morphMap().preMotionPoints());
551 cutter.updateMesh(morphMap());
559 mesh.setInstance(oldInstance);
562 // Write resulting mesh
563 Info << "Writing modified mesh to time " << runTime.timeName() << endl;
566 else if (edgeToPos.size())
568 Info<< nl << "All input edges located. Modifying mesh." << endl;
570 // Mesh change engine
571 edgeCollapser cutter(mesh);
573 pointField newPoints(mesh.points());
575 // Get new positions and construct collapse network
576 forAllConstIter(Map<point>, edgeToPos, iter)
578 label edgeI = iter.key();
579 const edge& e = mesh.edges()[edgeI];
581 cutter.collapseEdge(edgeI, e[0]);
582 newPoints[e[0]] = iter();
585 // Move master point to destination.
586 mesh.movePoints(newPoints);
588 // Topo change container
589 directTopoChange meshMod(mesh);
592 cutter.setRefinement(meshMod);
595 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
597 if (morphMap().hasMotionPoints())
599 mesh.movePoints(morphMap().preMotionPoints());
602 // Not implemented yet:
603 //cutter.updateMesh(morphMap());
612 mesh.setInstance(oldInstance);
615 // Write resulting mesh
616 Info << "Writing modified mesh to time " << runTime.timeName() << endl;
621 Info<< nl << "All input points located. Modifying mesh." << endl;
623 // Mesh change engine
624 boundaryCutter cutter(mesh);
626 // Topo change container
627 directTopoChange meshMod(mesh);
629 // Insert commands into meshMod
634 Map<labelPair>(0), // Faces to split diagonally
635 faceToDecompose, // Faces to triangulate
640 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
642 if (morphMap().hasMotionPoints())
644 mesh.movePoints(morphMap().preMotionPoints());
647 cutter.updateMesh(morphMap());
655 mesh.setInstance(oldInstance);
658 // Write resulting mesh
659 Info << "Writing modified mesh to time " << runTime.timeName() << endl;
664 Info << nl << "End" << endl;
670 // ************************************************************************* //