Loading...
Searching...
No Matches
controlMeshRefinement.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) 2013-2015 OpenFOAM Foundation
9 Copyright (C) 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
31#include "OFstream.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35namespace Foam
36{
38}
39
40// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
41
42
43// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44
45Foam::scalar Foam::controlMeshRefinement::calcFirstDerivative
46(
47 const Foam::point& a,
48 const scalar& cellSizeA,
49 const Foam::point& b,
50 const scalar& cellSizeB
51) const
52{
53 return (cellSizeA - cellSizeB)/mag(a - b);
54}
55
56
57//Foam::scalar Foam::controlMeshRefinement::calcSecondDerivative
58//(
59// const Foam::point& a,
60// const scalar& cellSizeA,
61// const Foam::point& midPoint,
62// const scalar& cellSizeMid,
63// const Foam::point& b,
64// const scalar& cellSizeB
65//) const
66//{
67// return (cellSizeA - 2*cellSizeMid + cellSizeB)/magSqr((a - b)/2);
68//}
69
70
71bool Foam::controlMeshRefinement::detectEdge
72(
73 const Foam::point& startPt,
74 const Foam::point& endPt,
75 pointHit& pointFound,
76 const scalar tolSqr,
77 const scalar secondDerivTolSqr
78) const
79{
80 Foam::point a(startPt);
81 Foam::point b(endPt);
82
83 Foam::point midPoint = (a + b)/2.0;
84
85 //label nIterations = 0;
86
87 while (true)
88 {
89 //++nIterations;
90
91 if
92 (
93 magSqr(a - b) < tolSqr
94 )
95 {
96 pointFound.hitPoint(midPoint);
97 return true;
98 }
99
100 // Split into two regions
101
102 scalar cellSizeA = sizeControls_.cellSize(a);
103 scalar cellSizeB = sizeControls_.cellSize(b);
104
105// if (magSqr(cellSizeA - cellSizeB) < 1e-6)
106// {
107// return false;
108// }
109
110 scalar cellSizeMid = sizeControls_.cellSize(midPoint);
111
112 // Region 1
113 Foam::point midPoint1 = (a + midPoint)/2.0;
114 const scalar cellSizeMid1 = sizeControls_.cellSize(midPoint1);
115
116// scalar firstDerivative1 =
117// calcFirstDerivative(cellSizeA, cellSizeMid);
118
119 scalar secondDerivative1 =
120 calcSecondDerivative
121 (
122 a,
123 cellSizeA,
124 midPoint1,
125 cellSizeMid1,
126 midPoint,
127 cellSizeMid
128 );
129
130 // Region 2
131 Foam::point midPoint2 = (midPoint + b)/2.0;
132 const scalar cellSizeMid2 = sizeControls_.cellSize(midPoint2);
133
134// scalar firstDerivative2 =
135// calcFirstDerivative(f, cellSizeMid, cellSizeB);
136
137 scalar secondDerivative2 =
138 calcSecondDerivative
139 (
140 midPoint,
141 cellSizeMid,
142 midPoint2,
143 cellSizeMid2,
144 b,
145 cellSizeB
146 );
147
148 // Neither region appears to have an inflection
149 // To be sure should use higher order derivatives
150 if
151 (
152 magSqr(secondDerivative1) < secondDerivTolSqr
153 && magSqr(secondDerivative2) < secondDerivTolSqr
154 )
155 {
156 return false;
157 }
158
159 // Pick region with greatest second derivative
160 if (magSqr(secondDerivative1) > magSqr(secondDerivative2))
161 {
162 b = midPoint;
163 midPoint = midPoint1;
164 }
165 else
166 {
167 a = midPoint;
168 midPoint = midPoint2;
169 }
170 }
171}
172
173
174Foam::pointHit Foam::controlMeshRefinement::findDiscontinuities
175(
176 const linePointRef& l
177) const
178{
180
181 const scalar tolSqr = sqr(1e-3);
182 const scalar secondDerivTolSqr = sqr(1e-3);
183
184 detectEdge
185 (
186 l.start(),
187 l.end(),
188 p,
189 tolSqr,
190 secondDerivTolSqr
191 );
192
193 return p;
194}
195
196
197// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
198
199
200// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
201
202Foam::controlMeshRefinement::controlMeshRefinement
203(
204 cellShapeControl& shapeController
205)
206:
207 shapeController_(shapeController),
208 mesh_(shapeController.shapeControlMesh()),
209 sizeControls_(shapeController.sizeAndAlignment()),
210 geometryToConformTo_(sizeControls_.geometryToConformTo())
211{}
212
213
214// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
215
217{}
218
219
220// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
221
223(
224 const autoPtr<backgroundMeshDecomposition>& decomposition
225)
226{
227 if (shapeController_.shapeControlMesh().vertexCount() > 0)
228 {
229 // Mesh already populated.
230 Info<< "Cell size and alignment mesh already populated." << endl;
231 return;
232 }
233
234 autoPtr<boundBox> overallBoundBox;
235
236 // Need to pass in the background mesh decomposition so that can test if
237 // a point to insert is on the processor.
238 if (Pstream::parRun())
239 {
240// overallBoundBox.set(new boundBox(decomposition().procBounds()));
241 }
242 else
243 {
244// overallBoundBox.set
245// (
246// new boundBox(geometryToConformTo_.geometry().bounds())
247// );
248//
249// mesh_.insertBoundingPoints
250// (
251// overallBoundBox(),
252// sizeControls_
253// );
254 }
255
256 Map<label> priorityMap;
257
258 const PtrList<cellSizeAndAlignmentControl>& controlFunctions =
259 sizeControls_.controlFunctions();
260
261 forAll(controlFunctions, fI)
262 {
263 const cellSizeAndAlignmentControl& controlFunction =
264 controlFunctions[fI];
265
266 const Switch forceInsertion =
267 controlFunction.forceInitialPointInsertion();
268
269 Info<< "Inserting points from " << controlFunction.name()
270 << " (" << controlFunction.type() << ")" << endl;
271 Info<< " Force insertion is " << forceInsertion.c_str() << endl;
272
274 scalarField sizes;
275 triadField alignments;
276
277 controlFunction.initialVertices(pts, sizes, alignments);
278
279 Info<< " Got initial vertices list of size " << pts.size() << endl;
280
282
283 // Clip the minimum size
284 for (label vI = 0; vI < pts.size(); ++vI)
285 {
287
288 label maxPriority = -1;
289 scalar size = sizeControls_.cellSize(pts[vI], maxPriority);
290
291 if (maxPriority > controlFunction.maxPriority())
292 {
293 vertices[vI].targetCellSize() = max
294 (
295 size,
296 shapeController_.minimumCellSize()
297 );
298 }
299// else if (maxPriority == controlFunction.maxPriority())
300// {
301// vertices[vI].targetCellSize() = max
302// (
303// min(sizes[vI], size),
304// shapeController_.minimumCellSize()
305// );
306// }
307 else
308 {
309 vertices[vI].targetCellSize() = max
310 (
311 sizes[vI],
312 shapeController_.minimumCellSize()
313 );
314 }
315
316 vertices[vI].alignment() = alignments[vI];
317 }
318
319 Info<< " Clipped minimum size" << endl;
320
321 pts.clear();
322 sizes.clear();
323 alignments.clear();
324
325 bitSet keepVertex(vertices.size(), true);
326
327 forAll(vertices, vI)
328 {
329 bool keep = true;
330
332
333 if (Pstream::parRun())
334 {
335 keep = decomposition().positionOnThisProcessor(pt);
336 }
337
338 if (keep && geometryToConformTo_.wellOutside(pt, SMALL))
339 {
340 keep = false;
341 }
342
343 if (!keep)
344 {
345 keepVertex.unset(vI);
346 }
347 }
348
349 inplaceSubset(keepVertex, vertices);
350
351 const label preInsertedSize = mesh_.number_of_vertices();
352
353 Info<< " Check sizes" << endl;
354
355 forAll(vertices, vI)
356 {
357 bool insertPoint = false;
358
360
361 if
362 (
363 mesh_.dimension() < 3
364 || mesh_.is_infinite
365 (
366 mesh_.locate(vertices[vI].point())
367 )
368 )
369 {
370 insertPoint = true;
371 }
372
373 const scalar interpolatedCellSize = shapeController_.cellSize(pt);
374 const triad interpolatedAlignment =
375 shapeController_.cellAlignment(pt);
376 const scalar calculatedCellSize = vertices[vI].targetCellSize();
377 const triad calculatedAlignment = vertices[vI].alignment();
378
379 if (debug)
380 {
381 Info<< "Point = " << pt << nl
382 << " Size(interp) = " << interpolatedCellSize << nl
383 << " Size(calc) = " << calculatedCellSize << nl
384 << " Align(interp) = " << interpolatedAlignment << nl
385 << " Align(calc) = " << calculatedAlignment << nl
386 << endl;
387 }
388
389 const scalar sizeDiff =
390 mag(interpolatedCellSize - calculatedCellSize);
391 const scalar alignmentDiff =
392 diff(interpolatedAlignment, calculatedAlignment);
393
394 if (debug)
395 {
396 Info<< " size difference = " << sizeDiff << nl
397 << ", alignment difference = " << alignmentDiff << endl;
398 }
399
400 // TODO: Also need to base it on the alignments
401 if
402 (
403 sizeDiff/interpolatedCellSize > 0.1
404 || alignmentDiff > 0.15
405 )
406 {
407 insertPoint = true;
408 }
409
410 if (forceInsertion || insertPoint)
411 {
412 const label oldSize = mesh_.vertexCount();
413
414 cellShapeControlMesh::Vertex_handle insertedVert = mesh_.insert
415 (
416 pt,
417 calculatedCellSize,
418 vertices[vI].alignment(),
420 );
421
422 if (oldSize == mesh_.vertexCount() - 1)
423 {
424 priorityMap.insert
425 (
426 insertedVert->index(),
427 controlFunction.maxPriority()
428 );
429 }
430 }
431 }
432
433 //mesh_.rangeInsertWithInfo(vertices.begin(), vertices.end());
434
435 Info<< " Inserted "
436 << returnReduce
437 (
438 label(mesh_.number_of_vertices()) - preInsertedSize,
440 )
441 << "/" << returnReduce(vertices.size(), sumOp<label>())
442 << endl;
443 }
444
445
446
447 forAll(controlFunctions, fI)
448 {
449 const cellSizeAndAlignmentControl& controlFunction =
450 controlFunctions[fI];
451
452 const Switch forceInsertion =
453 controlFunction.forceInitialPointInsertion();
454
455 Info<< "Inserting points from " << controlFunction.name()
456 << " (" << controlFunction.type() << ")" << endl;
457 Info<< " Force insertion is " << forceInsertion.c_str() << endl;
458
460 DynamicList<scalar> extraSizes;
461
462 controlFunction.cellSizeFunctionVertices(extraPts, extraSizes);
463
464 List<Vb> vertices(extraPts.size());
465
466 // Clip the minimum size
467 for (label vI = 0; vI < extraPts.size(); ++vI)
468 {
469 vertices[vI] = Vb(extraPts[vI], Vb::vtUnassigned);
470
471 label maxPriority = -1;
472 scalar size = sizeControls_.cellSize(extraPts[vI], maxPriority);
473
474 if (maxPriority > controlFunction.maxPriority())
475 {
476 vertices[vI].targetCellSize() = max
477 (
478 size,
479 shapeController_.minimumCellSize()
480 );
481 }
482 else if (maxPriority == controlFunction.maxPriority())
483 {
484 vertices[vI].targetCellSize() = max
485 (
486 min(extraSizes[vI], size),
487 shapeController_.minimumCellSize()
488 );
489 }
490 else
491 {
492 vertices[vI].targetCellSize() = max
493 (
494 extraSizes[vI],
495 shapeController_.minimumCellSize()
496 );
497 }
498 }
499
500 bitSet keepVertex(vertices.size(), true);
501
502 forAll(vertices, vI)
503 {
504 bool keep = true;
505
507
508 if (Pstream::parRun())
509 {
510 keep = decomposition().positionOnThisProcessor(pt);
511 }
512
513 if (keep && geometryToConformTo_.wellOutside(pt, SMALL))
514 {
515 keep = false;
516 }
517
518 if (!keep)
519 {
520 keepVertex.unset(vI);
521 }
522 }
523
524 inplaceSubset(keepVertex, vertices);
525
526 const label preInsertedSize = mesh_.number_of_vertices();
527
528 forAll(vertices, vI)
529 {
530 bool insertPoint = false;
531
533
534 if
535 (
536 mesh_.dimension() < 3
537 || mesh_.is_infinite
538 (
539 mesh_.locate(vertices[vI].point())
540 )
541 )
542 {
543 insertPoint = true;
544 }
545
546 const scalar interpolatedCellSize = shapeController_.cellSize(pt);
547 const scalar calculatedCellSize = vertices[vI].targetCellSize();
548
549 if (debug)
550 {
551 Info<< "Point = " << pt << nl
552 << " Size(interp) = " << interpolatedCellSize << nl
553 << " Size(calc) = " << calculatedCellSize << nl
554 << endl;
555 }
556
557 const scalar sizeDiff =
558 mag(interpolatedCellSize - calculatedCellSize);
559
560 if (debug)
561 {
562 Info<< " size difference = " << sizeDiff << endl;
563 }
564
565 // TODO: Also need to base it on the alignments
566 if (sizeDiff/interpolatedCellSize > 0.1)
567 {
568 insertPoint = true;
569 }
570
571 if (forceInsertion || insertPoint)
572 {
573 // Check the priority
574
575// cellShapeControlMesh::Cell_handle ch =
576// mesh_.locate(toPoint<cellShapeControlMesh::Point>(pt));
577
578// if (mesh_.is_infinite(ch))
579// {
580// continue;
581// }
582
583// const label newPtPriority = controlFunction.maxPriority();
584
585// label highestPriority = -1;
586// for (label cI = 0; cI < 4; ++cI)
587// {
588// if (mesh_.is_infinite(ch->vertex(cI)))
589// {
590// continue;
591// }
592
593// const label vertPriority =
594// priorityMap[ch->vertex(cI)->index()];
595
596// if (vertPriority > highestPriority)
597// {
598// highestPriority = vertPriority;
599// }
600// }
601
602// if (newPtPriority >= highestPriority)
603// {
604// const label oldSize = mesh_.vertexCount();
605//
606// cellShapeControlMesh::Vertex_handle insertedVert =
607 mesh_.insert
608 (
609 pt,
610 calculatedCellSize,
611 vertices[vI].alignment(),
613 );
614
615// if (oldSize == mesh_.vertexCount() - 1)
616// {
617// priorityMap.insert
618// (
619// insertedVert->index(),
620// newPtPriority
621// );
622// }
623// }
624 }
625 }
626
627 //mesh_.rangeInsertWithInfo(vertices.begin(), vertices.end());
628
629 Info<< " Inserted extra points "
630 << returnReduce
631 (
632 label(mesh_.number_of_vertices()) - preInsertedSize,
634 )
635 << "/" << returnReduce(vertices.size(), sumOp<label>())
636 << endl;
637 }
638
639 // Change cell size function of bounding points to be consistent
640 // with their nearest neighbours
641// for
642// (
643// CellSizeDelaunay::Finite_vertices_iterator vit =
644// mesh_.finite_vertices_begin();
645// vit != mesh_.finite_vertices_end();
646// ++vit
647// )
648// {
649// if (vit->uninitialised())
650// {
651// // Get its adjacent vertices
652// std::list<CellSizeDelaunay::Vertex_handle> adjacentVertices;
653//
654// mesh_.adjacent_vertices
655// (
656// vit,
657// std::back_inserter(adjacentVertices)
658// );
659//
660// scalar totalCellSize = 0;
661// label nVerts = 0;
662//
663// for
664// (
665// std::list<CellSizeDelaunay::Vertex_handle>::iterator avit =
666// adjacentVertices.begin();
667// avit != adjacentVertices.end();
668// ++avit
669// )
670// {
671// if (!(*avit)->uninitialised())
672// {
673// totalCellSize += (*avit)->targetCellSize();
674// nVerts++;
675// }
676// }
677//
678// Pout<< "Changing " << vit->info();
679//
680// vit->targetCellSize() = totalCellSize/nVerts;
681// vit->type() = Vb::vtInternalNearBoundary;
682//
683// Pout<< "to " << vit->info() << endl;
684// }
685// }
686}
687
688
690(
691 const autoPtr<backgroundMeshDecomposition>& decomposition
692)
693{
694 Info<< "Iterate over "
695 << returnReduce(label(mesh_.number_of_finite_edges()), sumOp<label>())
696 << " cell size mesh edges" << endl;
697
698 DynamicList<Vb> verts(mesh_.number_of_vertices());
699
700 label count = 0;
701
702 for
703 (
704 CellSizeDelaunay::Finite_edges_iterator eit =
705 mesh_.finite_edges_begin();
706 eit != mesh_.finite_edges_end();
707 ++eit
708 )
709 {
710 if (count % 10000 == 0)
711 {
712 Info<< count << " edges, inserted " << verts.size()
713 << " Time = " << mesh_.time().elapsedCpuTime()
714 << endl;
715 }
716 count++;
717
718 CellSizeDelaunay::Cell_handle c = eit->first;
719 CellSizeDelaunay::Vertex_handle vA = c->vertex(eit->second);
720 CellSizeDelaunay::Vertex_handle vB = c->vertex(eit->third);
721
722 if
723 (
724 mesh_.is_infinite(vA)
725 || mesh_.is_infinite(vB)
726 || (vA->referred() && vB->referred())
727 || (vA->referred() && (vA->procIndex() > vB->procIndex()))
728 || (vB->referred() && (vB->procIndex() > vA->procIndex()))
729 )
730 {
731 continue;
732 }
733
734 pointFromPoint ptA(topoint(vA->point()));
735 pointFromPoint ptB(topoint(vB->point()));
736
737 linePointRef l(ptA, ptB);
738
739 const pointHit hitPt = findDiscontinuities(l);
740
741 if (hitPt.hit())
742 {
743 const Foam::point& pt = hitPt.point();
744
745 if (!geometryToConformTo_.inside(pt))
746 {
747 continue;
748 }
749
750 if (Pstream::parRun())
751 {
752 if (!decomposition().positionOnThisProcessor(pt))
753 {
754 continue;
755 }
756 }
757
758 verts.append
759 (
760 Vb
761 (
762 toPoint(pt),
764 )
765 );
766
767 verts.last().targetCellSize() = sizeControls_.cellSize(pt);
768 verts.last().alignment() = triad::unset;
769 }
770 }
771
772 mesh_.insertPoints(verts, false);
773
774 return verts.size();
775}
776
777
778// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
779
780
781// * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * * //
782
783
784// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
785
786
787// ************************************************************************* //
CGAL::indexedVertex< K > Vb
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
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
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition Switch.H:81
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static const Form max
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
CellSizeDelaunay::Vertex_handle Vertex_handle
void initialMeshPopulation(const autoPtr< backgroundMeshDecomposition > &decomposition)
~controlMeshRefinement()
Destructor.
label refineMesh(const autoPtr< backgroundMeshDecomposition > &decomposition)
Mid-point interpolation (weighting factors = 0.5) scheme class.
Definition midPoint.H:54
Representation of a 3D Cartesian coordinate system as a Vector of row vectors.
Definition triad.H:63
static const triad unset
Definition triad.H:107
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
volScalarField & p
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
const dimensionedScalar c
Speed of light in a vacuum.
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
void inplaceSubset(const BoolListType &select, ListType &input, const bool invert=false)
Inplace extract elements of the input list when select is true.
PointHit< point > pointHit
A PointHit with a 3D point.
Definition pointHit.H:51
dimensionedSymmTensor sqr(const dimensionedVector &dv)
PointFrompoint toPoint(const Foam::point &p)
pointFromPoint topoint(const Point &P)
messageStream Info
Information stream (stdout output on master, null elsewhere).
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 & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition triad.C:373
line< point, const point & > linePointRef
A line using referred points.
Definition line.H:66
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
pointField vertices(const blockVertexList &bvl)
vector point
Point is a vector.
Definition point.H:37
Field< triad > triadField
Specialisation of Field<T> for triad.
vectorField pointField
pointField is a vectorField.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
Foam::point pointFromPoint
const pointField & pts
volScalarField & b
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299