blockMeshMergeTopological.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) 2015-2016 OpenFOAM Foundation
9 Copyright (C) 2019-2020 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 "blockMesh.H"
30
31// * * * * * * * * * * * * * * * Private Functions * * * * * * * * * * * * * //
32
33namespace Foam
34{
35
36// faces
37// 6
38// (
39// 4(0 4 7 3) // x-min
40// 4(1 2 6 5) // x-max
41// 4(0 1 5 4) // y-min
42// 4(3 7 6 2) // y-max
43// 4(0 3 2 1) // z-min
44// 4(4 5 6 7) // z-max
45// );
46
47// Face-edge directions
48static const int faceEdgeDirs[6][4] =
49{
50 {2, 1, -2, -1},
51 {1, 2, -1, -2},
52 {1, 2, -1, -2},
53 {2, 1, -2, -1},
54 {2, 1, -2, -1},
55 {1, 2, -1, -2}
56};
57
58// The face-face-rotation direction correspondence map
59static Pair<int> faceFaceRotMap[6][6][4];
60
61// Generate the face-face-rotation direction correspondence map
63{
64 for(int facePi=0; facePi<6; facePi++)
65 {
66 for(int faceNi=0; faceNi<6; faceNi++)
67 {
68 for(int rot=0; rot<4; rot++)
69 {
70 Pair<int>& map = faceFaceRotMap[facePi][faceNi][rot];
71
72 for(int Pp=0; Pp<2; Pp++)
73 {
74 int Pdir = faceEdgeDirs[facePi][Pp];
75 int Np = (3 - Pp + rot)%4;
76 int Ndir = faceEdgeDirs[faceNi][Np];
77 map[Pdir-1] = -Ndir;
78 }
79
80 // Handle sign change due to match-face transpose
81 if (mag(map[0]) == 2 && map[0]*map[1] < 0)
82 {
83 map[0] = -map[0];
84 map[1] = -map[1];
85 }
86 }
87 }
88 }
89}
90
91
92// Return the direction map for the merge-faces
94(
95 const label facePi,
96 const face& faceP,
97 const label faceNi,
98 const face& faceN
99)
100{
101 // Search for the point on faceN corresponding to the 0-point on faceP
102 for(int rot=0; rot<4; rot++)
103 {
104 if (faceN[rot] == faceP[0])
105 {
106 return faceFaceRotMap[facePi][faceNi][rot];
107 }
108 }
109
111 << "Cannot find point correspondence for faces "
112 << faceP << " and " << faceN
113 << exit(FatalError);
114
115 return Pair<int>(0, 0);
116}
117
118
119// Set the block and face indices for all the merge faces
121(
122 const cellList& topoCells,
123 const faceList::subList& topoInternalFaces,
124 const labelList& topoFaceCell,
125 List<Pair<label>>& mergeBlock
126)
127{
128 forAll(topoInternalFaces, topoFacei)
129 {
130 label topoPi = topoFaceCell[topoFacei];
131 const labelList& topoPfaces = topoCells[topoPi];
132
133 bool foundFace = false;
134 label topoPfacei;
135 for
136 (
137 topoPfacei = 0;
138 topoPfacei < topoPfaces.size();
139 topoPfacei++
140 )
141 {
142 if (topoPfaces[topoPfacei] == topoFacei)
143 {
144 foundFace = true;
145 break;
146 }
147 }
148
149 if (!foundFace)
150 {
152 << "Cannot find merge face for block " << topoPi
153 << exit(FatalError);
154 }
155
156 mergeBlock[topoFacei].first() = topoPi;
157 mergeBlock[topoFacei].second() = topoPfacei;
158 }
159}
160
161
162// Return the number of divisions in each direction for the face
163Pair<label> faceNij(const label facei, const block& block)
164{
165 Pair<label> fnij;
166
167 int i = facei/2;
168
169 if (i == 0)
170 {
171 fnij.first() = block.density().y() + 1;
172 fnij.second() = block.density().z() + 1;
173 }
174 else if (i == 1)
175 {
176 fnij.first() = block.density().x() + 1;
177 fnij.second() = block.density().z() + 1;
178 }
179 else if (i == 2)
180 {
181 fnij.first() = block.density().x() + 1;
182 fnij.second() = block.density().y() + 1;
183 }
184
185 return fnij;
186}
187
188
189// Sign the index corresponding to the map
190inline label signIndex(const int map, const label i)
191{
192 return map < 0 ? -i-1 : i;
193}
194
195
196// Reverse a signed index with the number of divisions
197inline label unsignIndex(const label i, const label ni)
198{
199 return i >= 0 ? i : ni + i + 1;
200}
201
202
203// Return the mapped index
204inline label mapij(const int map, const label i, const label j)
205{
206 return signIndex(map, mag(map) == 1 ? i : j);
207}
208
209
210// Return the face point index
211inline label facePoint
212(
213 const int facei,
214 const block& block,
215 const label i,
216 const label j
217)
218{
219 switch (facei)
220 {
221 case 0:
222 return block.pointLabel(0, i, j);
223 case 1:
224 return block.pointLabel(block.density().x(), i, j);
225 case 2:
226 return block.pointLabel(i, 0, j);
227 case 3:
228 return block.pointLabel(i, block.density().y(), j);
229 case 4:
230 return block.pointLabel(i, j, 0);
231 case 5:
232 return block.pointLabel(i, j, block.density().z());
233 default:
234 return -1;
235 }
236}
237
238
239// Return the neighbour face point from the signed indices
240inline label facePointN
241(
242 const block& block,
243 const label i,
244 const label j,
245 const label k
246)
247{
248 return block.pointLabel
249 (
250 unsignIndex(i, block.density().x()),
251 unsignIndex(j, block.density().y()),
253 );
254}
255
256
257// Return the neighbour face point from the mapped indices
258inline label facePointN
259(
260 const int facei,
261 const block& block,
262 const label i,
263 const label j
264)
265{
266 switch (facei)
267 {
268 case 0:
269 return facePointN(block, 0, i, j);
270 case 1:
271 return facePointN(block, block.density().x(), i, j);
272 case 2:
273 return facePointN(block, i, 0, j);
274 case 3:
275 return facePointN(block, i, block.density().y(), j);
276 case 4:
277 return facePointN(block, i, j, 0);
278 case 5:
279 return facePointN(block, i, j, block.density().z());
280 default:
281 return -1;
282 }
283}
284
285
286// Return the neighbour face point using the map
287inline label facePointN
288(
289 const int facei,
290 const Pair<int>& fmap,
291 const block& block,
292 const label i,
293 const label j
294)
295{
296 return facePointN(facei, block, mapij(fmap[0], i, j), mapij(fmap[1], i, j));
297}
298
299} // End namespace Foam
300
301
302// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
303
304void Foam::blockMesh::calcTopologicalMerge()
305{
306 // Generate the static face-face map
308
309 const blockList& blocks = *this;
310
311 if (verbose_)
312 {
313 Info<< "Creating block offsets" << endl;
314 }
315
316 blockOffsets_.resize(blocks.size());
317
318 nPoints_ = 0;
319 nCells_ = 0;
320
321 forAll(blocks, blocki)
322 {
323 blockOffsets_[blocki] = nPoints_;
324
325 nPoints_ += blocks[blocki].nPoints();
326 nCells_ += blocks[blocki].nCells();
327 }
328
329 if (verbose_)
330 {
331 Info<< "Creating merge list (topological search).." << flush;
332 }
333
334 // Size merge list and initialize to -1
335 mergeList_.setSize(nPoints_, -1);
336
337 // Block mesh topology
338 const polyMesh& topoMesh = topology();
339
340 const pointField& topoPoints = topoMesh.points();
341 const cellList& topoCells = topoMesh.cells();
342 const faceList& topoFaces = topoMesh.faces();
343 const labelList& topoFaceOwn = topoMesh.faceOwner();
344 const labelList& topoFaceNei = topoMesh.faceNeighbour();
345
346 // Topological merging is only necessary for internal block faces
347 // Note edge and face collapse may apply to boundary faces
348 // but is not yet supported in the "fast" algorithm
349 const faceList::subList topoInternalFaces
350 (
351 topoFaces,
353 );
354
355 List<Pair<label>> mergeBlockP(topoInternalFaces.size());
357 (
358 topoCells,
359 topoInternalFaces,
360 topoFaceOwn,
361 mergeBlockP
362 );
363
364 List<Pair<label>> mergeBlockN(topoInternalFaces.size());
366 (
367 topoCells,
368 topoInternalFaces,
369 topoFaceNei,
370 mergeBlockN
371 );
372
373 DebugInfo << endl;
374
375 forAll(topoInternalFaces, topoFacei)
376 {
377 DebugInfo << "Processing face " << topoFacei << endl;
378
379 label blockPi = mergeBlockP[topoFacei].first();
380 label blockPfacei = mergeBlockP[topoFacei].second();
381
382 label blockNi = mergeBlockN[topoFacei].first();
383 label blockNfacei = mergeBlockN[topoFacei].second();
384
385 Pair<int> fmap
386 (
387 faceMap
388 (
389 blockPfacei,
390 blocks[blockPi].blockShape().faces()[blockPfacei],
391 blockNfacei,
392 blocks[blockNi].blockShape().faces()[blockNfacei]
393 )
394 );
395
397 << " Face map for faces "
398 << blocks[blockPi].blockShape().faces()[blockPfacei] << " "
399 << blocks[blockNi].blockShape().faces()[blockNfacei] << ": "
400 << fmap << endl;
401
402 const pointField& blockPpoints = blocks[blockPi].points();
403 const pointField& blockNpoints = blocks[blockNi].points();
404
405 Pair<label> Pnij(faceNij(blockPfacei, blocks[blockPi]));
406
407 // Check block subdivision correspondence
408 {
409 Pair<label> Nnij(faceNij(blockNfacei, blocks[blockNi]));
410 Pair<label> NPnij;
411 NPnij[0] = Nnij[mag(fmap[0]) - 1];
412 NPnij[1] = Nnij[mag(fmap[1]) - 1];
413
414 if (Pnij != NPnij)
415 {
417 << "Sub-division mismatch between face "
418 << blockPfacei << " of block " << blockPi << Pnij
419 << " and face "
420 << blockNfacei << " of block " << blockNi << Nnij
421 << exit(FatalError);
422 }
423 }
424
425 // Calculate a suitable test distance from the bounding box of the face.
426 // Note this is used only as a sanity check and for diagnostics in
427 // case there is a grading inconsistency.
428 const boundBox bb(topoCells[blockPi].points(topoFaces, topoPoints));
429 const scalar testSqrDist = magSqr(1e-6*bb.span());
430
431 // Accumulate the maximum merge distance for diagnostics
432 scalar maxSqrDist = 0;
433
434 for (label j=0; j<Pnij.second(); j++)
435 {
436 for (label i=0; i<Pnij.first(); i++)
437 {
438 label blockPpointi =
439 facePoint(blockPfacei, blocks[blockPi], i, j);
440
441 label blockNpointi =
442 facePointN(blockNfacei, fmap, blocks[blockNi], i, j);
443
444 scalar sqrDist
445 (
446 magSqr
447 (
448 blockPpoints[blockPpointi]
449 - blockNpoints[blockNpointi]
450 )
451 );
452
453 if (sqrDist > testSqrDist)
454 {
456 << "Point merge failure between face "
457 << blockPfacei << " of block " << blockPi
458 << " and face "
459 << blockNfacei << " of block " << blockNi
460 << endl
461 << " Points: " << blockPpoints[blockPpointi]
462 << " " << blockNpoints[blockNpointi]
463 << endl
464 << " This may be due to inconsistent grading."
465 << exit(FatalError);
466 }
467
468 maxSqrDist = max(maxSqrDist, sqrDist);
469
470 label Ppointi = blockPpointi + blockOffsets_[blockPi];
471 label Npointi = blockNpointi + blockOffsets_[blockNi];
472
473 label minPNi = min(Ppointi, Npointi);
474
475 if (mergeList_[Ppointi] != -1)
476 {
477 minPNi = min(minPNi, mergeList_[Ppointi]);
478 }
479
480 if (mergeList_[Npointi] != -1)
481 {
482 minPNi = min(minPNi, mergeList_[Npointi]);
483 }
484
485 mergeList_[Ppointi] = mergeList_[Npointi] = minPNi;
486 }
487 }
488
490 << " Max distance between merge points: "
491 << sqrt(maxSqrDist) << endl;
492 }
493
494
495 bool changedPointMerge = false;
496 label nPasses = 0;
497
498 do
499 {
500 changedPointMerge = false;
501 nPasses++;
502
503 forAll(topoInternalFaces, topoFacei)
504 {
505 label blockPi = mergeBlockP[topoFacei].first();
506 label blockPfacei = mergeBlockP[topoFacei].second();
507
508 label blockNi = mergeBlockN[topoFacei].first();
509 label blockNfacei = mergeBlockN[topoFacei].second();
510
511 Pair<int> fmap
512 (
513 faceMap
514 (
515 blockPfacei,
516 blocks[blockPi].blockShape().faces()[blockPfacei],
517 blockNfacei,
518 blocks[blockNi].blockShape().faces()[blockNfacei]
519 )
520 );
521
522 Pair<label> Pnij(faceNij(blockPfacei, blocks[blockPi]));
523
524 for (label j=0; j<Pnij.second(); j++)
525 {
526 for (label i=0; i<Pnij.first(); i++)
527 {
528 label blockPpointi =
529 facePoint(blockPfacei, blocks[blockPi], i, j);
530
531 label blockNpointi =
532 facePointN(blockNfacei, fmap, blocks[blockNi], i, j);
533
534 label Ppointi =
535 blockPpointi + blockOffsets_[blockPi];
536
537 label Npointi =
538 blockNpointi + blockOffsets_[blockNi];
539
540 if (mergeList_[Ppointi] != mergeList_[Npointi])
541 {
542 changedPointMerge = true;
543
544 mergeList_[Ppointi]
545 = mergeList_[Npointi]
546 = min(mergeList_[Ppointi], mergeList_[Npointi]);
547 }
548 }
549 }
550 }
551
552 if (verbose_)
553 {
554 Info<< '.' << flush;
555 }
556
557 if (nPasses > 100)
558 {
560 << "Point merging failed after 100 passes."
561 << exit(FatalError);
562 }
563
564 } while (changedPointMerge);
565
566 if (verbose_)
567 {
568 Info<< endl;
569 }
570
571 // Sort merge list and count number of unique points
572 label nUniqPoints = 0;
573
574 forAll(mergeList_, pointi)
575 {
576 if (mergeList_[pointi] > pointi)
577 {
579 << "Merge list contains point index out of range"
580 << exit(FatalError);
581 }
582
583 if (mergeList_[pointi] == -1 || mergeList_[pointi] == pointi)
584 {
585 mergeList_[pointi] = nUniqPoints++;
586 }
587 else
588 {
589 mergeList_[pointi] = mergeList_[mergeList_[pointi]];
590 }
591 }
592
593 // Correct number of points in mesh
594 nPoints_ = nUniqPoints;
595}
596
597
598// ************************************************************************* //
label k
const polyMesh & topoMesh
Definition: blockMeshOBJ.H:29
T & first() noexcept
The first element of the list, position [0].
Definition: FixedListI.H:207
SubList< face > subList
Declare type of subList.
Definition: List.H:111
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:69
const T & second() const noexcept
Return second element, which is also the last element.
Definition: PairI.H:120
A List obtained as a section of another List.
Definition: SubList.H:70
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
const labelVector & density() const noexcept
The mesh density (number of cells) in the i,j,k directions.
const blockFaceList & faces() const noexcept
The curved faces.
Definition: blockMesh.H:386
const pointField & points() const
Definition: blockMesh.C:366
const polyMesh & topology() const
PtrList< block > blockList
The list of blocks is stored as a PtrList.
Definition: blockMesh.H:174
Creates a single block of cells from point coordinates, numbers of cells in each direction and an exp...
Definition: block.H:61
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
label pointLabel(const label i, const label j, const label k) const
The linear point index for an i-j-k position.
Definition: ijkMeshI.H:183
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
label nInternalFaces() const noexcept
Number of internal faces.
const cellList & cells() const
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
#define DebugInfo
Report an information message using Foam::Info.
Namespace for OpenFOAM.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
static const int faceEdgeDirs[6][4]
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
label unsignIndex(const label i, const label ni)
label facePoint(const int facei, const block &block, const label i, const label j)
label facePointN(const block &block, const label i, const label j, const label k)
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
label mapij(const int map, const label i, const label j)
Pair< label > faceNij(const label facei, const block &block)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
label signIndex(const int map, const label i)
void setBlockFaceCorrespondence(const cellList &topoCells, const faceList::subList &topoInternalFaces, const labelList &topoFaceCell, List< Pair< label > > &mergeBlock)
static Pair< int > faceFaceRotMap[6][6][4]
error FatalError
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:364
void genFaceFaceRotMap()
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333