conformalVoronoiMeshZones.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-2016 OpenFOAM Foundation
9 Copyright (C) 2021 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
30#include "polyModifyFace.H"
31#include "polyModifyCell.H"
32#include "syncTools.H"
33#include "regionSplit.H"
34#include "surfaceZonesInfo.H"
35
36// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
37
38void Foam::conformalVoronoiMesh::calcNeighbourCellCentres
39(
40 const polyMesh& mesh,
41 const pointField& cellCentres,
42 pointField& neiCc
43) const
44{
45 const label nBoundaryFaces = mesh.nBoundaryFaces();
46
47 if (neiCc.size() != nBoundaryFaces)
48 {
50 << "nBoundaries:" << nBoundaryFaces
51 << " neiCc:" << neiCc.size()
52 << abort(FatalError);
53 }
54
55 const polyBoundaryMesh& patches = mesh.boundaryMesh();
56
57 forAll(patches, patchi)
58 {
59 const polyPatch& pp = patches[patchi];
60
61 const labelUList& faceCells = pp.faceCells();
62
63 label bFacei = pp.start() - mesh.nInternalFaces();
64
65 if (pp.coupled())
66 {
67 forAll(faceCells, i)
68 {
69 neiCc[bFacei] = cellCentres[faceCells[i]];
70 bFacei++;
71 }
72 }
73 }
74
75 // Swap coupled boundaries. Apply separation to cc since is coordinate.
77}
78
79
80void Foam::conformalVoronoiMesh::selectSeparatedCoupledFaces
81(
82 const polyMesh& mesh,
83 boolList& selected
84) const
85{
86 for (const polyPatch& pp : mesh.boundaryMesh())
87 {
88 // Check all coupled. Avoid using .coupled() so we also pick up AMI.
89
90 const auto* cpp = isA<coupledPolyPatch>(pp);
91
92 if (cpp && (cpp->separated() || !cpp->parallel()))
93 {
94 SubList<bool>(selected, pp.size(), pp.start()) = true;
95 }
96 }
97}
98
99
100void Foam::conformalVoronoiMesh::findCellZoneInsideWalk
101(
102 const polyMesh& mesh,
103 const labelList& locationSurfaces, // indices of surfaces with inside point
104 const labelList& faceToSurface, // per face index of named surface
105 labelList& cellToSurface
106) const
107{
108 // Analyse regions. Reuse regionsplit
109 boolList blockedFace(mesh.nFaces());
110 selectSeparatedCoupledFaces(mesh, blockedFace);
111
112 forAll(faceToSurface, facei)
113 {
114 if (faceToSurface[facei] == -1)
115 {
116 blockedFace[facei] = false;
117 }
118 else
119 {
120 blockedFace[facei] = true;
121 }
122 }
123 // No need to sync since namedSurfaceIndex already is synced
124
125 // Set region per cell based on walking
126 regionSplit cellRegion(mesh, blockedFace);
127 blockedFace.clear();
128
129
130 // Force calculation of face decomposition (used in findCell)
131 (void)mesh.tetBasePtIs();
132
133 const PtrList<surfaceZonesInfo>& surfZones =
134 geometryToConformTo().surfZones();
135
136 // For all locationSurface find the cell
137 forAll(locationSurfaces, i)
138 {
139 label surfI = locationSurfaces[i];
140
141 const Foam::point& insidePoint = surfZones[surfI].zoneInsidePoint();
142
143 const word& surfName = geometryToConformTo().geometry().names()[surfI];
144
145 Info<< " For surface " << surfName
146 << " finding inside point " << insidePoint
147 << endl;
148
149 // Find the region containing the insidePoint
150 label keepRegionI = -1;
151
152 label celli = mesh.findCell(insidePoint);
153
154 if (celli != -1)
155 {
156 keepRegionI = cellRegion[celli];
157 }
158 reduce(keepRegionI, maxOp<label>());
159
160 Info<< " For surface " << surfName
161 << " found point " << insidePoint << " in cell " << celli
162 << " in global region " << keepRegionI
163 << " out of " << cellRegion.nRegions() << " regions." << endl;
164
165 if (keepRegionI == -1)
166 {
168 << "Point " << insidePoint
169 << " is not inside the mesh." << nl
170 << "Bounding box of the mesh:" << mesh.bounds()
171 << exit(FatalError);
172 }
173
174 // Set all cells with this region
175 forAll(cellRegion, celli)
176 {
177 if (cellRegion[celli] == keepRegionI)
178 {
179 if (cellToSurface[celli] == -2)
180 {
181 cellToSurface[celli] = surfI;
182 }
183 else if (cellToSurface[celli] != surfI)
184 {
186 << "Cell " << celli
187 << " at " << mesh.cellCentres()[celli]
188 << " is inside surface " << surfName
189 << " but already marked as being in zone "
190 << cellToSurface[celli] << endl
191 << "This can happen if your surfaces are not"
192 << " (sufficiently) closed."
193 << endl;
194 }
195 }
196 }
197 }
198}
199
200
201Foam::labelList Foam::conformalVoronoiMesh::calcCellZones
202(
203 const pointField& cellCentres
204) const
205{
206 labelList cellToSurface(cellCentres.size(), label(-1));
207
208 const PtrList<surfaceZonesInfo>& surfZones =
209 geometryToConformTo().surfZones();
210
211 // Get list of closed surfaces
212 labelList closedNamedSurfaces
213 (
215 (
216 surfZones,
217 geometryToConformTo().geometry(),
218 geometryToConformTo().surfaces()
219 )
220 );
221
222 forAll(closedNamedSurfaces, i)
223 {
224 label surfI = closedNamedSurfaces[i];
225
226 const searchableSurface& surface =
227 allGeometry()[geometryToConformTo().surfaces()[surfI]];
228
229 const surfaceZonesInfo::areaSelectionAlgo selectionMethod =
230 surfZones[surfI].zoneInside();
231
232 if
233 (
234 selectionMethod != surfaceZonesInfo::INSIDE
235 && selectionMethod != surfaceZonesInfo::OUTSIDE
236 && selectionMethod != surfaceZonesInfo::INSIDEPOINT
237 )
238 {
240 << "Trying to use surface "
241 << surface.name()
242 << " which has non-geometric inside selection method "
244 << exit(FatalError);
245 }
246
247 if (surface.hasVolumeType())
248 {
249 List<volumeType> volType;
250 surface.getVolumeType(cellCentres, volType);
251
252 bool selectInside = true;
253 if (selectionMethod == surfaceZonesInfo::INSIDEPOINT)
254 {
255 List<volumeType> volTypeInsidePoint;
256 surface.getVolumeType
257 (
258 pointField(1, surfZones[surfI].zoneInsidePoint()),
259 volTypeInsidePoint
260 );
261
262 if (volTypeInsidePoint[0] == volumeType::OUTSIDE)
263 {
264 selectInside = false;
265 }
266 }
267 else if (selectionMethod == surfaceZonesInfo::OUTSIDE)
268 {
269 selectInside = false;
270 }
271
272 forAll(volType, pointi)
273 {
274 if (cellToSurface[pointi] == -1)
275 {
276 if
277 (
278 (
279 volType[pointi] == volumeType::INSIDE
280 && selectInside
281 )
282 || (
283 volType[pointi] == volumeType::OUTSIDE
284 && !selectInside
285 )
286 )
287 {
288 cellToSurface[pointi] = surfI;
289 }
290 }
291 }
292 }
293 }
294
295 return cellToSurface;
296}
297
298
299void Foam::conformalVoronoiMesh::calcFaceZones
300(
301 const polyMesh& mesh,
302 const pointField& cellCentres,
303 const labelList& cellToSurface,
304 labelList& faceToSurface,
305 boolList& flipMap
306) const
307{
308 faceToSurface.setSize(mesh.nFaces(), -1);
309 flipMap.setSize(mesh.nFaces(), false);
310
311 const faceList& faces = mesh.faces();
312 const labelList& faceOwner = mesh.faceOwner();
313 const labelList& faceNeighbour = mesh.faceNeighbour();
314
315 labelList neiFaceOwner(mesh.nBoundaryFaces(), label(-1));
316
317 const polyBoundaryMesh& patches = mesh.boundaryMesh();
318
319 forAll(patches, patchi)
320 {
321 const polyPatch& pp = patches[patchi];
322
323 const labelUList& faceCells = pp.faceCells();
324
325 label bFacei = pp.start() - mesh.nInternalFaces();
326
327 if (pp.coupled())
328 {
329 forAll(faceCells, i)
330 {
331 neiFaceOwner[bFacei] = cellToSurface[faceCells[i]];
332 bFacei++;
333 }
334 }
335 }
336
338
339 forAll(faces, facei)
340 {
341 const label ownerSurfacei = cellToSurface[faceOwner[facei]];
342
343 if (faceToSurface[facei] >= 0)
344 {
345 continue;
346 }
347
348 if (mesh.isInternalFace(facei))
349 {
350 const label neiSurfacei = cellToSurface[faceNeighbour[facei]];
351
352 if
353 (
354 (ownerSurfacei >= 0 || neiSurfacei >= 0)
355 && ownerSurfacei != neiSurfacei
356 )
357 {
358 flipMap[facei] =
359 (
360 ownerSurfacei == max(ownerSurfacei, neiSurfacei)
361 ? false
362 : true
363 );
364
365 faceToSurface[facei] = max(ownerSurfacei, neiSurfacei);
366 }
367 }
368 else
369 {
370 label patchID = mesh.boundaryMesh().whichPatch(facei);
371
372 if (mesh.boundaryMesh()[patchID].coupled())
373 {
374 const label neiSurfacei =
375 neiFaceOwner[facei - mesh.nInternalFaces()];
376
377 if
378 (
379 (ownerSurfacei >= 0 || neiSurfacei >= 0)
380 && ownerSurfacei != neiSurfacei
381 )
382 {
383 flipMap[facei] =
384 (
385 ownerSurfacei == max(ownerSurfacei, neiSurfacei)
386 ? false
387 : true
388 );
389
390 faceToSurface[facei] = max(ownerSurfacei, neiSurfacei);
391 }
392 }
393 else
394 {
395 if (ownerSurfacei >= 0)
396 {
397 faceToSurface[facei] = ownerSurfacei;
398 }
399 }
400 }
401 }
402
403
404 const PtrList<surfaceZonesInfo>& surfZones =
405 geometryToConformTo().surfZones();
406
407 labelList unclosedSurfaces
408 (
410 (
411 surfZones,
412 geometryToConformTo().geometry(),
413 geometryToConformTo().surfaces()
414 )
415 );
416
418 calcNeighbourCellCentres
419 (
420 mesh,
421 cellCentres,
422 neiCc
423 );
424
425 // Use intersection of cellCentre connections
426 forAll(faces, facei)
427 {
428 if (faceToSurface[facei] >= 0)
429 {
430 continue;
431 }
432
433 label patchID = mesh.boundaryMesh().whichPatch(facei);
434
435 const label own = faceOwner[facei];
436
437 List<pointIndexHit> surfHit;
438 labelList hitSurface;
439
440 if (mesh.isInternalFace(facei))
441 {
442 const label nei = faceNeighbour[facei];
443
444 geometryToConformTo().findSurfaceAllIntersections
445 (
446 cellCentres[own],
447 cellCentres[nei],
448 surfHit,
449 hitSurface
450 );
451 }
452 else if (patchID != -1 && mesh.boundaryMesh()[patchID].coupled())
453 {
454 geometryToConformTo().findSurfaceAllIntersections
455 (
456 cellCentres[own],
457 neiCc[facei - mesh.nInternalFaces()],
458 surfHit,
459 hitSurface
460 );
461 }
462
463 // If there are multiple intersections then do not add to
464 // a faceZone
465 if (surfHit.size() == 1 && surfHit[0].hit())
466 {
467 if (unclosedSurfaces.found(hitSurface[0]))
468 {
469 vectorField norm;
470 geometryToConformTo().getNormal
471 (
472 hitSurface[0],
473 List<pointIndexHit>(1, surfHit[0]),
474 norm
475 );
476
477 const vector areaNorm = faces[facei].areaNormal(mesh.points());
478
479 if ((norm[0] & areaNorm) < 0)
480 {
481 flipMap[facei] = true;
482 }
483 else
484 {
485 flipMap[facei] = false;
486 }
487
488 faceToSurface[facei] = hitSurface[0];
489 }
490 }
491 }
492
493
494// labelList neiCellSurface(mesh.nBoundaryFaces());
495//
496// forAll(patches, patchi)
497// {
498// const polyPatch& pp = patches[patchi];
499//
500// if (pp.coupled())
501// {
502// forAll(pp, i)
503// {
504// label facei = pp.start()+i;
505// label ownSurface = cellToSurface[faceOwner[facei]];
506// neiCellSurface[facei - mesh.nInternalFaces()] = ownSurface;
507// }
508// }
509// }
510// syncTools::swapBoundaryFaceList(mesh, neiCellSurface);
511//
512// forAll(patches, patchi)
513// {
514// const polyPatch& pp = patches[patchi];
515//
516// if (pp.coupled())
517// {
518// forAll(pp, i)
519// {
520// label facei = pp.start()+i;
521// label ownSurface = cellToSurface[faceOwner[facei]];
522// label neiSurface =
523// neiCellSurface[facei-mesh.nInternalFaces()];
524//
525// if (faceToSurface[facei] == -1 && (ownSurface != neiSurface))
526// {
527// // Give face the max cell zone
528// faceToSurface[facei] = max(ownSurface, neiSurface);
529// }
530// }
531// }
532// }
533
534 // Sync
535 syncTools::syncFaceList(mesh, faceToSurface, maxEqOp<label>());
536}
537
538
539void Foam::conformalVoronoiMesh::addZones
540(
541 polyMesh& mesh,
542 const pointField& cellCentres
543) const
544{
545 Info<< " Adding zones to mesh" << endl;
546
547 const PtrList<surfaceZonesInfo>& surfZones =
548 geometryToConformTo().surfZones();
549
550 labelList cellToSurface(calcCellZones(cellCentres));
551
552 labelList faceToSurface;
553 boolList flipMap;
554
555 calcFaceZones
556 (
557 mesh,
558 cellCentres,
559 cellToSurface,
560 faceToSurface,
561 flipMap
562 );
563
564 labelList insidePointNamedSurfaces
565 (
567 );
568
569 findCellZoneInsideWalk
570 (
571 mesh,
572 insidePointNamedSurfaces,
573 faceToSurface,
574 cellToSurface
575 );
576
577 labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
578
579 // Tbd. No support yet for multi-faceZones on outside of cellZone
580
581 forAll(namedSurfaces, i)
582 {
583 label surfI = namedSurfaces[i];
584 const wordList& fzNames = surfZones[surfI].faceZoneNames();
585
586 Info<< incrIndent << indent << "Surface : "
587 << geometryToConformTo().geometry().names()[surfI] << nl
588 << indent << " faceZone : "
589 << (fzNames.size() ? fzNames[0] : "") << nl
590 << indent << " cellZone : "
591 << surfZones[surfI].cellZoneName()
592 << decrIndent << endl;
593 }
594
595 // Add zones to mesh
596 labelList surfaceToFaceZone(surfZones.size(), -1);
597 {
598 const labelListList surfaceToFaceZones
599 (
601 (
602 surfZones,
603 namedSurfaces,
604 mesh
605 )
606 );
607 forAll(surfaceToFaceZones, surfi)
608 {
609 if (surfaceToFaceZones[surfi].size())
610 {
611 surfaceToFaceZone[surfi] = surfaceToFaceZones[surfi][0];
612 }
613 }
614 }
615
616 const labelList surfaceToCellZone
617 (
619 (
620 surfZones,
621 namedSurfaces,
622 mesh
623 )
624 );
625
626 // Topochange container
627 polyTopoChange meshMod(mesh);
628
629 forAll(cellToSurface, celli)
630 {
631 label surfacei = cellToSurface[celli];
632
633 if (surfacei >= 0)
634 {
635 label zoneI = surfaceToCellZone[surfacei];
636
637 if (zoneI >= 0)
638 {
639 meshMod.setAction
640 (
641 polyModifyCell
642 (
643 celli,
644 false, // removeFromZone
645 zoneI
646 )
647 );
648 }
649 }
650 }
651
652 const labelList& faceOwner = mesh.faceOwner();
653 const labelList& faceNeighbour = mesh.faceNeighbour();
654
655 forAll(faceToSurface, facei)
656 {
657 label surfacei = faceToSurface[facei];
658
659 if (surfacei < 0)
660 {
661 continue;
662 }
663
664 label patchID = mesh.boundaryMesh().whichPatch(facei);
665
666 if (mesh.isInternalFace(facei))
667 {
668 label own = faceOwner[facei];
669 label nei = faceNeighbour[facei];
670
671 meshMod.setAction
672 (
673 polyModifyFace
674 (
675 mesh.faces()[facei], // modified face
676 facei, // label of face
677 own, // owner
678 nei, // neighbour
679 false, // face flip
680 -1, // patch for face
681 false, // remove from zone
682 surfaceToFaceZone[surfacei], // zone for face
683 flipMap[facei] // face flip in zone
684 )
685 );
686 }
687 else if (patchID != -1 && mesh.boundaryMesh()[patchID].coupled())
688 {
689 label own = faceOwner[facei];
690
691 meshMod.setAction
692 (
693 polyModifyFace
694 (
695 mesh.faces()[facei], // modified face
696 facei, // label of face
697 own, // owner
698 -1, // neighbour
699 false, // face flip
700 patchID, // patch for face
701 false, // remove from zone
702 surfaceToFaceZone[surfacei], // zone for face
703 flipMap[facei] // face flip in zone
704 )
705 );
706 }
707 }
708
709 // Change the mesh (no inflation, parallel sync)
710 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
711}
712
713
714// ************************************************************************* //
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
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 boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:462
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:906
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
label nInternalFaces() const noexcept
Number of internal faces.
const vectorField & cellCentres() const
label nFaces() const noexcept
Number of mesh faces.
static labelList getInsidePointNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of surfaces with a cellZone that have 'insidePoint'.
areaSelectionAlgo
Types of selection of area.
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
static labelList getAllClosedNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList, const searchableSurfaces &allGeometry, const labelList &surfaces)
Get indices of surfaces with a cellZone that are closed.
static labelList addCellZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
static labelList getUnclosedNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList, const searchableSurfaces &allGeometry, const labelList &surfaces)
Get indices of surfaces with a cellZone that are unclosed.
static labelListList addFaceZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
static const Enum< areaSelectionAlgo > areaSelectionAlgoNames
static void swapBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions)
Swap coupled positions. Uses eqOp.
Definition: syncTools.H:461
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:396
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:445
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
@ OUTSIDE
A location outside the volume.
Definition: volumeType.H:69
@ INSIDE
A location inside the volume.
Definition: volumeType.H:68
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
#define WarningInFunction
Report a warning using Foam::Warning.
const wordList surface
Standard surface field types (scalar, vector, tensor, etc)
List< word > wordList
A List of words.
Definition: fileName.H:63
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
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:349
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:342
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< bool > boolList
A List of bools.
Definition: List.H:64
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
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:356
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333