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"
30 #include "meshSurfaceEngineModifier.H"
32 #include "meshSurfaceMapper.H"
33 #include "surfaceOptimizer.H"
34 #include "refLabelledPoint.H"
35 #include "helperFunctions.H"
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
46 void meshSurfaceOptimizer::nodeDisplacementLaplacianParallel
48 const labelLongList& nodesToSmooth,
49 const bool transformIntoPlane
52 if( returnReduce(nodesToSmooth.size(), sumOp<label>()) == 0 )
55 //- create storage for data
56 std::map<label, labelledPoint> localData;
58 //- exchange data with other processors
59 std::map<label, LongList<refLabelledPoint> > exchangeData;
61 const pointField& points = surfaceEngine_.points();
62 const labelList& bPoints = surfaceEngine_.boundaryPoints();
63 const VRWGraph& pPoints = surfaceEngine_.pointPoints();
64 const vectorField& pNormals = surfaceEngine_.pointNormals();
65 const labelList& globalPointLabel =
66 surfaceEngine_.globalBoundaryPointLabel();
67 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
68 const Map<label>& globalToLocal =
69 surfaceEngine_.globalToLocalBndPointAddressing();
72 forAll(nodesToSmooth, pI)
74 const label bpI = nodesToSmooth[pI];
76 if( magSqr(pNormals[bpI]) < VSMALL )
79 const plane pl(points[bPoints[bpI]], pNormals[bpI]);
81 //- project points onto the plane
82 localData.insert(std::make_pair(bpI, labelledPoint(0, vector::zero)));
83 labelledPoint& lpd = localData[bpI];
85 forAllRow(pPoints, bpI, ppI)
87 const label nei = pPoints(bpI, ppI);
89 if( bpAtProcs.sizeOfRow(nei) != 0 )
91 label pMin(Pstream::nProcs());
92 forAllRow(bpAtProcs, nei, procI)
94 const label procJ = bpAtProcs(nei, procI);
95 if( (procJ < pMin) && bpAtProcs.contains(bpI, procJ) )
99 if( pMin != Pstream::myProcNo() )
103 const point& p = points[bPoints[nei]];
105 lpd.coordinates() += transformIntoPlane?pl.nearestPoint(p):p;
108 forAllRow(bpAtProcs, bpI, procI)
110 const label neiProc = bpAtProcs(bpI, procI);
111 if( neiProc == Pstream::myProcNo() )
114 if( exchangeData.find(neiProc) == exchangeData.end() )
118 std::make_pair(neiProc, LongList<refLabelledPoint>())
122 //- add data to the list which will be sent to other processor
123 LongList<refLabelledPoint>& dts = exchangeData[neiProc];
124 dts.append(refLabelledPoint(globalPointLabel[bpI], lpd));
128 //- exchange data with other processors
129 LongList<refLabelledPoint> receivedData;
130 help::exchangeMap(exchangeData, receivedData);
132 forAll(receivedData, i)
134 const refLabelledPoint& lp = receivedData[i];
135 const label bpI = globalToLocal[lp.objectLabel()];
137 labelledPoint& lpd = localData[bpI];
139 lpd.pointLabel() += lp.lPoint().pointLabel();
140 lpd.coordinates() += lp.lPoint().coordinates();
143 forAll(nodesToSmooth, pI)
145 const label bpI = nodesToSmooth[pI];
147 if( localData.find(bpI) == localData.end() )
150 //- create new point position
151 const labelledPoint& lp = localData[bpI];
152 const point newP = lp.coordinates() / lp.pointLabel();
154 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
155 surfaceModifier.moveBoundaryVertexNoUpdate
163 void meshSurfaceOptimizer::nodeDisplacementLaplacianFCParallel
165 const labelLongList& nodesToSmooth,
166 const bool transformIntoPlane
169 if( returnReduce(nodesToSmooth.size(), sumOp<label>()) == 0 )
172 //- create storage for data
173 std::map<label, labelledPoint> localData;
175 //- exchange data with other processors
176 std::map<label, LongList<refLabelledPoint> > exchangeData;
178 const pointField& points = surfaceEngine_.points();
179 const labelList& bPoints = surfaceEngine_.boundaryPoints();
180 const VRWGraph& pFaces = surfaceEngine_.pointFaces();
181 const vectorField& faceCentres = surfaceEngine_.faceCentres();
182 const vectorField& pNormals = surfaceEngine_.pointNormals();
184 const labelList& globalPointLabel =
185 surfaceEngine_.globalBoundaryPointLabel();
186 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
187 const Map<label>& globalToLocal =
188 surfaceEngine_.globalToLocalBndPointAddressing();
190 //- perform smoothing
191 forAll(nodesToSmooth, pI)
193 const label bpI = nodesToSmooth[pI];
195 if( magSqr(pNormals[bpI]) < VSMALL )
198 const plane pl(points[bPoints[bpI]], pNormals[bpI]);
200 //- project points onto the plane
201 localData.insert(std::make_pair(bpI, labelledPoint(0, vector::zero)));
202 labelledPoint& lpd = localData[bpI];
204 forAllRow(pFaces, bpI, pfI)
206 const point& p = faceCentres[pFaces(bpI, pfI)];
208 lpd.coordinates() += transformIntoPlane?pl.nearestPoint(p):p;
211 forAllRow(bpAtProcs, bpI, procI)
213 const label neiProc = bpAtProcs(bpI, procI);
214 if( neiProc == Pstream::myProcNo() )
217 if( exchangeData.find(neiProc) == exchangeData.end() )
221 std::make_pair(neiProc, LongList<refLabelledPoint>())
225 //- add data to the list which will be sent to other processor
226 LongList<refLabelledPoint>& dts = exchangeData[neiProc];
227 dts.append(refLabelledPoint(globalPointLabel[bpI], lpd));
231 //- exchange data with other processors
232 LongList<refLabelledPoint> receivedData;
233 help::exchangeMap(exchangeData, receivedData);
235 forAll(receivedData, i)
237 const refLabelledPoint& lp = receivedData[i];
238 const label bpI = globalToLocal[lp.objectLabel()];
240 labelledPoint& lpd = localData[bpI];
242 lpd.pointLabel() += lp.lPoint().pointLabel();
243 lpd.coordinates() += lp.lPoint().coordinates();
246 pointField newPositions(nodesToSmooth.size());
249 # pragma omp parallel for schedule(dynamic, 20)
251 forAll(nodesToSmooth, pI)
253 const label bpI = nodesToSmooth[pI];
255 if( localData.find(bpI) == localData.end() )
257 newPositions[pI] = points[bPoints[bpI]];
261 //- create new point position
262 const labelledPoint& lp = localData[bpI];
263 const point newP = lp.coordinates() / lp.pointLabel();
265 newPositions[pI] = newP;
268 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
270 # pragma omp parallel for schedule(dynamic, 20)
272 forAll(newPositions, pI)
274 surfaceModifier.moveBoundaryVertexNoUpdate
282 void meshSurfaceOptimizer::nodeDisplacementSurfaceOptimizerParallel
284 const labelLongList& nodesToSmooth
287 if( returnReduce(nodesToSmooth.size(), sumOp<label>()) == 0 )
290 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
292 //- exchange data with other processors
293 std::map<label, DynList<parTriFace> > m;
294 exchangeData(nodesToSmooth, m);
296 const pointField& points = surfaceEngine_.points();
297 const labelList& bPoints = surfaceEngine_.boundaryPoints();
298 const vectorField& pNormals = surfaceEngine_.pointNormals();
300 //- perform smoothing
301 pointField newPositions(nodesToSmooth.size());
304 # pragma omp parallel for schedule(dynamic, 10)
306 forAll(nodesToSmooth, pI)
308 const label bpI = nodesToSmooth[pI];
310 if( magSqr(pNormals[bpI]) < VSMALL )
312 newPositions[pI] = points[bPoints[bpI]];
316 plane pl(points[bPoints[bpI]], pNormals[bpI]);
319 DynList<triFace> trias;
321 if( !transformIntoPlaneParallel(bpI, pl, m, vecX, vecY, pts, trias) )
323 newPositions[pI] = points[bPoints[bpI]];
327 surfaceOptimizer so(pts, trias);
328 point newPoint = so.optimizePoint(0.001);
332 points[bPoints[bpI]] +
333 vecX * newPoint.x() +
337 if( help::isnan(newP) || help::isinf(newP) )
339 newPositions[pI] = points[bPoints[bpI]];
343 newPositions[pI] = newP;
348 # pragma omp parallel for schedule(dynamic, 50)
350 forAll(newPositions, pI)
351 surfaceModifier.moveBoundaryVertexNoUpdate
357 //- make sure that moved points have the same coordinates on all processors
358 surfaceModifier.syncVerticesAtParallelBoundaries(nodesToSmooth);
361 void meshSurfaceOptimizer::edgeNodeDisplacementParallel
363 const labelLongList& nodesToSmooth
366 std::map<label, DynList<labelledPoint, 2> > mPts;
368 //- insert labels into the map
369 const labelList& globalPointLabel =
370 surfaceEngine_.globalBoundaryPointLabel();
372 forAll(nodesToSmooth, nI)
378 globalPointLabel[nodesToSmooth[nI]],
379 DynList<labelledPoint, 2>()
384 //- add local edge points
385 const pointField& points = surfaceEngine_.points();
386 const labelList& bPoints = surfaceEngine_.boundaryPoints();
387 const edgeList& edges = surfaceEngine_.edges();
388 const VRWGraph& bpEdges = surfaceEngine_.boundaryPointEdges();
389 const labelList& bp = surfaceEngine_.bp();
391 forAll(nodesToSmooth, nI)
393 const label bpI = nodesToSmooth[nI];
394 DynList<labelledPoint, 2>& neiPoints = mPts[globalPointLabel[bpI]];
396 forAllRow(bpEdges, bpI, epI)
398 const edge& e = edges[bpEdges(bpI, epI)];
399 const label pI = bp[e.otherVertex(bPoints[bpI])];
400 if( vertexType_[pI] & (EDGE+CORNER) )
404 labelledPoint(globalPointLabel[pI], points[bPoints[pI]])
410 //- start preparing data which can be exchanged with other processors
411 const DynList<label>& neiProcs = surfaceEngine_.bpNeiProcs();
412 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
414 std::map<label, LongList<refLabelledPoint> > mProcs;
415 forAll(neiProcs, procI)
417 const label neiProc = neiProcs[procI];
419 if( neiProc == Pstream::myProcNo() )
422 mProcs.insert(std::make_pair(neiProc, LongList<refLabelledPoint>()));
425 forAll(nodesToSmooth, nI)
427 const label bpI = nodesToSmooth[nI];
429 const DynList<labelledPoint, 2>& neiPoints =
430 mPts[globalPointLabel[bpI]];
432 forAllRow(bpAtProcs, bpI, procI)
434 const label neiProc = bpAtProcs(bpI, procI);
436 if( neiProc == Pstream::myProcNo() )
439 forAll(neiPoints, npI)
441 LongList<refLabelledPoint>& neiProcPts = mProcs[neiProc];
444 refLabelledPoint(globalPointLabel[bpI], neiPoints[npI])
450 //- exchange data with other processors
451 LongList<refLabelledPoint> receivedData;
452 help::exchangeMap(mProcs, receivedData);
454 forAll(receivedData, prI)
456 const refLabelledPoint& lp = receivedData[prI];
457 DynList<labelledPoint, 2>& lPts = mPts[lp.objectLabel()];
458 lPts.appendIfNotIn(receivedData[prI].lPoint());
461 //- Finally, the data is ready to start smoothing
462 meshSurfaceEngineModifier sm(surfaceEngine_);
464 pointField newPositions(nodesToSmooth.size());
466 # pragma omp parallel for schedule(dynamic, 20)
468 forAll(nodesToSmooth, pI)
470 const label bpI = nodesToSmooth[pI];
472 const DynList<labelledPoint, 2>& nPts = mPts[globalPointLabel[bpI]];
473 point newP(vector::zero);
475 newP += nPts[ppI].coordinates();
477 if( nPts.size() == 2 )
480 newPositions[pI] = newP;
484 newPositions[pI] = points[bPoints[bpI]];
489 # pragma omp parallel for schedule(dynamic, 20)
491 forAll(newPositions, pI)
492 sm.moveBoundaryVertexNoUpdate(nodesToSmooth[pI], newPositions[pI]);
495 void meshSurfaceOptimizer::exchangeData
497 const labelLongList& nodesToSmooth,
498 std::map<label, DynList<parTriFace> >& m
502 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
503 const DynList<label>& neiProcs = surfaceEngine_.bpNeiProcs();
505 std::map<label, LongList<parTriFace> > shareData;
506 forAll(neiProcs, procI)
508 const label neiProc = neiProcs[procI];
510 if( neiProc == Pstream::myProcNo() )
513 shareData.insert(std::make_pair(neiProc, LongList<parTriFace>()));
516 //- create data which will be sent to other processors
517 const pointField& points = surfaceEngine_.points();
518 const labelList& globalPointLabel =
519 surfaceEngine_.globalBoundaryPointLabel();
520 const labelList& bPoints = surfaceEngine_.boundaryPoints();
521 const LongList<triFace>& triangles = this->triangles();
522 const VRWGraph& pTriangles = pointTriangles();
525 std::map<label, DynList<parTriFace> >::iterator pIter;
526 forAll(nodesToSmooth, nI)
528 const label bpI = nodesToSmooth[nI];
530 pIter = m.find(globalPointLabel[bpI]);
531 if( pIter == m.end() )
535 std::make_pair(globalPointLabel[bpI], DynList<parTriFace>())
538 pIter = m.find(globalPointLabel[bpI]);
541 forAll(pTriangles[bpI], ptI)
543 const triFace& tri = triangles[pTriangles[bpI][ptI]];
547 globalPointLabel[tri[0]],
548 globalPointLabel[tri[1]],
549 globalPointLabel[tri[2]],
550 triangle<point, point>
552 points[bPoints[tri[0]]],
553 points[bPoints[tri[1]]],
554 points[bPoints[tri[2]]]
558 pIter->second.append(ptf);
561 forAllRow(bpAtProcs, bpI, procI)
563 const label neiProc = bpAtProcs(bpI, procI);
564 if( neiProc == Pstream::myProcNo() )
567 LongList<parTriFace>& shData = shareData[neiProc];
569 const DynList<parTriFace>& localData = pIter->second;
572 shData.append(localData[i]);
576 //- send data to other processors
577 LongList<parTriFace> receivedData;
578 help::exchangeMap(shareData, receivedData);
580 forAll(receivedData, tI)
582 const label gpI = receivedData[tI].globalLabelOfPoint(0);
585 if( pIter == m.end() )
589 "void meshSurfaceOptimizer::exchangeData("
590 "const labelLongList& nodesToSmooth,"
591 "map<label, DynList<parTriFace> >& m"
593 ) << "Unknown point " << gpI << abort(FatalError);
596 pIter->second.append(receivedData[tI]);
601 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
603 } // End namespace Foam
605 // ************************************************************************* //