1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 cfMesh 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 cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "demandDrivenData.H"
29 #include "meshSurfaceOptimizer.H"
32 #include "surfaceOptimizer.H"
33 #include "helperFunctions.H"
34 #include "partTriMeshSimplex.H"
40 #include "triSurfModifier.H"
41 #include "helperFunctions.H"
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 inline const partTriMesh& meshSurfaceOptimizer::triMesh() const
54 calculateTrianglesAndAddressing();
59 inline void meshSurfaceOptimizer::updateTriMesh(const labelLongList& selPoints)
64 "inline void meshSurfaceOptimizer::updateTriMesh"
65 "(const labelLongList&)"
66 ) << "triMeshPtr_ is not allocated " << abort(FatalError);
68 triMeshPtr_->updateVertices(selPoints);
71 inline void meshSurfaceOptimizer::updateTriMesh()
76 "inline void meshSurfaceOptimizer::updateTriMesh()"
77 ) << "triMeshPtr_ is not allocated " << abort(FatalError);
79 triMeshPtr_->updateVertices();
82 inline bool meshSurfaceOptimizer::transformIntoPlane
89 DynList<triFace>& trias
93 Pout << "Transforming boundary node " << bpI << endl;
96 const partTriMesh& triMesh = this->triMesh();
97 const label triPointI = triMesh.meshSurfacePointLabelInTriMesh()[bpI];
101 partTriMeshSimplex simplex(triMesh, triPointI);
103 const DynList<point, 32>& sPts = simplex.pts();
105 //- create vecX and vecY
106 const point& p = simplex.centrePoint();
111 const point sp = pl.nearestPoint(sPts[pI]);
112 const scalar d = mag(sp - p);
117 vecY = pl.normal() ^ vecX;
127 trias = simplex.triangles();
130 Pout << "VecX " << vecX << endl;
131 Pout << "vecY " << vecY << endl;
134 //- transform the vertices
135 pts.setSize(sPts.size());
141 ((sPts[pI] - p) & vecX),
142 ((sPts[pI] - p) & vecY),
150 Info << "Original triangles " << endl;
151 forAll(simplex.triangles(), triI)
152 Info << "Tri " << triI << " is " << simplex.triangles()[triI] << endl;
153 Info << "Transformed triangles are " << trias << endl;
154 Info << "Transformed vertices " << pts << endl;
157 triSurfModifier sMod(surf);
158 pointField& sPoints = sMod.pointsAccess();
159 sPoints.setSize(pts.size());
162 LongList<labelledTri>& sTrias = sMod.facetsAccess();
163 sTrias.setSize(trias.size());
166 labelledTri& tf = sTrias[i];
173 sMod.patchesAccess().setSize(1);
174 sMod.patchesAccess()[0].name() = "bnd";
175 sMod.patchesAccess()[0].geometricType() = "patch";
177 fileName sName("bndSimplex_");
178 sName += help::scalarToText(bpI);
180 surf.writeSurface(sName);
186 inline point meshSurfaceOptimizer::newPositionLaplacian
189 const bool transformIntoPlane
192 const VRWGraph& pPoints = surfaceEngine_.pointPoints();
193 const pointFieldPMG& points = surfaceEngine_.points();
194 const labelList& bPoints = surfaceEngine_.boundaryPoints();
196 if( vertexType_[bpI] & LOCKED )
197 return points[bPoints[bpI]];
199 vector newP(vector::zero);
200 if( transformIntoPlane )
202 const vector& pNormal = surfaceEngine_.pointNormals()[bpI];
204 if( magSqr(pNormal) < VSMALL )
205 return points[bPoints[bpI]];
207 plane pl(points[bPoints[bpI]], pNormal);
209 DynList<point> projectedPoints;
210 projectedPoints.setSize(pPoints.sizeOfRow(bpI));
211 forAllRow(pPoints, bpI, pI)
212 projectedPoints[pI] =
213 pl.nearestPoint(points[bPoints[pPoints(bpI, pI)]]);
215 forAll(projectedPoints, pI)
216 newP += projectedPoints[pI];
218 newP /= projectedPoints.size();
222 forAllRow(pPoints, bpI, pI)
223 newP += points[bPoints[pPoints(bpI, pI)]];
225 newP /= pPoints.sizeOfRow(bpI);
231 inline point meshSurfaceOptimizer::newPositionLaplacianFC
234 const bool transformIntoPlane
237 const VRWGraph& pointFaces = surfaceEngine_.pointFaces();
238 const pointFieldPMG& points = surfaceEngine_.points();
239 const vectorField& faceCentres = surfaceEngine_.faceCentres();
240 const labelList& bPoints = surfaceEngine_.boundaryPoints();
242 if( vertexType_[bpI] & LOCKED )
243 return points[bPoints[bpI]];
245 vector newP(vector::zero);
247 if( transformIntoPlane )
249 const vector& pNormal = surfaceEngine_.pointNormals()[bpI];
251 if( magSqr(pNormal) < VSMALL )
252 return points[bPoints[bpI]];
254 plane pl(points[bPoints[bpI]], pNormal);
256 DynList<point> projectedPoints;
257 projectedPoints.setSize(pointFaces.sizeOfRow(bpI));
258 forAllRow(pointFaces, bpI, pfI)
259 projectedPoints[pfI] =
260 pl.nearestPoint(faceCentres[pointFaces(bpI, pfI)]);
262 forAll(projectedPoints, pI)
263 newP += projectedPoints[pI];
265 newP /= projectedPoints.size();
269 forAllRow(pointFaces, bpI, pfI)
270 newP += faceCentres[pointFaces(bpI, pfI)];
272 newP /= pointFaces.sizeOfRow(bpI);
278 inline point meshSurfaceOptimizer::newPositionLaplacianWFC
281 const bool transformIntoPlane
284 const VRWGraph& pointFaces = surfaceEngine_.pointFaces();
285 const pointFieldPMG& points = surfaceEngine_.points();
286 const vectorField& faceAreas = surfaceEngine_.faceNormals();
287 const vectorField& faceCentres = surfaceEngine_.faceCentres();
288 const labelList& bPoints = surfaceEngine_.boundaryPoints();
290 if( vertexType_[bpI] & LOCKED )
291 return points[bPoints[bpI]];
293 vector newP(vector::zero);
295 if( transformIntoPlane )
297 const vector& pNormal = surfaceEngine_.pointNormals()[bpI];
299 if( magSqr(pNormal) < VSMALL )
300 return points[bPoints[bpI]];
302 plane pl(points[bPoints[bpI]], pNormal);
304 DynList<point> projectedPoints;
305 projectedPoints.setSize(pointFaces.sizeOfRow(bpI));
306 forAllRow(pointFaces, bpI, pfI)
307 projectedPoints[pfI] =
308 pl.nearestPoint(faceCentres[pointFaces(bpI, pfI)]);
311 forAll(projectedPoints, pI)
313 const label bfI = pointFaces(bpI, pI);
314 const scalar w = (faceAreas[bfI] & faceAreas[bfI]);
315 newP += w * projectedPoints[pI];
319 newP /= Foam::max(sumW, VSMALL);
324 forAllRow(pointFaces, bpI, pfI)
326 const label bfI = pointFaces(bpI, pfI);
327 const scalar w = (faceAreas[bfI] & faceAreas[bfI]);
328 newP += w * faceCentres[pointFaces(bpI, pfI)];
332 newP /= Foam::max(sumW, VSMALL);
338 inline point meshSurfaceOptimizer::newPositionSurfaceOptimizer
344 const pointFieldPMG& points = surfaceEngine_.points();
345 const labelList& bPoints = surfaceEngine_.boundaryPoints();
347 if( vertexType_[bpI] & LOCKED )
348 return points[bPoints[bpI]];
351 Pout << "Smoothing boundary node " << bpI << endl;
352 Pout << "Node label in the mesh is " << bPoints[bpI] << endl;
353 Pout << "Point coordinates " << points[bPoints[bpI]] << endl;
356 //- project vertices onto the plane
357 const vector& pNormal = surfaceEngine_.pointNormals()[bpI];
358 if( magSqr(pNormal) < VSMALL )
359 return points[bPoints[bpI]];
361 const plane pl(points[bPoints[bpI]], pNormal);
364 DynList<triFace> trias;
366 bool success = this->transformIntoPlane(bpI, pl, vecX, vecY, pts, trias);
369 //Warning << "Cannot transform to plane" << endl;
370 return points[bPoints[bpI]];
373 surfaceOptimizer so(pts, trias);
374 const point newPoint = so.optimizePoint(tol);
378 points[bPoints[bpI]] +
379 vecX * newPoint.x() +
383 if( help::isnan(newP) || help::isinf(newP) )
387 "inline point meshSurfaceOptimizer::newPositionSurfaceOptimizer"
388 "(const label, const scalar) const"
389 ) << "Cannot move point " << bpI << endl;
391 return points[bPoints[bpI]];
397 inline point meshSurfaceOptimizer::newEdgePositionLaplacian
402 const labelList& bPoints = surfaceEngine_.boundaryPoints();
403 const edgeList& edges = surfaceEngine_.edges();
404 const VRWGraph& bpEdges = surfaceEngine_.boundaryPointEdges();
405 const pointFieldPMG& points = surfaceEngine_.points();
407 if( vertexType_[bpI] & LOCKED )
408 return points[bPoints[bpI]];
410 const labelHashSet& featureEdges = partitionerPtr_->featureEdges();
412 DynList<label> edgePoints;
414 forAllRow(bpEdges, bpI, i)
416 const label beI = bpEdges(bpI, i);
418 if( featureEdges.found(beI) )
420 edgePoints.append(edges[beI].otherVertex(bPoints[bpI]));
424 if( edgePoints.size() != 2 )
425 return points[bPoints[bpI]];
428 Info << "Edge points " << edgePoints << endl;
431 vector pos(vector::zero);
432 forAll(edgePoints, epI)
433 pos += points[edgePoints[epI]];
435 pos /= edgePoints.size();
440 template<class labelListType>
441 inline void meshSurfaceOptimizer::lockBoundaryFaces(const labelListType& l)
443 lockedSurfaceFaces_ = l;
445 const faceList::subList& bFaces = surfaceEngine_.boundaryFaces();
446 const labelList& bp = surfaceEngine_.bp();
449 # pragma omp parallel for schedule(dynamic, 20)
451 forAll(lockedSurfaceFaces_, lfI)
453 const face& bf = bFaces[lockedSurfaceFaces_[lfI]];
456 vertexType_[bp[bf[pI]]] |= LOCKED;
459 if( Pstream::parRun() )
461 const Map<label>& globalToLocal =
462 surfaceEngine_.globalToLocalBndPointAddressing();
463 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
464 const DynList<label>& bpNeiProcs = surfaceEngine_.bpNeiProcs();
466 std::map<label, labelLongList> exchangeData;
467 forAll(bpNeiProcs, i)
468 exchangeData[bpNeiProcs[i]].clear();
470 //- prepare data which will be sent to other processors
471 forAllConstIter(Map<label>, globalToLocal, it)
473 const label bpI = it();
475 if( vertexType_[bpI] & LOCKED )
477 forAllRow(bpAtProcs, bpI, i)
479 const label neiProc = bpAtProcs(bpI, i);
481 if( neiProc == Pstream::myProcNo() )
484 exchangeData[neiProc].append(it.key());
489 labelLongList receivedData;
490 help::exchangeMap(exchangeData, receivedData);
492 forAll(receivedData, i)
494 const label bpI = globalToLocal[receivedData[i]];
496 vertexType_[bpI] |= LOCKED;
501 template<class labelListType>
502 inline void meshSurfaceOptimizer::lockBoundaryPoints(const labelListType& l)
505 # pragma omp parallel for schedule(dynamic, 50)
509 const label bpI = l[i];
511 vertexType_[bpI] |= LOCKED;
514 if( Pstream::parRun() )
516 const Map<label>& globalToLocal =
517 surfaceEngine_.globalToLocalBndPointAddressing();
518 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
519 const DynList<label>& bpNeiProcs = surfaceEngine_.bpNeiProcs();
521 std::map<label, labelLongList> exchangeData;
522 forAll(bpNeiProcs, i)
523 exchangeData[bpNeiProcs[i]].clear();
525 //- prepare data which will be sent to other processors
526 forAllConstIter(Map<label>, globalToLocal, it)
528 const label bpI = it();
530 if( vertexType_[bpI] & LOCKED )
532 forAllRow(bpAtProcs, bpI, i)
534 const label neiProc = bpAtProcs(bpI, i);
536 if( neiProc == Pstream::myProcNo() )
539 exchangeData[neiProc].append(it.key());
544 labelLongList receivedData;
545 help::exchangeMap(exchangeData, receivedData);
547 forAll(receivedData, i)
549 const label bpI = globalToLocal[receivedData[i]];
551 vertexType_[bpI] |= LOCKED;
557 inline void meshSurfaceOptimizer::lockFeatureEdges()
560 # pragma omp parallel for schedule(dynamic, 50)
562 forAll(vertexType_, bpI)
563 if( vertexType_[bpI] & (EDGE | CORNER) )
564 vertexType_[bpI] |= LOCKED;
567 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
569 } // End namespace Foam
571 // ************************************************************************* //