Loading...
Searching...
No Matches
medialAxisMeshMover.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2014-2015 OpenFOAM Foundation
9 Copyright (C) 2015-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "medialAxisMeshMover.H"
31#include "pointFields.H"
33#include "PointEdgeWave.H"
34#include "meshRefinement.H"
35#include "unitConversion.H"
36#include "PatchTools.H"
37#include "OBJstream.H"
38#include "PointData.H"
40#include "pointSet.H"
42// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43
44namespace Foam
45{
47
49 (
53 );
54}
55
56
57// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
58
59// Tries and find a medial axis point. Done by comparing vectors to nearest
60// wall point for both vertices of edge.
61bool Foam::medialAxisMeshMover::isMaxEdge
62(
63 const List<PointData<vector>>& pointWallDist,
64 const label edgeI,
65 const scalar minCos,
66 const bool disableWallEdges
67) const
68{
69 const pointField& points = mesh().points();
70 const edge& e = mesh().edges()[edgeI];
71
72 if (disableWallEdges)
73 {
74 // 1. Do not mark edges with one side on moving wall.
75 vector v0(points[e[0]] - pointWallDist[e[0]].origin());
76 scalar magV0(mag(v0));
77 if (magV0 < SMALL)
78 {
79 return false;
80 }
81
82 vector v1(points[e[1]] - pointWallDist[e[1]].origin());
83 scalar magV1(mag(v1));
84 if (magV1 < SMALL)
85 {
86 return false;
87 }
88 }
89
91 //vector v0(points[e[0]] - pointWallDist[e[0]].origin());
92 //scalar magV0(mag(v0));
93 //vector v1(points[e[1]] - pointWallDist[e[1]].origin());
94 //scalar magV1(mag(v1));
95 //if (magV0 < SMALL && magV1 < SMALL)
96 //{
97 // return false;
98 //}
99
101 //v0 /= magV0;
102 //v1 /= magV1;
103 //
105 //if ((v0 & v1) < minCos)
106 //{
107 // return true;
108 //}
109 //else
110 //{
111 // return false;
112 //}
113
114 //- Detect based on extrusion vector differing for both endpoints
115 // the idea is that e.g. a sawtooth wall can still be extruded
116 // successfully as long as it is done all to the same direction.
117 if ((pointWallDist[e[0]].data() & pointWallDist[e[1]].data()) < minCos)
118 {
119 return true;
120 }
121
122 return false;
123}
124
125
126void Foam::medialAxisMeshMover::update(const dictionary& coeffDict)
127{
128 Info<< typeName
129 << " : Calculating distance to Medial Axis ..." << endl;
130
131 const pointField& points = mesh().points();
132
133 const indirectPrimitivePatch& pp = adaptPatchPtr_();
134 const labelList& meshPoints = pp.meshPoints();
135
136
137 // Read a few parameters
138 // ~~~~~~~~~~~~~~~~~~~~~
139
140 //- Smooth surface normals
141 const label nSmoothSurfaceNormals
142 (
144 (
145 coeffDict,
146 "nSmoothSurfaceNormals",
147 dryRun_
148 )
149 );
150
151 const scalar minMedialAxisAngle
152 (
154 (
155 coeffDict,
156 "minMedialAxisAngle",
157 dryRun_
158 )
159 );
160
161 const scalar minMedialAxisAngleCos(Foam::cos(degToRad(minMedialAxisAngle)));
162
163 //- Feature angle when to stop adding layers
164 const scalar featureAngle
165 (
166 meshRefinement::get<scalar>(coeffDict, "featureAngle", dryRun_)
167 );
168
169 //- When to slip along wall
170 const scalar slipFeatureAngle
171 (
172 coeffDict.getOrDefault<scalar>("slipFeatureAngle", (0.5*featureAngle))
173 );
174
175 //- Smooth internal normals
176 const label nSmoothNormals
177 (
178 meshRefinement::get<label>(coeffDict, "nSmoothNormals", dryRun_)
179 );
180
181 //- Number of edges walking out
182 const label nMedialAxisIter = coeffDict.getOrDefault<label>
183 (
184 "nMedialAxisIter",
186 );
187
188 const bool disableWallEdges = coeffDict.getOrDefault<bool>
189 (
190 "disableWallEdges",
191 false
192 );
193
194
195
196 // Predetermine mesh edges
197 // ~~~~~~~~~~~~~~~~~~~~~~~
198
199 // Precalulate (mesh) master point/edge (only relevant for shared pts/edges)
200 const bitSet isMeshMasterPoint(syncTools::getMasterPoints(mesh()));
201 const bitSet isMeshMasterEdge(syncTools::getMasterEdges(mesh()));
202 // Precalculate meshEdge per pp edge
203 const labelList meshEdges
204 (
206 (
207 mesh().edges(),
208 mesh().pointEdges()
209 )
210 );
211
212 // Precalulate (patch) master point/edge
213 const bitSet isPatchMasterPoint
214 (
216 (
217 mesh(),
218 meshPoints
219 )
220 );
221 const bitSet isPatchMasterEdge
222 (
224 (
225 mesh(),
226 meshEdges
227 )
228 );
229
230 // Determine pointNormal
231 // ~~~~~~~~~~~~~~~~~~~~~
232
233 pointField pointNormals(PatchTools::pointNormals(mesh(), pp));
234
235 // Smooth patch normal vectors
236 fieldSmoother_.smoothPatchNormals
237 (
238 nSmoothSurfaceNormals,
239 isPatchMasterPoint,
240 isPatchMasterEdge,
241 pp,
242 pointNormals
243 );
244
245
246 // Calculate distance to pp points
247 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
248
249 // Distance to wall
250 List<PointData<vector>> pointWallDist(mesh().nPoints());
251
252 // Dummy additional info for PointEdgeWave
253 int dummyTrackData = 0;
254
255
256 // 1. Calculate distance to points where displacement is specified.
257 {
258 // Seed data.
259 List<PointData<vector>> wallInfo(meshPoints.size());
260
261 forAll(meshPoints, patchPointI)
262 {
263 label pointI = meshPoints[patchPointI];
264 wallInfo[patchPointI] = PointData<vector>
265 (
266 points[pointI],
267 0.0,
268 pointNormals[patchPointI] // surface normals
269 );
270 }
271
272 // Do all calculations
273 List<PointData<vector>> edgeWallDist(mesh().nEdges());
275 (
276 mesh(),
277 meshPoints,
278 wallInfo,
279 pointWallDist,
280 edgeWallDist,
281 0, // max iterations
282 dummyTrackData
283 );
284 wallDistCalc.iterate(nMedialAxisIter);
285
286 const label nUnvisit = returnReduce
287 (
288 wallDistCalc.nUnvisitedPoints(),
290 );
291
292 if (nUnvisit > 0)
293 {
294 if (nMedialAxisIter > 0)
295 {
296 Info<< typeName
297 << " : Limited walk to " << nMedialAxisIter
298 << " steps. Not visited " << nUnvisit
299 << " out of " << mesh().globalData().nTotalPoints()
300 << " points" << endl;
301 }
302 else
303 {
305 << "Walking did not visit all points." << nl
306 << " Did not visit " << nUnvisit
307 << " out of " << mesh().globalData().nTotalPoints()
308 << " points. This is not necessarily a problem" << nl
309 << " and might be due to faceZones splitting of part"
310 << " of the domain." << nl << endl;
311 }
312 }
313 }
314
315
316 // 2. Find points with max distance and transport information back to
317 // wall.
318 {
319 List<pointEdgePoint> pointMedialDist(mesh().nPoints());
320 List<pointEdgePoint> edgeMedialDist(mesh().nEdges());
321
322 // Seed point data.
323 DynamicList<pointEdgePoint> maxInfo(meshPoints.size());
324 DynamicList<label> maxPoints(meshPoints.size());
325
326 // 1. Medial axis points
327
328 const edgeList& edges = mesh().edges();
329
330 forAll(edges, edgeI)
331 {
332 const edge& e = edges[edgeI];
333
334 if
335 (
336 !pointWallDist[e[0]].valid(dummyTrackData)
337 || !pointWallDist[e[1]].valid(dummyTrackData)
338 )
339 {
340 // Unvisited point. See above about nUnvisit warning
341 forAll(e, ep)
342 {
343 label pointI = e[ep];
344
345 if (!pointMedialDist[pointI].valid(dummyTrackData))
346 {
347 maxPoints.append(pointI);
348 maxInfo.append
349 (
351 (
352 points[pointI],
353 0.0
354 )
355 );
356 pointMedialDist[pointI] = maxInfo.last();
357 }
358 }
359
360 }
361 else if
362 (
363 isMaxEdge
364 (
365 pointWallDist,
366 edgeI,
367 minMedialAxisAngleCos,
368 disableWallEdges
369 )
370 )
371 {
372 // Both end points of edge have very different nearest wall
373 // point. Mark both points as medial axis points.
374
375 // Approximate medial axis location on edge.
376 //const point medialAxisPt = e.centre(points);
377 vector eVec = e.vec(points);
378 scalar eMag = mag(eVec);
379 if (eMag > VSMALL)
380 {
381 eVec /= eMag;
382
383 // Calculate distance along edge
384 const point& p0 = points[e[0]];
385 const point& origin0 = pointWallDist[e[0]].origin();
386 const point& p1 = points[e[1]];
387 const point& origin1 = pointWallDist[e[1]].origin();
388 scalar dist0 = (p0-origin0) & eVec;
389 scalar dist1 = (origin1-p1) & eVec;
390 scalar s = 0.5*(dist1+eMag+dist0);
391
392 point medialAxisPt(vector::max);
393 if (s <= dist0)
394 {
395 // Make sure point is not on wall. Note that this
396 // check used to be inside isMaxEdge.
397 if (magSqr((p0-origin0)) > Foam::sqr(SMALL))
398 {
399 medialAxisPt = p0;
400 }
401 }
402 else if (s >= dist0+eMag)
403 {
404 // Make sure point is not on wall. Note that this
405 // check used to be inside isMaxEdge.
406 if (magSqr((p1-origin1)) > Foam::sqr(SMALL))
407 {
408 medialAxisPt = p1;
409 }
410 }
411 else
412 {
413 medialAxisPt = p0+(s-dist0)*eVec;
414 }
415
416 if (medialAxisPt != vector::max)
417 {
418 forAll(e, ep)
419 {
420 label pointI = e[ep];
421
422 if (!pointMedialDist[pointI].valid(dummyTrackData))
423 {
424 maxPoints.append(pointI);
425 maxInfo.append
426 (
428 (
429 medialAxisPt, //points[pointI],
430 magSqr(points[pointI]-medialAxisPt)//0.0
431 )
432 );
433 pointMedialDist[pointI] = maxInfo.last();
434 }
435 }
436 }
437 }
438 }
439 }
440
441
442 // 2. Seed non-adapt patches
444
445 labelHashSet adaptPatches(adaptPatchIDs_);
446
447
448 forAll(patches, patchI)
449 {
450 const polyPatch& pp = patches[patchI];
451 const pointPatchVectorField& pvf =
452 pointDisplacement().boundaryField()[patchI];
453
454 if
455 (
456 !pp.coupled()
458 && !adaptPatches.found(patchI)
459 )
460 {
461 const labelList& meshPoints = pp.meshPoints();
462
463 // Check the type of the patchField. The types are
464 // - fixedValue (0 or more layers) but the >0 layers have
465 // already been handled in the adaptPatches loop
466 // - constraint (but not coupled) types, e.g. symmetryPlane,
467 // slip.
468 if (pvf.fixesValue())
469 {
470 // Disable all movement on fixedValue patchFields
471 Info<< typeName
472 << " : Inserting all points on patch " << pp.name()
473 << endl;
474
475 forAll(meshPoints, i)
476 {
477 label pointI = meshPoints[i];
478 if (!pointMedialDist[pointI].valid(dummyTrackData))
479 {
480 maxPoints.append(pointI);
481 maxInfo.append
482 (
484 (
485 points[pointI],
486 0.0
487 )
488 );
489 pointMedialDist[pointI] = maxInfo.last();
490 }
491 }
492 }
493 else
494 {
495 // Based on geometry: analyse angle w.r.t. nearest moving
496 // point. In the pointWallDist we transported the
497 // normal as the passive vector. Note that this points
498 // out of the originating wall so inside of the domain
499 // on this patch.
500 Info<< typeName
501 << " : Inserting points on patch " << pp.name()
502 << " if angle to nearest layer patch > "
503 << slipFeatureAngle << " degrees." << endl;
504
505 scalar slipFeatureAngleCos = Foam::cos
506 (
507 degToRad(slipFeatureAngle)
508 );
509 pointField pointNormals
510 (
512 );
513
514 forAll(meshPoints, i)
515 {
516 label pointI = meshPoints[i];
517
518 if
519 (
520 pointWallDist[pointI].valid(dummyTrackData)
521 && !pointMedialDist[pointI].valid(dummyTrackData)
522 )
523 {
524 // Check if angle not too large.
525 scalar cosAngle =
526 (
527 -pointWallDist[pointI].data()
528 & pointNormals[i]
529 );
530 if (cosAngle > slipFeatureAngleCos)
531 {
532 // Extrusion direction practically perpendicular
533 // to the patch. Disable movement at the patch.
534
535 maxPoints.append(pointI);
536 maxInfo.append
537 (
539 (
540 points[pointI],
541 0.0
542 )
543 );
544 pointMedialDist[pointI] = maxInfo.last();
545 }
546 else
547 {
548 // Extrusion direction makes angle with patch
549 // so allow sliding - don't insert zero points
550 }
551 }
552 }
553 }
554 }
555 }
556
557 maxInfo.shrink();
558 maxPoints.shrink();
559
560
561 if (debug)
562 {
563 mkDir(mesh().time().timePath());
564 OBJstream str(mesh().time().timePath()/"medialSurfacePoints.obj");
565
566 pointSet seedPoints
567 (
568 mesh(),
569 "medialSurfacePoints",
570 maxPoints
571 );
572
573 Info<< typeName
574 << " : Writing estimated medial surface:" << nl << incrIndent
575 << indent << "locations : " << str.name() << nl
576 << indent << "pointSet : " << seedPoints.name() << nl
577 << decrIndent << endl;
578
579 for (const auto& info : maxInfo)
580 {
581 str.write(info.origin());
582 }
583 seedPoints.write();
584 }
585
586
587 // Do all calculations
588 PointEdgeWave<pointEdgePoint> medialDistCalc
589 (
590 mesh(),
591 maxPoints,
592 maxInfo,
593
594 pointMedialDist,
595 edgeMedialDist,
596 0, // max iterations
597 dummyTrackData
598 );
599 medialDistCalc.iterate(2*nMedialAxisIter);
600
601
602 // Extract medial axis distance as pointScalarField
603 forAll(pointMedialDist, pointI)
604 {
605 if (pointMedialDist[pointI].valid(dummyTrackData))
606 {
607 medialDist_[pointI] = Foam::sqrt
608 (
609 pointMedialDist[pointI].distSqr()
610 );
611 medialVec_[pointI] = pointMedialDist[pointI].origin();
612 }
613 else
614 {
615 // Unvisited. Do as if on medial axis so unmoving
616 medialDist_[pointI] = 0.0;
617 medialVec_[pointI] = point(1, 0, 0);
618 }
619 }
620 }
621
622 // Extract transported surface normals as pointVectorField
623 forAll(dispVec_, i)
624 {
625 if (!pointWallDist[i].valid(dummyTrackData))
626 {
627 dispVec_[i] = vector(1, 0, 0);
628 }
629 else
630 {
631 dispVec_[i] = pointWallDist[i].data();
632 }
633 }
634
635 // Smooth normal vectors. Do not change normals on pp.meshPoints
636 fieldSmoother_.smoothNormals
637 (
638 nSmoothNormals,
639 isMeshMasterPoint,
640 isMeshMasterEdge,
641 meshPoints,
642 dispVec_
643 );
644
645 // Calculate ratio point medial distance to point wall distance
646 forAll(medialRatio_, pointI)
647 {
648 if (!pointWallDist[pointI].valid(dummyTrackData))
649 {
650 medialRatio_[pointI] = 0.0;
651 }
652 else
653 {
654 scalar wDist2 = pointWallDist[pointI].distSqr();
655 scalar mDist = medialDist_[pointI];
656
657 if (wDist2 < sqr(SMALL) && mDist < SMALL)
658 //- Note: maybe less strict:
659 //(
660 // wDist2 < sqr(meshRefiner_.mergeDistance())
661 // && mDist < meshRefiner_.mergeDistance()
662 //)
663 {
664 medialRatio_[pointI] = 0.0;
665 }
666 else
667 {
668 medialRatio_[pointI] = mDist / (Foam::sqrt(wDist2) + mDist);
669 }
670 }
671 }
672
673
674 if (debug)
675 {
676 Info<< typeName
677 << " : Writing medial axis fields:" << nl << incrIndent
678 << indent << "ratio of medial distance to wall distance : "
679 << medialRatio_.name() << nl
680 << indent << "distance to nearest medial axis : "
681 << medialDist_.name() << nl
682 << indent << "nearest medial axis location : "
683 << medialVec_.name() << nl
684 << indent << "normal at nearest wall : "
685 << dispVec_.name() << nl
686 << decrIndent << endl;
687
688 dispVec_.write();
689 medialRatio_.write();
690 medialDist_.write();
691 medialVec_.write();
692 }
693}
694
695
696bool Foam::medialAxisMeshMover::unmarkExtrusion
697(
698 const label patchPointI,
699 pointField& patchDisp,
701)
702{
703 if (extrudeStatus[patchPointI] == snappyLayerDriver::EXTRUDE)
704 {
705 extrudeStatus[patchPointI] = snappyLayerDriver::NOEXTRUDE;
706 patchDisp[patchPointI] = Zero;
707 return true;
708 }
709 else if (extrudeStatus[patchPointI] == snappyLayerDriver::EXTRUDEREMOVE)
710 {
711 extrudeStatus[patchPointI] = snappyLayerDriver::NOEXTRUDE;
712 patchDisp[patchPointI] = Zero;
713 return true;
714 }
715
716 return false;
717}
718
719
720void Foam::medialAxisMeshMover::syncPatchDisplacement
721(
722 const scalarField& minThickness,
723 pointField& patchDisp,
725) const
726{
727 const indirectPrimitivePatch& pp = adaptPatchPtr_();
728 const labelList& meshPoints = pp.meshPoints();
729
730 //label nChangedTotal = 0;
731
732 while (true)
733 {
734 label nChanged = 0;
735
736 // Sync displacement (by taking min)
738 (
739 mesh(),
740 meshPoints,
741 patchDisp,
743 point::rootMax // null value
744 );
745
746 // Unmark if displacement too small
747 forAll(patchDisp, i)
748 {
749 if (mag(patchDisp[i]) < minThickness[i])
750 {
751 if (unmarkExtrusion(i, patchDisp, extrudeStatus))
752 {
753 nChanged++;
754 }
755 }
756 }
757
758 //labelList syncPatchNLayers(patchNLayers);
759 //
760 //syncTools::syncPointList
761 //(
762 // mesh(),
763 // meshPoints,
764 // syncPatchNLayers,
765 // minEqOp<label>(),
766 // labelMax // null value
767 //);
768 //
771 //forAll(syncPatchNLayers, i)
772 //{
773 // if (syncPatchNLayers[i] != patchNLayers[i])
774 // {
775 // if
776 // (
777 // unmarkExtrusion
778 // (
779 // i,
780 // patchDisp,
781 // patchNLayers,
782 // extrudeStatus
783 // )
784 // )
785 // {
786 // nChanged++;
787 // }
788 // }
789 //}
790 //
791 //syncTools::syncPointList
792 //(
793 // mesh(),
794 // meshPoints,
795 // syncPatchNLayers,
796 // maxEqOp<label>(),
797 // labelMin // null value
798 //);
799 //
802 //forAll(syncPatchNLayers, i)
803 //{
804 // if (syncPatchNLayers[i] != patchNLayers[i])
805 // {
806 // if
807 // (
808 // unmarkExtrusion
809 // (
810 // i,
811 // patchDisp,
812 // patchNLayers,
813 // extrudeStatus
814 // )
815 // )
816 // {
817 // nChanged++;
818 // }
819 // }
820 //}
821
822 //nChangedTotal += nChanged;
823
824 if (!returnReduceOr(nChanged))
825 {
826 break;
827 }
828 }
829
830 //Info<< "Prevented extrusion on "
831 // << returnReduce(nChangedTotal, sumOp<label>())
832 // << " coupled patch points during syncPatchDisplacement." << endl;
833}
834
835
836// Stop layer growth where mesh wraps around edge with a
837// large feature angle
838void Foam::medialAxisMeshMover::
839handleFeatureAngleLayerTerminations
840(
841 const scalar minCos,
842 const bitSet& isPatchMasterPoint,
843 const labelList& meshEdges,
845 pointField& patchDisp,
846 label& nPointCounter
847) const
848{
849 const indirectPrimitivePatch& pp = adaptPatchPtr_();
850
851 // Mark faces that have all points extruded
852 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
853
854 boolList extrudedFaces(pp.size(), true);
855
856 forAll(pp.localFaces(), faceI)
857 {
858 const face& f = pp.localFaces()[faceI];
859
860 forAll(f, fp)
861 {
862 if (extrudeStatus[f[fp]] == snappyLayerDriver::NOEXTRUDE)
863 {
864 extrudedFaces[faceI] = false;
865 break;
866 }
867 }
868 }
869
870
871
872 //label nOldPointCounter = nPointCounter;
873
874 // Detect situation where two featureedge-neighbouring faces are partly or
875 // not extruded and the edge itself is extruded. In this case unmark the
876 // edge for extrusion.
877
878
879 List<List<point>> edgeFaceNormals(pp.nEdges());
880 List<List<bool>> edgeFaceExtrude(pp.nEdges());
881
882 const labelListList& edgeFaces = pp.edgeFaces();
883 const vectorField& faceNormals = pp.faceNormals();
884
885 forAll(edgeFaces, edgeI)
886 {
887 const labelList& eFaces = edgeFaces[edgeI];
888
889 edgeFaceNormals[edgeI].setSize(eFaces.size());
890 edgeFaceExtrude[edgeI].setSize(eFaces.size());
891 forAll(eFaces, i)
892 {
893 label faceI = eFaces[i];
894 edgeFaceNormals[edgeI][i] = faceNormals[faceI];
895 edgeFaceExtrude[edgeI][i] = extrudedFaces[faceI];
896 }
897 }
898
900 (
901 mesh(),
902 meshEdges,
903 edgeFaceNormals,
905 List<point>() // null value
906 );
907
909 (
910 mesh(),
911 meshEdges,
912 edgeFaceExtrude,
914 List<bool>() // null value
915 );
916
917
918 forAll(edgeFaceNormals, edgeI)
919 {
920 const List<point>& eFaceNormals = edgeFaceNormals[edgeI];
921 const List<bool>& eFaceExtrude = edgeFaceExtrude[edgeI];
922
923 if (eFaceNormals.size() == 2)
924 {
925 const edge& e = pp.edges()[edgeI];
926 label v0 = e[0];
927 label v1 = e[1];
928
929 if
930 (
931 extrudeStatus[v0] != snappyLayerDriver::NOEXTRUDE
932 || extrudeStatus[v1] != snappyLayerDriver::NOEXTRUDE
933 )
934 {
935 if (!eFaceExtrude[0] || !eFaceExtrude[1])
936 {
937 const vector& n0 = eFaceNormals[0];
938 const vector& n1 = eFaceNormals[1];
939
940 if ((n0 & n1) < minCos)
941 {
942 if (unmarkExtrusion(v0, patchDisp, extrudeStatus))
943 {
944 if (isPatchMasterPoint[v0])
945 {
946 nPointCounter++;
947 }
948 }
949 if (unmarkExtrusion(v1, patchDisp, extrudeStatus))
950 {
951 if (isPatchMasterPoint[v1])
952 {
953 nPointCounter++;
954 }
955 }
956 }
957 }
958 }
959 }
960 }
961
962 //Info<< "Added "
963 // << returnReduce(nPointCounter-nOldPointCounter, sumOp<label>())
964 // << " point not to extrude due to minCos "
965 // << minCos << endl;
966}
967
968
969// Find isolated islands (points, edges and faces and layer terminations)
970// in the layer mesh and stop any layer growth at these points.
971void Foam::medialAxisMeshMover::findIsolatedRegions
972(
973 const scalar minCosLayerTermination,
974 const bool detectExtrusionIsland,
975 const bitSet& isPatchMasterPoint,
976 const bitSet& isPatchMasterEdge,
977 const labelList& meshEdges,
978 const scalarField& minThickness,
980 pointField& patchDisp
981) const
982{
983 const indirectPrimitivePatch& pp = adaptPatchPtr_();
984 const labelListList& pointFaces = pp.pointFaces();
985 const labelList& meshPoints = pp.meshPoints();
986
987
988 Info<< typeName << " : Removing isolated regions ..." << nl
989 << indent << "- if partially extruded faces make angle < "
990 << Foam::radToDeg(Foam::acos(minCosLayerTermination)) << nl;
991 if (detectExtrusionIsland)
992 {
993 Info<< indent << "- if exclusively surrounded by non-extruded points"
994 << nl;
995 }
996 else
997 {
998 Info<< indent << "- if exclusively surrounded by non-extruded faces"
999 << nl;
1000 }
1001
1002 // Keep count of number of points unextruded
1003 label nPointCounter = 0;
1004
1005 while (true)
1006 {
1007 // Stop layer growth where mesh wraps around edge with a
1008 // large feature angle
1009 if (minCosLayerTermination > -1)
1010 {
1011 handleFeatureAngleLayerTerminations
1012 (
1013 minCosLayerTermination,
1014 isPatchMasterPoint,
1015 meshEdges,
1016
1017 extrudeStatus,
1018 patchDisp,
1019 nPointCounter
1020 );
1021
1022 syncPatchDisplacement(minThickness, patchDisp, extrudeStatus);
1023 }
1024
1025
1026 // Detect either:
1027 // - point where all surrounding points are not extruded
1028 // (detectExtrusionIsland)
1029 // or
1030 // - point where all the faces surrounding it are not fully
1031 // extruded
1032
1033 boolList keptPoints(pp.nPoints(), false);
1034
1035 if (detectExtrusionIsland)
1036 {
1037 // Do not extrude from point where all neighbouring
1038 // points are not grown
1039 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1040
1041 labelList islandPoint(pp.size(), -1);
1042 forAll(pp, faceI)
1043 {
1044 const face& f = pp.localFaces()[faceI];
1045
1046 forAll(f, fp)
1047 {
1048 if (extrudeStatus[f[fp]] != snappyLayerDriver::NOEXTRUDE)
1049 {
1050 if (islandPoint[faceI] == -1)
1051 {
1052 // First point to extrude
1053 islandPoint[faceI] = f[fp];
1054 }
1055 else if (islandPoint[faceI] != -2)
1056 {
1057 // Second or more point to extrude
1058 islandPoint[faceI] = -2;
1059 }
1060 }
1061 }
1062 }
1063
1064 // islandPoint:
1065 // -1 : no point extruded on face
1066 // -2 : >= 2 points extruded on face
1067 // >=0: label of point extruded
1068
1069 // Check all surrounding faces that I am the islandPoint
1070 forAll(pointFaces, patchPointI)
1071 {
1072 if (extrudeStatus[patchPointI] != snappyLayerDriver::NOEXTRUDE)
1073 {
1074 const labelList& pFaces = pointFaces[patchPointI];
1075
1076 forAll(pFaces, i)
1077 {
1078 label faceI = pFaces[i];
1079 if (islandPoint[faceI] != patchPointI)
1080 {
1081 keptPoints[patchPointI] = true;
1082 break;
1083 }
1084 }
1085 }
1086 }
1087 }
1088 else
1089 {
1090 // Do not extrude from point where all neighbouring
1091 // faces are not grown
1092 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1093
1094 boolList extrudedFaces(pp.size(), true);
1095 forAll(pp.localFaces(), faceI)
1096 {
1097 const face& f = pp.localFaces()[faceI];
1098 forAll(f, fp)
1099 {
1100 if (extrudeStatus[f[fp]] == snappyLayerDriver::NOEXTRUDE)
1101 {
1102 extrudedFaces[faceI] = false;
1103 break;
1104 }
1105 }
1106 }
1107
1108 const labelListList& pointFaces = pp.pointFaces();
1109
1110 forAll(keptPoints, patchPointI)
1111 {
1112 const labelList& pFaces = pointFaces[patchPointI];
1113
1114 forAll(pFaces, i)
1115 {
1116 label faceI = pFaces[i];
1117 if (extrudedFaces[faceI])
1118 {
1119 keptPoints[patchPointI] = true;
1120 break;
1121 }
1122 }
1123 }
1124 }
1125
1126
1128 (
1129 mesh(),
1130 meshPoints,
1131 keptPoints,
1132 orEqOp<bool>(),
1133 false // null value
1134 );
1135
1136 label nChanged = 0;
1137
1138 forAll(keptPoints, patchPointI)
1139 {
1140 if (!keptPoints[patchPointI])
1141 {
1142 if (unmarkExtrusion(patchPointI, patchDisp, extrudeStatus))
1143 {
1144 nPointCounter++;
1145 nChanged++;
1146 }
1147 }
1148 }
1149
1150
1151 if (!returnReduceOr(nChanged))
1152 {
1153 break;
1154 }
1155 }
1156
1157 const edgeList& edges = pp.edges();
1158
1159
1160 // Count number of mesh edges using a point
1161 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1162
1163 labelList isolatedPoint(pp.nPoints(), Zero);
1164
1165 forAll(edges, edgeI)
1166 {
1167 if (isPatchMasterEdge[edgeI])
1168 {
1169 const edge& e = edges[edgeI];
1170
1171 label v0 = e[0];
1172 label v1 = e[1];
1173
1174 if (extrudeStatus[v1] != snappyLayerDriver::NOEXTRUDE)
1175 {
1176 isolatedPoint[v0] += 1;
1177 }
1178 if (extrudeStatus[v0] != snappyLayerDriver::NOEXTRUDE)
1179 {
1180 isolatedPoint[v1] += 1;
1181 }
1182 }
1183 }
1184
1186 (
1187 mesh(),
1188 meshPoints,
1189 isolatedPoint,
1191 label(0) // null value
1192 );
1193
1194 // stop layer growth on isolated faces
1195 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1196 forAll(pp, faceI)
1197 {
1198 const face& f = pp.localFaces()[faceI];
1199 bool failed = false;
1200 forAll(f, fp)
1201 {
1202 if (isolatedPoint[f[fp]] > 2)
1203 {
1204 failed = true;
1205 break;
1206 }
1207 }
1208 bool allPointsExtruded = true;
1209 if (!failed)
1210 {
1211 forAll(f, fp)
1212 {
1213 if (extrudeStatus[f[fp]] == snappyLayerDriver::NOEXTRUDE)
1214 {
1215 allPointsExtruded = false;
1216 break;
1217 }
1218 }
1219
1220 if (allPointsExtruded)
1221 {
1222 forAll(f, fp)
1223 {
1224 if
1225 (
1226 unmarkExtrusion
1227 (
1228 f[fp],
1229 patchDisp,
1230 extrudeStatus
1231 )
1232 )
1233 {
1234 nPointCounter++;
1235 }
1236 }
1237 }
1238 }
1239 }
1240
1241 Info<< typeName
1242 << " : Number of isolated points extrusion stopped : "
1243 << returnReduce(nPointCounter, sumOp<label>()) << endl;
1244}
1245
1246
1247// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1248
1249Foam::medialAxisMeshMover::medialAxisMeshMover
1250(
1251 const dictionary& dict,
1252 const List<labelPair>& baffles,
1253 pointVectorField& pointDisplacement,
1254 const bool dryRun
1255)
1256:
1257 externalDisplacementMeshMover(dict, baffles, pointDisplacement, dryRun),
1259 adaptPatchPtr_(getPatch(mesh(), adaptPatchIDs_)),
1260 scale_
1261 (
1262 IOobject
1263 (
1264 "scale",
1265 pointDisplacement.time().timeName(),
1266 pointDisplacement.db(),
1267 IOobject::NO_READ,
1268 IOobject::AUTO_WRITE
1269 ),
1270 pMesh(),
1271 dimensionedScalar("scale", dimless, 1.0)
1272 ),
1273 oldPoints_(mesh().points()),
1274 meshMover_
1275 (
1276 const_cast<polyMesh&>(mesh()),
1277 const_cast<pointMesh&>(pMesh()),
1278 adaptPatchPtr_(),
1280 scale_,
1281 oldPoints_,
1282 adaptPatchIDs_,
1283 dict,
1284 dryRun
1285 ),
1286 fieldSmoother_(mesh()),
1287 dispVec_
1288 (
1289 IOobject
1290 (
1291 "dispVec",
1292 pointDisplacement.time().timeName(),
1293 pointDisplacement.db(),
1294 IOobject::NO_READ,
1295 IOobject::NO_WRITE,
1296 IOobject::NO_REGISTER
1297 ),
1298 pMesh(),
1300 ),
1301 medialRatio_
1302 (
1303 IOobject
1304 (
1305 "medialRatio",
1306 pointDisplacement.time().timeName(),
1307 pointDisplacement.db(),
1308 IOobject::NO_READ,
1309 IOobject::NO_WRITE,
1310 IOobject::NO_REGISTER
1311 ),
1312 pMesh(),
1314 ),
1315 medialDist_
1316 (
1317 IOobject
1318 (
1319 "pointMedialDist",
1320 pointDisplacement.time().timeName(),
1321 pointDisplacement.db(),
1322 IOobject::NO_READ,
1323 IOobject::NO_WRITE,
1324 IOobject::NO_REGISTER
1325 ),
1326 pMesh(),
1328 ),
1329 medialVec_
1330 (
1331 IOobject
1332 (
1333 "medialVec",
1334 pointDisplacement.time().timeName(),
1335 pointDisplacement.db(),
1336 IOobject::NO_READ,
1337 IOobject::NO_WRITE,
1338 IOobject::NO_REGISTER
1339 ),
1340 pMesh(),
1342 )
1343{
1344 update(dict);
1345}
1346
1347
1348// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1349
1351{}
1352
1353
1354// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1355
1356void Foam::medialAxisMeshMover::calculateDisplacement
1357(
1358 const dictionary& coeffDict,
1359 const scalarField& minThickness,
1361 pointField& patchDisp
1362)
1363{
1364 Info<< typeName << " : Smoothing using Medial Axis ..." << endl;
1365
1366 const indirectPrimitivePatch& pp = *adaptPatchPtr_;
1367 const labelList& meshPoints = pp.meshPoints();
1368
1369
1370 // Read settings
1371 // ~~~~~~~~~~~~~
1372
1373 //- (lambda-mu) smoothing of internal displacement
1374 const label nSmoothDisplacement =
1375 coeffDict.getOrDefault("nSmoothDisplacement", 0);
1376
1377 //- Layer thickness too big
1378 const scalar maxThicknessToMedialRatio =
1379 coeffDict.get<scalar>("maxThicknessToMedialRatio");
1380
1381 //- Feature angle when to stop adding layers
1382 const scalar featureAngle = coeffDict.get<scalar>("featureAngle");
1383
1384 //- Stop layer growth where mesh wraps around sharp edge
1385 scalar layerTerminationAngle = coeffDict.getOrDefault<scalar>
1386 (
1387 "layerTerminationAngle",
1388 0.5*featureAngle
1389 );
1390 scalar minCosLayerTermination = Foam::cos(degToRad(layerTerminationAngle));
1391
1392 //- Smoothing wanted patch thickness
1393 const label nSmoothPatchThickness =
1394 coeffDict.get<label>("nSmoothThickness");
1395
1396 //- Number of edges walking out
1397 const label nMedialAxisIter = coeffDict.getOrDefault<label>
1398 (
1399 "nMedialAxisIter",
1401 );
1402
1403 //- Use strict extrusionIsland detection
1404 const bool detectExtrusionIsland = coeffDict.getOrDefault
1405 (
1406 "detectExtrusionIsland",
1407 false
1408 );
1409
1410
1411 // Precalulate master points/edge (only relevant for shared points/edges)
1412 const bitSet isMeshMasterPoint(syncTools::getMasterPoints(mesh()));
1413 const bitSet isMeshMasterEdge(syncTools::getMasterEdges(mesh()));
1414 // Precalculate meshEdge per pp edge
1415 const labelList meshEdges
1416 (
1417 pp.meshEdges
1418 (
1419 mesh().edges(),
1420 mesh().pointEdges()
1421 )
1422 );
1423
1424 // Precalulate (patch) master point/edge
1425 const bitSet isPatchMasterPoint
1426 (
1428 (
1429 mesh(),
1430 meshPoints
1431 )
1432 );
1433 const bitSet isPatchMasterEdge
1434 (
1436 (
1437 mesh(),
1438 meshEdges
1439 )
1440 );
1441
1442
1443 scalarField thickness(mag(patchDisp));
1444
1445 forAll(thickness, patchPointI)
1446 {
1447 if (extrudeStatus[patchPointI] == snappyLayerDriver::NOEXTRUDE)
1448 {
1449 thickness[patchPointI] = 0.0;
1450 }
1451 }
1452
1453 label numThicknessRatioExclude = 0;
1454
1455 // reduce thickness where thickness/medial axis distance large
1456 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1457
1459 if (debug)
1460 {
1461 str.reset
1462 (
1463 new OBJstream
1464 (
1465 mesh().time().path()
1466 / "thicknessRatioExcludePoints_"
1467 + mesh().time().timeName()
1468 + ".obj"
1469 )
1470 );
1471 Info<< typeName
1472 << " : Writing points with too large an extrusion distance to "
1473 << str().name() << endl;
1474 }
1475
1476 autoPtr<OBJstream> medialVecStr;
1477 if (debug)
1478 {
1479 medialVecStr.reset
1480 (
1481 new OBJstream
1482 (
1483 mesh().time().path()
1484 / "thicknessRatioExcludeMedialVec_"
1485 + mesh().time().timeName()
1486 + ".obj"
1487 )
1488 );
1489 Info<< typeName
1490 << " : Writing medial axis vectors on points with too large"
1491 << " an extrusion distance to " << medialVecStr().name() << endl;
1492 }
1493
1494 forAll(meshPoints, patchPointI)
1495 {
1496 if (extrudeStatus[patchPointI] != snappyLayerDriver::NOEXTRUDE)
1497 {
1498 label pointI = meshPoints[patchPointI];
1499
1500 //- Option 1: look only at extrusion thickness v.s. distance
1501 // to nearest (medial axis or static) point.
1502 scalar mDist = medialDist_[pointI];
1503 scalar thicknessRatio = thickness[patchPointI]/(mDist+VSMALL);
1504
1505 //- Option 2: Look at component in the direction
1506 // of nearest (medial axis or static) point.
1507 const vector n = normalised(patchDisp[patchPointI]);
1508 const vector mVec =
1510 (
1511 medialVec_[pointI] - mesh().points()[pointI]
1512 );
1513
1514 thicknessRatio *= (n & mVec);
1515
1516 if (thicknessRatio > maxThicknessToMedialRatio)
1517 {
1518 // Truncate thickness.
1519 if (debug&2)
1520 {
1521 Pout<< "truncating displacement at "
1522 << mesh().points()[pointI]
1523 << " from " << thickness[patchPointI]
1524 << " to "
1525 << 0.5
1526 *(
1527 minThickness[patchPointI]
1528 +thickness[patchPointI]
1529 )
1530 << " medial direction:" << mVec
1531 << " extrusion direction:" << n
1532 << " with thicknessRatio:" << thicknessRatio
1533 << endl;
1534 }
1535
1536 thickness[patchPointI] =
1537 0.5*(minThickness[patchPointI]+thickness[patchPointI]);
1538
1539 patchDisp[patchPointI] = thickness[patchPointI]*n;
1540
1541 if (isPatchMasterPoint[patchPointI])
1542 {
1543 numThicknessRatioExclude++;
1544 }
1545
1546 if (str)
1547 {
1548 const point& pt = mesh().points()[pointI];
1549 str().writeLine(pt, pt+patchDisp[patchPointI]);
1550 }
1551 if (medialVecStr)
1552 {
1553 const point& pt = mesh().points()[pointI];
1554 medialVecStr().writeLine(pt, medialVec_[pointI]);
1555 }
1556 }
1557 }
1558 }
1559
1560 Info<< typeName << " : Reducing layer thickness at "
1561 << returnReduce(numThicknessRatioExclude, sumOp<label>())
1562 << " nodes where thickness to medial axis distance is large " << endl;
1563
1564
1565 // find points where layer growth isolated to a lone point, edge or face
1566
1567 findIsolatedRegions
1568 (
1569 minCosLayerTermination,
1570 detectExtrusionIsland,
1571
1572 isPatchMasterPoint,
1573 isPatchMasterEdge,
1574 meshEdges,
1575 minThickness,
1576
1577 extrudeStatus,
1578 patchDisp
1579 );
1580
1581 // Update thickness for changed extrusion
1582 forAll(thickness, patchPointI)
1583 {
1584 if (extrudeStatus[patchPointI] == snappyLayerDriver::NOEXTRUDE)
1585 {
1586 thickness[patchPointI] = 0.0;
1587 }
1588 }
1589
1590
1591 // Smooth layer thickness on moving patch. Since some locations will have
1592 // disabled the extrusion this might cause big jumps in wanted displacement
1593 // for neighbouring patch points. So smooth the wanted displacement
1594 // before actually trying to move the mesh.
1595 fieldSmoother_.minSmoothField
1596 (
1597 nSmoothPatchThickness,
1598 isPatchMasterPoint,
1599 isPatchMasterEdge,
1600 pp,
1601 minThickness,
1602 thickness
1603 );
1604
1605
1606 // Dummy additional info for PointEdgeWave
1607 int dummyTrackData = 0;
1608
1609 List<PointData<scalar>> pointWallDist(mesh().nPoints());
1610
1611 const pointField& points = mesh().points();
1612 // 1. Calculate distance to points where displacement is specified.
1613 // This wave is used to transport layer thickness
1614 {
1615 // Distance to wall and medial axis on edges.
1616 List<PointData<scalar>> edgeWallDist(mesh().nEdges());
1617 labelList wallPoints(meshPoints.size());
1618
1619 // Seed data.
1620 List<PointData<scalar>> wallInfo(meshPoints.size());
1621
1622 forAll(meshPoints, patchPointI)
1623 {
1624 label pointI = meshPoints[patchPointI];
1625 wallPoints[patchPointI] = pointI;
1626 wallInfo[patchPointI] = PointData<scalar>
1627 (
1628 points[pointI],
1629 0.0,
1630 thickness[patchPointI] // transport layer thickness
1631 );
1632 }
1633
1634 // Do all calculations
1636 (
1637 mesh(),
1638 wallPoints,
1639 wallInfo,
1640 pointWallDist,
1641 edgeWallDist,
1642 0, // max iterations
1643 dummyTrackData
1644 );
1645 wallDistCalc.iterate(nMedialAxisIter);
1646 }
1647
1648
1649 // Calculate scaled displacement vector
1650 pointField& displacement = pointDisplacement_;
1651
1652 forAll(displacement, pointI)
1653 {
1654 if (!pointWallDist[pointI].valid(dummyTrackData))
1655 {
1656 displacement[pointI] = Zero;
1657 }
1658 else
1659 {
1660 // 1) displacement on nearest wall point, scaled by medialRatio
1661 // (wall distance / medial distance)
1662 // 2) pointWallDist[pointI].data() is layer thickness transported
1663 // from closest wall point.
1664 // 3) shrink in opposite direction of addedPoints
1665 displacement[pointI] =
1666 -medialRatio_[pointI]
1667 *pointWallDist[pointI].data()
1668 *dispVec_[pointI];
1669 }
1670 }
1671
1672
1673 // Smear displacement away from fixed values (medialRatio=0 or 1)
1674 if (nSmoothDisplacement > 0)
1675 {
1676 bitSet isToBeSmoothed(displacement.size(), false);
1677
1678 forAll(displacement, i)
1679 {
1680 if (medialRatio_[i] > SMALL && medialRatio_[i] < 1-SMALL)
1681 {
1682 isToBeSmoothed.set(i);
1683 }
1684 }
1685
1686 fieldSmoother_.smoothLambdaMuDisplacement
1687 (
1688 nSmoothDisplacement,
1689 isMeshMasterPoint,
1690 isMeshMasterEdge,
1691 isToBeSmoothed,
1692 displacement
1693 );
1694 }
1695
1696 if (str)
1697 {
1698 Info<< typeName
1699 << " : Written " << returnReduce(str().nVertices(), sumOp<label>())
1700 << " points with too large an extrusion distance to "
1701 << str().name() << endl;
1702 }
1703 if (medialVecStr)
1704 {
1705 Info<< typeName
1706 << " : Written "
1707 << returnReduce(medialVecStr().nVertices(), sumOp<label>())
1708 << " medial axis vectors on points with too large"
1709 << " an extrusion distance to " << medialVecStr().name() << endl;
1710 }
1711}
1712
1713
1714bool Foam::medialAxisMeshMover::shrinkMesh
1715(
1716 const dictionary& meshQualityDict,
1717 const label nAllowableErrors,
1718 labelList& checkFaces
1719)
1720{
1721 //- Number of attempts shrinking the mesh
1722 const label nSnap = meshQualityDict.get<label>("nRelaxIter");
1723
1724
1725 // Make sure displacement boundary conditions is uptodate with
1726 // internal field
1727 meshMover_.setDisplacementPatchFields();
1728
1729 Info<< typeName << " : Moving mesh ..." << endl;
1730 scalar oldErrorReduction = -1;
1731
1732 bool meshOk = false;
1733
1734 for (label iter = 0; iter < 2*nSnap ; iter++)
1735 {
1736 Info<< typeName
1737 << " : Iteration " << iter << endl;
1738 if (iter == nSnap)
1739 {
1740 Info<< typeName
1741 << " : Displacement scaling for error reduction set to 0."
1742 << endl;
1743 oldErrorReduction = meshMover_.setErrorReduction(0.0);
1744 }
1745
1746 if
1747 (
1748 meshMover_.scaleMesh
1749 (
1750 checkFaces,
1751 baffles_,
1752 meshMover_.paramDict(),
1753 meshQualityDict,
1754 true,
1755 nAllowableErrors
1756 )
1757 )
1758 {
1759 Info<< typeName << " : Successfully moved mesh" << endl;
1760 meshOk = true;
1761 break;
1762 }
1763 }
1764
1765 if (oldErrorReduction >= 0)
1766 {
1767 meshMover_.setErrorReduction(oldErrorReduction);
1768 }
1769
1770 Info<< typeName << " : Finished moving mesh ..." << endl;
1771
1772 return meshOk;
1773}
1774
1775
1777(
1778 const dictionary& moveDict,
1779 const label nAllowableErrors,
1780 labelList& checkFaces
1781)
1782{
1783 // Read a few settings
1784 // ~~~~~~~~~~~~~~~~~~~
1785
1786 //- Name of field specifying min thickness
1787 const word minThicknessName = moveDict.get<word>("minThicknessName");
1788
1789
1790 // Extract out patch-wise displacement
1791 const indirectPrimitivePatch& pp = adaptPatchPtr_();
1792
1793 scalarField zeroMinThickness;
1794 if (minThicknessName == "none")
1795 {
1796 zeroMinThickness = scalarField(pp.nPoints(), Zero);
1797 }
1798 const scalarField& minThickness =
1799 (
1800 (minThicknessName == "none")
1801 ? zeroMinThickness
1802 : mesh().lookupObject<scalarField>(minThicknessName)
1803 );
1804
1805
1806 pointField patchDisp
1808 pointDisplacement_.internalField(),
1809 pp.meshPoints()
1810 );
1811
1813 (
1814 pp.nPoints(),
1816 );
1817 forAll(extrudeStatus, pointI)
1818 {
1819 if (mag(patchDisp[pointI]) <= minThickness[pointI]+SMALL)
1820 {
1821 extrudeStatus[pointI] = snappyLayerDriver::NOEXTRUDE;
1822 }
1823 }
1824
1825
1826 // Solve displacement
1827 calculateDisplacement(moveDict, minThickness, extrudeStatus, patchDisp);
1828
1829 //- Move mesh according to calculated displacement
1830 return shrinkMesh
1831 (
1832 moveDict, // meshQualityDict,
1833 nAllowableErrors, // nAllowableErrors
1834 checkFaces
1835 );
1836}
1837
1838
1840{
1842
1843 // Update motionSmoother for new geometry (moves adaptPatchPtr_)
1844 meshMover_.movePoints();
1845
1846 // Assume current mesh location is correct (reset oldPoints, scale)
1847 meshMover_.correct();
1848}
1849
1850
1851// ************************************************************************* //
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
label size() const noexcept
The number of elements in the list.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
An OFstream that keeps track of vertices and provides convenience output methods for OBJ files.
Definition OBJstream.H:58
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &, const bitSet &flipMap=bitSet::null())
Return parallel consistent point normals for patches using mesh points.
Variant of pointEdgePoint with some transported additional data. Templated on the transported data ty...
Definition PointData.H:61
Wave propagation of information through grid. Every iteration information goes through one layer of e...
label nEdges() const
Number of edges in patch.
label nPoints() const
Number of points supporting patch faces.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
labelList meshEdges(const edgeList &allEdges, const labelListList &cellEdges, const labelList &faceCells) const
Return labels of patch edges in the global edge list using cell addressing.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
const labelListList & pointFaces() const
Return point-face addressing.
const labelListList & edgeFaces() const
Return edge-face addressing.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition UListI.H:274
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static const Form max
static const Form rootMax
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition autoPtrI.H:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
Virtual base class for mesh movers with externally provided displacement field giving the boundary co...
static labelList getFixedValueBCs(const pointVectorField &)
Extract fixed-value patchfields.
static autoPtr< indirectPrimitivePatch > getPatch(const polyMesh &, const labelList &)
Construct patch on selected patches.
virtual void movePoints(const pointField &)
Update local data for geometry changes.
pointVectorField & pointDisplacement()
Return reference to the point motion displacement field.
pointVectorField & pointDisplacement_
Reference to point motion field.
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
label nTotalPoints() const noexcept
Total global number of mesh points. Not compensated for duplicate points!
Mesh motion solver that uses a medial axis algorithm to work out a fraction between the (nearest poin...
virtual bool move(const dictionary &, const label nAllowableErrors, labelList &checkFaces)
Move mesh using current pointDisplacement boundary values.
virtual void movePoints(const pointField &)
Update local data for geometry changes.
static bitSet getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
static Type get(const dictionary &dict, const word &keyword, const bool noExit, enum keyType::option matchOpt=keyType::REGEX, const Type &deflt=Zero)
Wrapper around dictionary::get which does not exit.
static bitSet getMasterEdges(const polyMesh &mesh, const labelList &meshEdges)
Determine master edge for subset of edges. If coupled.
const Type & lookupObject(const word &name, const bool recursive=false) const
Lookup and return const reference to the object of the given Type. Fatal if not found or the wrong ty...
Holds information regarding nearest wall point. Used in PointEdgeWave. (so not standard FaceCellWave)...
Mesh representing a set of points created from polyMesh.
Definition pointMesh.H:49
A set of point labels.
Definition pointSet.H:50
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
@ NOEXTRUDE
Do not extrude. No layers added.
static bitSet getMasterPoints(const polyMesh &mesh)
Get per point whether it is uncoupled or a master of a coupled set of points.
Definition syncTools.C:61
static bitSet getMasterEdges(const polyMesh &mesh)
Get per edge whether it is uncoupled or a master of a coupled set of edges.
Definition syncTools.C:90
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
For use with FaceCellWave. Determines topological distance to starting faces.
Definition wallPoints.H:60
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
volScalarField & p
const volScalarField & p0
Definition EEqn.H:36
mesh update()
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
const pointField & points
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
FaceCellWave< wallPoints, wallPoints::trackData > wallDistCalc(mesh_, changedFaces, faceDist, allFaceInfo, allCellInfo, 0, td)
word timeName
Definition getTimeIndex.H:3
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
const dimensionSet dimless
Dimensionless.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
dimensionedSymmTensor sqr(const dimensionedVector &dv)
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition POSIX.C:616
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
messageStream Info
Information stream (stdout output on master, null elsewhere).
GeometricField< vector, pointPatchField, pointMesh > pointVectorField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition Ostream.H:490
const word GlobalIOList< Tuple2< scalar, vector > >::typeName("scalarVectorTable")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
Ostream & indent(Ostream &os)
Indent stream.
Definition Ostream.H:481
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
dimensionedScalar sqrt(const dimensionedScalar &ds)
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
constexpr scalar radToDeg() noexcept
Multiplication factor for radians to degrees conversion.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Field< vector > vectorField
Specialisation of Field<T> for vector.
pointPatchField< vector > pointPatchVectorField
vector point
Point is a vector.
Definition point.H:37
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Vector< scalar > vector
Definition vector.H:57
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition Ostream.H:499
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar cos(const dimensionedScalar &ds)
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
dimensionedScalar acos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};constexpr label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< DynamicList< face > > pFaces[nBCs]
labelList f(nPoints)
dictionary dict
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
List helper to append y elements onto the end of x.
Definition ListOps.H:712
Unit conversion functions.