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 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"
37#include "voxelMeshSearch.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 }
132 Pstream::listCombineGather(isVoxelInMesh, orEqOp<bool>());
133 }
134 else
135 {
136 const cellList& cells = mesh.cells();
137 const faceList& faces = mesh.faces();
138 const pointField& points = mesh.points();
139
140 for (label celli = 0; celli < mesh.nCells(); celli++)
141 {
142 const cell& cFaces = cells[celli];
143 boundBox cellBb(boundBox::invertedBox);
144 forAll(cFaces, cFacei)
145 {
146 const face& f = faces[cFaces[cFacei]];
147 forAll(f, fp)
148 {
149 cellBb.add(points[f[fp]]);
150 }
151 }
153 (
154 isVoxelInMesh,
155 bb_,
156 n_,
157 cellBb,
158 1,
159 orEqOp<bool>()
160 );
161 }
162 Pstream::listCombineGather(isVoxelInMesh, orEqOp<bool>());
163 }
164}
165
166
167void Foam::snappyVoxelMeshDriver::markSurfaceRefinement
168(
169 labelList& voxelLevel,
170 labelList& globalRegion
171) const
172{
173 // Insert cell level for all refinementSurfaces
174
175 const refinementSurfaces& s = meshRefiner_.surfaces();
176 forAll(s.surfaces(), surfi)
177 {
178 label geomi = s.surfaces()[surfi];
179 const searchableSurface& geom = s.geometry()[geomi];
180 //Pout<< "Geometry:" << s.names()[surfi] << endl;
181 if (isA<triSurface>(geom))
182 {
183 const triSurface& ts = refCast<const triSurface>(geom);
184 const pointField& points = ts.points();
185
186 forAll(ts, trii)
187 {
188 label regioni = ts[trii].region();
189 label globalRegioni = s.regionOffset()[surfi]+regioni;
190 const boundBox triBb(points, ts[trii], false);
191
192 // Fill cellLevel
193 label level = s.minLevel()[globalRegioni];
195 (
196 voxelLevel,
197 bb_,
198 n_,
199 triBb,
200 level,
201 maxEqOp<label>()
202 );
204 (
205 globalRegion,
206 bb_,
207 n_,
208 triBb,
209 globalRegioni,
210 maxEqOp<label>()
211 );
212 }
213 }
214 // else: maybe do intersection tests?
215 }
216}
217
218
219void Foam::snappyVoxelMeshDriver::findVoxels
220(
221 const labelList& voxelLevel,
222 const pointField& locationsOutsideMesh,
223 labelList& voxels
224) const
225{
226 voxels.setSize(locationsOutsideMesh.size());
227 voxels = -1;
228 forAll(locationsOutsideMesh, loci)
229 {
230 const point& pt = locationsOutsideMesh[loci];
231 label voxeli = voxelMeshSearch::index(bb_, n_, pt, false);
232
233 if (voxeli == -1 || voxelLevel[voxeli] == labelMax)
234 {
235 WarningInFunction << "Location outside mesh "
236 << pt << " is outside mesh with bounding box "
237 << bb_ << endl;
238 }
239 else
240 {
241 voxels[loci] = voxeli;
242 }
243 }
244}
245
246
247void Foam::snappyVoxelMeshDriver::floodFill
248(
249 const label startVoxeli,
250 const label newLevel,
251 labelList& voxelLevel
252) const
253{
254 DynamicList<labelVector> front;
255 front.append(voxelMeshSearch::index3(n_, startVoxeli));
256
257 DynamicList<labelVector> newFront;
258 while (true)
259 {
260 newFront.clear();
261 for (const auto& voxel : front)
262 {
263 label voxeli = voxelMeshSearch::index(n_, voxel);
264 if (voxelLevel[voxeli] == -1)
265 {
266 voxelLevel[voxeli] = 0;
267 addNeighbours
268 (
269 voxelLevel,
270 voxel,
271 voxeli,
272 newFront
273 );
274 }
275 }
276
277 if (newFront.empty())
278 {
279 break;
280 }
281 front.transfer(newFront);
282 }
283}
284
285
287(
288 const labelList& maxLevel,
289 labelList& voxelLevel
290) const
291{
292 // Mark voxels with level
294
295 label voxeli = voxelMeshSearch::index(n_, labelVector(0, 0, 0));
296 for (label k = 0; k < n_[2]; k++)
297 {
298 const label start1 = voxeli;
299 for (label j = 0; j < n_[1]; j++)
300 {
301 const label start0 = voxeli;
302 for (label i = 0; i < n_[0]; i++)
303 {
304 voxelLevel[voxeli] = Foam::max
305 (
306 voxelLevel[voxeli],
307 maxLevel[voxeli]
308 );
309 voxeli += off[0];
310 }
311 voxeli = start0 + off[1];
312 }
313 voxeli = start1 + off[2];
314 }
315}
316
317
319(
320 const labelList& voxelLevel
321) const
322{
323
324 label maxLevel = 0;
325 for (const auto level : voxelLevel)
326 {
327 if (level != labelMax)
328 {
329 maxLevel = Foam::max(maxLevel, level);
330 }
331 }
332 labelList count(maxLevel+1, 0);
333
335
336 label voxeli = voxelMeshSearch::index(n_, labelVector(0, 0, 0));
337 for (label k = 0; k < n_[2]; k++)
338 {
339 const label start1 = voxeli;
340 for (label j = 0; j < n_[1]; j++)
341 {
342 const label start0 = voxeli;
343 for (label i = 0; i < n_[0]; i++)
344 {
345 label level = voxelLevel[voxeli];
346
347 if (level != -1 && level != labelMax)
348 {
349 ++count[level];
350 }
351 voxeli += off[0];
352 }
353 voxeli = start0 + off[1];
354 }
355 voxeli = start1 + off[2];
356 }
357
358 return count;
359}
360
361
362// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
363
365(
366 meshRefinement& meshRefiner,
367 const labelUList& globalToMasterPatch,
368 const labelUList& globalToSlavePatch
369)
370:
371 meshRefiner_(meshRefiner),
372 globalToMasterPatch_(globalToMasterPatch),
373 globalToSlavePatch_(globalToSlavePatch),
374 bb_(meshRefiner_.mesh().bounds())
375{
376 label maxLevel = labelMin;
377
378 // Feature refinement
379 const labelListList& featLevels = meshRefiner_.features().levels();
380 forAll(featLevels, feati)
381 {
382 maxLevel = Foam::max(maxLevel, Foam::max(featLevels[feati]));
383 }
384
385 // Surface refinement
386 const labelList& surfaceLevels = meshRefiner_.surfaces().maxLevel();
387 maxLevel = Foam::max(maxLevel, Foam::max(surfaceLevels));
388
389 // Shell refinement
390 maxLevel = Foam::max(maxLevel, meshRefiner_.shells().maxLevel());
391
392 const scalar level0Len = meshRefiner_.meshCutter().level0EdgeLength();
393
394 const int oldWidth = Sout.width();
395
396 Info<< nl
397 << "Cell size estimate :" << nl
398 << " Level "
399 << setw(2) << label(0) << setw(oldWidth)
400 << " : " << level0Len << nl
401 << " Level "
402 << setw(2) << maxLevel << setw(oldWidth)
403 << " : " << level0Len/pow(2.0, maxLevel) << nl
404 << endl;
405
406
407 // Define voxel mesh with similar dimensions as mesh
408 const vector meshSpan(bb_.span());
409 n_ = labelVector
410 (
411 round(meshSpan.x()/level0Len),
412 round(meshSpan.y()/level0Len),
413 round(meshSpan.z()/level0Len)
414 );
415 label nTot = n_.x()*n_.y()*n_.z();
416 while (nTot < 1000000) //1048576)
417 {
418 n_ *= 2;
419 nTot = n_.x()*n_.y()*n_.z();
420 }
421
422 Info<< "Voxellating initial mesh : " << n_ << nl << endl;
423
424 tmp<pointField> tcc(voxelCentres());
425 const pointField& cc = tcc();
426
427 Info<< "Voxel refinement :" << nl
428 << " Initial : (" << nTot << ')' << endl;
429
430 boolList isVoxelInMesh;
431 isInside(cc, isVoxelInMesh);
432
433 if (Pstream::master())
434 {
435 voxelLevel_.setSize(nTot, -1);
436 globalRegion_.setSize(nTot, -1);
437
438 // Remove cells outside initial mesh
439 forAll(isVoxelInMesh, voxeli)
440 {
441 if (!isVoxelInMesh[voxeli])
442 {
443 voxelLevel_[voxeli] = labelMax;
444 globalRegion_[voxeli] = -1;
445 }
446 }
447
448 //if (debug)
449 {
450 Info<< " After removing outside cells : " << count(voxelLevel_)
451 << endl;
452 }
453 }
454}
455
456
457// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
458
460(
461 const refinementParameters& refineParams
462)
463{
464 const scalar level0Len = meshRefiner_.meshCutter().level0EdgeLength();
465
466 tmp<pointField> tcc(voxelCentres());
467 const pointField& cc = tcc();
468
469 boolList isVoxelInMesh;
470 isInside(cc, isVoxelInMesh);
471
472 if (Pstream::master())
473 {
474 // Mark voxels containing (parts of) triangles
475 markSurfaceRefinement(voxelLevel_, globalRegion_);
476
477 //if (debug)
478 {
479 Info<< " After surface refinement : " << count(voxelLevel_)
480 << endl;
481 }
482
483
484 // Find outside locations (and their current refinement level)
485 const pointField& outsidePoints = refineParams.locationsOutsideMesh();
486 labelList outsideMeshVoxels;
487 findVoxels
488 (
489 voxelLevel_,
490 outsidePoints,
491 outsideMeshVoxels
492 );
493 labelList outsideOldLevel(outsideMeshVoxels.size(), -1);
494 forAll(outsideMeshVoxels, loci)
495 {
496 label voxeli = outsideMeshVoxels[loci];
497 if (voxeli >= 0)
498 {
499 outsideOldLevel[loci] = voxelLevel_[outsideMeshVoxels[loci]];
500 if (outsideOldLevel[loci] >= 0)
501 {
502 WarningInFunction << "Location outside mesh "
503 << outsidePoints[loci]
504 << " is inside mesh or close to surface" << endl;
505 }
506 }
507 }
508
509
510 // Find inside locations
511 labelList insideMeshVoxels;
512 findVoxels
513 (
514 voxelLevel_,
515 refineParams.locationsInMesh(),
516 insideMeshVoxels
517 );
518
519 forAll(insideMeshVoxels, loci)
520 {
521 label voxeli = insideMeshVoxels[loci];
522 if (voxeli != -1)
523 {
524 if (voxelLevel_[voxeli] != -1)
525 {
526 WarningInFunction << "Location inside mesh "
527 << refineParams.locationsInMesh()[loci]
528 << " is marked as a surface voxel " << voxeli
529 << " with cell level " << voxelLevel_[voxeli] << endl;
530 }
531 else
532 {
533 // Flood-fill out from voxel
534 floodFill(voxeli, 0, voxelLevel_);
535 }
536 }
537 }
538
539 //if (debug)
540 {
541 Info<< " After keeping inside voxels : " << count(voxelLevel_)
542 << endl;
543 }
544
545
546 // Re-check the outside locations to see if they have been bled into
547 {
548 forAll(outsideMeshVoxels, loci)
549 {
550 label voxeli = outsideMeshVoxels[loci];
551 if (voxeli >= 0 && voxelLevel_[voxeli] != outsideOldLevel[loci])
552 {
553 WarningInFunction << "Location outside mesh "
554 << outsidePoints[loci]
555 << " is reachable from an inside location" << nl
556 << "Either your locations are too close to the"
557 << " geometry or there might be a leak in the"
558 << " geometry" << endl;
559 }
560 }
561 }
562
563
564 // Shell refinement : find ccs inside higher shells
565 labelList maxLevel;
566 meshRefiner_.shells().findHigherLevel(cc, voxelLevel_, maxLevel);
567
568 // Assign max of maxLevel and voxelLevel
569 max(maxLevel, voxelLevel_);
570
571 // Determine number of levels
572 const labelList levelCounts(count(voxelLevel_));
573
574 //if (debug)
575 {
576 Info<< " After shell refinement : " << levelCounts << endl;
577 }
578
579
580 const vector meshSpan(bb_.span());
581 const vector voxel0Size
582 (
583 meshSpan[0]/n_[0],
584 meshSpan[1]/n_[1],
585 meshSpan[2]/n_[2]
586 );
587 label cellCount = 0;
588 forAll(levelCounts, leveli)
589 {
590 const scalar s = level0Len/pow(2.0, leveli);
591 const scalar nCellsPerVoxel
592 (
593 voxel0Size[0]/s
594 *voxel0Size[1]/s
595 *voxel0Size[2]/s
596 );
597 cellCount += levelCounts[leveli]*nCellsPerVoxel;
598 }
599 Info<< "Estimated cell count : " << cellCount << endl;
600 }
601}
602
603
604// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
label k
void setSize(const label n)
Alias for resize()
Definition: List.H:218
virtual int width() const
Get width of output field.
Definition: OSstream.C:314
virtual char fill() const =0
Get padding character.
scalar centre() const
Mid-point location, zero for an empty list.
Definition: PDRblockI.H:67
static void listCombineGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
static const boundBox invertedBox
A large inverted boundBox: min/max == +/- ROOTVGREAT.
Definition: boundBox.H:86
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:127
label nTotalCells() const noexcept
Return total number of cells in decomposed mesh.
scalar level0EdgeLength() const
Typical edge length between unrefined points.
Definition: hexRef8.H:413
const vector & offset() const noexcept
Offset vector (from patch faces to destination mesh objects)
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.
static const complex max
complex (VGREAT,VGREAT)
Definition: complex.H:293
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition: polyMesh.C:1522
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1310
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
label nCells() const noexcept
Number of mesh cells.
const cellList & cells() const
label count() const
const labelListList & levels() const
Per featureEdgeMesh the list of level.
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.
const labelList & maxLevel() const
From global region number to refinement level.
label maxLevel() const
Highest shell level.
Equivalent of snappyRefineDriver but operating on a voxel mesh.
void doRefine(const refinementParameters &refineParams)
splitCell * master() const
Definition: splitCell.H:113
A class for managing temporary objects.
Definition: tmp.H:65
static labelVector index3(const labelVector &nDivs, const label voxeli)
Combined voxel index to individual indices.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
dynamicFvMesh & mesh
const pointField & points
const cellShapeList & cells
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:78
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:47
List< label > labelList
A List of labels.
Definition: List.H:66
List< cell > cellList
A List of cells.
Definition: cellListFwd.H:47
constexpr label labelMin
Definition: label.H:60
Vector< label > labelVector
Vector of labels.
Definition: labelVector.H:51
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
constexpr label labelMax
Definition: label.H:61
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:372
uint8_t direction
Definition: direction.H:56
List< bool > boolList
A List of bools.
Definition: List.H:64
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333