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 "refineBoundaryLayers.H"
29 #include "meshSurfaceEngine.H"
30 #include "helperFunctions.H"
31 #include "polyMeshGenAddressing.H"
32 #include "polyMeshGen2DEngine.H"
33 #include "VRWGraphList.H"
34 #include "meshSurfacePartitioner.H"
35 #include "detectBoundaryLayers.H"
37 #include "labelledPair.H"
38 #include "labelledScalar.H"
50 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
55 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
57 bool refineBoundaryLayers::analyseLayers()
59 const meshSurfaceEngine& mse = surfaceEngine();
60 const faceList::subList& bFaces = mse.boundaryFaces();
61 const labelList& facePatch = mse.boundaryFacePatches();
63 meshSurfacePartitioner mPart(mse);
64 detectBoundaryLayers dbl(mPart, is2DMesh_);
66 const label nGroups = dbl.nDistinctLayers();
67 const labelList& faceInLayer = dbl.faceInLayer();
69 //- get the hair edges
70 splitEdges_ = dbl.hairEdges();
73 OFstream file("hairEdges.vtk");
76 file << "# vtk DataFile Version 3.0\n";
77 file << "vtk output\n";
79 file << "DATASET POLYDATA\n";
82 file << "POINTS " << 2*splitEdges_.size() << " float\n";
83 forAll(splitEdges_, seI)
85 const point& p = mse.mesh().points()[splitEdges_[seI].start()];
87 file << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
89 const point op = mse.mesh().points()[splitEdges_[seI].end()];
91 file << op.x() << ' ' << op.y() << ' ' << op.z() << nl;
95 file << "\nLINES " << splitEdges_.size()
96 << " " << 3*splitEdges_.size() << nl;
97 forAll(splitEdges_, eI)
99 file << 2 << " " << 2*eI << " " << (2*eI+1) << nl;
105 //- create point to split edges addressing
106 splitEdgesAtPoint_.reverseAddressing(splitEdges_);
108 //- check if the layer is valid
109 bool validLayer(true);
111 # pragma omp parallel for schedule(dynamic, 40)
113 forAll(faceInLayer, bfI)
115 if( faceInLayer[bfI] < 0 )
118 const face& bf = bFaces[bfI];
121 if( splitEdgesAtPoint_.sizeOfRow(bf[pI]) == 0 )
126 Info << "Number of independent layers in the mesh is " << nGroups << endl;
127 Info << "Is valid layer " << validLayer << endl;
130 const PtrList<boundaryPatch>& boundaries = mesh_.boundaries();
132 //- create patch name to index addressing
133 std::map<word, label> patchNameToIndex;
134 forAll(boundaries, patchI)
135 patchNameToIndex[boundaries[patchI].patchName()] = patchI;
137 //- check layer labels over a patch
138 layerAtPatch_.setSize(boundaries.size());
139 forAll(layerAtPatch_, i)
140 layerAtPatch_[i].clear();
141 List<DynList<label> > groupsAtPatch(boundaries.size());
142 forAll(faceInLayer, bfI)
143 groupsAtPatch[facePatch[bfI]].appendIfNotIn(faceInLayer[bfI]);
145 //- set the information which patches have an extruded layer
146 forAll(groupsAtPatch, patchI)
148 const DynList<label>& layers = groupsAtPatch[patchI];
154 layerAtPatch_[patchI].clear();
159 layerAtPatch_[patchI].append(layers[i]);
165 Info << "Layer at patch " << layerAtPatch_ << endl;
168 //- set the information which patches are a single boundary layer face
169 patchesInLayer_.setSize(nGroups);
170 forAll(layerAtPatch_, patchI)
172 const DynList<label>& layers = layerAtPatch_[patchI];
175 patchesInLayer_[layers[i]].append
177 boundaries[patchI].patchName()
182 Info << "Patches in layer " << patchesInLayer_ << endl;
185 //- set the number of boundary layers for each patch
186 labelList nLayersAtPatch(layerAtPatch_.size(), -1);
187 boolList protectedValue(layerAtPatch_.size(), false);
189 forAll(patchesInLayer_, layerI)
191 const DynList<word>& layerPatches = patchesInLayer_[layerI];
193 label maxNumLayers(1);
194 bool hasLocalValue(false);
196 //- find the maximum requested number of layers over the layer
197 forAll(layerPatches, lpI)
199 const word pName = layerPatches[lpI];
201 std::map<word, label>::const_iterator it =
202 numLayersForPatch_.find(pName);
204 if( it != numLayersForPatch_.end() )
206 //- check if the layer is interrupted at this patch
208 discontinuousLayersForPatch_.find(pName) !=
209 discontinuousLayersForPatch_.end()
212 //- set the number of layers and lock this location
213 nLayersAtPatch[patchNameToIndex[pName]] = it->second;
214 protectedValue[patchNameToIndex[pName]] = true;
215 hasLocalValue = true;
219 //- take the maximum number of layers
220 maxNumLayers = Foam::max(maxNumLayers, it->second);
221 hasLocalValue = true;
226 //- apply the global value if no local values exist
228 maxNumLayers = globalNumLayers_;
230 //- apply the maximum number of ayer of all unprotected patches
231 forAll(layerPatches, lpI)
233 const label ptchI = patchNameToIndex[layerPatches[lpI]];
235 if( !protectedValue[ptchI] )
236 nLayersAtPatch[ptchI] = maxNumLayers;
242 polyMeshGen2DEngine mesh2DEngine(mesh_);
243 const boolList& zMinPoint = mesh2DEngine.zMinPoints();
244 const boolList& zMaxPoint = mesh2DEngine.zMaxPoints();
246 const faceList::subList& bFaces = mse.boundaryFaces();
248 boolList allZMax(mesh_.boundaries().size(), true);
249 boolList allZMin(mesh_.boundaries().size(), true);
252 # pragma omp parallel for schedule(dynamic, 50)
256 const face& bf = bFaces[bfI];
260 if( !zMinPoint[bf[pI]] )
261 allZMin[facePatch[bfI]] = false;
262 if( !zMaxPoint[bf[pI]] )
263 allZMax[facePatch[bfI]] = false;
267 //- mark empty patches as already used
268 forAll(allZMin, patchI)
270 if( allZMin[patchI] ^ allZMax[patchI] )
272 nLayersAtPatch[patchI] = -1;
273 layerAtPatch_[patchI].clear();
278 //- perform reduction over all processors
279 reduce(nLayersAtPatch, maxOp<labelList>());
282 Pout << "nLayersAtPatch " << nLayersAtPatch << endl;
285 //- set the number of boundary layers which shall be generated above
286 //- each boundary face
287 nLayersAtBndFace_.setSize(facePatch.size());
288 nLayersAtBndFace_ = globalNumLayers_;
291 # pragma omp parallel for schedule(dynamic, 50)
293 forAll(nLayersAtBndFace_, bfI)
295 const label patchI = facePatch[bfI];
297 if( nLayersAtPatch[patchI] < 0 )
299 nLayersAtBndFace_[bfI] = 1;
303 nLayersAtBndFace_[bfI] = nLayersAtPatch[patchI];
307 ++nLayersAtBndFace_[bfI];
313 forAll(nLayersAtBndFace_, bfI)
314 Pout << "Boundary face " << bfI << " in patch "
315 << facePatch[bfI] << " num layers " << nLayersAtBndFace_[bfI] << endl;
322 void refineBoundaryLayers::generateNewVertices()
324 const PtrList<boundaryPatch>& boundaries = mesh_.boundaries();
325 pointFieldPMG& points = mesh_.points();
327 const meshSurfaceEngine& mse = surfaceEngine();
328 const faceList::subList& bFaces = mse.boundaryFaces();
329 const VRWGraph& pointFaces = mse.pointFaces();
330 const labelList& facePatch = mse.boundaryFacePatches();
331 const labelList& bp = mse.bp();
333 //- allocate the data from storing parameters applying to a split edge
334 LongList<scalar> firstLayerThickness(splitEdges_.size());
335 LongList<scalar> thicknessRatio(splitEdges_.size());
336 labelLongList nNodesAtEdge(splitEdges_.size());
337 labelLongList nLayersAtEdge(splitEdges_.size());
339 //- count the number of vertices for each split edge
341 const label nThreads = 3 * omp_get_num_procs();
343 const label nThreads = 1;
347 # pragma omp parallel num_threads(nThreads)
350 //- start counting vertices at each thread
352 # pragma omp for schedule(static, 1)
354 forAll(splitEdges_, seI)
356 const edge& e = splitEdges_[seI];
358 //- get the requested number of boundary layers
360 scalar ratio(globalThicknessRatio_);
361 scalar thickness(globalMaxThicknessFirstLayer_);
362 bool overridenThickness(false);
364 const label bpI = bp[e.start()];
366 forAllRow(pointFaces, bpI, pfI)
368 const label bfI = pointFaces(bpI, pfI);
369 const label pos = help::positionOfEdgeInFace(e, bFaces[bfI]);
373 const word& patchName =
374 boundaries[facePatch[bfI]].patchName();
376 //- overrride the global value with the maximum number of layers
378 nLayers = Foam::max(nLayers, nLayersAtBndFace_[bfI]);
380 //- override with the maximum ratio
381 const std::map<word, scalar>::const_iterator rIt =
382 thicknessRatioForPatch_.find(patchName);
383 if( rIt != thicknessRatioForPatch_.end() )
388 //- override with the minimum thickness set for this edge
389 const std::map<word, scalar>::const_iterator tIt =
390 maxThicknessForPatch_.find(patchName);
391 if( tIt != maxThicknessForPatch_.end() )
393 if( overridenThickness )
395 thickness = Foam::min(thickness, tIt->second);
399 thickness = tIt->second;
400 overridenThickness = true;
405 //- store the information
406 firstLayerThickness[seI] = thickness;
407 thicknessRatio[seI] = ratio;
408 nLayersAtEdge[seI] = nLayers;
412 nNodesAtEdge[seI] = nLayers + 1;
416 nNodesAtEdge[seI] = 3;
421 if( Pstream::parRun() )
423 //- transfer the information over all processor for edges
424 //- at inter-processor boundaries
425 const labelLongList& globalEdgeLabel =
426 mesh_.addressingData().globalEdgeLabel();
427 const VRWGraph& edgeAtProcs = mesh_.addressingData().edgeAtProcs();
428 const Map<label>& globalToLocal =
429 mesh_.addressingData().globalToLocalEdgeAddressing();
430 const DynList<label>& neiProcs = mesh_.addressingData().edgeNeiProcs();
431 const edgeList& edges = mesh_.addressingData().edges();
432 const VRWGraph& pointEdges = mesh_.addressingData().pointEdges();
434 //- exchange point number of layers
435 std::map<label, LongList<labelPair> > exchangeNumLayers;
436 std::map<label, LongList<labelPair> > exchangeNumNodesAtEdge;
437 std::map<label, LongList<labelledScalar> > exchangeThickness;
438 std::map<label, LongList<labelledScalar> > exchangeRatio;
441 exchangeNumNodesAtEdge.insert
443 std::make_pair(neiProcs[i], LongList<labelPair>())
445 exchangeNumLayers.insert
447 std::make_pair(neiProcs[i], LongList<labelPair>())
449 exchangeThickness.insert
451 std::make_pair(neiProcs[i], LongList<labelledScalar>())
455 std::make_pair(neiProcs[i], LongList<labelledScalar>())
459 //- exchange the number of layers
460 forAll(splitEdges_, seI)
462 const edge& se = splitEdges_[seI];
464 const label s = se.start();
466 forAllRow(pointEdges, s, peI)
468 const label eI = pointEdges(s, peI);
470 if( edges[eI] == se )
477 const label geI = globalEdgeLabel[edgeI];
479 if( globalToLocal.found(geI) )
481 forAllRow(edgeAtProcs, edgeI, i)
483 const label neiProc = edgeAtProcs(edgeI, i);
485 if( neiProc == Pstream::myProcNo() )
488 exchangeNumNodesAtEdge[neiProc].append
490 labelPair(geI, nNodesAtEdge[seI])
492 exchangeNumLayers[neiProc].append
494 labelPair(geI, nLayersAtEdge[seI])
496 exchangeThickness[neiProc].append
498 labelledScalar(geI, firstLayerThickness[seI])
500 exchangeRatio[neiProc].append
502 labelledScalar(geI, thicknessRatio[seI])
508 //- exchange number of nodes at split edge
509 LongList<labelPair> receivedNumLayers;
510 help::exchangeMap(exchangeNumNodesAtEdge, receivedNumLayers);
512 forAll(receivedNumLayers, i)
514 const labelPair& lp = receivedNumLayers[i];
515 const label eI = globalToLocal[lp.first()];
516 const edge& e = edges[eI];
518 forAllRow(splitEdgesAtPoint_, e.start(), i)
520 const label seJ = splitEdgesAtPoint_(e.start(), i);
521 if( splitEdges_[seJ] == e )
527 nNodesAtEdge[seI] = std::max(nNodesAtEdge[seI], lp.second());
530 //- exchange number of layers
531 receivedNumLayers.clear();
532 help::exchangeMap(exchangeNumLayers, receivedNumLayers);
534 forAll(receivedNumLayers, i)
536 const labelPair& lp = receivedNumLayers[i];
537 const label eI = globalToLocal[lp.first()];
538 const edge& e = edges[eI];
540 forAllRow(splitEdgesAtPoint_, e.start(), i)
542 const label seJ = splitEdgesAtPoint_(e.start(), i);
543 if( splitEdges_[seJ] == e )
549 nLayersAtEdge[seI] = std::max(nLayersAtEdge[seI], lp.second());
552 //- exchange thickness ratio
553 LongList<labelledScalar> receivedScalar;
554 help::exchangeMap(exchangeRatio, receivedScalar);
556 forAll(receivedScalar, i)
558 const labelledScalar& ls = receivedScalar[i];
559 const label eI = globalToLocal[ls.scalarLabel()];
560 const edge& e = edges[eI];
562 forAllRow(splitEdgesAtPoint_, e.start(), i)
564 const label seJ = splitEdgesAtPoint_(e.start(), i);
565 if( splitEdges_[seJ] == e )
571 thicknessRatio[seI] = std::max(thicknessRatio[seI], ls.value());
574 //- exchange maximum thickness of the first layer
575 receivedScalar.clear();
576 help::exchangeMap(exchangeThickness, receivedScalar);
578 forAll(receivedScalar, i)
580 const labelledScalar& ls = receivedScalar[i];
581 const label eI = globalToLocal[ls.scalarLabel()];
582 const edge& e = edges[eI];
584 forAllRow(splitEdgesAtPoint_, e.start(), i)
586 const label seJ = splitEdgesAtPoint_(e.start(), i);
587 if( splitEdges_[seJ] == e )
593 firstLayerThickness[seI] =
594 std::min(firstLayerThickness[seI], ls.value());
598 //- calculate the number of additional vertices which will be generated
599 //- on edges of the mesh
600 DynList<label> numPointsAtThread;
601 numPointsAtThread.setSize(nThreads);
602 numPointsAtThread = 0;
605 # pragma omp parallel for num_threads(nThreads) schedule(static, 1)
607 forAll(nNodesAtEdge, seI)
610 const label threadI = omp_get_thread_num();
612 const label threadI(0);
615 numPointsAtThread[threadI] += nNodesAtEdge[seI] - 2;
618 //- allocate the space in a graph storing ids of points on a split edge
619 newVerticesForSplitEdge_.setSizeAndRowSize(nNodesAtEdge);
621 //- calculate the number of points which will be generated
623 label numPoints = points.size();
624 forAll(numPointsAtThread, threadI)
626 const label nPts = numPointsAtThread[threadI];
627 numPointsAtThread[threadI] = numPoints;
631 points.setSize(numPoints);
634 Info << "Generating split vertices" << endl;
637 //- generate vertices on split edges
639 # pragma omp parallel num_threads(nThreads)
643 const label threadI = omp_get_thread_num();
645 const label threadI(0);
648 label& nPoints = numPointsAtThread[threadI];
651 # pragma omp for schedule(static, 1)
653 forAll(splitEdges_, seI)
655 const edge& e = splitEdges_[seI];
657 const vector v = e.vec(points);
658 const scalar magv = mag(v);
660 const label nLayers = newVerticesForSplitEdge_.sizeOfRow(seI) - 1;
662 scalar firstThickness = magv / nLayersAtEdge[seI];
663 if( thicknessRatio[seI] > (1. + SMALL) )
668 (1 - Foam::pow(thicknessRatio[seI], nLayersAtEdge[seI]))
669 / (1.0 - thicknessRatio[seI])
673 Pout << "Thread " << threadI << endl;
674 Pout << "Generating vertices at split edge "
675 << " start point " << points[e.start()]
676 << " end point " << points[e.end()] << endl;
677 Pout << "Edge length " << magv << endl;
678 Pout << "Thickness of the first layer "
679 << firstThickness << endl;
686 Foam::max(firstLayerThickness[seI], SMALL),
692 scalar t = firstThickness;
694 for(label i=1;i<nLayersAtEdge[seI]-1;++i)
695 t += firstThickness * Foam::pow(thicknessRatio[seI], i);
700 //- generate vertices for this edge
701 newVerticesForSplitEdge_(seI, 0) = e.start();
703 scalar param = firstThickness;
704 const vector vec = v / (magv + VSMALL);
706 for(label pI=1;pI<nLayers;++pI)
708 //- generate the new vertex
709 const point newP = points[e.start()] + param * vec;
712 Pout << "Split edge " << seI << " edge points " << e
713 << " start point " << points[e.start()]
714 << " end point " << points[e.end()]
715 << " param " << param
716 << " new point " << nPoints
717 << " has coordinates " << newP << endl;
720 param += firstThickness * Foam::pow(thicknessRatio[seI], pI);
722 newVerticesForSplitEdge_(seI, pI) = nPoints;
723 points[nPoints++] = newP;
726 newVerticesForSplitEdge_(seI, nLayers) = e.end();
732 //- set the number of layers to 2
733 forAll(nLayersAtBndFace_, bfI)
734 if( nLayersAtBndFace_[bfI] > 1 )
735 nLayersAtBndFace_[bfI] = 2;
739 for(label procI=0;procI<Pstream::nProcs();++procI)
741 if( procI == Pstream::myProcNo() )
743 forAll(splitEdges_, seI)
745 Pout << "\nSplit edge " << seI << " nodes " << splitEdges_[seI]
746 << " coordinates " << points[splitEdges_[seI][0]]
747 << " " << points[splitEdges_[seI][1]]
748 << " has new points "
749 << newVerticesForSplitEdge_[seI] << endl;
751 forAllRow(newVerticesForSplitEdge_, seI, i)
752 Pout << "Point " << i << " on edge ha coordinates "
753 << points[newVerticesForSplitEdge_(seI, i)] << endl;
757 returnReduce(1, sumOp<label>());
760 Info << "Finished generating vertices at split edges" << endl;
765 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
767 } // End namespace Foam
769 // ************************************************************************* //