Loading...
Searching...
No Matches
snappyVoxelMeshDriver.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) 2018-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
29#include "meshRefinement.H"
30#include "fvMesh.H"
31#include "Time.H"
33#include "refinementSurfaces.H"
34#include "refinementFeatures.H"
35#include "shellSurfaces.H"
36#include "searchableSurfaces.H"
38#include "IOmanip.H"
39
40// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41
42namespace Foam
43{
45} // End namespace Foam
46
47
48// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49
50void Foam::snappyVoxelMeshDriver::addNeighbours
51(
52 const labelList& cellLevel,
53 const labelVector& voxel,
54 const label voxeli,
55 DynamicList<labelVector>& front
56) const
57{
59
60 for (direction dir = 0; dir < 3; ++dir)
61 {
62 if (voxel[dir] > 0)
63 {
64 labelVector left(voxel);
65 left[dir] -= 1;
66 if (cellLevel[voxeli-off[dir]] == -1)
67 {
68 front.append(left);
69 }
70 }
71 if (voxel[dir] < n_[dir]-1)
72 {
73 labelVector right(voxel);
74 right[dir] += 1;
75 if (cellLevel[voxeli+off[dir]] == -1)
76 {
77 front.append(right);
78 }
79 }
80 }
81}
82
83
84// Insert cell level for all volume refinement
85Foam::tmp<Foam::pointField> Foam::snappyVoxelMeshDriver::voxelCentres() const
86{
87 tmp<pointField> tcc(tmp<pointField>::New(n_.x()*n_.y()*n_.z()));
88 pointField& cc = tcc.ref();
89
91 label voxeli = voxelMeshSearch::index(n_, labelVector(0, 0, 0));
92 for (label k = 0; k < n_[2]; k++)
93 {
94 const label start1 = voxeli;
95 for (label j = 0; j < n_[1]; j++)
96 {
97 const label start0 = voxeli;
98 for (label i = 0; i < n_[0]; i++)
99 {
100 const labelVector voxel(i, j, k);
101 cc[voxeli] = voxelMeshSearch::centre(bb_, n_, voxel);
102 voxeli += off[0];
103 }
104 voxeli = start0 + off[1];
105 }
106 voxeli = start1 + off[2];
107 }
108 return tcc;
109}
110
111
112void Foam::snappyVoxelMeshDriver::isInside
113(
114 const pointField& cc,
115 boolList& isVoxelInMesh
116) const
117{
118 const fvMesh& mesh = meshRefiner_.mesh();
119
120 isVoxelInMesh.setSize(cc.size());
121 if (isVoxelInMesh.size() < mesh.globalData().nTotalCells())
122 {
123 forAll(cc, voxeli)
124 {
125 const label celli = mesh.findCell
126 (
127 cc[voxeli],
129 );
130 isVoxelInMesh[voxeli] = (celli != -1);
131 }
133 }
134 else
135 {
136 for (label celli = 0; celli < mesh.nCells(); ++celli)
137 {
138 const boundBox cellBb(mesh.cellBb(celli));
139
141 (
142 isVoxelInMesh,
143 bb_,
144 n_,
145 cellBb,
146 1,
148 );
149 }
151 }
152}
153
154
155void Foam::snappyVoxelMeshDriver::markSurfaceRefinement
156(
157 labelList& voxelLevel,
158 labelList& globalRegion
159) const
160{
161 // Insert cell level for all refinementSurfaces
162
163 const refinementSurfaces& s = meshRefiner_.surfaces();
164 forAll(s.surfaces(), surfi)
165 {
166 label geomi = s.surfaces()[surfi];
167 const searchableSurface& geom = s.geometry()[geomi];
168 //Pout<< "Geometry:" << s.names()[surfi] << endl;
169 if (isA<triSurface>(geom))
170 {
171 const triSurface& ts = refCast<const triSurface>(geom);
172 const pointField& points = ts.points();
173
174 for (const labelledTri& tri : ts)
175 {
176 label regioni = tri.region();
177 label globalRegioni = s.regionOffset()[surfi]+regioni;
178 const boundBox triBb(tri.box(points));
179
180 // Fill cellLevel
181 label level = s.minLevel()[globalRegioni];
183 (
184 voxelLevel,
185 bb_,
186 n_,
187 triBb,
188 level,
190 );
192 (
193 globalRegion,
194 bb_,
195 n_,
196 triBb,
197 globalRegioni,
199 );
200 }
201 }
202 // else: maybe do intersection tests?
203 }
204}
205
206
207void Foam::snappyVoxelMeshDriver::findVoxels
208(
209 const labelList& voxelLevel,
210 const pointField& locationsOutsideMesh,
211 labelList& voxels
212) const
213{
214 voxels.setSize(locationsOutsideMesh.size());
215 voxels = -1;
216 forAll(locationsOutsideMesh, loci)
217 {
218 const point& pt = locationsOutsideMesh[loci];
219 label voxeli = voxelMeshSearch::index(bb_, n_, pt, false);
220
221 if (voxeli == -1 || voxelLevel[voxeli] == labelMax)
222 {
223 WarningInFunction << "Location outside mesh "
224 << pt << " is outside mesh with bounding box "
225 << bb_ << endl;
226 }
227 else
228 {
229 voxels[loci] = voxeli;
230 }
231 }
232}
233
234
235void Foam::snappyVoxelMeshDriver::floodFill
236(
237 const label startVoxeli,
238 const label newLevel,
239 labelList& voxelLevel
240) const
241{
243 front.append(voxelMeshSearch::index3(n_, startVoxeli));
244
246 while (true)
247 {
248 newFront.clear();
249 for (const auto& voxel : front)
250 {
251 label voxeli = voxelMeshSearch::index(n_, voxel);
252 if (voxelLevel[voxeli] == -1)
253 {
254 voxelLevel[voxeli] = 0;
255 addNeighbours
256 (
257 voxelLevel,
258 voxel,
259 voxeli,
260 newFront
261 );
262 }
263 }
264
265 if (newFront.empty())
266 {
267 break;
268 }
269 front.transfer(newFront);
270 }
271}
272
273
274void Foam::snappyVoxelMeshDriver::max
275(
276 const labelList& maxLevel,
277 labelList& voxelLevel
278) const
279{
280 // Mark voxels with level
282
283 label voxeli = voxelMeshSearch::index(n_, labelVector(0, 0, 0));
284 for (label k = 0; k < n_[2]; k++)
285 {
286 const label start1 = voxeli;
287 for (label j = 0; j < n_[1]; j++)
288 {
289 const label start0 = voxeli;
290 for (label i = 0; i < n_[0]; i++)
291 {
292 voxelLevel[voxeli] = Foam::max
293 (
294 voxelLevel[voxeli],
295 maxLevel[voxeli]
296 );
297 voxeli += off[0];
298 }
299 voxeli = start0 + off[1];
300 }
301 voxeli = start1 + off[2];
302 }
303}
304
305
306Foam::labelList Foam::snappyVoxelMeshDriver::count
307(
308 const labelList& voxelLevel
309) const
310{
311
312 label maxLevel = 0;
313 for (const auto level : voxelLevel)
314 {
315 if (level != labelMax)
316 {
317 maxLevel = Foam::max(maxLevel, level);
318 }
319 }
320 labelList count(maxLevel+1, 0);
321
323
324 label voxeli = voxelMeshSearch::index(n_, labelVector(0, 0, 0));
325 for (label k = 0; k < n_[2]; k++)
326 {
327 const label start1 = voxeli;
328 for (label j = 0; j < n_[1]; j++)
329 {
330 const label start0 = voxeli;
331 for (label i = 0; i < n_[0]; i++)
332 {
333 label level = voxelLevel[voxeli];
334
335 if (level != -1 && level != labelMax)
336 {
337 ++count[level];
338 }
339 voxeli += off[0];
340 }
341 voxeli = start0 + off[1];
342 }
343 voxeli = start1 + off[2];
344 }
346 return count;
347}
348
349
350// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
351
352Foam::snappyVoxelMeshDriver::snappyVoxelMeshDriver
353(
354 meshRefinement& meshRefiner,
355 const labelUList& globalToMasterPatch,
356 const labelUList& globalToSlavePatch
357)
358:
359 meshRefiner_(meshRefiner),
360 globalToMasterPatch_(globalToMasterPatch),
361 globalToSlavePatch_(globalToSlavePatch),
362 bb_(meshRefiner_.mesh().bounds())
363{
364 label maxLevel = labelMin;
365
366 // Feature refinement
367 const labelListList& featLevels = meshRefiner_.features().levels();
368 forAll(featLevels, feati)
369 {
370 maxLevel = Foam::max(maxLevel, Foam::max(featLevels[feati]));
371 }
372
373 // Surface refinement
374 const labelList& surfaceLevels = meshRefiner_.surfaces().maxLevel();
375 maxLevel = Foam::max(maxLevel, Foam::max(surfaceLevels));
376
377 // Shell refinement
378 maxLevel = Foam::max(maxLevel, meshRefiner_.shells().maxLevel());
379
380 const scalar level0Len = meshRefiner_.meshCutter().level0EdgeLength();
381
382 const int oldWidth = Sout.width();
383
384 Info<< nl
385 << "Cell size estimate :" << nl
386 << " Level "
387 << setw(2) << label(0) << setw(oldWidth)
388 << " : " << level0Len << nl
389 << " Level "
390 << setw(2) << maxLevel << setw(oldWidth)
391 << " : " << level0Len/pow(2.0, maxLevel) << nl
392 << endl;
393
394
395 // Define voxel mesh with similar dimensions as mesh
396 const vector meshSpan(bb_.span());
397 n_ = labelVector
398 (
399 round(meshSpan.x()/level0Len),
400 round(meshSpan.y()/level0Len),
401 round(meshSpan.z()/level0Len)
402 );
403 label nTot = n_.x()*n_.y()*n_.z();
404 while (nTot < 1000000) //1048576)
405 {
406 n_ *= 2;
407 nTot = n_.x()*n_.y()*n_.z();
408 }
409
410 Info<< "Voxellating initial mesh : " << n_ << nl << endl;
411
412 tmp<pointField> tcc(voxelCentres());
413 const pointField& cc = tcc();
414
415 Info<< "Voxel refinement :" << nl
416 << " Initial : (" << nTot << ')' << endl;
417
418 boolList isVoxelInMesh;
419 isInside(cc, isVoxelInMesh);
420
421 if (Pstream::master())
422 {
423 voxelLevel_.setSize(nTot, -1);
424 globalRegion_.setSize(nTot, -1);
425
426 // Remove cells outside initial mesh
427 forAll(isVoxelInMesh, voxeli)
428 {
429 if (!isVoxelInMesh[voxeli])
430 {
431 voxelLevel_[voxeli] = labelMax;
432 globalRegion_[voxeli] = -1;
433 }
434 }
435
436 //if (debug)
437 {
438 Info<< " After removing outside cells : " << count(voxelLevel_)
439 << endl;
441 }
442}
443
444
445// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
446
448(
449 const refinementParameters& refineParams
450)
451{
452 const scalar level0Len = meshRefiner_.meshCutter().level0EdgeLength();
453
454 tmp<pointField> tcc(voxelCentres());
455 const pointField& cc = tcc();
456
457 boolList isVoxelInMesh;
458 isInside(cc, isVoxelInMesh);
459
460 if (Pstream::master())
461 {
462 // Mark voxels containing (parts of) triangles
463 markSurfaceRefinement(voxelLevel_, globalRegion_);
464
465 //if (debug)
466 {
467 Info<< " After surface refinement : " << count(voxelLevel_)
468 << endl;
469 }
470
471
472 // Find outside locations (and their current refinement level)
473 const pointField& outsidePoints = refineParams.locationsOutsideMesh();
474 labelList outsideMeshVoxels;
475 findVoxels
476 (
477 voxelLevel_,
478 outsidePoints,
479 outsideMeshVoxels
480 );
481 labelList outsideOldLevel(outsideMeshVoxels.size(), -1);
482 forAll(outsideMeshVoxels, loci)
483 {
484 label voxeli = outsideMeshVoxels[loci];
485 if (voxeli >= 0)
486 {
487 outsideOldLevel[loci] = voxelLevel_[outsideMeshVoxels[loci]];
488 if (outsideOldLevel[loci] >= 0)
489 {
490 WarningInFunction << "Location outside mesh "
491 << outsidePoints[loci]
492 << " is inside mesh or close to surface" << endl;
493 }
494 }
495 }
496
497
498 // Find inside locations
499 labelList insideMeshVoxels;
500 findVoxels
501 (
502 voxelLevel_,
503 refineParams.locationsInMesh(),
504 insideMeshVoxels
505 );
506
507 forAll(insideMeshVoxels, loci)
508 {
509 label voxeli = insideMeshVoxels[loci];
510 if (voxeli != -1)
511 {
512 if (voxelLevel_[voxeli] != -1)
513 {
514 WarningInFunction << "Location inside mesh "
515 << refineParams.locationsInMesh()[loci]
516 << " is marked as a surface voxel " << voxeli
517 << " with cell level " << voxelLevel_[voxeli] << endl;
518 }
519 else
520 {
521 // Flood-fill out from voxel
522 floodFill(voxeli, 0, voxelLevel_);
523 }
524 }
525 }
526
527 //if (debug)
528 {
529 Info<< " After keeping inside voxels : " << count(voxelLevel_)
530 << endl;
531 }
532
533
534 // Re-check the outside locations to see if they have been bled into
535 {
536 forAll(outsideMeshVoxels, loci)
537 {
538 label voxeli = outsideMeshVoxels[loci];
539 if (voxeli >= 0 && voxelLevel_[voxeli] != outsideOldLevel[loci])
540 {
541 WarningInFunction << "Location outside mesh "
542 << outsidePoints[loci]
543 << " is reachable from an inside location" << nl
544 << "Either your locations are too close to the"
545 << " geometry or there might be a leak in the"
546 << " geometry" << endl;
547 }
548 }
549 }
550
551
552 // Shell refinement : find ccs inside higher shells
553 labelList maxLevel;
554 meshRefiner_.shells().findHigherLevel(cc, voxelLevel_, maxLevel);
555
556 // Assign max of maxLevel and voxelLevel
557 max(maxLevel, voxelLevel_);
558
559 // Determine number of levels
560 const labelList levelCounts(count(voxelLevel_));
561
562 //if (debug)
563 {
564 Info<< " After shell refinement : " << levelCounts << endl;
565 }
566
567
568 const vector meshSpan(bb_.span());
569 const vector voxel0Size
570 (
571 meshSpan[0]/n_[0],
572 meshSpan[1]/n_[1],
573 meshSpan[2]/n_[2]
574 );
575 label cellCount = 0;
576 forAll(levelCounts, leveli)
577 {
578 const scalar s = level0Len/pow(2.0, leveli);
579 const scalar nCellsPerVoxel
580 (
581 voxel0Size[0]/s
582 *voxel0Size[1]/s
583 *voxel0Size[2]/s
584 );
585 cellCount += levelCounts[leveli]*nCellsPerVoxel;
586 }
587 Info<< "Estimated cell count : " << cellCount << endl;
588 }
589}
590
591
592// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
label k
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
virtual int width() const override
Get width of output field.
Definition OSstream.C:331
static void listCombineGather(UList< T > &values, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Forwards to Pstream::listGather with an in-place cop.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
const Cmpt & x() const noexcept
Access to the vector x component.
Definition Vector.H:135
const Cmpt & z() const noexcept
Access to the vector z component.
Definition Vector.H:145
const Cmpt & y() const noexcept
Access to the vector y component.
Definition Vector.H:140
A bounding box defined in terms of min/max extrema points.
Definition boundBox.H:71
vector span() const
The bounding box span (from minimum to maximum).
Definition boundBoxI.H:192
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
label nTotalCells() const noexcept
Total global number of mesh cells.
scalar level0EdgeLength() const
Typical edge length between unrefined points.
Definition hexRef8.H:499
A triFace with additional (region) index.
Definition labelledTri.H:56
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
const hexRef8 & meshCutter() const
Reference to meshcutting engine.
const refinementSurfaces & surfaces() const
Reference to surface search engines.
const shellSurfaces & shells() const
Reference to refinement shells (regions).
const refinementFeatures & features() const
Reference to feature edge mesh.
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition polyMesh.C:1496
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
label nCells() const noexcept
Number of mesh cells.
boundBox cellBb(const label celli) const
The bounding box for given cell index.
Simple container to keep together refinement specific information.
const pointField & locationsOutsideMesh() const
Optional points which are checked to be outside the mesh.
const pointField & locationsInMesh() const
Areas to keep.
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
const labelList & surfaces() const
const labelList & maxLevel() const
From global region number to refinement level.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
label maxLevel() const
Highest shell level.
Equivalent of snappyRefineDriver but operating on a voxel mesh.
void doRefine(const refinementParameters &refineParams)
A class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
Triangulated surface description with patch information.
Definition triSurface.H:74
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
static labelVector index3(const labelVector &nDivs, const label voxeli)
Combined voxel index to individual indices.
static label index(const labelVector &nDivs, const labelVector &voxel)
Find cells. Returns number of cells found.
static void fill(Container &elems, const boundBox &bb, const labelVector &nDivs, const boundBox &subBb, const Type val)
Fill voxels indicated by bounding box.
static labelVector offset(const labelVector &nDivs)
Change in combined voxel index for change in components.
static point centre(const boundBox &bb, const labelVector &nDivs, const labelVector &voxel)
Voxel index to voxel centre.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
dynamicFvMesh & mesh
const pointField & points
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))
#define WarningInFunction
Report a warning using Foam::Warning.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
Namespace for bounding specifications. At the moment, mostly for tables.
Namespace for OpenFOAM.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
Vector< label > labelVector
Vector of labels.
Definition labelVector.H:47
constexpr label labelMin
Definition label.H:54
messageStream Info
Information stream (stdout output on master, null elsewhere).
constexpr label labelMax
Definition label.H:55
OSstream Sout
OSstream wrapped stdout (std::cout).
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Omanip< int > setw(const int i)
Definition IOmanip.H:199
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
uint8_t direction
Definition direction.H:49
vector point
Point is a vector.
Definition point.H:37
List< bool > boolList
A List of bools.
Definition List.H:60
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
UList< label > labelUList
A UList of labels.
Definition UList.H:75
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299