meshRefinementBaffles.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) 2011-2014 OpenFOAM Foundation
9 Copyright (C) 2015-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
29#include "meshRefinement.H"
30#include "fvMesh.H"
31#include "syncTools.H"
32#include "Time.H"
33#include "refinementSurfaces.H"
34#include "faceSet.H"
36#include "polyTopoChange.H"
37#include "meshTools.H"
38#include "polyModifyFace.H"
39#include "polyModifyCell.H"
40#include "polyAddFace.H"
41#include "polyRemoveFace.H"
42#include "localPointRegion.H"
43#include "duplicatePoints.H"
44#include "regionSplit.H"
45#include "removeCells.H"
46#include "unitConversion.H"
47#include "OBJstream.H"
49#include "PatchEdgeFaceWave.H"
51#include "polyMeshAdder.H"
52#include "IOmanip.H"
54#include "shellSurfaces.H"
56#include "volFields.H"
57#include "holeToFace.H"
58
59#include "FaceCellWave.H"
60#include "wallPoints.H"
61#include "searchableSurfaces.H"
62
63// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
64
65Foam::label Foam::meshRefinement::createBaffle
66(
67 const label faceI,
68 const label ownPatch,
69 const label neiPatch,
70 polyTopoChange& meshMod
71) const
72{
73 const face& f = mesh_.faces()[faceI];
74 label zoneID = mesh_.faceZones().whichZone(faceI);
75 bool zoneFlip = false;
76
77 if (zoneID >= 0)
78 {
79 const faceZone& fZone = mesh_.faceZones()[zoneID];
80 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
81 }
82
83 meshMod.setAction
84 (
85 polyModifyFace
86 (
87 f, // modified face
88 faceI, // label of face
89 mesh_.faceOwner()[faceI], // owner
90 -1, // neighbour
91 false, // face flip
92 ownPatch, // patch for face
93 false, // remove from zone
94 zoneID, // zone for face
95 zoneFlip // face flip in zone
96 )
97 );
98
99
100 label dupFaceI = -1;
101
102 if (mesh_.isInternalFace(faceI))
103 {
104 if (neiPatch == -1)
105 {
107 << "No neighbour patch for internal face " << faceI
108 << " fc:" << mesh_.faceCentres()[faceI]
109 << " ownPatch:" << ownPatch << abort(FatalError);
110 }
111
112 bool reverseFlip = false;
113 if (zoneID >= 0)
114 {
115 reverseFlip = !zoneFlip;
116 }
117
118 dupFaceI = meshMod.setAction
119 (
120 polyAddFace
121 (
122 f.reverseFace(), // modified face
123 mesh_.faceNeighbour()[faceI],// owner
124 -1, // neighbour
125 -1, // masterPointID
126 -1, // masterEdgeID
127 faceI, // masterFaceID,
128 true, // face flip
129 neiPatch, // patch for face
130 zoneID, // zone for face
131 reverseFlip // face flip in zone
132 )
133 );
134 }
135 return dupFaceI;
136}
137
138
145//bool Foam::meshRefinement::validBaffleTopology
146//(
147// const label faceI,
148// const vector& n1,
149// const vector& n2,
150// const vector& testDir
151//) const
152//{
153//
154// label patchI = mesh_.boundaryMesh().whichPatch(faceI);
155// if (patchI == -1 || mesh_.boundaryMesh()[patchI].coupled())
156// {
157// return true;
158// }
159// else if (mag(n1&n2) > cos(degToRad(30.0)))
160// {
161// // Both normals aligned. Check that test vector perpendicularish to
162// // surface normal
163// scalar magTestDir = mag(testDir);
164// if (magTestDir > VSMALL)
165// {
166// if (mag(n1&(testDir/magTestDir)) < cos(degToRad(45.0)))
167// {
168// //Pout<< "** disabling baffling face "
169// // << mesh_.faceCentres()[faceI] << endl;
170// return false;
171// }
172// }
173// }
174// return true;
175//}
176
177
178void Foam::meshRefinement::getIntersections
179(
180 const labelList& surfacesToTest,
181 const pointField& neiCc,
182 const labelList& testFaces,
183
184 labelList& globalRegion1,
185 labelList& globalRegion2
186) const
187{
188 autoPtr<OBJstream> str;
189 if (debug&OBJINTERSECTIONS)
190 {
191 mkDir(mesh_.time().path()/timeName());
192 str.reset
193 (
194 new OBJstream
195 (
196 mesh_.time().path()/timeName()/"intersections.obj"
197 )
198 );
199
200 Pout<< "getIntersections : Writing surface intersections to file "
201 << str().name() << nl << endl;
202 }
203
204
205 globalRegion1.setSize(mesh_.nFaces());
206 globalRegion1 = -1;
207 globalRegion2.setSize(mesh_.nFaces());
208 globalRegion2 = -1;
209
210
211 // Collect segments
212 // ~~~~~~~~~~~~~~~~
213
214 pointField start(testFaces.size());
215 pointField end(testFaces.size());
216
217 {
218 labelList minLevel;
219 calcCellCellRays
220 (
221 neiCc,
222 labelList(neiCc.size(), -1),
223 testFaces,
224 start,
225 end,
226 minLevel
227 );
228 }
229
230
231 // Do test for intersections
232 // ~~~~~~~~~~~~~~~~~~~~~~~~~
233
234 labelList surface1;
235 List<pointIndexHit> hit1;
236 labelList region1;
237 labelList surface2;
238 List<pointIndexHit> hit2;
239 labelList region2;
240 surfaces_.findNearestIntersection
241 (
242 surfacesToTest,
243 start,
244 end,
245
246 surface1,
247 hit1,
248 region1,
249
250 surface2,
251 hit2,
252 region2
253 );
254
255
256 forAll(testFaces, i)
257 {
258 label faceI = testFaces[i];
259
260 if (hit1[i].hit() && hit2[i].hit())
261 {
262 if (str)
263 {
264 str().write(linePointRef(start[i], hit1[i].rawPoint()));
265 str().write
266 (
267 linePointRef(hit1[i].rawPoint(), hit2[i].rawPoint())
268 );
269 str().write(linePointRef(hit2[i].rawPoint(), end[i]));
270 }
271
272 // Pick up the patches
273 globalRegion1[faceI] =
274 surfaces_.globalRegion(surface1[i], region1[i]);
275 globalRegion2[faceI] =
276 surfaces_.globalRegion(surface2[i], region2[i]);
277
278 if (globalRegion1[faceI] == -1 || globalRegion2[faceI] == -1)
279 {
281 << "problem." << abort(FatalError);
282 }
283 }
284 }
285}
286
287
288void Foam::meshRefinement::getBafflePatches
289(
290 const label nErodeCellZones,
291 const labelList& globalToMasterPatch,
292 const pointField& locationsInMesh,
293 const wordList& zonesInMesh,
294 const pointField& locationsOutsideMesh,
295 const bool exitIfLeakPath,
296 const refPtr<coordSetWriter>& leakPathFormatter,
297 const labelList& neiLevel,
298 const pointField& neiCc,
299
300 labelList& ownPatch,
301 labelList& neiPatch
302) const
303{
304 // This determines the patches for the intersected faces to
305 // - remove the outside of the mesh
306 // - introduce baffles for (non-faceZone) intersections
307 // Any baffles for faceZones (faceType 'baffle'/'boundary') get introduced
308 // later
309
310
311 // 1. Determine intersections with unnamed surfaces and cell zones
312 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
313 // Notice that this also does hole-closure so the unnamed* is not just
314 // the surface intersections.
315
316 labelList cellToZone;
317 labelList unnamedRegion1;
318 labelList unnamedRegion2;
319 labelList namedSurfaceRegion;
320 {
321 bitSet posOrientation;
322 zonify
323 (
324 true, // allowFreeStandingZoneFaces
325 nErodeCellZones,
326 -2, // zone to put unreached cells into
327 locationsInMesh,
328 zonesInMesh,
329 locationsOutsideMesh,
330 exitIfLeakPath,
331 leakPathFormatter,
332
333 cellToZone,
334 unnamedRegion1,
335 unnamedRegion2,
336 namedSurfaceRegion,
337 posOrientation
338 );
339 }
340
341
342 // 2. Baffle all boundary faces
343 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
344 // The logic is that all intersections with unnamed surfaces become
345 // baffles except where we're inbetween a cellZone and background
346 // or inbetween two different cellZones.
347
348 labelList neiCellZone;
349 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
350
351 ownPatch.setSize(mesh_.nFaces());
352 ownPatch = -1;
353 neiPatch.setSize(mesh_.nFaces());
354 neiPatch = -1;
355
356 forAll(ownPatch, faceI)
357 {
358 if (unnamedRegion1[faceI] != -1 || unnamedRegion2[faceI] != -1)
359 {
360 label ownMasterPatch = -1;
361 if (unnamedRegion1[faceI] != -1)
362 {
363 ownMasterPatch = globalToMasterPatch[unnamedRegion1[faceI]];
364 }
365 label neiMasterPatch = -1;
366 if (unnamedRegion2[faceI] != -1)
367 {
368 neiMasterPatch = globalToMasterPatch[unnamedRegion2[faceI]];
369 }
370
371
372 // Now we always want to produce a baffle except if
373 // one side is a valid cellZone
374
375 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
376 label neiZone = -1;
377
378 if (mesh_.isInternalFace(faceI))
379 {
380 neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
381 }
382 else
383 {
384 neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
385 }
386
387
388 if
389 (
390 (ownZone != neiZone)
391 && (
392 (ownZone >= 0 && neiZone != -2)
393 || (neiZone >= 0 && ownZone != -2)
394 )
395 && (
396 namedSurfaceRegion.size() == 0
397 || namedSurfaceRegion[faceI] == -1
398 )
399 )
400 {
401 // One side is a valid cellZone and the neighbour is a different
402 // one (or -1 but not -2). Do not baffle unless the user has
403 // put both an unnamed and a named surface there. In that
404 // case assume that the user wants both: baffle and faceZone.
405 }
406 else
407 {
408 ownPatch[faceI] = ownMasterPatch;
409 neiPatch[faceI] = neiMasterPatch;
410 }
411 }
412 }
413
414 // No need to parallel sync since intersection data (surfaceIndex_ etc.)
415 // already guaranteed to be synced...
416 // However:
417 // - owncc and neicc are reversed on different procs so might pick
418 // up different regions reversed? No problem. Neighbour on one processor
419 // might not be owner on the other processor but the neighbour is
420 // not used when creating baffles from proc faces.
421 // - tolerances issues occasionally crop up.
422 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
423 syncTools::syncFaceList(mesh_, neiPatch, maxEqOp<label>());
424}
425
426
427Foam::Map<Foam::labelPair> Foam::meshRefinement::getZoneBafflePatches
428(
429 const bool allowBoundary,
430 const labelList& globalToMasterPatch,
431 const labelList& globalToSlavePatch
432) const
433{
434 Map<labelPair> bafflePatch(mesh_.nFaces()/1000);
435
436 const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
437 const faceZoneMesh& fZones = mesh_.faceZones();
438
439 forAll(surfZones, surfI)
440 {
441 const wordList& faceZoneNames = surfZones[surfI].faceZoneNames();
442
443 forAll(faceZoneNames, fzi)
444 {
445 // Get zone
446 const word& faceZoneName = faceZoneNames[fzi];
447 label zoneI = fZones.findZoneID(faceZoneName);
448 const faceZone& fZone = fZones[zoneI];
449
450 // Get patch allocated for zone
451 label globalRegionI = surfaces_.globalRegion(surfI, fzi);
452 labelPair zPatches
453 (
454 globalToMasterPatch[globalRegionI],
455 globalToSlavePatch[globalRegionI]
456 );
457
458 Info<< "For zone " << fZone.name() << " found patches "
459 << mesh_.boundaryMesh()[zPatches[0]].name() << " and "
460 << mesh_.boundaryMesh()[zPatches[1]].name()
461 << endl;
462
463 forAll(fZone, i)
464 {
465 label faceI = fZone[i];
466
467 if (allowBoundary || mesh_.isInternalFace(faceI))
468 {
469 labelPair patches = zPatches;
470 if (fZone.flipMap()[i])
471 {
473 }
474
475 if (!bafflePatch.insert(faceI, patches))
476 {
478 << "Face " << faceI
479 << " fc:" << mesh_.faceCentres()[faceI]
480 << " in zone " << fZone.name()
481 << " is in multiple zones!"
482 << abort(FatalError);
483 }
484 }
485 }
486 }
487 }
488 return bafflePatch;
489}
490
491
493(
494 const labelList& ownPatch,
495 const labelList& neiPatch
496)
497{
498 if
499 (
500 ownPatch.size() != mesh_.nFaces()
501 || neiPatch.size() != mesh_.nFaces()
502 )
503 {
505 << "Illegal size :"
506 << " ownPatch:" << ownPatch.size()
507 << " neiPatch:" << neiPatch.size()
508 << ". Should be number of faces:" << mesh_.nFaces()
509 << abort(FatalError);
510 }
511
512 if (debug)
513 {
514 labelList syncedOwnPatch(ownPatch);
515 syncTools::syncFaceList(mesh_, syncedOwnPatch, maxEqOp<label>());
516 labelList syncedNeiPatch(neiPatch);
517 syncTools::syncFaceList(mesh_, syncedNeiPatch, maxEqOp<label>());
518
519 forAll(syncedOwnPatch, faceI)
520 {
521 if
522 (
523 (ownPatch[faceI] == -1 && syncedOwnPatch[faceI] != -1)
524 || (neiPatch[faceI] == -1 && syncedNeiPatch[faceI] != -1)
525 )
526 {
528 << "Non synchronised at face:" << faceI
529 << " on patch:" << mesh_.boundaryMesh().whichPatch(faceI)
530 << " fc:" << mesh_.faceCentres()[faceI] << endl
531 << "ownPatch:" << ownPatch[faceI]
532 << " syncedOwnPatch:" << syncedOwnPatch[faceI]
533 << " neiPatch:" << neiPatch[faceI]
534 << " syncedNeiPatch:" << syncedNeiPatch[faceI]
535 << abort(FatalError);
536 }
537 }
538 }
539
540 // Topochange container
541 polyTopoChange meshMod(mesh_);
542
543 label nBaffles = 0;
544
545 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
546 {
547 if (ownPatch[faceI] != -1)
548 {
549 // Create baffle or repatch face. Return label of inserted baffle
550 // face.
551 createBaffle
552 (
553 faceI,
554 ownPatch[faceI], // owner side patch
555 neiPatch[faceI], // neighbour side patch
556 meshMod
557 );
558 nBaffles++;
559 }
560 }
561 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
562
563 forAll(pbm, patchI)
564 {
565 const polyPatch& pp = pbm[patchI];
566
567 label coupledPatchI = -1;
568 if
569 (
570 pp.coupled()
571 && !refCast<const coupledPolyPatch>(pp).separated()
572 )
573 {
574 coupledPatchI = patchI;
575 }
576
577 forAll(pp, i)
578 {
579 label faceI = pp.start()+i;
580
581 if (ownPatch[faceI] != -1)
582 {
583 createBaffle
584 (
585 faceI,
586 ownPatch[faceI], // owner side patch
587 neiPatch[faceI], // neighbour side patch
588 meshMod
589 );
590
591 if (coupledPatchI != -1)
592 {
593 faceToCoupledPatch_.insert(faceI, coupledPatchI);
594 }
595
596 nBaffles++;
597 }
598 }
599 }
600
601
603 if (returnReduce(nBaffles, sumOp<label>()))
604 {
605 // Remove any unnecessary fields
606 mesh_.clearOut();
607 mesh_.moving(false);
608
609 // Change the mesh (no inflation, parallel sync)
610 mapPtr = meshMod.changeMesh(mesh_, false, true);
611 mapPolyMesh& map = *mapPtr;
612
613 // Update fields
614 mesh_.updateMesh(map);
615
616 // Move mesh if in inflation mode
617 if (map.hasMotionPoints())
618 {
619 mesh_.movePoints(map.preMotionPoints());
620 }
621 else
622 {
623 // Delete mesh volumes.
624 mesh_.clearOut();
625 }
626
627
628 // Reset the instance for if in overwrite mode
629 mesh_.setInstance(timeName());
630
631 //- Redo the intersections on the newly create baffle faces. Note that
632 // this changes also the cell centre positions.
633 faceSet baffledFacesSet(mesh_, "baffledFacesSet", 2*nBaffles);
634
635 const labelList& reverseFaceMap = map.reverseFaceMap();
636 const labelList& faceMap = map.faceMap();
637
638 // Pick up owner side of baffle
639 forAll(ownPatch, oldFaceI)
640 {
641 label faceI = reverseFaceMap[oldFaceI];
642
643 if (ownPatch[oldFaceI] != -1 && faceI >= 0)
644 {
645 const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
646
647 baffledFacesSet.insert(ownFaces);
648 }
649 }
650 // Pick up neighbour side of baffle (added faces)
651 forAll(faceMap, faceI)
652 {
653 label oldFaceI = faceMap[faceI];
654
655 if (oldFaceI >= 0 && reverseFaceMap[oldFaceI] != faceI)
656 {
657 const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
658
659 baffledFacesSet.insert(ownFaces);
660 }
661 }
662 baffledFacesSet.sync(mesh_);
663
664 updateMesh(map, baffledFacesSet.toc());
665 }
666
667 return mapPtr;
668}
669
670
672(
674) const
675{
676 const faceZoneMesh& faceZones = mesh_.faceZones();
677
678 DynamicList<label> zoneIDs(faceZones.size());
679
680 forAll(faceZones, zoneI)
681 {
682 const faceZone& fZone = faceZones[zoneI];
683
684 label mpI, spI;
686 bool hasInfo = getFaceZoneInfo(fZone.name(), mpI, spI, fzType);
687
688 if (hasInfo && fzTypes.found(fzType))
689 {
690 zoneIDs.append(zoneI);
691 }
692 }
693 return zoneIDs;
694}
695
696
697// Subset those baffles where both faces are on the same zone
699(
700 const polyMesh& mesh,
701 const labelList& zoneIDs,
702 const List<labelPair>& baffles
703)
704{
705 const faceZoneMesh& faceZones = mesh.faceZones();
706
707 // Mark zone per face
708 labelList faceToZone(mesh.nFaces(), -1);
709
710 for (const label zoneID : zoneIDs)
711 {
712 labelUIndList(faceToZone, faceZones[zoneID]) = zoneID;
713 }
714
715
716 // Subset baffles
717 DynamicList<labelPair> newBaffles(baffles.size());
718 forAll(baffles, i)
719 {
720 const labelPair& p = baffles[i];
721 if (faceToZone[p[0]] != -1 && (faceToZone[p[0]] == faceToZone[p[1]]))
722 {
723 newBaffles.append(p);
724 }
725 }
726
727 return newBaffles;
728}
729
730
732(
733 const labelList& zoneIDs,
735 labelList& ownPatch,
736 labelList& neiPatch,
737 labelList& nBaffles
738) const
739{
740 const faceZoneMesh& faceZones = mesh_.faceZones();
741
742 // Per (internal) face the patch related to the faceZone
743 ownPatch.setSize(mesh_.nFaces());
744 ownPatch= -1;
745 neiPatch.setSize(mesh_.nFaces());
746 neiPatch = -1;
747 faceZoneID.setSize(mesh_.nFaces());
748 faceZoneID = -1;
749 nBaffles.setSize(zoneIDs.size());
750 nBaffles = Zero;
751
752
753 //- Get per face whether it is internal or coupled
754 const bitSet isInternalOrCoupled
755 (
757 );
758
759 forAll(zoneIDs, j)
760 {
761 label zoneI = zoneIDs[j];
762 const faceZone& fz = faceZones[zoneI];
763 const word& masterName = faceZoneToMasterPatch_[fz.name()];
764 label masterPatchI = mesh_.boundaryMesh().findPatchID(masterName);
765 const word& slaveName = faceZoneToSlavePatch_[fz.name()];
766 label slavePatchI = mesh_.boundaryMesh().findPatchID(slaveName);
767
768 if (masterPatchI == -1 || slavePatchI == -1)
769 {
771 << "Problem: masterPatchI:" << masterPatchI
772 << " slavePatchI:" << slavePatchI << exit(FatalError);
773 }
774
775 forAll(fz, i)
776 {
777 label faceI = fz[i];
778 if (isInternalOrCoupled[faceI])
779 {
780 if (fz.flipMap()[i])
781 {
782 ownPatch[faceI] = slavePatchI;
783 neiPatch[faceI] = masterPatchI;
784 }
785 else
786 {
787 ownPatch[faceI] = masterPatchI;
788 neiPatch[faceI] = slavePatchI;
789 }
790 faceZoneID[faceI] = zoneI;
791
792 nBaffles[j]++;
793 }
794 }
795 }
796}
797
798
800(
801 const labelList& zoneIDs,
802 List<labelPair>& baffles,
803 labelList& originatingFaceZone
804)
805{
807
808 if (zoneIDs.size() > 0)
809 {
810 const faceZoneMesh& faceZones = mesh_.faceZones();
811
812 // Split internal faces on interface surfaces
813 Info<< "Converting zoned faces into baffles ..." << endl;
814
815 // Get faceZone and patch(es) per face (or -1 if face not on faceZone)
817 labelList ownPatch;
818 labelList neiPatch;
819 labelList nBaffles;
820 getZoneFaces(zoneIDs, faceZoneID, ownPatch, neiPatch, nBaffles);
821
822 label nLocalBaffles = sum(nBaffles);
823
824
825 label nTotalBaffles = returnReduce(nLocalBaffles, sumOp<label>());
826
827 if (nTotalBaffles > 0)
828 {
830
831 Info<< nl
832 << setf(ios_base::left)
833 << setw(30) << "FaceZone"
834 << setw(10) << "FaceType"
835 << setw(10) << "nBaffles"
836 << nl
837 << setw(30) << "--------"
838 << setw(10) << "--------"
839 << setw(10) << "--------"
840 << endl;
841
842 forAll(zoneIDs, j)
843 {
844 label zoneI = zoneIDs[j];
845 const faceZone& fz = faceZones[zoneI];
846
847 label mpI, spI;
849 bool hasInfo = getFaceZoneInfo(fz.name(), mpI, spI, fzType);
850
851 if (hasInfo)
852 {
853 Info<< setf(ios_base::left)
854 << setw(30) << fz.name()
855 << setw(10)
857 << setw(10) << nBaffles[j]
858 << nl;
859 }
860 }
861 Info<< endl;
862
863 // Create baffles.
864 map = createBaffles(ownPatch, neiPatch);
865
866 // Get pairs of faces created.
867 // Just loop over faceMap and store baffle if we encounter a slave
868 // face.
869
870 baffles.setSize(nLocalBaffles);
871 originatingFaceZone.setSize(nLocalBaffles);
872 label baffleI = 0;
873
874 const labelList& faceMap = map().faceMap();
875 const labelList& reverseFaceMap = map().reverseFaceMap();
876
877 for
878 (
879 label faceI = mesh_.nInternalFaces();
880 faceI < mesh_.nFaces();
881 faceI++
882 )
883 {
884 label oldFaceI = faceMap[faceI];
885 label masterFaceI = reverseFaceMap[oldFaceI];
886 if (masterFaceI != faceI && ownPatch[oldFaceI] != -1)
887 {
888 baffles[baffleI] = labelPair(masterFaceI, faceI);
889 originatingFaceZone[baffleI] = faceZoneID[oldFaceI];
890 baffleI++;
891 }
892 }
893
894 if (baffleI != baffles.size())
895 {
897 << "Had " << baffles.size() << " baffles to create "
898 << " but encountered " << baffleI
899 << " slave faces originating from patcheable faces."
900 << abort(FatalError);
901 }
902
903 if (debug&MESH)
904 {
905 const_cast<Time&>(mesh_.time())++;
906 Pout<< "Writing zone-baffled mesh to time " << timeName()
907 << endl;
908 write
909 (
910 debugType(debug),
911 writeType(writeLevel() | WRITEMESH),
912 mesh_.time().path()/"baffles"
913 );
914 }
915 }
916 Info<< "Created " << nTotalBaffles << " baffles in = "
917 << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl;
918 }
919 else
920 {
921 baffles.clear();
922 originatingFaceZone.clear();
923 }
924
925 return map;
926}
927
928
929Foam::List<Foam::labelPair> Foam::meshRefinement::freeStandingBaffles
930(
931 const List<labelPair>& couples,
932 const scalar planarAngle
933) const
934{
935 // Done by counting the number of baffles faces per mesh edge. If edge
936 // has 2 boundary faces and both are baffle faces it is the edge of a baffle
937 // region.
938
939 // All duplicate faces on edge of the patch are to be merged.
940 // So we count for all edges of duplicate faces how many duplicate
941 // faces use them.
942 labelList nBafflesPerEdge(mesh_.nEdges(), Zero);
943
944
945 // This algorithm is quite tricky. We don't want to use edgeFaces and
946 // also want it to run in parallel so it is now an algorithm over
947 // all (boundary) faces instead.
948 // We want to pick up any edges that are only used by the baffle
949 // or internal faces but not by any other boundary faces. So
950 // - increment count on an edge by 1 if it is used by any (uncoupled)
951 // boundary face.
952 // - increment count on an edge by 1000000 if it is used by a baffle face
953 // - sum in parallel
954 //
955 // So now any edge that is used by baffle faces only will have the
956 // value 2*1000000+2*1.
957
958
959 const label baffleValue = 1000000;
960
961
962 // Count number of boundary faces per edge
963 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
964
965 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
966
967 forAll(patches, patchI)
968 {
969 const polyPatch& pp = patches[patchI];
970
971 // Count number of boundary faces. Discard coupled boundary faces.
972 if (!pp.coupled())
973 {
974 label faceI = pp.start();
975
976 forAll(pp, i)
977 {
978 const labelList& fEdges = mesh_.faceEdges(faceI);
979
980 forAll(fEdges, fEdgeI)
981 {
982 nBafflesPerEdge[fEdges[fEdgeI]]++;
983 }
984 faceI++;
985 }
986 }
987 }
988
989
990 DynamicList<label> fe0;
991 DynamicList<label> fe1;
992
993
994 // Count number of duplicate boundary faces per edge
995 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
996
997 forAll(couples, i)
998 {
999 {
1000 label f0 = couples[i].first();
1001 const labelList& fEdges0 = mesh_.faceEdges(f0, fe0);
1002 forAll(fEdges0, fEdgeI)
1003 {
1004 nBafflesPerEdge[fEdges0[fEdgeI]] += baffleValue;
1005 }
1006 }
1007
1008 {
1009 label f1 = couples[i].second();
1010 const labelList& fEdges1 = mesh_.faceEdges(f1, fe1);
1011 forAll(fEdges1, fEdgeI)
1012 {
1013 nBafflesPerEdge[fEdges1[fEdgeI]] += baffleValue;
1014 }
1015 }
1016 }
1017
1018 // Add nBaffles on shared edges
1020 (
1021 mesh_,
1022 nBafflesPerEdge,
1023 plusEqOp<label>(), // in-place add
1024 label(0) // initial value
1025 );
1026
1027
1028 // Baffles which are not next to other boundaries and baffles will have
1029 // nBafflesPerEdge value 2*baffleValue+2*1 (from 2 boundary faces which
1030 // are both baffle faces)
1031
1032 List<labelPair> filteredCouples(couples.size());
1033 label filterI = 0;
1034
1035 forAll(couples, i)
1036 {
1037 const labelPair& couple = couples[i];
1038
1039 if
1040 (
1041 patches.whichPatch(couple.first())
1042 == patches.whichPatch(couple.second())
1043 )
1044 {
1045 const labelList& fEdges = mesh_.faceEdges(couple.first());
1046
1047 forAll(fEdges, fEdgeI)
1048 {
1049 label edgeI = fEdges[fEdgeI];
1050
1051 if (nBafflesPerEdge[edgeI] == 2*baffleValue+2*1)
1052 {
1053 filteredCouples[filterI++] = couple;
1054 break;
1055 }
1056 }
1057 }
1058 }
1059 filteredCouples.setSize(filterI);
1060
1061
1062 label nFiltered = returnReduce(filteredCouples.size(), sumOp<label>());
1063
1064 Info<< "freeStandingBaffles : detected "
1065 << nFiltered
1066 << " free-standing baffles out of "
1067 << returnReduce(couples.size(), sumOp<label>())
1068 << nl << endl;
1069
1070
1071 if (nFiltered > 0)
1072 {
1073 // Collect segments
1074 // ~~~~~~~~~~~~~~~~
1075
1076 pointField start(filteredCouples.size());
1077 pointField end(filteredCouples.size());
1078
1079 const pointField& cellCentres = mesh_.cellCentres();
1080
1081 forAll(filteredCouples, i)
1082 {
1083 const labelPair& couple = filteredCouples[i];
1084 start[i] = cellCentres[mesh_.faceOwner()[couple.first()]];
1085 end[i] = cellCentres[mesh_.faceOwner()[couple.second()]];
1086 }
1087
1088 // Extend segments a bit
1089 {
1090 const vectorField smallVec(ROOTSMALL*(end-start));
1091 start -= smallVec;
1092 end += smallVec;
1093 }
1094
1095
1096 // Do test for intersections
1097 // ~~~~~~~~~~~~~~~~~~~~~~~~~
1098 labelList surface1;
1099 List<pointIndexHit> hit1;
1100 labelList region1;
1101 vectorField normal1;
1102
1103 labelList surface2;
1104 List<pointIndexHit> hit2;
1105 labelList region2;
1106 vectorField normal2;
1107
1108 surfaces_.findNearestIntersection
1109 (
1110 identity(surfaces_.surfaces().size()),
1111 start,
1112 end,
1113
1114 surface1,
1115 hit1,
1116 region1,
1117 normal1,
1118
1119 surface2,
1120 hit2,
1121 region2,
1122 normal2
1123 );
1124
1125 //mkDir(mesh_.time().path()/timeName());
1126 //OBJstream str
1127 //(
1128 // mesh_.time().path()/timeName()/"flatBaffles.obj"
1129 //);
1130
1131 const scalar planarAngleCos = Foam::cos(degToRad(planarAngle));
1132
1133 label filterI = 0;
1134 forAll(filteredCouples, i)
1135 {
1136 const labelPair& couple = filteredCouples[i];
1137
1138 // Note: for a baffle-surface we do not want to merge the baffle.
1139 // We could either check for hitting the same triangle (but you
1140 // might hit same point on neighbouring triangles due to tolerance
1141 // issues) or better just to compare the hit point.
1142 // This might still go wrong for a ray in the plane of the triangle
1143 // which might hit two different points on the same triangle due
1144 // to tolerances...
1145
1146 if
1147 (
1148 hit1[i].hit()
1149 && hit2[i].hit()
1150 && mag(hit1[i].hitPoint()-hit2[i].hitPoint()) > mergeDistance_
1151 )
1152 {
1153 // Two different hits. Check angle.
1154 //str.write
1155 //(
1156 // linePointRef(hit1[i].hitPoint(), hit2[i].hitPoint()),
1157 // normal1[i],
1158 // normal2[i]
1159 //);
1160
1161 if ((normal1[i]&normal2[i]) > planarAngleCos)
1162 {
1163 // Both normals aligned
1164 vector n = end[i]-start[i];
1165 scalar magN = mag(n);
1166 if (magN > VSMALL)
1167 {
1168 filteredCouples[filterI++] = couple;
1169 }
1170 }
1171 }
1172 else if (hit1[i].hit() || hit2[i].hit())
1173 {
1174 // Single hit. Do not include in freestanding baffles.
1175 }
1176 }
1177
1178 filteredCouples.setSize(filterI);
1179
1180 Info<< "freeStandingBaffles : detected "
1181 << returnReduce(filterI, sumOp<label>())
1182 << " planar (within " << planarAngle
1183 << " degrees) free-standing baffles out of "
1184 << nFiltered
1185 << nl << endl;
1186 }
1187
1188 return filteredCouples;
1189}
1190
1191
1193(
1194 const List<labelPair>& couples,
1195 const Map<label>& faceToPatch
1196)
1197{
1198 autoPtr<mapPolyMesh> mapPtr;
1199
1200 if (returnReduce(couples.size()+faceToPatch.size(), sumOp<label>()))
1201 {
1202 // Mesh change engine
1203 polyTopoChange meshMod(mesh_);
1204
1205 const faceList& faces = mesh_.faces();
1206 const labelList& faceOwner = mesh_.faceOwner();
1207 const faceZoneMesh& faceZones = mesh_.faceZones();
1208
1209 forAll(couples, i)
1210 {
1211 label face0 = couples[i].first();
1212 label face1 = couples[i].second();
1213
1214 // face1 < 0 signals a coupled face that has been converted to
1215 // baffle
1216
1217 label own0 = faceOwner[face0];
1218 label own1 = faceOwner[face1];
1219
1220 if (face1 < 0 || own0 < own1)
1221 {
1222 // Use face0 as the new internal face.
1223 label zoneID = faceZones.whichZone(face0);
1224 bool zoneFlip = false;
1225
1226 if (zoneID >= 0)
1227 {
1228 const faceZone& fZone = faceZones[zoneID];
1229 zoneFlip = fZone.flipMap()[fZone.whichFace(face0)];
1230 }
1231
1232 label nei = (face1 < 0 ? -1 : own1);
1233
1234 meshMod.setAction(polyRemoveFace(face1));
1235 meshMod.setAction
1236 (
1238 (
1239 faces[face0], // modified face
1240 face0, // label of face being modified
1241 own0, // owner
1242 nei, // neighbour
1243 false, // face flip
1244 -1, // patch for face
1245 false, // remove from zone
1246 zoneID, // zone for face
1247 zoneFlip // face flip in zone
1248 )
1249 );
1250 }
1251 else
1252 {
1253 // Use face1 as the new internal face.
1254 label zoneID = faceZones.whichZone(face1);
1255 bool zoneFlip = false;
1256
1257 if (zoneID >= 0)
1258 {
1259 const faceZone& fZone = faceZones[zoneID];
1260 zoneFlip = fZone.flipMap()[fZone.whichFace(face1)];
1261 }
1262
1263 meshMod.setAction(polyRemoveFace(face0));
1264 meshMod.setAction
1265 (
1267 (
1268 faces[face1], // modified face
1269 face1, // label of face being modified
1270 own1, // owner
1271 own0, // neighbour
1272 false, // face flip
1273 -1, // patch for face
1274 false, // remove from zone
1275 zoneID, // zone for face
1276 zoneFlip // face flip in zone
1277 )
1278 );
1279 }
1280 }
1281
1282 forAllConstIters(faceToPatch, iter)
1283 {
1284 const label faceI = iter.key();
1285 const label patchI = iter.val();
1286
1287 if (!mesh_.isInternalFace(faceI))
1288 {
1290 << "problem: face:" << faceI
1291 << " at:" << mesh_.faceCentres()[faceI]
1292 << "(wanted patch:" << patchI
1293 << ") is an internal face" << exit(FatalError);
1294 }
1295
1296 label zoneID = faceZones.whichZone(faceI);
1297 bool zoneFlip = false;
1298
1299 if (zoneID >= 0)
1300 {
1301 const faceZone& fZone = faceZones[zoneID];
1302 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
1303 }
1304
1305 meshMod.setAction
1306 (
1308 (
1309 faces[faceI], // modified face
1310 faceI, // label of face being modified
1311 faceOwner[faceI], // owner
1312 -1, // neighbour
1313 false, // face flip
1314 patchI, // patch for face
1315 false, // remove from zone
1316 zoneID, // zone for face
1317 zoneFlip // face flip in zone
1318 )
1319 );
1320 }
1321
1322
1323 // Remove any unnecessary fields
1324 mesh_.clearOut();
1325 mesh_.moving(false);
1326
1327 // Change the mesh (no inflation)
1328 mapPtr = meshMod.changeMesh(mesh_, false, true);
1329 mapPolyMesh& map = *mapPtr;
1330
1331 // Update fields
1332 mesh_.updateMesh(map);
1333
1334 // Move mesh (since morphing does not do this)
1335 if (map.hasMotionPoints())
1336 {
1337 mesh_.movePoints(map.preMotionPoints());
1338 }
1339 else
1340 {
1341 // Delete mesh volumes.
1342 mesh_.clearOut();
1343 }
1344
1345 // Reset the instance for if in overwrite mode
1346 mesh_.setInstance(timeName());
1347
1348 // Update intersections. Recalculate intersections on merged faces since
1349 // this seems to give problems? Note: should not be necessary since
1350 // baffles preserve intersections from when they were created.
1351 labelList newExposedFaces(2*couples.size());
1352 label newI = 0;
1353
1354 forAll(couples, i)
1355 {
1356 const label newFace0 = map.reverseFaceMap()[couples[i].first()];
1357 if (newFace0 != -1)
1358 {
1359 newExposedFaces[newI++] = newFace0;
1360 }
1361
1362 const label newFace1 = map.reverseFaceMap()[couples[i].second()];
1363 if (newFace1 != -1)
1364 {
1365 newExposedFaces[newI++] = newFace1;
1366 }
1367 }
1368 newExposedFaces.setSize(newI);
1369 updateMesh(map, newExposedFaces);
1370 }
1371
1372 return mapPtr;
1373}
1374
1375
1377(
1378 const bool doInternalZones,
1379 const bool doBaffleZones
1380)
1381{
1383 {
1385 if (doInternalZones)
1386 {
1388 }
1389 if (doBaffleZones)
1390 {
1392 }
1393 zoneIDs = getZones(fzTypes);
1394 }
1395
1396 List<labelPair> zoneBaffles
1397 (
1398 subsetBaffles
1399 (
1400 mesh_,
1401 zoneIDs,
1403 )
1404 );
1405
1406 autoPtr<mapPolyMesh> mapPtr;
1407 if (returnReduce(zoneBaffles.size(), sumOp<label>()))
1408 {
1409 mapPtr = mergeBaffles(zoneBaffles, Map<label>(0));
1410 }
1411 return mapPtr;
1412}
1413
1414
1415// Finds region per cell for cells inside closed named surfaces
1416void Foam::meshRefinement::findCellZoneGeometric
1417(
1418 const pointField& neiCc,
1419 const labelList& closedNamedSurfaces, // indices of closed surfaces
1420 labelList& namedSurfaceRegion, // per face: named surface region
1421 const labelList& surfaceToCellZone, // cell zone index per surface
1422
1423 labelList& cellToZone
1424) const
1425{
1426 const pointField& cellCentres = mesh_.cellCentres();
1427 const labelList& faceOwner = mesh_.faceOwner();
1428 const labelList& faceNeighbour = mesh_.faceNeighbour();
1429
1430 // Check if cell centre is inside
1431 labelList insideSurfaces;
1432 surfaces_.findInside
1433 (
1434 closedNamedSurfaces,
1435 cellCentres,
1436 insideSurfaces
1437 );
1438
1439 forAll(insideSurfaces, cellI)
1440 {
1441 label surfI = insideSurfaces[cellI];
1442
1443 if (surfI != -1)
1444 {
1445 if (cellToZone[cellI] == -2)
1446 {
1447 cellToZone[cellI] = surfaceToCellZone[surfI];
1448 }
1449 else if (cellToZone[cellI] == -1)
1450 {
1451 // ? Allow named surface to override background zone (-1)
1452 // This is used in the multiRegionHeater tutorial where the
1453 // locationInMesh is inside a named surface.
1454 cellToZone[cellI] = surfaceToCellZone[surfI];
1455 }
1456 }
1457 }
1458
1459
1460 // Some cells with cell centres close to surface might have
1461 // had been put into wrong surface. Recheck with perturbed cell centre.
1462
1463
1464 // 1. Collect points
1465
1466 // Count points to test.
1467 label nCandidates = 0;
1468 forAll(namedSurfaceRegion, faceI)
1469 {
1470 if (namedSurfaceRegion[faceI] != -1)
1471 {
1472 if (mesh_.isInternalFace(faceI))
1473 {
1474 nCandidates += 2;
1475 }
1476 else
1477 {
1478 nCandidates += 1;
1479 }
1480 }
1481 }
1482
1483 // Collect points.
1484 pointField candidatePoints(nCandidates);
1485 nCandidates = 0;
1486 forAll(namedSurfaceRegion, faceI)
1487 {
1488 if (namedSurfaceRegion[faceI] != -1)
1489 {
1490 label own = faceOwner[faceI];
1491 const point& ownCc = cellCentres[own];
1492
1493 if (mesh_.isInternalFace(faceI))
1494 {
1495 label nei = faceNeighbour[faceI];
1496 const point& neiCc = cellCentres[nei];
1497 // Perturbed cc
1498 const vector d = 1e-4*(neiCc - ownCc);
1499 candidatePoints[nCandidates++] = ownCc-d;
1500 candidatePoints[nCandidates++] = neiCc+d;
1501 }
1502 else
1503 {
1504 //const point& neiFc = mesh_.faceCentres()[faceI];
1505 const point& neiFc = neiCc[faceI-mesh_.nInternalFaces()];
1506
1507 // Perturbed cc
1508 const vector d = 1e-4*(neiFc - ownCc);
1509 candidatePoints[nCandidates++] = ownCc-d;
1510 }
1511 }
1512 }
1513
1514
1515 // 2. Test points for inside
1516
1517 surfaces_.findInside
1518 (
1519 closedNamedSurfaces,
1520 candidatePoints,
1521 insideSurfaces
1522 );
1523
1524
1525 // 3. Update zone information
1526
1527 nCandidates = 0;
1528 forAll(namedSurfaceRegion, faceI)
1529 {
1530 if (namedSurfaceRegion[faceI] != -1)
1531 {
1532 label own = faceOwner[faceI];
1533
1534 if (mesh_.isInternalFace(faceI))
1535 {
1536 label ownSurfI = insideSurfaces[nCandidates++];
1537 if (ownSurfI != -1)
1538 {
1539 cellToZone[own] = surfaceToCellZone[ownSurfI];
1540 }
1541
1542 label neiSurfI = insideSurfaces[nCandidates++];
1543 if (neiSurfI != -1)
1544 {
1545 label nei = faceNeighbour[faceI];
1546
1547 cellToZone[nei] = surfaceToCellZone[neiSurfI];
1548 }
1549 }
1550 else
1551 {
1552 label ownSurfI = insideSurfaces[nCandidates++];
1553 if (ownSurfI != -1)
1554 {
1555 cellToZone[own] = surfaceToCellZone[ownSurfI];
1556 }
1557 }
1558 }
1559 }
1560
1561
1562 // Adapt the namedSurfaceRegion
1563 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1564 // for if any cells were not completely covered.
1565
1566 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1567 {
1568 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
1569 label neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
1570
1571 if (namedSurfaceRegion[faceI] == -1 && (ownZone != neiZone))
1572 {
1573 // Give face the zone of min cell zone (but only if the
1574 // cellZone originated from a closed, named surface)
1575
1576 label minZone;
1577 if (ownZone == -1)
1578 {
1579 minZone = neiZone;
1580 }
1581 else if (neiZone == -1)
1582 {
1583 minZone = ownZone;
1584 }
1585 else
1586 {
1587 minZone = min(ownZone, neiZone);
1588 }
1589
1590 // Make sure the cellZone originated from a closed surface. Use
1591 // hardcoded region 0 inside named surface.
1592 label geomSurfI = surfaceToCellZone.find(minZone);
1593
1594 if (geomSurfI != -1)
1595 {
1596 namedSurfaceRegion[faceI] =
1597 surfaces_.globalRegion(geomSurfI, 0);
1598 }
1599 }
1600 }
1601
1602 labelList neiCellZone;
1603 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
1604
1605 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1606
1607 forAll(patches, patchI)
1608 {
1609 const polyPatch& pp = patches[patchI];
1610
1611 if (pp.coupled())
1612 {
1613 forAll(pp, i)
1614 {
1615 label faceI = pp.start()+i;
1616 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
1617 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
1618
1619 if (namedSurfaceRegion[faceI] == -1 && (ownZone != neiZone))
1620 {
1621 // Give face the min cell zone
1622 label minZone;
1623 if (ownZone == -1)
1624 {
1625 minZone = neiZone;
1626 }
1627 else if (neiZone == -1)
1628 {
1629 minZone = ownZone;
1630 }
1631 else
1632 {
1633 minZone = min(ownZone, neiZone);
1634 }
1635
1636 // Make sure the cellZone originated from a closed surface.
1637 // Use hardcoded region 0 inside named surface.
1638 label geomSurfI = surfaceToCellZone.find(minZone);
1639
1640 if (geomSurfI != -1)
1641 {
1642 namedSurfaceRegion[faceI] =
1643 surfaces_.globalRegion(geomSurfI, 0);
1644 }
1645 }
1646 }
1647 }
1648 }
1649
1650 // Sync
1651 syncTools::syncFaceList(mesh_, namedSurfaceRegion, maxEqOp<label>());
1652}
1653
1654
1655void Foam::meshRefinement::findCellZoneInsideWalk
1656(
1657 const pointField& locationsInMesh,
1658 const labelList& zonesInMesh,
1659 const labelList& faceToZone, // per face -1 or some index >= 0
1660
1661 labelList& cellToZone
1662) const
1663{
1664 // Analyse regions. Reuse regionsplit
1665 boolList blockedFace(mesh_.nFaces());
1666 //selectSeparatedCoupledFaces(blockedFace);
1667
1668 forAll(blockedFace, faceI)
1669 {
1670 if (faceToZone[faceI] == -1)
1671 {
1672 blockedFace[faceI] = false;
1673 }
1674 else
1675 {
1676 blockedFace[faceI] = true;
1677 }
1678 }
1679 // No need to sync since faceToZone already is synced
1680
1681 // Set region per cell based on walking
1682 regionSplit cellRegion(mesh_, blockedFace);
1683 blockedFace.clear();
1684
1685 // Force calculation of face decomposition (used in findCell)
1686 (void)mesh_.tetBasePtIs();
1687
1688 // For all locationsInMesh find the cell
1689 forAll(locationsInMesh, i)
1690 {
1691 // Get location and index of zone ("none" for cellZone -1)
1692 const point& insidePoint = locationsInMesh[i];
1693 label zoneID = zonesInMesh[i];
1694
1695 // Find the region containing the insidePoint
1696 label keepRegionI = findRegion
1697 (
1698 mesh_,
1699 cellRegion,
1700 vector::uniform(mergeDistance_),
1701 insidePoint
1702 );
1703
1704 Info<< "For cellZone "
1705 << (
1706 zoneID == -1
1707 ? "none"
1708 : mesh_.cellZones()[zoneID].name()
1709 )
1710 << " found point " << insidePoint
1711 << " in global region " << keepRegionI
1712 << " out of " << cellRegion.nRegions() << " regions." << endl;
1713
1714 if (keepRegionI == -1)
1715 {
1717 << "Point " << insidePoint
1718 << " is not inside the mesh." << nl
1719 << "Bounding box of the mesh:" << mesh_.bounds()
1720 << exit(FatalError);
1721 }
1722
1723
1724
1725 // Set all cells with this region to the zoneID
1726 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1727
1728 label nWarnings = 0;
1729
1730 forAll(cellRegion, cellI)
1731 {
1732 if (cellRegion[cellI] == keepRegionI)
1733 {
1734 if (cellToZone[cellI] == -2)
1735 {
1736 // First visit of cell
1737 cellToZone[cellI] = zoneID;
1738 }
1739 else if (cellToZone[cellI] != zoneID)
1740 {
1741 if (cellToZone[cellI] != -1 && nWarnings < 10)
1742 {
1744 << "Cell " << cellI
1745 << " at " << mesh_.cellCentres()[cellI]
1746 << " is inside cellZone "
1747 << (
1748 zoneID == -1
1749 ? "none"
1750 : mesh_.cellZones()[zoneID].name()
1751 )
1752 << " from locationInMesh " << insidePoint
1753 << " but already marked as being in zone "
1754 << mesh_.cellZones()[cellToZone[cellI]].name()
1755 << endl
1756 << "This can happen if your surfaces are not"
1757 << " (sufficiently) closed."
1758 << endl;
1759 nWarnings++;
1760 }
1761
1762 // Override the zone
1763 cellToZone[cellI] = zoneID;
1764 }
1765 }
1766 }
1767 }
1768}
1769
1770
1771void Foam::meshRefinement::findCellZoneInsideWalk
1772(
1773 const pointField& locationsInMesh,
1774 const wordList& zoneNamesInMesh,
1775 const labelList& faceToZone, // per face -1 or some index >= 0
1776
1777 labelList& cellToZone
1778) const
1779{
1780 const cellZoneMesh& czs = mesh_.cellZones();
1781
1782 labelList zoneIDs(zoneNamesInMesh.size());
1783 forAll(zoneNamesInMesh, i)
1784 {
1785 zoneIDs[i] = czs.findZoneID(zoneNamesInMesh[i]);
1786 }
1787 findCellZoneInsideWalk
1788 (
1789 locationsInMesh,
1790 zoneIDs,
1791 faceToZone,
1792 cellToZone
1793 );
1794}
1795
1796
1797bool Foam::meshRefinement::calcRegionToZone
1798(
1799 const label backgroundZoneID,
1800 const label surfZoneI,
1801 const label ownRegion,
1802 const label neiRegion,
1803
1804 labelList& regionToCellZone
1805) const
1806{
1807 bool changed = false;
1808
1809 // Check whether inbetween different regions
1810 if (ownRegion != neiRegion)
1811 {
1812 // Jump. Change one of the sides to my type.
1813
1814 // 1. Interface between my type and unset region.
1815 // Set region to keepRegion
1816
1817 if (regionToCellZone[ownRegion] == -2)
1818 {
1819 if (surfZoneI == -1)
1820 {
1821 // Special: face is -on faceZone -not real boundary
1822 // -not on cellZone
1823 // so make regions same on either side
1824 if (regionToCellZone[neiRegion] != -2)
1825 {
1826 regionToCellZone[ownRegion] = regionToCellZone[neiRegion];
1827 changed = true;
1828 }
1829 }
1830 else if (regionToCellZone[neiRegion] == surfZoneI)
1831 {
1832 // Face between unset and my region. Put unset
1833 // region into background region
1834 //MEJ: see comment in findCellZoneTopo
1835 if (backgroundZoneID != -2)
1836 {
1837 regionToCellZone[ownRegion] = backgroundZoneID;
1838 changed = true;
1839 }
1840 }
1841 else if (regionToCellZone[neiRegion] != -2)
1842 {
1843 // Face between unset and other region.
1844 // Put unset region into my region
1845 regionToCellZone[ownRegion] = surfZoneI;
1846 changed = true;
1847 }
1848 }
1849 else if (regionToCellZone[neiRegion] == -2)
1850 {
1851 if (surfZoneI == -1)
1852 {
1853 // Special: face is -on faceZone -not real boundary
1854 // -not on cellZone
1855 // so make regions same on either side
1856 regionToCellZone[neiRegion] = regionToCellZone[ownRegion];
1857 changed = true;
1858 }
1859 else if (regionToCellZone[ownRegion] == surfZoneI)
1860 {
1861 // Face between unset and my region. Put unset
1862 // region into background region
1863 if (backgroundZoneID != -2)
1864 {
1865 regionToCellZone[neiRegion] = backgroundZoneID;
1866 changed = true;
1867 }
1868 }
1869 else if (regionToCellZone[ownRegion] != -2)
1870 {
1871 // Face between unset and other region.
1872 // Put unset region into my region
1873 regionToCellZone[neiRegion] = surfZoneI;
1874 changed = true;
1875 }
1876 }
1877 }
1878 return changed;
1879}
1880
1881
1882void Foam::meshRefinement::findCellZoneTopo
1883(
1884 const label backgroundZoneID,
1885 const pointField& locationsInMesh,
1886 const labelList& unnamedSurfaceRegion,
1887 const labelList& namedSurfaceRegion,
1888 const labelList& surfaceToCellZone,
1889 labelList& cellToZone
1890) const
1891{
1892 // This routine fixes small problems with left over unassigned regions
1893 // (after all off the unreachable bits of the mesh have been removed).
1894 // This routine splits the mesh into regions, based on the intersection
1895 // with a surface. The problem is that we know the surface which
1896 // (intersected) face belongs to (in namedSurfaceRegion) but we don't
1897 // know which side of the face it relates to. So all we are doing here
1898 // is get the correspondence between surface/cellZone and regionSplit
1899 // region. See the logic in calcRegionToZone.
1900 // Basically it looks at the neighbours of a face on a named surface.
1901 // If one side is in the cellZone corresponding to the surface and
1902 // the other side is unassigned (-2) it sets this to the background zone.
1903 // So the zone to set these unmarked cells to is provided as argument:
1904 // - backgroundZoneID = -2 : do not change so remove cells
1905 // - backgroundZoneID = -1 : put into background
1906
1907 // Assumes:
1908 // - region containing keepPoint does not go into a cellZone
1909 // - all other regions can be found by crossing faces marked in
1910 // namedSurfaceRegion.
1911
1912 // Analyse regions. Reuse regionsplit
1913 boolList blockedFace(mesh_.nFaces());
1914
1915 forAll(unnamedSurfaceRegion, faceI)
1916 {
1917 if
1918 (
1919 unnamedSurfaceRegion[faceI] == -1
1920 && namedSurfaceRegion[faceI] == -1
1921 )
1922 {
1923 blockedFace[faceI] = false;
1924 }
1925 else
1926 {
1927 blockedFace[faceI] = true;
1928 }
1929 }
1930 // No need to sync since namedSurfaceRegion already is synced
1931
1932 // Set region per cell based on walking
1933 regionSplit cellRegion(mesh_, blockedFace);
1934 blockedFace.clear();
1935
1936 // Per mesh region the zone the cell should be put in.
1937 // -2 : not analysed yet
1938 // -1 : keepPoint region. Not put into any cellzone.
1939 // >= 0 : index of cellZone
1940 labelList regionToCellZone(cellRegion.nRegions(), -2);
1941
1942 // See which cells already are set in the cellToZone (from geometric
1943 // searching) and use these to take over their zones.
1944 // Note: could be improved to count number of cells per region.
1945 forAll(cellToZone, cellI)
1946 {
1947 label regionI = cellRegion[cellI];
1948 if (cellToZone[cellI] != -2 && regionToCellZone[regionI] == -2)
1949 {
1950 regionToCellZone[regionI] = cellToZone[cellI];
1951 }
1952 }
1953
1954 // Synchronise regionToCellZone.
1955 // Note:
1956 // - region numbers are identical on all processors
1957 // - keepRegion is identical ,,
1958 // - cellZones are identical ,,
1959 Pstream::listCombineAllGather(regionToCellZone, maxEqOp<label>());
1960
1961
1962 // Find the region containing the keepPoint
1963 forAll(locationsInMesh, i)
1964 {
1965 const point& keepPoint = locationsInMesh[i];
1966 label keepRegionI = findRegion
1967 (
1968 mesh_,
1969 cellRegion,
1970 vector::uniform(mergeDistance_),
1971 keepPoint
1972 );
1973
1974 Info<< "Found point " << keepPoint
1975 << " in global region " << keepRegionI
1976 << " out of " << cellRegion.nRegions() << " regions." << endl;
1977
1978 if (keepRegionI == -1)
1979 {
1981 << "Point " << keepPoint
1982 << " is not inside the mesh." << nl
1983 << "Bounding box of the mesh:" << mesh_.bounds()
1984 << exit(FatalError);
1985 }
1986
1987 // Mark default region with zone -1. Note that all regions should
1988 // already be matched to a cellZone through the loop over cellToZone.
1989 // This is just to mop up any remaining regions. Not sure whether
1990 // this is needed?
1991 if (regionToCellZone[keepRegionI] == -2)
1992 {
1993 regionToCellZone[keepRegionI] = -1;
1994 }
1995 }
1996
1997
1998 // Find correspondence between cell zone and surface
1999 // by changing cell zone every time we cross a surface.
2000 while (true)
2001 {
2002 // Synchronise regionToCellZone.
2003 // Note:
2004 // - region numbers are identical on all processors
2005 // - keepRegion is identical ,,
2006 // - cellZones are identical ,,
2007 // This done at top of loop to account for geometric matching
2008 // not being synchronised.
2009 Pstream::listCombineAllGather(regionToCellZone, maxEqOp<label>());
2010
2011
2012 bool changed = false;
2013
2014 // Internal faces
2015
2016 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
2017 {
2018 label regionI = namedSurfaceRegion[faceI];
2019
2020 // Connected even if no cellZone defined for surface
2021 if (unnamedSurfaceRegion[faceI] == -1 && regionI != -1)
2022 {
2023 // Calculate region to zone from cellRegions on either side
2024 // of internal face.
2025
2026 label surfI = surfaces_.whichSurface(regionI).first();
2027
2028 bool changedCell = calcRegionToZone
2029 (
2030 backgroundZoneID,
2031 surfaceToCellZone[surfI],
2032 cellRegion[mesh_.faceOwner()[faceI]],
2033 cellRegion[mesh_.faceNeighbour()[faceI]],
2034 regionToCellZone
2035 );
2036
2037 changed = changed | changedCell;
2038 }
2039 }
2040
2041 // Boundary faces
2042
2043 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2044
2045 // Get coupled neighbour cellRegion
2046 labelList neiCellRegion;
2047 syncTools::swapBoundaryCellList(mesh_, cellRegion, neiCellRegion);
2048
2049 // Calculate region to zone from cellRegions on either side of coupled
2050 // face.
2051 forAll(patches, patchI)
2052 {
2053 const polyPatch& pp = patches[patchI];
2054
2055 if (pp.coupled())
2056 {
2057 forAll(pp, i)
2058 {
2059 label faceI = pp.start()+i;
2060
2061 label regionI = namedSurfaceRegion[faceI];
2062
2063 // Connected even if no cellZone defined for surface
2064 if (unnamedSurfaceRegion[faceI] == -1 && regionI != -1)
2065 {
2066 label surfI = surfaces_.whichSurface(regionI).first();
2067
2068 bool changedCell = calcRegionToZone
2069 (
2070 backgroundZoneID,
2071 surfaceToCellZone[surfI],
2072 cellRegion[mesh_.faceOwner()[faceI]],
2073 neiCellRegion[faceI-mesh_.nInternalFaces()],
2074 regionToCellZone
2075 );
2076
2077 changed = changed | changedCell;
2078 }
2079 }
2080 }
2081 }
2082
2083 if (!returnReduce(changed, orOp<bool>()))
2084 {
2085 break;
2086 }
2087 }
2088
2089
2090 if (debug)
2091 {
2092 Pout<< "meshRefinement::findCellZoneTopo :"
2093 << " nRegions:" << regionToCellZone.size()
2094 << " of which visited (-1 = background, >= 0 : cellZone) :"
2095 << endl;
2096
2097 forAll(regionToCellZone, regionI)
2098 {
2099 if (regionToCellZone[regionI] != -2)
2100 {
2101 Pout<< "Region " << regionI
2102 << " becomes cellZone:" << regionToCellZone[regionI]
2103 << endl;
2104 }
2105 }
2106 }
2107
2108 // Rework into cellToZone
2109 forAll(cellToZone, cellI)
2110 {
2111 label regionI = cellRegion[cellI];
2112 if (cellToZone[cellI] == -2 && regionToCellZone[regionI] != -2)
2113 {
2114 cellToZone[cellI] = regionToCellZone[regionI];
2115 }
2116 }
2117}
2118
2119
2120void Foam::meshRefinement::erodeCellZone
2121(
2122 const label nErodeCellZones,
2123 const label backgroundZoneID,
2124 const labelList& unnamedSurfaceRegion,
2125 const labelList& namedSurfaceRegion,
2126 labelList& cellToZone
2127) const
2128{
2129 // This routine fixes small problems with left over unassigned regions
2130 // (after all off the unreachable bits of the mesh have been removed).
2131 // The problem is that the cell zone information might be inconsistent
2132 // with the face zone information. So what we do here is to erode
2133 // any cell zones until we hit a named face.
2134 // - backgroundZoneID = -2 : do not change so remove cells
2135 // - backgroundZoneID = -1 : put into background
2136 // Note that is the opposite of findCellZoneTopo which moves unassigned
2137 // regions into a neighbouring region(=cellZone) unless there is an
2138 // intersected faces inbetween the two.
2139
2140 for (label iter = 0; iter < nErodeCellZones; iter++)
2141 {
2142 label nChanged = 0;
2143
2144 labelList erodedCellToZone(cellToZone);
2145
2146 // Do internal faces
2147 for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2148 {
2149 if
2150 (
2151 unnamedSurfaceRegion[facei] == -1
2152 && namedSurfaceRegion[facei] == -1
2153 )
2154 {
2155 label own = mesh_.faceOwner()[facei];
2156 label nei = mesh_.faceNeighbour()[facei];
2157 if (cellToZone[own] == -2 && cellToZone[nei] >= -1)
2158 {
2159 erodedCellToZone[nei] = backgroundZoneID;
2160 nChanged++;
2161 }
2162 else if (cellToZone[nei] == -2 && cellToZone[own] >= -1)
2163 {
2164 erodedCellToZone[own] = backgroundZoneID;
2165 nChanged++;
2166 }
2167 }
2168 }
2169
2170 // Do boundary faces
2171
2172 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2173
2174 // Get coupled neighbour cellRegion
2175 labelList neiCellZone;
2176 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
2177
2178 // Calculate region to zone from cellRegions on either side of coupled
2179 // face.
2180 forAll(patches, patchi)
2181 {
2182 const polyPatch& pp = patches[patchi];
2183
2184 if (pp.coupled())
2185 {
2186 forAll(pp, i)
2187 {
2188 label facei = pp.start()+i;
2189 if
2190 (
2191 unnamedSurfaceRegion[facei] == -1
2192 && namedSurfaceRegion[facei] == -1
2193 )
2194 {
2195 label own = mesh_.faceOwner()[facei];
2196 label bFacei = facei-mesh_.nInternalFaces();
2197 if (neiCellZone[bFacei] == -2 && cellToZone[own] >= -1)
2198 {
2199 erodedCellToZone[own] = backgroundZoneID;
2200 nChanged++;
2201 }
2202 }
2203 }
2204 }
2205 }
2206
2207 cellToZone.transfer(erodedCellToZone);
2208
2209 reduce(nChanged, sumOp<label>());
2210 if (debug)
2211 {
2212 Pout<< "erodeCellZone : eroded " << nChanged
2213 << " cells (moved from cellZone to background zone "
2214 << backgroundZoneID << endl;
2215 }
2216
2217 if (nChanged == 0)
2218 {
2219 break;
2220 }
2221 }
2222}
2223
2224
2225void Foam::meshRefinement::growCellZone
2226(
2227 const label nGrowCellZones,
2228 const label backgroundZoneID,
2229 labelList& unnamedSurfaceRegion1,
2230 labelList& unnamedSurfaceRegion2,
2231 labelList& namedSurfaceRegion, // potentially zero size if no faceZones
2232 labelList& cellToZone
2233) const
2234{
2235 if (nGrowCellZones != 1)
2236 {
2238 << "Growing currently only supported for single layer."
2239 << " Exiting zone growing" << endl;
2240 return;
2241 }
2242
2243
2244 // See meshRefinement::markProximityRefinementWave:
2245 // - walk out nGrowCellZones iterations from outside of cellZone
2246 // and wall into unassigned cells
2247 // - detect any cells inbetween
2248 // - multiple zones
2249 // - zone and wall
2250 // and
2251 // - assign cells to the cellZone
2252 // - unblock faces (along the path) inbetween
2253
2254
2255 // Special tag for walls
2256 const FixedList<label, 3> wallTag
2257 ({
2258 labelMax, // Special value for wall face. Loses out to cellZone tag
2259 labelMax,
2260 labelMax
2261 });
2262
2263 // Work arrays
2264 pointField origins(1);
2265 scalarField distSqrs(1);
2266 List<FixedList<label, 3>> surfaces(1);
2267
2268
2269 // Set up blockage. Marked with 0 distance (so always wins)
2270
2271 //List<wallPoints> allFaceInfo(mesh_.nFaces());
2272 //for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2273 //{
2274 // if
2275 // (
2276 // unnamedSurfaceRegion1[facei] != -1
2277 // || unnamedSurfaceRegion2[facei] != -1
2278 // )
2279 // {
2280 // origins[0] = mesh_.faceCentres()[facei];
2281 // distSqrs[0] = 0.0; // Initial distance
2282 // surfaces[0] = wallTag;
2283 // allFaceInfo[facei] = wallPoints(origins, distSqrs, surfaces);
2284 // }
2285 //}
2286 List<wallPoints> allCellInfo(mesh_.nCells());
2287 forAll(cellToZone, celli)
2288 {
2289 if (cellToZone[celli] >= 0)
2290 {
2291 const FixedList<label, 3> zoneTag
2292 ({
2293 cellToZone[celli], // zone
2294 0, // 'region'
2295 labelMax // 'sub-region'
2296 });
2297
2298 origins[0] = mesh_.cellCentres()[celli];
2299 distSqrs[0] = 0.0; // Initial distance
2300 surfaces[0] = zoneTag;
2301 allCellInfo[celli] = wallPoints(origins, distSqrs, surfaces);
2302 }
2303 }
2304
2305
2306 DynamicList<wallPoints> faceDist(mesh_.nFaces()/128);
2307 DynamicList<label> changedFaces(mesh_.nFaces()/128);
2308
2309 for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
2310 {
2311 const label own = mesh_.faceOwner()[facei];
2312 const label nei = mesh_.faceNeighbour()[facei];
2313 if (cellToZone[own] >= 0 && cellToZone[nei] < 0)
2314 {
2315 // boundary between cellZone (own) and background/unvisited (nei)
2316
2317 origins[0] = mesh_.faceCentres()[facei];
2318 distSqrs[0] = 0.0; // Initial distance
2319 surfaces[0] = FixedList<label, 3>
2320 ({
2321 cellToZone[own], // zone
2322 0, // 'region'
2323 labelMax // 'sub-region'
2324 });
2325 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2326 changedFaces.append(facei);
2327 }
2328 else if (cellToZone[own] < 0 && cellToZone[nei] >= 0)
2329 {
2330 // boundary between cellZone (nei) and background/unvisited (own)
2331
2332 origins[0] = mesh_.faceCentres()[facei];
2333 distSqrs[0] = 0.0; // Initial distance
2334 surfaces[0] = FixedList<label, 3>
2335 ({
2336 cellToZone[nei], // zone
2337 0, // 'region'
2338 labelMax // 'sub-region'
2339 });
2340 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2341 changedFaces.append(facei);
2342 }
2343 else if
2344 (
2345 unnamedSurfaceRegion1[facei] != -1
2346 || unnamedSurfaceRegion2[facei] != -1
2347 )
2348 {
2349 // Seed (yet unpatched) wall faces
2350
2351 origins[0] = mesh_.faceCentres()[facei];
2352 distSqrs[0] = 0.0; // Initial distance
2353 surfaces[0] = wallTag;
2354 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2355 changedFaces.append(facei);
2356 }
2357 }
2358
2359 // Get coupled neighbour cellRegion
2360 labelList neiCellZone;
2361 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
2362
2363 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2364
2365 // Calculate region to zone from cellRegions on either side of coupled
2366 // face.
2367 forAll(patches, patchi)
2368 {
2369 const polyPatch& pp = patches[patchi];
2370
2371 if (pp.coupled())
2372 {
2373 // Like internal faces
2374 forAll(pp, i)
2375 {
2376 label facei = pp.start()+i;
2377 label own = mesh_.faceOwner()[facei];
2378 label bFacei = facei-mesh_.nInternalFaces();
2379 if (cellToZone[own] >= 0 && neiCellZone[bFacei] < 0)
2380 {
2381 origins[0] = mesh_.faceCentres()[facei];
2382 distSqrs[0] = 0.0;
2383 surfaces[0] = FixedList<label, 3>
2384 ({
2385 cellToZone[own], // zone
2386 0, // 'region'
2387 labelMax // 'sub-region'
2388 });
2389 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2390 changedFaces.append(facei);
2391 }
2392 else if (cellToZone[own] < 0 && neiCellZone[bFacei] >= 0)
2393 {
2394 // Handled on nbr processor
2395 }
2396 else if
2397 (
2398 unnamedSurfaceRegion1[facei] != -1
2399 || unnamedSurfaceRegion2[facei] != -1
2400 )
2401 {
2402 // Seed (yet unpatched) wall faces
2403 origins[0] = mesh_.faceCentres()[facei];
2404 distSqrs[0] = 0.0; // Initial distance
2405 surfaces[0] = wallTag;
2406 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2407 changedFaces.append(facei);
2408 }
2409 }
2410 }
2411 else
2412 {
2413 // Seed wall faces
2414 forAll(pp, i)
2415 {
2416 label facei = pp.start()+i;
2417 label own = mesh_.faceOwner()[facei];
2418 if (cellToZone[own] < 0)
2419 {
2420 origins[0] = mesh_.faceCentres()[facei];
2421 distSqrs[0] = 0.0; // Initial distance
2422 surfaces[0] = wallTag;
2423 faceDist.append(wallPoints(origins, distSqrs, surfaces));
2424 changedFaces.append(facei);
2425 }
2426 }
2427 }
2428 }
2429
2430
2431 List<wallPoints> allFaceInfo(mesh_.nFaces());
2432
2433 // No blocked faces, limitless gap size
2434 const bitSet isBlockedFace(mesh_.nFaces());
2435 List<scalarList> regionToBlockSize(surfaces_.surfaces().size());
2436 {
2437 forAll(surfaces_.surfaces(), surfi)
2438 {
2439 const label geomi = surfaces_.surfaces()[surfi];
2440 const auto& s = surfaces_.geometry()[geomi];
2441 const label nRegions = s.regions().size();
2442 regionToBlockSize[surfi].setSize(nRegions, Foam::sqr(GREAT));
2443 }
2444 }
2445
2446
2447 wallPoints::trackData td(isBlockedFace, regionToBlockSize);
2448 FaceCellWave<wallPoints, wallPoints::trackData> wallDistCalc
2449 (
2450 mesh_,
2451 changedFaces,
2452 faceDist,
2453 allFaceInfo,
2454 allCellInfo,
2455 0, // max iterations
2456 td
2457 );
2458 wallDistCalc.iterate(nGrowCellZones);
2459
2460
2461 // Check for cells which are within nGrowCellZones of two cellZones or
2462 // one cellZone and a wall
2463 // TBD. Currently only one layer of growth handled.
2464
2465 bitSet isChangedCell(mesh_.nCells());
2466
2467 forAll(allCellInfo, celli)
2468 {
2469 if (allCellInfo[celli].valid(wallDistCalc.data()))
2470 {
2471 const List<FixedList<label, 3>>& surfaces =
2472 allCellInfo[celli].surface();
2473
2474 if (surfaces.size())
2475 {
2476 // Cell close to cellZone. Remove any free-standing baffles.
2477 // Done by marking as changed cell. Wip.
2478 isChangedCell.set(celli);
2479 }
2480
2481 if (surfaces.size() > 1)
2482 {
2483 // Check if inbetween two cellZones or cellZone and wall
2484 // Find 'nearest' other cellZone
2485 scalar minDistSqr = Foam::sqr(GREAT);
2486 label minZone = -1;
2487 for (label i = 0; i < surfaces.size(); i++)
2488 {
2489 const label zonei = surfaces[i][0];
2490 const scalar d2 = allCellInfo[celli].distSqr()[i];
2491 if (zonei != cellToZone[celli] && d2 < minDistSqr)
2492 {
2493 minDistSqr = d2;
2494 minZone = zonei; // zoneID
2495 }
2496 }
2497
2498 if (minDistSqr < Foam::sqr(GREAT))
2499 {
2500 if (minZone != cellToZone[celli] && minZone != wallTag[0])
2501 {
2502 cellToZone[celli] = minZone;
2503 isChangedCell.set(celli);
2504 }
2505 }
2506 }
2507 }
2508 }
2509
2510 // Fix any left-over unvisited cells
2511 if (backgroundZoneID != -2)
2512 {
2513 forAll(cellToZone, celli)
2514 {
2515 if (cellToZone[celli] == -2)
2516 {
2517 cellToZone[celli] = backgroundZoneID;
2518 }
2519 }
2520 }
2521
2522
2523 // Make sure to unset faces of changed cell
2524
2525 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
2526
2527
2528 label nUnnamed = 0;
2529 label nNamed = 0;
2530 for (const label celli : isChangedCell)
2531 {
2532 const cell& cFaces = mesh_.cells()[celli];
2533 for (const label facei : cFaces)
2534 {
2535 const label own = mesh_.faceOwner()[facei];
2536 const label ownZone = cellToZone[own];
2537
2538 label nbrZone = -1;
2539 if (mesh_.isInternalFace(facei))
2540 {
2541 const label neiZone = cellToZone[mesh_.faceNeighbour()[facei]];
2542 nbrZone = (own != celli ? ownZone : neiZone);
2543 }
2544 else
2545 {
2546 nbrZone = neiCellZone[facei-mesh_.nInternalFaces()];
2547 }
2548
2549 if (nbrZone == cellToZone[celli])
2550 {
2551 if
2552 (
2553 unnamedSurfaceRegion1[facei] != -1
2554 || unnamedSurfaceRegion2[facei] != -1
2555 )
2556 {
2557 unnamedSurfaceRegion1[facei] = -1;
2558 unnamedSurfaceRegion2[facei] = -1;
2559 nUnnamed++;
2560 }
2561 if
2562 (
2563 namedSurfaceRegion.size()
2564 && namedSurfaceRegion[facei] != -1
2565 )
2566 {
2567 namedSurfaceRegion[facei] = -1;
2568 nNamed++;
2569 }
2570 }
2571 }
2572 }
2573
2574 reduce(nUnnamed, sumOp<label>());
2575 reduce(nNamed, sumOp<label>());
2576
2577 // Do always; might bypass if nNamed,nUnnamed zero
2579 (
2580 mesh_,
2581 unnamedSurfaceRegion1,
2582 maxEqOp<label>()
2583 );
2585 (
2586 mesh_,
2587 unnamedSurfaceRegion2,
2588 maxEqOp<label>()
2589 );
2590 if (namedSurfaceRegion.size())
2591 {
2593 (
2594 mesh_,
2595 namedSurfaceRegion,
2596 maxEqOp<label>()
2597 );
2598 }
2599
2600 if (debug)
2601 {
2602 Pout<< "growCellZone : grown cellZones by "
2603 << returnReduce(isChangedCell.count(), sumOp<label>())
2604 << " cells (moved from background to nearest cellZone)"
2605 << endl;
2606 Pout<< "growCellZone : unmarked " << nUnnamed
2607 << " unzoned intersections; " << nNamed << " zoned intersections; "
2608 << endl;
2609 }
2610}
2611
2612
2613void Foam::meshRefinement::makeConsistentFaceIndex
2614(
2615 const labelList& surfaceMap,
2616 const labelList& cellToZone,
2617 labelList& namedSurfaceRegion
2618) const
2619{
2620 // Make namedSurfaceRegion consistent with cellToZone - clear out any
2621 // blocked faces inbetween same cell zone (or background (=-1))
2622 // Do not do this for surfaces relating to 'pure' faceZones i.e.
2623 // faceZones without a cellZone. Note that we cannot check here
2624 // for different cellZones on either side but no namedSurfaceRegion
2625 // since cellZones can now originate from locationsInMesh as well
2626 // (instead of only through named surfaces)
2627
2628 const labelList& faceOwner = mesh_.faceOwner();
2629 const labelList& faceNeighbour = mesh_.faceNeighbour();
2630
2631 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
2632 {
2633 label ownZone = cellToZone[faceOwner[faceI]];
2634 label neiZone = cellToZone[faceNeighbour[faceI]];
2635 label globalI = namedSurfaceRegion[faceI];
2636
2637 if
2638 (
2639 ownZone == neiZone
2640 && globalI != -1
2641 && surfaceMap[surfaces_.whichSurface(globalI).first()] == -1
2642 )
2643 {
2644 namedSurfaceRegion[faceI] = -1;
2645 }
2646 }
2647
2648 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2649
2650 // Get coupled neighbour cellZone
2651 labelList neiCellZone;
2652 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
2653
2654 // Use coupled cellZone to do check
2655 forAll(patches, patchI)
2656 {
2657 const polyPatch& pp = patches[patchI];
2658
2659 if (pp.coupled())
2660 {
2661 forAll(pp, i)
2662 {
2663 label faceI = pp.start()+i;
2664
2665 label ownZone = cellToZone[faceOwner[faceI]];
2666 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
2667 label globalI = namedSurfaceRegion[faceI];
2668
2669 if
2670 (
2671 ownZone == neiZone
2672 && globalI != -1
2673 && surfaceMap[surfaces_.whichSurface(globalI).first()] == -1
2674 )
2675 {
2676 namedSurfaceRegion[faceI] = -1;
2677 }
2678 }
2679 }
2680 else
2681 {
2682 // Unzonify boundary faces
2683 forAll(pp, i)
2684 {
2685 label faceI = pp.start()+i;
2686 label globalI = namedSurfaceRegion[faceI];
2687
2688 if
2689 (
2690 globalI != -1
2691 && surfaceMap[surfaces_.whichSurface(globalI).first()] == -1
2692 )
2693 {
2694 namedSurfaceRegion[faceI] = -1;
2695 }
2696 }
2697 }
2698 }
2699}
2700
2701
2702void Foam::meshRefinement::getIntersections
2703(
2704 const labelList& surfacesToTest,
2705 const pointField& neiCc,
2706 const labelList& testFaces,
2707
2708 labelList& namedSurfaceRegion,
2709 bitSet& posOrientation
2710) const
2711{
2712 namedSurfaceRegion.setSize(mesh_.nFaces());
2713 namedSurfaceRegion = -1;
2714
2715 posOrientation.setSize(mesh_.nFaces());
2716 posOrientation = false;
2717
2718 // Statistics: number of faces per faceZone
2719 labelList nSurfFaces(surfaces_.surfZones().size(), Zero);
2720
2721 // Collect segments
2722 // ~~~~~~~~~~~~~~~~
2723
2724 pointField start(testFaces.size());
2725 pointField end(testFaces.size());
2726
2727 {
2728 labelList minLevel;
2729 calcCellCellRays
2730 (
2731 neiCc,
2732 labelList(neiCc.size(), -1),
2733 testFaces,
2734 start,
2735 end,
2736 minLevel
2737 );
2738 }
2739
2740 // Do test for intersections
2741 // ~~~~~~~~~~~~~~~~~~~~~~~~~
2742 // Note that we intersect all intersected faces again. Could reuse
2743 // the information already in surfaceIndex_.
2744
2745 labelList surface1;
2746 labelList region1;
2747 List<pointIndexHit> hit1;
2748 vectorField normal1;
2749 labelList surface2;
2750 labelList region2;
2751 List<pointIndexHit> hit2;
2752 vectorField normal2;
2753
2754 surfaces_.findNearestIntersection
2755 (
2756 surfacesToTest,
2757 start,
2758 end,
2759
2760 surface1,
2761 hit1,
2762 region1,
2763 normal1,
2764
2765 surface2,
2766 hit2,
2767 region2,
2768 normal2
2769 );
2770
2771 forAll(testFaces, i)
2772 {
2773 label faceI = testFaces[i];
2774 const vector& area = mesh_.faceAreas()[faceI];
2775
2776 if (surface1[i] != -1)
2777 {
2778 // If both hit should probably choose 'nearest'
2779 if
2780 (
2781 surface2[i] != -1
2782 && (
2783 magSqr(hit2[i].hitPoint())
2784 < magSqr(hit1[i].hitPoint())
2785 )
2786 )
2787 {
2788 namedSurfaceRegion[faceI] = surfaces_.globalRegion
2789 (
2790 surface2[i],
2791 region2[i]
2792 );
2793 posOrientation.set(faceI, ((area&normal2[i]) > 0));
2794 nSurfFaces[surface2[i]]++;
2795 }
2796 else
2797 {
2798 namedSurfaceRegion[faceI] = surfaces_.globalRegion
2799 (
2800 surface1[i],
2801 region1[i]
2802 );
2803 posOrientation.set(faceI, ((area&normal1[i]) > 0));
2804 nSurfFaces[surface1[i]]++;
2805 }
2806 }
2807 else if (surface2[i] != -1)
2808 {
2809 namedSurfaceRegion[faceI] = surfaces_.globalRegion
2810 (
2811 surface2[i],
2812 region2[i]
2813 );
2814 posOrientation.set(faceI, ((area&normal2[i]) > 0));
2815 nSurfFaces[surface2[i]]++;
2816 }
2817 }
2818
2819
2820 // surfaceIndex might have different surfaces on both sides if
2821 // there happen to be a (obviously thin) surface with different
2822 // regions between the cell centres. If one is on a named surface
2823 // and the other is not this might give problems so sync.
2825 (
2826 mesh_,
2827 namedSurfaceRegion,
2828 maxEqOp<label>()
2829 );
2830
2831 // Print a bit
2832 if (debug)
2833 {
2834 forAll(nSurfFaces, surfI)
2835 {
2836 Pout<< "Surface:"
2837 << surfaces_.names()[surfI]
2838 << " nZoneFaces:" << nSurfFaces[surfI] << nl;
2839 }
2840 Pout<< endl;
2841 }
2842}
2843
2844
2845void Foam::meshRefinement::zonify
2846(
2847 const bool allowFreeStandingZoneFaces,
2848 const label nErodeCellZones,
2849 const label backgroundZoneID,
2850 const pointField& locationsInMesh,
2851 const wordList& zonesInMesh,
2852 const pointField& locationsOutsideMesh,
2853 const bool exitIfLeakPath,
2854 const refPtr<coordSetWriter>& leakPathFormatter,
2855
2856 labelList& cellToZone,
2857 labelList& unnamedRegion1,
2858 labelList& unnamedRegion2,
2859 labelList& namedSurfaceRegion,
2860 bitSet& posOrientation
2861) const
2862{
2863 // Determine zones for cells and faces
2864 // cellToZone:
2865 // -2 : unset
2866 // -1 : not in any zone (zone 'none' or background zone)
2867 // >=0 : zoneID
2868 // namedSurfaceRegion, posOrientation:
2869 // -1 : face not intersected by named surface
2870 // >=0 : globalRegion (surface+region)
2871 // (and posOrientation: surface normal v.s. face normal)
2872
2873 const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
2874
2875 // Collect inside and outside into single list
2876 const List<pointField> allLocations
2877 (
2879 (
2880 locationsInMesh,
2881 zonesInMesh,
2882 locationsOutsideMesh
2883 )
2884 );
2885
2886 // Swap neighbouring cell centres and cell level
2887 labelList neiLevel(mesh_.nBoundaryFaces());
2888 pointField neiCc(mesh_.nBoundaryFaces());
2889 calcNeighbourData(neiLevel, neiCc);
2890
2891
2892 labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
2893 labelList unnamedSurfaces(surfaceZonesInfo::getUnnamedSurfaces(surfZones));
2894
2895 // Get map from surface to cellZone (or -1)
2896 labelList surfaceToCellZone;
2897 if (namedSurfaces.size())
2898 {
2899 // Get/add cellZones corresponding to surface names
2900 surfaceToCellZone = surfaceZonesInfo::addCellZonesToMesh
2901 (
2902 surfZones,
2903 namedSurfaces,
2904 mesh_
2905 );
2906 }
2907
2908
2909 cellToZone.setSize(mesh_.nCells());
2910 cellToZone = -2;
2911
2912 namedSurfaceRegion.clear();
2913 posOrientation.clear();
2914
2915
2916
2917 // 1. Test all (unnamed & named) surfaces
2918
2919 // Unnamed surfaces. Global surface region of intersection (or -1)
2920 getIntersections
2921 (
2922 unnamedSurfaces,
2923 neiCc,
2924 intersectedFaces(),
2925 unnamedRegion1,
2926 unnamedRegion2
2927 );
2928
2929 // Extend with hole closing faces (only if locationsOutsideMesh)
2930 labelList unnamedFaces;
2931 labelList unnamedClosureFaces;
2932 labelList unnamedToClosure;
2933 autoPtr<mapDistribute> unnamedMapPtr;
2934 if (locationsOutsideMesh.size())
2935 {
2936 unnamedFaces = ListOps::findIndices
2937 (
2938 unnamedRegion1,
2939 [](const label x){return x != -1;}
2940 );
2941
2942 const globalIndex globalUnnamedFaces(unnamedFaces.size());
2943
2944 unnamedMapPtr = holeToFace::calcClosure
2945 (
2946 mesh_,
2947 allLocations,
2948 unnamedFaces,
2949 globalUnnamedFaces,
2950 true, // allow erosion
2951
2952 unnamedClosureFaces,
2953 unnamedToClosure
2954 );
2955
2956 if (debug)
2957 {
2958 Pout<< "meshRefinement::zonify : found wall closure faces:"
2959 << unnamedClosureFaces.size()
2960 << " map:" << unnamedMapPtr.valid() << endl;
2961 }
2962
2963
2964 // Add to unnamedRegion1, unnamedRegion2
2965 if (unnamedMapPtr.valid())
2966 {
2967 // Dump leak path
2968 if (leakPathFormatter)
2969 {
2970 boolList blockedFace(mesh_.nFaces(), false);
2971 UIndirectList<bool>(blockedFace, unnamedFaces) = true;
2972 const fileName fName
2973 (
2974 writeLeakPath
2975 (
2976 mesh_,
2977 locationsInMesh,
2978 locationsOutsideMesh,
2979 blockedFace,
2980 leakPathFormatter.constCast()
2981 )
2982 );
2983 Info<< "Dumped leak path to " << fName << endl;
2984 }
2985
2986 auto& err =
2987 (
2988 exitIfLeakPath
2991 );
2992
2993 err << "Locations in mesh " << locationsInMesh
2994 << " connect to one of the locations outside mesh "
2995 << locationsOutsideMesh << endl;
2996
2997 if (exitIfLeakPath)
2998 {
3000 }
3001
3002
3003 labelList packedRegion1
3004 (
3005 UIndirectList<label>(unnamedRegion1, unnamedFaces)
3006 );
3007 unnamedMapPtr->distribute(packedRegion1);
3008 labelList packedRegion2
3009 (
3010 UIndirectList<label>(unnamedRegion2, unnamedFaces)
3011 );
3012 unnamedMapPtr->distribute(packedRegion2);
3013 forAll(unnamedClosureFaces, i)
3014 {
3015 const label sloti = unnamedToClosure[i];
3016
3017 if (sloti != -1)
3018 {
3019 const label facei = unnamedClosureFaces[i];
3020 const label region1 = unnamedRegion1[facei];
3021 const label slotRegion1 = packedRegion1[sloti];
3022 const label region2 = unnamedRegion2[facei];
3023 const label slotRegion2 = packedRegion2[sloti];
3024
3025 if (slotRegion1 != region1 || slotRegion2 != region2)
3026 {
3027 unnamedRegion1[facei] = slotRegion1;
3028 unnamedRegion2[facei] = slotRegion2;
3029 }
3030 }
3031 }
3032 }
3033 }
3034
3035
3036 // Extend with hole closing faces (only if locationsOutsideMesh)
3037 labelList namedFaces;
3038 labelList namedClosureFaces;
3039 labelList namedToClosure;
3040 autoPtr<mapDistribute> namedMapPtr;
3041 if (namedSurfaces.size())
3042 {
3043 getIntersections
3044 (
3045 namedSurfaces,
3046 neiCc,
3047 intersectedFaces(),
3048 namedSurfaceRegion,
3049 posOrientation
3050 );
3051
3052 // Ideally we'd like to close 'cellZone' surfaces. The problem is
3053 // that we don't (easily) know which locationsInMesh should be inside
3054 // the surface and which aren't. With 'insidePoint' definition of
3055 // cellZone we have a location inside the cellZone but how do we
3056 // know where the locationsInMesh are? Are they inside the cellZone
3057 // as well? Only with the 'locationsInMesh' notation where we specify
3058 // the cellZone and the seedpoint could we make sure that we cannot
3059 // walk from one to the other.
3060 // For now disable hole closure on cellZones
3061
3062 //if (locationsOutsideMesh.size())
3063 //{
3064 // namedFaces = ListOps::findIndices
3065 // (
3066 // namedSurfaceRegion,
3067 // [](const label x){return x != -1;}
3068 // );
3069 //
3070 // {
3071 // OBJstream str(mesh_.time().timePath()/"namedFaces.obj");
3072 // Pout<< "Writing " << namedFaces.size() << " zone faces to "
3073 // << str.name() << endl;
3074 // str.write
3075 // (
3076 // UIndirectList<face>(mesh_.faces(), namedFaces)(),
3077 // mesh_.points()
3078 // );
3079 // }
3080 //
3081 //
3082 // const globalIndex globalNamedFaces(namedFaces.size());
3083 //
3084 // namedMapPtr = holeToFace::calcClosure
3085 // (
3086 // mesh_,
3087 // allLocations,
3088 // namedFaces, // or also unnamedFaces?
3089 // globalNamedFaces,
3090 // true, // allow erosion
3091 //
3092 // namedClosureFaces,
3093 // namedToClosure
3094 // );
3095 //
3096 // if (debug)
3097 // {
3098 // Pout<< "meshRefinement::zonify :"
3099 // << " found faceZone closure faces:"
3100 // << namedClosureFaces.size()
3101 // << " map:" << namedMapPtr.valid() << endl;
3102 // }
3103 //
3104 // // Add to namedSurfaceRegion, posOrientation
3105 // if (namedMapPtr.valid())
3106 // {
3107 // WarningInFunction
3108 // << "Detected and closed leak path"
3109 // << " through zoned surfaces from "
3110 // << locationsInMesh << " to " << locationsOutsideMesh
3111 // << endl;
3112 //
3113 // // Dump leak path
3114 // if (leakPathFormatter)
3115 // {
3116 // boolList blockedFace(mesh_.nFaces(), false);
3117 // UIndirectList<bool>(blockedFace, unnamedFaces) = true;
3118 // UIndirectList<bool>(blockedFace, namedFaces) = true;
3119 // const fileName fName
3120 // (
3121 // writeLeakPath
3122 // (
3123 // mesh_,
3124 // locationsInMesh,
3125 // locationsOutsideMesh,
3126 // blockedFace,
3127 // leakPathFormatter.constCast()
3128 // )
3129 // );
3130 // Info<< "Dumped leak path to " << fName << endl;
3131 // }
3132 //
3133 // labelList packedSurfaceRegion
3134 // (
3135 // UIndirectList<label>(namedSurfaceRegion, namedFaces)
3136 // );
3137 // namedMapPtr->distribute(packedSurfaceRegion);
3138 // boolList packedOrientation(posOrientation.size());
3139 // forAll(namedFaces, i)
3140 // {
3141 // const label facei = namedFaces[i];
3142 // packedOrientation[i] = posOrientation[facei];
3143 // }
3144 // namedMapPtr->distribute(packedOrientation);
3145 // forAll(namedClosureFaces, i)
3146 // {
3147 // const label sloti = namedToClosure[i];
3148 // if (sloti != -1)
3149 // {
3150 // const label facei = namedClosureFaces[i];
3151 // const label regioni = namedSurfaceRegion[facei];
3152 // const label slotRegioni = packedSurfaceRegion[sloti];
3153 // const bool orient = posOrientation[facei];
3154 // const bool slotOrient = packedOrientation[sloti];
3155 //
3156 // if (slotRegioni != regioni || slotOrient != orient)
3157 // {
3158 // namedSurfaceRegion[facei] = slotRegioni;
3159 // posOrientation[facei] = slotOrient;
3160 // }
3161 // }
3162 // }
3163 // }
3164 //}
3165 }
3166
3167
3168 // 1b. Add any hole closure faces to frozenPoints pointZone
3169 {
3170 bitSet isClosureFace(mesh_.nFaces());
3171 isClosureFace.set(unnamedClosureFaces);
3172 isClosureFace.set(namedClosureFaces);
3173 const labelList closureFaces(isClosureFace.sortedToc());
3174
3176 (
3177 UIndirectList<face>(mesh_.faces(), closureFaces),
3178 mesh_.points()
3179 );
3180
3181 // Count number of faces per edge
3182 const labelList nEdgeFaces(countEdgeFaces(pp));
3183
3184 // Freeze all internal points
3185 bitSet isFrozenPoint(mesh_.nPoints());
3186 forAll(nEdgeFaces, edgei)
3187 {
3188 if (nEdgeFaces[edgei] != 1)
3189 {
3190 const edge& e = pp.edges()[edgei];
3191 isFrozenPoint.set(pp.meshPoints()[e[0]]);
3192 isFrozenPoint.set(pp.meshPoints()[e[1]]);
3193 }
3194 }
3195
3196 // Lookup/add pointZone and include its points
3197 pointZoneMesh& pointZones =
3198 const_cast<pointZoneMesh&>(mesh_.pointZones());
3199 const label zonei =
3200 const_cast<meshRefinement&>(*this).addPointZone("frozenPoints");
3201 const bitSet oldSet(mesh_.nPoints(), pointZones[zonei]);
3202 isFrozenPoint.set(oldSet);
3203
3205 (
3206 mesh_,
3207 isFrozenPoint,
3208 orEqOp<unsigned int>(),
3209 0u
3210 );
3211
3212 // Override addressing
3213 pointZones.clearAddressing();
3214 pointZones[zonei] = isFrozenPoint.sortedToc();
3215
3216 if (debug)
3217 {
3218 const pointZone& pz = pointZones[zonei];
3219 mkDir(mesh_.time().timePath());
3220 OBJstream str(mesh_.time().timePath()/pz.name()+".obj");
3221 Pout<< "Writing " << pz.size() << " frozen points to "
3222 << str.name() << endl;
3223 for (const label pointi : pz)
3224 {
3225 str.write(mesh_.points()[pointi]);
3226 }
3227 }
3228
3229 if (debug && returnReduce(unnamedClosureFaces.size(), sumOp<label>()))
3230 {
3231 mkDir(mesh_.time().timePath());
3232 OBJstream str(mesh_.time().timePath()/"unnamedClosureFaces.obj");
3233 Pout<< "Writing " << unnamedClosureFaces.size()
3234 << " unnamedClosureFaces to " << str.name() << endl;
3235 for (const label facei : unnamedClosureFaces)
3236 {
3237 str.write(mesh_.faces()[facei], mesh_.points(), false);
3238 }
3239 }
3240 if (debug && returnReduce(namedClosureFaces.size(), sumOp<label>()))
3241 {
3242 mkDir(mesh_.time().timePath());
3243 OBJstream str(mesh_.time().timePath()/"namedClosureFaces.obj");
3244 Pout<< "Writing " << namedClosureFaces.size()
3245 << " namedClosureFaces to " << str.name() << endl;
3246 for (const label facei : namedClosureFaces)
3247 {
3248 str.write(mesh_.faces()[facei], mesh_.points(), false);
3249 }
3250 }
3251 }
3252
3253
3254
3255 // 2. Walk from locationsInMesh. Hard set cellZones.
3256 // Note: walk through faceZones! (these might get overridden later)
3257
3258 if (locationsInMesh.size())
3259 {
3260 Info<< "Setting cellZones according to locationsInMesh:" << endl;
3261
3262 labelList locationsZoneIDs(zonesInMesh.size(), -1);
3263 forAll(locationsInMesh, i)
3264 {
3265 const word& name = zonesInMesh[i];
3266
3267 Info<< "Location : " << locationsInMesh[i] << nl
3268 << " cellZone : " << name << endl;
3269
3270 if (name != "none")
3271 {
3272 label zoneID = mesh_.cellZones().findZoneID(name);
3273 if (zoneID == -1)
3274 {
3275 FatalErrorInFunction << "problem" << abort(FatalError);
3276 }
3277 locationsZoneIDs[i] = zoneID;
3278 }
3279 }
3280 Info<< endl;
3281
3282
3283 // Assign cellZone according to seed points. Walk through named surfaces
3284 findCellZoneInsideWalk
3285 (
3286 locationsInMesh, // locations
3287 locationsZoneIDs, // index of cellZone (or -1)
3288 unnamedRegion1, // per face -1 (unblocked) or >= 0 (blocked)
3289 cellToZone
3290 );
3291 }
3292
3293
3294 // 3. Mark named-surfaces-with-insidePoint. Hard set cellZones.
3295
3296 labelList locationSurfaces
3297 (
3299 );
3300
3301 if (locationSurfaces.size())
3302 {
3303 Info<< "Found " << locationSurfaces.size()
3304 << " named surfaces with a provided inside point."
3305 << " Assigning cells inside these surfaces"
3306 << " to the corresponding cellZone."
3307 << nl << endl;
3308
3309 // Collect per surface the -insidePoint -cellZone
3310 pointField insidePoints(locationSurfaces.size());
3311 labelList insidePointCellZoneIDs(locationSurfaces.size(), -1);
3312 forAll(locationSurfaces, i)
3313 {
3314 label surfI = locationSurfaces[i];
3315 insidePoints[i] = surfZones[surfI].zoneInsidePoint();
3316
3317 const word& name = surfZones[surfI].cellZoneName();
3318 if (name != "none")
3319 {
3320 label zoneID = mesh_.cellZones().findZoneID(name);
3321 if (zoneID == -1)
3322 {
3324 << "problem"
3325 << abort(FatalError);
3326 }
3327 insidePointCellZoneIDs[i] = zoneID;
3328 }
3329 }
3330
3331
3332 // Stop at unnamed or named surface
3333 labelList allRegion1(mesh_.nFaces(), -1);
3334 forAll(namedSurfaceRegion, faceI)
3335 {
3336 allRegion1[faceI] = max
3337 (
3338 unnamedRegion1[faceI],
3339 namedSurfaceRegion[faceI]
3340 );
3341 }
3342
3343 findCellZoneInsideWalk
3344 (
3345 insidePoints, // locations
3346 insidePointCellZoneIDs, // index of cellZone
3347 allRegion1, // per face -1 (unblocked) or >= 0 (blocked)
3348 cellToZone
3349 );
3350 }
3351
3352
3353 // 4. Mark named-surfaces-with-geometric faces. Do geometric test. Soft set
3354 // cellZones. Correct through making consistent.
3355
3356 // Closed surfaces with cellZone specified.
3357 labelList closedNamedSurfaces
3358 (
3360 (
3361 surfZones,
3362 surfaces_.geometry(),
3363 surfaces_.surfaces()
3364 )
3365 );
3366
3367 if (closedNamedSurfaces.size())
3368 {
3369 Info<< "Found " << closedNamedSurfaces.size()
3370 << " closed, named surfaces. Assigning cells in/outside"
3371 << " these surfaces to the corresponding cellZone."
3372 << nl << endl;
3373
3374 findCellZoneGeometric
3375 (
3376 neiCc,
3377 closedNamedSurfaces, // indices of closed surfaces
3378 namedSurfaceRegion, // per face index of named surface + region
3379 surfaceToCellZone, // cell zone index per surface
3380
3381 cellToZone
3382 );
3383 }
3384
3385
3386 // 5. Find any unassigned regions (from regionSplit)
3387
3388 if (namedSurfaces.size())
3389 {
3390 if (nErodeCellZones == 0)
3391 {
3392 Info<< "Walking from known cellZones; crossing a faceZone "
3393 << "face changes cellZone" << nl << endl;
3394
3395 // Put unassigned regions into any connected cellZone
3396 findCellZoneTopo
3397 (
3398 backgroundZoneID,
3399 pointField(0),
3400 unnamedRegion1, // Intersections with unnamed surfaces
3401 namedSurfaceRegion, // Intersections with named surfaces
3402 surfaceToCellZone,
3403 cellToZone
3404 );
3405 }
3406 else if (nErodeCellZones < 0)
3407 {
3408 Info<< "Growing cellZones by " << -nErodeCellZones
3409 << " layers" << nl << endl;
3410
3411 growCellZone
3412 (
3413 -nErodeCellZones,
3414 backgroundZoneID,
3415 unnamedRegion1,
3416 unnamedRegion2,
3417 namedSurfaceRegion,
3418 cellToZone
3419 );
3420 }
3421 else
3422 {
3423 Info<< "Eroding cellZone cells to make these consistent with"
3424 << " faceZone faces" << nl << endl;
3425
3426 // Erode cell zone cells (connected to an unassigned cell)
3427 // and put them into backgroundZone
3428 erodeCellZone
3429 (
3430 nErodeCellZones,
3431 backgroundZoneID,
3432 unnamedRegion1,
3433 namedSurfaceRegion,
3434 cellToZone
3435 );
3436 }
3437
3438
3439 // Make sure namedSurfaceRegion is unset inbetween same cell zones.
3440 if (!allowFreeStandingZoneFaces)
3441 {
3442 Info<< "Only keeping zone faces inbetween different cellZones."
3443 << nl << endl;
3444
3445 // Surfaces with faceZone but no cellZone
3446 labelList standaloneNamedSurfaces
3447 (
3449 (
3450 surfZones
3451 )
3452 );
3453
3454 // Construct map from surface index to index in
3455 // standaloneNamedSurfaces (or -1)
3456 labelList surfaceMap(surfZones.size(), -1);
3457 forAll(standaloneNamedSurfaces, i)
3458 {
3459 surfaceMap[standaloneNamedSurfaces[i]] = i;
3460 }
3461
3462 makeConsistentFaceIndex
3463 (
3464 surfaceMap,
3465 cellToZone,
3466 namedSurfaceRegion
3467 );
3468 }
3469 }
3470 else if (nErodeCellZones < 0 && gMax(cellToZone) >= 0)
3471 {
3472 // With multiple locationsInMesh and non-trivial cellZones we allow
3473 // some growing of the cellZones to avoid any background cells
3474
3475 Info<< "Growing cellZones by " << -nErodeCellZones
3476 << " layers" << nl << endl;
3477
3478 growCellZone
3479 (
3480 -nErodeCellZones,
3481 backgroundZoneID,
3482 unnamedRegion1,
3483 unnamedRegion2,
3484 namedSurfaceRegion, // note: potentially zero sized
3485 cellToZone
3486 );
3487
3488 // Make sure namedSurfaceRegion is unset inbetween same cell zones.
3489 if (!allowFreeStandingZoneFaces && namedSurfaceRegion.size())
3490 {
3491 Info<< "Only keeping zone faces inbetween different cellZones."
3492 << nl << endl;
3493
3494 // Surfaces with faceZone but no cellZone
3495 labelList standaloneNamedSurfaces
3496 (
3498 (
3499 surfZones
3500 )
3501 );
3502
3503 // Construct map from surface index to index in
3504 // standaloneNamedSurfaces (or -1)
3505 labelList surfaceMap(surfZones.size(), -1);
3506 forAll(standaloneNamedSurfaces, i)
3507 {
3508 surfaceMap[standaloneNamedSurfaces[i]] = i;
3509 }
3510
3511 makeConsistentFaceIndex
3512 (
3513 surfaceMap,
3514 cellToZone,
3515 namedSurfaceRegion
3516 );
3517 }
3518 }
3519
3520
3521 // Some stats
3522 if (debug)
3523 {
3524 label nZones = gMax(cellToZone)+1;
3525
3526 label nUnvisited = 0;
3527 label nBackgroundCells = 0;
3528 labelList nZoneCells(nZones, Zero);
3529 forAll(cellToZone, cellI)
3530 {
3531 label zoneI = cellToZone[cellI];
3532 if (zoneI >= 0)
3533 {
3534 nZoneCells[zoneI]++;
3535 }
3536 else if (zoneI == -1)
3537 {
3538 nBackgroundCells++;
3539 }
3540 else if (zoneI == -2)
3541 {
3542 nUnvisited++;
3543 }
3544 else
3545 {
3547 << "problem" << exit(FatalError);
3548 }
3549 }
3550 reduce(nUnvisited, sumOp<label>());
3551 reduce(nBackgroundCells, sumOp<label>());
3552 forAll(nZoneCells, zoneI)
3553 {
3554 reduce(nZoneCells[zoneI], sumOp<label>());
3555 }
3556 Info<< "nUnvisited :" << nUnvisited << endl;
3557 Info<< "nBackgroundCells:" << nBackgroundCells << endl;
3558 Info<< "nZoneCells :" << nZoneCells << endl;
3559 }
3560 if (debug&MESH)
3561 {
3562 const_cast<Time&>(mesh_.time())++;
3563 Pout<< "Writing cell zone allocation on mesh to time "
3564 << timeName() << endl;
3565 write
3566 (
3567 debugType(debug),
3568 writeType(writeLevel() | WRITEMESH),
3569 mesh_.time().path()/"cell2Zone"
3570 );
3571 volScalarField volCellToZone
3572 (
3573 IOobject
3574 (
3575 "cellToZone",
3576 timeName(),
3577 mesh_,
3580 false
3581 ),
3582 mesh_,
3584 zeroGradientFvPatchScalarField::typeName
3585 );
3586
3587 forAll(cellToZone, cellI)
3588 {
3589 volCellToZone[cellI] = cellToZone[cellI];
3590 }
3591 volCellToZone.write();
3592
3593
3594 //mkDir(mesh_.time().path()/timeName());
3595 //OBJstream str
3596 //(
3597 // mesh_.time().path()/timeName()/"zoneBoundaryFaces.obj"
3598 //);
3599 //Pout<< "Writing zone boundaries to " << str.name() << endl;
3600 //for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
3601 //{
3602 // const label ownZone = cellToZone[mesh_.faceOwner()[facei]];
3603 // const label neiZone = cellToZone[mesh_.faceNeighbour()[facei]];
3604 // if (ownZone != neiZone)
3605 // {
3606 // str.write(mesh_.faces()[facei], mesh_.points(), false);
3607 // }
3608 //}
3609 //labelList neiCellZone;
3610 //syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
3611 //for
3612 //(
3613 // label facei = mesh_.nInternalFaces();
3614 // facei < mesh_.nFaces();
3615 // facei++
3616 //)
3617 //{
3618 // const label ownZone = cellToZone[mesh_.faceOwner()[facei]];
3619 // const label bFacei = facei-mesh_.nInternalFaces();
3620 // const label neiZone = neiCellZone[bFacei];
3621 // if (ownZone != neiZone)
3622 // {
3623 // str.write(mesh_.faces()[facei], mesh_.points(), false);
3624 // }
3625 //}
3626
3627 //mkDir(mesh_.time().path()/timeName());
3628 //OBJstream str1
3629 //(
3630 // mesh_.time().path()/timeName()/"unnamedRegion1.obj"
3631 //);
3632 //OBJstream str2
3633 //(
3634 // mesh_.time().path()/timeName()/"unnamedRegion2.obj"
3635 //);
3636 //Pout<< "Writing unnamed1 to " << str1.name() << endl;
3637 //Pout<< "Writing unnamed2 to " << str2.name() << endl;
3638 //for (label facei = 0; facei < mesh_.nFaces(); facei++)
3639 //{
3640 // if
3641 // (
3642 // unnamedRegion1[facei] < -1
3643 // || unnamedRegion2[facei] < -1
3644 // )
3645 // {
3646 // FatalErrorInFunction << "face:"
3647 // << mesh_.faceCentres()[facei]
3648 // << " unnamed1:" << unnamedRegion1[facei]
3649 // << " unnamed2:" << unnamedRegion2[facei]
3650 // << exit(FatalError);
3651 // }
3652 //
3653 // if (unnamedRegion1[facei] >= 0)
3654 // {
3655 // str1.write(mesh_.faces()[facei], mesh_.points(), false);
3656 // }
3657 //
3658 // if (unnamedRegion2[facei] >= 0)
3659 // {
3660 // str2.write(mesh_.faces()[facei], mesh_.points(), false);
3661 // }
3662 //}
3663
3664 //if (namedSurfaceRegion.size())
3665 //{
3666 // OBJstream strNamed
3667 // (
3668 // mesh_.time().path()/timeName()/"namedSurfaceRegion.obj"
3669 // );
3670 // Pout<< "Writing named to " << strNamed.name() << endl;
3671 // for (label facei = 0; facei < mesh_.nFaces(); facei++)
3672 // {
3673 // const face& f = mesh_.faces()[facei];
3674 // if (namedSurfaceRegion[facei] < -1)
3675 // {
3676 // FatalErrorInFunction << "face:"
3677 // << mesh_.faceCentres()[facei]
3678 // << " unnamed1:" << unnamedRegion1[facei]
3679 // << " unnamed2:" << unnamedRegion2[facei]
3680 // << " named:" << namedSurfaceRegion[facei]
3681 // << exit(FatalError);
3682 // }
3683 // if (namedSurfaceRegion[facei] >= 0)
3684 // {
3685 // strNamed.write(f, mesh_.points(), false);
3686 // }
3687 // }
3688 //}
3689 }
3690}
3691
3692
3694(
3695 const snapParameters& snapParams,
3696 const bool useTopologicalSnapDetection,
3697 const bool removeEdgeConnectedCells,
3698 const scalarField& perpendicularAngle,
3699 const dictionary& motionDict,
3700 Time& runTime,
3701 const labelList& globalToMasterPatch,
3702 const labelList& globalToSlavePatch
3703)
3704{
3705 Info<< nl
3706 << "Introducing baffles to block off problem cells" << nl
3707 << "----------------------------------------------" << nl
3708 << endl;
3709
3710 labelList facePatch;
3711 labelList faceZone;
3712 if (useTopologicalSnapDetection)
3713 {
3714 markFacesOnProblemCells
3715 (
3716 motionDict,
3717 removeEdgeConnectedCells,
3718 perpendicularAngle,
3719 globalToMasterPatch,
3720
3721 facePatch,
3722 faceZone
3723 );
3724 }
3725 else
3726 {
3727 markFacesOnProblemCellsGeometric
3728 (
3729 snapParams,
3730 motionDict,
3731 globalToMasterPatch,
3732 globalToSlavePatch,
3733
3734 facePatch,
3735 faceZone
3736 );
3737 }
3738 Info<< "Analyzed problem cells in = "
3739 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
3740
3741 if (debug&MESH)
3742 {
3743 faceSet problemFaces(mesh_, "problemFaces", mesh_.nFaces()/100);
3744
3745 forAll(facePatch, faceI)
3746 {
3747 if (facePatch[faceI] != -1)
3748 {
3749 problemFaces.insert(faceI);
3750 }
3751 }
3752 problemFaces.instance() = timeName();
3753 Pout<< "Dumping " << problemFaces.size()
3754 << " problem faces to " << problemFaces.objectPath() << endl;
3755 problemFaces.write();
3756 }
3757
3758 Info<< "Introducing baffles to delete problem cells." << nl << endl;
3759
3760 if (debug)
3761 {
3762 ++runTime;
3763 }
3764
3765
3766 // Add faces-to-baffle to faceZone. For now do this outside of topoChanges
3767 {
3768 const faceZoneMesh& fzs = mesh_.faceZones();
3769 List<DynamicList<label>> zoneToFaces(fzs.size());
3770 List<DynamicList<bool>> zoneToFlip(fzs.size());
3771
3772 // Start off with original contents
3773 forAll(fzs, zonei)
3774 {
3775 zoneToFaces[zonei].append(fzs[zonei]);
3776 zoneToFlip[zonei].append(fzs[zonei].flipMap());
3777 }
3778
3779 // Add any to-be-patched face
3780 forAll(facePatch, facei)
3781 {
3782 if (facePatch[facei] != -1)
3783 {
3784 label zonei = faceZone[facei];
3785 if (zonei != -1)
3786 {
3787 zoneToFaces[zonei].append(facei);
3788 zoneToFlip[zonei].append(false);
3789 }
3790 }
3791 }
3792
3793 forAll(zoneToFaces, zonei)
3794 {
3796 (
3797 fzs[zonei].name(),
3798 zoneToFaces[zonei],
3799 zoneToFlip[zonei],
3800 mesh_
3801 );
3802 }
3803 }
3804
3805
3806 // Create baffles with same owner and neighbour for now.
3807 createBaffles(facePatch, facePatch);
3808
3809 if (debug)
3810 {
3811 // Debug:test all is still synced across proc patches
3812 checkData();
3813 }
3814 Info<< "Created baffles in = "
3815 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
3816
3817 printMeshInfo(debug, "After introducing baffles");
3818
3819 if (debug&MESH)
3820 {
3821 const_cast<Time&>(mesh_.time())++;
3822 Pout<< "Writing extra baffled mesh to time "
3823 << timeName() << endl;
3824 write
3825 (
3826 debugType(debug),
3827 writeType(writeLevel() | WRITEMESH),
3828 runTime.path()/"extraBaffles"
3829 );
3830 Pout<< "Dumped debug data in = "
3831 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
3832 }
3833}
3834
3835
3836Foam::labelList Foam::meshRefinement::freeStandingBaffleFaces
3837(
3838 const labelList& faceToZone,
3839 const labelList& cellToZone,
3840 const labelList& neiCellZone
3841) const
3842{
3843 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
3844 const labelList& faceOwner = mesh_.faceOwner();
3845 const labelList& faceNeighbour = mesh_.faceNeighbour();
3846
3847
3848 // We want to pick up the faces to orient. These faces come in
3849 // two variants:
3850 // - faces originating from stand-alone faceZones
3851 // (these will most likely have no cellZone on either side so
3852 // ownZone and neiZone both -1)
3853 // - sticky-up faces originating from a 'bulge' in a outside of
3854 // a cellZone. These will have the same cellZone on either side.
3855 // How to orient these is not really clearly defined so do them
3856 // same as stand-alone faceZone faces for now. (Normally these will
3857 // already have been removed by the 'allowFreeStandingZoneFaces=false'
3858 // default setting)
3859
3860 // Note that argument neiCellZone will have -1 on uncoupled boundaries.
3861
3862 DynamicList<label> faceLabels(mesh_.nFaces()/100);
3863
3864 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
3865 {
3866 if (faceToZone[faceI] != -1)
3867 {
3868 // Free standing baffle?
3869 label ownZone = cellToZone[faceOwner[faceI]];
3870 label neiZone = cellToZone[faceNeighbour[faceI]];
3871 if (ownZone == neiZone)
3872 {
3873 faceLabels.append(faceI);
3874 }
3875 }
3876 }
3877 forAll(patches, patchI)
3878 {
3879 const polyPatch& pp = patches[patchI];
3880
3881 forAll(pp, i)
3882 {
3883 label faceI = pp.start()+i;
3884 if (faceToZone[faceI] != -1)
3885 {
3886 // Free standing baffle?
3887 label ownZone = cellToZone[faceOwner[faceI]];
3888 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
3889 if (ownZone == neiZone)
3890 {
3891 faceLabels.append(faceI);
3892 }
3893 }
3894 }
3895 }
3896 return faceLabels.shrink();
3897}
3898
3899
3900void Foam::meshRefinement::calcPatchNumMasterFaces
3901(
3902 const bitSet& isMasterFace,
3903 const indirectPrimitivePatch& patch,
3904 labelList& nMasterFacesPerEdge
3905) const
3906{
3907 // Number of (master)faces per edge
3908 nMasterFacesPerEdge.setSize(patch.nEdges());
3909 nMasterFacesPerEdge = 0;
3910
3911 forAll(patch.addressing(), faceI)
3912 {
3913 const label meshFaceI = patch.addressing()[faceI];
3914
3915 if (isMasterFace.test(meshFaceI))
3916 {
3917 const labelList& fEdges = patch.faceEdges()[faceI];
3918 forAll(fEdges, fEdgeI)
3919 {
3920 nMasterFacesPerEdge[fEdges[fEdgeI]]++;
3921 }
3922 }
3923 }
3924
3926 (
3927 mesh_,
3928 patch.meshEdges(mesh_.edges(), mesh_.pointEdges()),
3929 nMasterFacesPerEdge,
3930 plusEqOp<label>(),
3931 label(0)
3932 );
3933}
3934
3935
3936Foam::label Foam::meshRefinement::markPatchZones
3937(
3938 const indirectPrimitivePatch& patch,
3939 const labelList& nMasterFacesPerEdge,
3940 labelList& faceToZone
3941) const
3942{
3943 List<edgeTopoDistanceData<label>> allEdgeInfo(patch.nEdges());
3944 List<edgeTopoDistanceData<label>> allFaceInfo(patch.size());
3945
3946
3947 // Protect all non-manifold edges
3948 {
3949 label nProtected = 0;
3950
3951 forAll(nMasterFacesPerEdge, edgeI)
3952 {
3953 if (nMasterFacesPerEdge[edgeI] > 2)
3954 {
3955 allEdgeInfo[edgeI] = edgeTopoDistanceData<label>(0, -2);
3956 nProtected++;
3957 }
3958 }
3959 //Info<< "Protected from visiting "
3960 // << returnReduce(nProtected, sumOp<label>())
3961 // << " non-manifold edges" << nl << endl;
3962 }
3963
3964
3965 // Hand out zones
3966
3967 DynamicList<label> changedEdges;
3968 DynamicList<edgeTopoDistanceData<label>> changedInfo;
3969
3970 const scalar tol = PatchEdgeFaceWave
3971 <
3973 edgeTopoDistanceData<label>
3974 >::propagationTol();
3975
3976 int dummyTrackData;
3977
3978 const globalIndex globalFaces(patch.size());
3979
3980 label faceI = 0;
3981
3982 label currentZoneI = 0;
3983
3984 while (true)
3985 {
3986 // Pick an unset face
3987 label globalSeed = labelMax;
3988 for (; faceI < allFaceInfo.size(); faceI++)
3989 {
3990 if (!allFaceInfo[faceI].valid(dummyTrackData))
3991 {
3992 globalSeed = globalFaces.toGlobal(faceI);
3993 break;
3994 }
3995 }
3996
3997 reduce(globalSeed, minOp<label>());
3998
3999 if (globalSeed == labelMax)
4000 {
4001 break;
4002 }
4003
4004 if (globalFaces.isLocal(globalSeed))
4005 {
4006 const label seedFaceI = globalFaces.toLocal(globalSeed);
4007
4008 edgeTopoDistanceData<label>& faceInfo = allFaceInfo[seedFaceI];
4009
4010 // Set face
4011 faceInfo = edgeTopoDistanceData<label>(0, currentZoneI);
4012
4013 // .. and seed its edges
4014 const labelList& fEdges = patch.faceEdges()[seedFaceI];
4015 forAll(fEdges, fEdgeI)
4016 {
4017 label edgeI = fEdges[fEdgeI];
4018
4019 edgeTopoDistanceData<label>& edgeInfo = allEdgeInfo[edgeI];
4020
4021 if
4022 (
4023 edgeInfo.updateEdge<int>
4024 (
4025 mesh_,
4026 patch,
4027 edgeI,
4028 seedFaceI,
4029 faceInfo,
4030 tol,
4031 dummyTrackData
4032 )
4033 )
4034 {
4035 changedEdges.append(edgeI);
4036 changedInfo.append(edgeInfo);
4037 }
4038 }
4039 }
4040
4041
4042 if (returnReduce(changedEdges.size(), sumOp<label>()) == 0)
4043 {
4044 break;
4045 }
4046
4047
4048 // Walk
4049 PatchEdgeFaceWave
4050 <
4052 edgeTopoDistanceData<label>
4053 > calc
4054 (
4055 mesh_,
4056 patch,
4057 changedEdges,
4058 changedInfo,
4059 allEdgeInfo,
4060 allFaceInfo,
4061 returnReduce(patch.nEdges(), sumOp<label>())
4062 );
4063
4064 currentZoneI++;
4065 }
4066
4067
4068 faceToZone.setSize(patch.size());
4069 forAll(allFaceInfo, faceI)
4070 {
4071 if (!allFaceInfo[faceI].valid(dummyTrackData))
4072 {
4074 << "Problem: unvisited face " << faceI
4075 << " at " << patch.faceCentres()[faceI]
4076 << exit(FatalError);
4077 }
4078 faceToZone[faceI] = allFaceInfo[faceI].data();
4079 }
4080
4081 return currentZoneI;
4082}
4083
4084
4085void Foam::meshRefinement::consistentOrientation
4086(
4087 const bitSet& isMasterFace,
4088 const indirectPrimitivePatch& patch,
4089 const labelList& nMasterFacesPerEdge,
4090 const labelList& faceToZone,
4091 const Map<label>& zoneToOrientation,
4092 bitSet& meshFlipMap
4093) const
4094{
4095 const polyBoundaryMesh& bm = mesh_.boundaryMesh();
4096
4097 // Data on all edges and faces
4098 List<patchFaceOrientation> allEdgeInfo(patch.nEdges());
4099 List<patchFaceOrientation> allFaceInfo(patch.size());
4100
4101 // Make sure we don't walk through
4102 // - slaves of coupled faces
4103 // - non-manifold edges
4104 {
4105 label nProtected = 0;
4106
4107 forAll(patch.addressing(), faceI)
4108 {
4109 const label meshFaceI = patch.addressing()[faceI];
4110 const label patchI = bm.whichPatch(meshFaceI);
4111
4112 if
4113 (
4114 patchI != -1
4115 && bm[patchI].coupled()
4116 && !isMasterFace.test(meshFaceI)
4117 )
4118 {
4119 // Slave side. Mark so doesn't get visited.
4120 allFaceInfo[faceI] = orientedSurface::NOFLIP;
4121 nProtected++;
4122 }
4123 }
4124 //Info<< "Protected from visiting "
4125 // << returnReduce(nProtected, sumOp<label>())
4126 // << " slaves of coupled faces" << nl << endl;
4127 }
4128 {
4129 label nProtected = 0;
4130
4131 forAll(nMasterFacesPerEdge, edgeI)
4132 {
4133 if (nMasterFacesPerEdge[edgeI] > 2)
4134 {
4135 allEdgeInfo[edgeI] = orientedSurface::NOFLIP;
4136 nProtected++;
4137 }
4138 }
4139
4140 Info<< "Protected from visiting "
4141 << returnReduce(nProtected, sumOp<label>())
4142 << " non-manifold edges" << nl << endl;
4143 }
4144
4145
4146
4147 DynamicList<label> changedEdges;
4148 DynamicList<patchFaceOrientation> changedInfo;
4149
4150 const scalar tol = PatchEdgeFaceWave
4151 <
4153 patchFaceOrientation
4154 >::propagationTol();
4155
4156 int dummyTrackData;
4157
4158 globalIndex globalFaces(patch.size());
4159
4160 while (true)
4161 {
4162 // Pick an unset face
4163 label globalSeed = labelMax;
4164 forAll(allFaceInfo, faceI)
4165 {
4166 if (allFaceInfo[faceI] == orientedSurface::UNVISITED)
4167 {
4168 globalSeed = globalFaces.toGlobal(faceI);
4169 break;
4170 }
4171 }
4172
4173 reduce(globalSeed, minOp<label>());
4174
4175 if (globalSeed == labelMax)
4176 {
4177 break;
4178 }
4179
4180 if (globalFaces.isLocal(globalSeed))
4181 {
4182 const label seedFaceI = globalFaces.toLocal(globalSeed);
4183
4184 // Determine orientation of seedFace
4185
4186 patchFaceOrientation& faceInfo = allFaceInfo[seedFaceI];
4187
4188 // Start off with correct orientation
4189 faceInfo = orientedSurface::NOFLIP;
4190
4191 if (zoneToOrientation[faceToZone[seedFaceI]] < 0)
4192 {
4193 faceInfo.flip();
4194 }
4195
4196
4197 const labelList& fEdges = patch.faceEdges()[seedFaceI];
4198 forAll(fEdges, fEdgeI)
4199 {
4200 label edgeI = fEdges[fEdgeI];
4201
4202 patchFaceOrientation& edgeInfo = allEdgeInfo[edgeI];
4203
4204 if
4205 (
4206 edgeInfo.updateEdge<int>
4207 (
4208 mesh_,
4209 patch,
4210 edgeI,
4211 seedFaceI,
4212 faceInfo,
4213 tol,
4214 dummyTrackData
4215 )
4216 )
4217 {
4218 changedEdges.append(edgeI);
4219 changedInfo.append(edgeInfo);
4220 }
4221 }
4222 }
4223
4224
4225 if (returnReduce(changedEdges.size(), sumOp<label>()) == 0)
4226 {
4227 break;
4228 }
4229
4230
4231
4232 // Walk
4233 PatchEdgeFaceWave
4234 <
4236 patchFaceOrientation
4237 > calc
4238 (
4239 mesh_,
4240 patch,
4241 changedEdges,
4242 changedInfo,
4243 allEdgeInfo,
4244 allFaceInfo,
4245 returnReduce(patch.nEdges(), sumOp<label>())
4246 );
4247 }
4248
4249
4250 // Push master zone info over to slave (since slave faces never visited)
4251 {
4252 labelList neiStatus
4253 (
4254 mesh_.nBoundaryFaces(),
4256 );
4257
4258 forAll(patch.addressing(), i)
4259 {
4260 const label meshFaceI = patch.addressing()[i];
4261 if (!mesh_.isInternalFace(meshFaceI))
4262 {
4263 neiStatus[meshFaceI-mesh_.nInternalFaces()] =
4264 allFaceInfo[i].flipStatus();
4265 }
4266 }
4267 syncTools::swapBoundaryFaceList(mesh_, neiStatus);
4268
4269 forAll(patch.addressing(), i)
4270 {
4271 const label meshFaceI = patch.addressing()[i];
4272 const label patchI = bm.whichPatch(meshFaceI);
4273
4274 if
4275 (
4276 patchI != -1
4277 && bm[patchI].coupled()
4278 && !isMasterFace.test(meshFaceI)
4279 )
4280 {
4281 // Slave side. Take flipped from neighbour
4282 label bFaceI = meshFaceI-mesh_.nInternalFaces();
4283
4284 if (neiStatus[bFaceI] == orientedSurface::NOFLIP)
4285 {
4286 allFaceInfo[i] = orientedSurface::FLIP;
4287 }
4288 else if (neiStatus[bFaceI] == orientedSurface::FLIP)
4289 {
4290 allFaceInfo[i] = orientedSurface::NOFLIP;
4291 }
4292 else
4293 {
4295 << "Incorrect status for face " << meshFaceI
4296 << abort(FatalError);
4297 }
4298 }
4299 }
4300 }
4301
4302
4303 // Convert to meshFlipMap and adapt faceZones
4304
4305 meshFlipMap.setSize(mesh_.nFaces());
4306 meshFlipMap = false;
4307
4308 forAll(allFaceInfo, faceI)
4309 {
4310 label meshFaceI = patch.addressing()[faceI];
4311
4312 if (allFaceInfo[faceI] == orientedSurface::NOFLIP)
4313 {
4314 meshFlipMap.unset(meshFaceI);
4315 }
4316 else if (allFaceInfo[faceI] == orientedSurface::FLIP)
4317 {
4318 meshFlipMap.set(meshFaceI);
4319 }
4320 else
4321 {
4323 << "Problem : unvisited face " << faceI
4324 << " centre:" << mesh_.faceCentres()[meshFaceI]
4325 << abort(FatalError);
4326 }
4327 }
4328}
4329
4330
4331void Foam::meshRefinement::zonify
4332(
4333 // Get per face whether is it master (of a coupled set of faces)
4334 const bitSet& isMasterFace,
4335 const labelList& cellToZone,
4336 const labelList& neiCellZone,
4337 const labelList& faceToZone,
4338 const bitSet& meshFlipMap,
4339 polyTopoChange& meshMod
4340) const
4341{
4342 const labelList& faceOwner = mesh_.faceOwner();
4343 const labelList& faceNeighbour = mesh_.faceNeighbour();
4344
4345 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
4346 {
4347 label faceZoneI = faceToZone[faceI];
4348
4349 if (faceZoneI != -1)
4350 {
4351 // Orient face zone to have slave cells in min cell zone.
4352 // Note: logic to use flipMap should be consistent with logic
4353 // to pick up the freeStandingBaffleFaces!
4354
4355 label ownZone = cellToZone[faceOwner[faceI]];
4356 label neiZone = cellToZone[faceNeighbour[faceI]];
4357
4358 bool flip;
4359
4360 if (ownZone == neiZone)
4361 {
4362 // free-standing face. Use geometrically derived orientation
4363 flip = meshFlipMap.test(faceI);
4364 }
4365 else
4366 {
4367 flip =
4368 (
4369 ownZone == -1
4370 || (neiZone != -1 && ownZone > neiZone)
4371 );
4372 }
4373
4374 meshMod.setAction
4375 (
4376 polyModifyFace
4377 (
4378 mesh_.faces()[faceI], // modified face
4379 faceI, // label of face
4380 faceOwner[faceI], // owner
4381 faceNeighbour[faceI], // neighbour
4382 false, // face flip
4383 -1, // patch for face
4384 false, // remove from zone
4385 faceZoneI, // zone for face
4386 flip // face flip in zone
4387 )
4388 );
4389 }
4390 }
4391
4392
4393 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4394
4395 // Set owner as no-flip
4396 forAll(patches, patchI)
4397 {
4398 const polyPatch& pp = patches[patchI];
4399
4400 label faceI = pp.start();
4401
4402 forAll(pp, i)
4403 {
4404 label faceZoneI = faceToZone[faceI];
4405
4406 if (faceZoneI != -1)
4407 {
4408 label ownZone = cellToZone[faceOwner[faceI]];
4409 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
4410
4411 bool flip;
4412
4413 if (ownZone == neiZone)
4414 {
4415 // free-standing face. Use geometrically derived orientation
4416 flip = meshFlipMap.test(faceI);
4417 }
4418 else
4419 {
4420 flip =
4421 (
4422 ownZone == -1
4423 || (neiZone != -1 && ownZone > neiZone)
4424 );
4425 }
4426
4427 meshMod.setAction
4428 (
4429 polyModifyFace
4430 (
4431 mesh_.faces()[faceI], // modified face
4432 faceI, // label of face
4433 faceOwner[faceI], // owner
4434 -1, // neighbour
4435 false, // face flip
4436 patchI, // patch for face
4437 false, // remove from zone
4438 faceZoneI, // zone for face
4439 flip // face flip in zone
4440 )
4441 );
4442 }
4443 faceI++;
4444 }
4445 }
4446
4447
4448 // Put the cells into the correct zone
4449 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4450
4451 forAll(cellToZone, cellI)
4452 {
4453 label zoneI = cellToZone[cellI];
4454
4455 if (zoneI >= 0)
4456 {
4457 meshMod.setAction
4458 (
4459 polyModifyCell
4460 (
4461 cellI,
4462 false, // removeFromZone
4463 zoneI
4464 )
4465 );
4466 }
4467 }
4468}
4469
4470
4471void Foam::meshRefinement::allocateInterRegionFaceZone
4472(
4473 const label ownZone,
4474 const label neiZone,
4475 wordPairHashTable& zonesToFaceZone,
4476 LabelPairMap<word>& zoneIDsToFaceZone
4477) const
4478{
4479 const cellZoneMesh& cellZones = mesh_.cellZones();
4480
4481 if (ownZone != neiZone)
4482 {
4483 // Make sure lowest number cellZone is master. Non-cellZone
4484 // areas are slave
4485 const bool swap =
4486 (
4487 ownZone == -1
4488 || (neiZone != -1 && ownZone > neiZone)
4489 );
4490
4491 // Quick check whether we already have pair of zones
4492 labelPair key(ownZone, neiZone);
4493 if (swap)
4494 {
4495 key.flip();
4496 }
4497
4498 if (!zoneIDsToFaceZone.found(key))
4499 {
4500 // Not found. Allocate.
4501 const word ownZoneName =
4502 (
4503 ownZone != -1
4504 ? cellZones[ownZone].name()
4505 : "none"
4506 );
4507 const word neiZoneName =
4508 (
4509 neiZone != -1
4510 ? cellZones[neiZone].name()
4511 : "none"
4512 );
4513
4514 // Get lowest zone first
4515 Pair<word> wordKey(ownZoneName, neiZoneName);
4516 if (swap)
4517 {
4518 wordKey.flip();
4519 }
4520
4521 word fzName = wordKey.first() + "_to_" + wordKey.second();
4522
4523 zoneIDsToFaceZone.insert(key, fzName);
4524 zonesToFaceZone.insert(wordKey, fzName);
4525 }
4526 }
4527}
4528
4529
4530// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
4531
4533(
4534 const bool doHandleSnapProblems,
4535 const snapParameters& snapParams,
4536 const bool useTopologicalSnapDetection,
4537 const bool removeEdgeConnectedCells,
4538 const scalarField& perpendicularAngle,
4539 const label nErodeCellZones,
4540 const dictionary& motionDict,
4541 Time& runTime,
4542 const labelList& globalToMasterPatch,
4543 const labelList& globalToSlavePatch,
4544
4545 const pointField& locationsInMesh,
4546 const wordList& zonesInMesh,
4547 const pointField& locationsOutsideMesh,
4548 const bool exitIfLeakPath,
4549 const refPtr<coordSetWriter>& leakPathFormatter
4550)
4551{
4552 // Introduce baffles
4553 // ~~~~~~~~~~~~~~~~~
4554
4555 // Split the mesh along internal faces wherever there is a pierce between
4556 // two cell centres.
4557
4558 Info<< "Introducing baffles for "
4559 << returnReduce(countHits(), sumOp<label>())
4560 << " faces that are intersected by the surface." << nl << endl;
4561
4562 // Swap neighbouring cell centres and cell level
4563 labelList neiLevel(mesh_.nBoundaryFaces());
4564 pointField neiCc(mesh_.nBoundaryFaces());
4565 calcNeighbourData(neiLevel, neiCc);
4566
4567 labelList ownPatch, neiPatch;
4568 getBafflePatches
4569 (
4570 nErodeCellZones,
4571 globalToMasterPatch,
4572
4573 locationsInMesh,
4574 zonesInMesh,
4575 locationsOutsideMesh,
4576 exitIfLeakPath,
4577 refPtr<coordSetWriter>(nullptr),
4578
4579 neiLevel,
4580 neiCc,
4581
4582 ownPatch,
4583 neiPatch
4584 );
4585
4586 createBaffles(ownPatch, neiPatch);
4587
4588 if (debug)
4589 {
4590 // Debug:test all is still synced across proc patches
4591 checkData();
4592 }
4593
4594 Info<< "Created baffles in = "
4595 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
4596
4597 printMeshInfo(debug, "After introducing baffles");
4598
4599 if (debug&MESH)
4600 {
4601 const_cast<Time&>(mesh_.time())++;
4602 Pout<< "Writing baffled mesh to time " << timeName()
4603 << endl;
4604 write
4605 (
4606 debugType(debug),
4607 writeType(writeLevel() | WRITEMESH),
4608 runTime.path()/"baffles"
4609 );
4610 Pout<< "Dumped debug data in = "
4611 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
4612 }
4613
4614
4615 // Introduce baffles to delete problem cells
4616 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4617
4618 // Create some additional baffles where we want surface cells removed.
4619
4620 if (doHandleSnapProblems)
4621 {
4622 handleSnapProblems
4623 (
4624 snapParams,
4625 useTopologicalSnapDetection,
4626 removeEdgeConnectedCells,
4627 perpendicularAngle,
4628 motionDict,
4629 runTime,
4630 globalToMasterPatch,
4631 globalToSlavePatch
4632 );
4633
4634 // Removing additional cells might have created disconnected bits
4635 // so re-do the surface intersections
4636 {
4637 // Swap neighbouring cell centres and cell level
4638 neiLevel.setSize(mesh_.nBoundaryFaces());
4639 neiCc.setSize(mesh_.nBoundaryFaces());
4640 calcNeighbourData(neiLevel, neiCc);
4641
4642 labelList ownPatch, neiPatch;
4643 getBafflePatches
4644 (
4645 nErodeCellZones,
4646 globalToMasterPatch,
4647
4648 locationsInMesh,
4649 zonesInMesh,
4650 locationsOutsideMesh,
4651 exitIfLeakPath,
4652 refPtr<coordSetWriter>(nullptr),
4653
4654 neiLevel,
4655 neiCc,
4656
4657 ownPatch,
4658 neiPatch
4659 );
4660
4661 createBaffles(ownPatch, neiPatch);
4662 }
4663
4664 if (debug)
4665 {
4666 // Debug:test all is still synced across proc patches
4667 checkData();
4668 }
4669 }
4670
4671
4672 // Select part of mesh
4673 // ~~~~~~~~~~~~~~~~~~~
4674
4675 Info<< nl
4676 << "Remove unreachable sections of mesh" << nl
4677 << "-----------------------------------" << nl
4678 << endl;
4679
4680 if (debug)
4681 {
4682 ++runTime;
4683 }
4684
4685 splitMeshRegions
4686 (
4687 globalToMasterPatch,
4688 globalToSlavePatch,
4689 locationsInMesh,
4690 locationsOutsideMesh,
4691 true, // Exit if any connection between inside and outside
4692 leakPathFormatter
4693 );
4694
4695 if (debug)
4696 {
4697 // Debug:test all is still synced across proc patches
4698 checkData();
4699 }
4700 Info<< "Split mesh in = "
4701 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
4702
4703 printMeshInfo(debug, "After subsetting");
4704
4705 if (debug&MESH)
4706 {
4707 ++runTime;
4708 Pout<< "Writing subsetted mesh to time " << timeName()
4709 << endl;
4710 write
4711 (
4712 debugType(debug),
4713 writeType(writeLevel() | WRITEMESH),
4715 );
4716 Pout<< "Dumped debug data in = "
4717 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
4718 }
4719}
4720
4721
4723(
4724 const snapParameters& snapParams,
4725 const bool useTopologicalSnapDetection,
4726 const bool removeEdgeConnectedCells,
4727 const scalarField& perpendicularAngle,
4728 const scalar planarAngle,
4729 const dictionary& motionDict,
4730 Time& runTime,
4731 const labelList& globalToMasterPatch,
4732 const labelList& globalToSlavePatch,
4733 const pointField& locationsInMesh,
4734 const pointField& locationsOutsideMesh
4735)
4736{
4737 // Merge baffles
4738 // ~~~~~~~~~~~~~
4739
4740 Info<< nl
4741 << "Merge free-standing baffles" << nl
4742 << "---------------------------" << nl
4743 << endl;
4744
4745
4746 // List of pairs of freestanding baffle faces.
4747 List<labelPair> couples
4748 (
4749 freeStandingBaffles // filter out freestanding baffles
4750 (
4752 planarAngle
4753 )
4754 );
4755
4756 label nCouples = couples.size();
4757 reduce(nCouples, sumOp<label>());
4758
4759 Info<< "Detected free-standing baffles : " << nCouples << endl;
4760
4761 if (nCouples > 0)
4762 {
4763 // Actually merge baffles. Note: not exactly parallellized. Should
4764 // convert baffle faces into processor faces if they resulted
4765 // from them.
4766 mergeBaffles(couples, Map<label>(0));
4767
4768 // Detect any problem cells resulting from merging of baffles
4769 // and delete them
4770 handleSnapProblems
4771 (
4772 snapParams,
4773 useTopologicalSnapDetection,
4774 removeEdgeConnectedCells,
4775 perpendicularAngle,
4776 motionDict,
4777 runTime,
4778 globalToMasterPatch,
4779 globalToSlavePatch
4780 );
4781
4782 // Very occasionally removing a problem cell might create a disconnected
4783 // region so re-check
4784
4785 Info<< nl
4786 << "Remove unreachable sections of mesh" << nl
4787 << "-----------------------------------" << nl
4788 << endl;
4789
4790 if (debug)
4791 {
4792 ++runTime;
4793 }
4794
4795 splitMeshRegions
4796 (
4797 globalToMasterPatch,
4798 globalToSlavePatch,
4799 locationsInMesh,
4800 locationsOutsideMesh,
4801 true, // Exit if any connection between inside and outside
4802 refPtr<coordSetWriter>(nullptr) // leakPathFormatter
4803 );
4804
4805
4806 if (debug)
4807 {
4808 // Debug:test all is still synced across proc patches
4809 checkData();
4810 }
4811 }
4812 Info<< "Merged free-standing baffles in = "
4813 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
4814}
4815
4816
4817Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh
4818(
4819 const label nBufferLayers,
4820 const label nErodeCellZones,
4821 const labelList& globalToMasterPatch,
4822 const labelList& globalToSlavePatch,
4823
4824 const pointField& locationsInMesh,
4825 const wordList& zonesInMesh,
4826 const pointField& locationsOutsideMesh,
4827 const bool exitIfLeakPath,
4828 const refPtr<coordSetWriter>& leakPathFormatter
4829)
4830{
4831 // Determine patches to put intersections into
4832 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4833
4834
4835 // Swap neighbouring cell centres and cell level
4836 labelList neiLevel(mesh_.nBoundaryFaces());
4837 pointField neiCc(mesh_.nBoundaryFaces());
4838 calcNeighbourData(neiLevel, neiCc);
4839
4840 // Find intersections with all unnamed(!) surfaces
4841 labelList ownPatch, neiPatch;
4842 getBafflePatches
4843 (
4844 nErodeCellZones,
4845 globalToMasterPatch,
4846
4847 locationsInMesh,
4848 zonesInMesh,
4849 locationsOutsideMesh,
4850 exitIfLeakPath,
4851 leakPathFormatter,
4852
4853 neiLevel,
4854 neiCc,
4855
4856 ownPatch,
4857 neiPatch
4858 );
4859
4860 // Analyse regions. Reuse regionsplit
4861 boolList blockedFace(mesh_.nFaces(), false);
4862
4863 forAll(ownPatch, faceI)
4864 {
4865 if (ownPatch[faceI] != -1 || neiPatch[faceI] != -1)
4866 {
4867 blockedFace[faceI] = true;
4868 }
4869 }
4870 syncTools::syncFaceList(mesh_, blockedFace, orEqOp<bool>());
4871
4872
4873 regionSplit cellRegion(mesh_, blockedFace);
4874
4875 // Set unreachable cells to -1
4876 findRegions
4877 (
4878 mesh_,
4879 vector::uniform(mergeDistance_), // perturbVec
4880 locationsInMesh,
4881 locationsOutsideMesh,
4882 cellRegion.nRegions(),
4883 cellRegion,
4884 blockedFace,
4885 // Leak-path
4886 false, // do not exit if outside location found
4887 leakPathFormatter
4888 );
4889
4890 return splitMesh
4891 (
4892 nBufferLayers,
4893 globalToMasterPatch,
4894 globalToSlavePatch,
4895 cellRegion,
4896 ownPatch,
4897 neiPatch
4898 );
4899}
4900
4901Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh
4902(
4903 const label nBufferLayers,
4904 const labelList& globalToMasterPatch,
4905 const labelList& globalToSlavePatch,
4906
4907 labelList& cellRegion,
4908 labelList& ownPatch,
4909 labelList& neiPatch
4910)
4911{
4912 // Walk out nBufferlayers from region boundary
4913 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4914 // (modifies cellRegion, ownPatch)
4915 // Takes over face patch onto points and then back to faces and cells
4916 // (so cell-face-point walk)
4917
4918 const labelList& faceOwner = mesh_.faceOwner();
4919 const labelList& faceNeighbour = mesh_.faceNeighbour();
4920
4921
4922 // Checks
4923 for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
4924 {
4925 if (ownPatch[facei] == -1 && neiPatch[facei] != -1)
4926 {
4927 FatalErrorInFunction << "Problem in face:" << facei
4928 << " at:" << mesh_.faceCentres()[facei]
4929 << " ownPatch:" << ownPatch[facei]
4930 << " neiPatch:" << neiPatch[facei]
4931 << exit(FatalError);
4932 }
4933 else
4934 {
4935 // Check if cellRegion indeed limited by patch
4936 const label ownRegion = cellRegion[faceOwner[facei]];
4937 const label neiRegion = cellRegion[faceNeighbour[facei]];
4938 if (ownRegion != neiRegion)
4939 {
4940 if (ownPatch[facei] == -1)
4941 {
4942 FatalErrorInFunction << "Problem in face:" << facei
4943 << " at:" << mesh_.faceCentres()[facei]
4944 << " ownPatch:" << ownPatch[facei]
4945 << " ownRegion:" << ownRegion
4946 << " neiPatch:" << neiPatch[facei]
4947 << " neiRegion:" << neiRegion
4948 << exit(FatalError);
4949 }
4950 }
4951 }
4952 }
4953
4954 // Determine on original data the nearest face. This is used as a fall-back
4955 // to set the patch if the nBufferLayers walking didn't work.
4956 labelList nearestOwnPatch;
4957 if (nBufferLayers)
4958 {
4959 DynamicList<label> startFaces;
4960 forAll(ownPatch, facei)
4961 {
4962 if (ownPatch[facei] != -1)
4963 {
4964 startFaces.append(facei);
4965 }
4966 }
4967
4968 // Per face the index to the start face.
4969 labelList faceToStart;
4970 autoPtr<mapDistribute> mapPtr;
4971 nearestFace
4972 (
4973 startFaces,
4974 bitSet(mesh_.nFaces()), // no blocked faces
4975 mapPtr,
4976 faceToStart,
4977 nBufferLayers+4 // bit more than nBufferLayers since
4978 // walking face-cell-face
4979 );
4980
4981 // Use map to push ownPatch to all reached faces
4982 labelList startOwnPatch(ownPatch, startFaces);
4983 mapPtr().distribute(startOwnPatch);
4984
4985 nearestOwnPatch.setSize(mesh_.nFaces());
4986 nearestOwnPatch = -1;
4987 forAll(faceToStart, facei)
4988 {
4989 const label sloti = faceToStart[facei];
4990 if (sloti != -1)
4991 {
4992 nearestOwnPatch[facei] = startOwnPatch[sloti];
4993 }
4994 }
4995 }
4996
4997 // Leak closure:
4998 // ~~~~~~~~~~~~~
4999 // We do not want to add buffer layers on the frozen points/faces
5000 // since these are the exact faces needed to close a hole (to an
5001 // locationOutsideMesh). Adding even
5002 // a single layer of cells would mean that in further manipulation there
5003 // is now no path to the locationOutsideMesh so the layer closure does
5004 // not get triggered and we keep the added 1 layer of cells on the
5005 // closure faces.
5006 bitSet isFrozenPoint(mesh_.nPoints());
5007 bitSet isFrozenFace(mesh_.nFaces());
5008
5009 if (nBufferLayers)
5010 {
5011 const labelListList& pointFaces = mesh_.pointFaces();
5012 const pointZoneMesh& pzs = mesh_.pointZones();
5013 const label pointZonei = pzs.findZoneID("frozenPoints");
5014 if (pointZonei != -1)
5015 {
5016 const pointZone& pz = pzs[pointZonei];
5017 isFrozenPoint.set(pz);
5018 for (const label pointi : pz)
5019 {
5020 isFrozenFace.set(pointFaces[pointi]);
5021 }
5022 }
5023
5024 const faceZoneMesh& fzs = mesh_.faceZones();
5025 const label faceZonei = fzs.findZoneID("frozenFaces");
5026 if (faceZonei != -1)
5027 {
5028 const faceZone& fz = fzs[faceZonei];
5029 isFrozenFace.set(fz);
5030 for (const label facei : fz)
5031 {
5032 isFrozenPoint.set(mesh_.faces()[facei]);
5033 }
5034 }
5035 }
5036
5037 // Patch for exposed faces for lack of anything sensible.
5038 label defaultPatch = 0;
5039 if (globalToMasterPatch.size())
5040 {
5041 defaultPatch = globalToMasterPatch[0];
5042 }
5043
5044 for (label i = 0; i < nBufferLayers; i++)
5045 {
5046 // 1. From cells (via faces) to points
5047
5048 labelList pointBaffle(mesh_.nPoints(), -1);
5049
5050 forAll(faceNeighbour, facei)
5051 {
5052 if (!isFrozenFace[facei])
5053 {
5054 const face& f = mesh_.faces()[facei];
5055
5056 const label ownRegion = cellRegion[faceOwner[facei]];
5057 const label neiRegion = cellRegion[faceNeighbour[facei]];
5058
5059 if (ownRegion == -1 && neiRegion != -1)
5060 {
5061 // Note max(..) since possibly regionSplit might have split
5062 // off extra unreachable parts of mesh. Note: or can this
5063 // only happen for boundary faces?
5064 forAll(f, fp)
5065 {
5066 if (!isFrozenPoint[f[fp]])
5067 {
5068 pointBaffle[f[fp]] =
5069 max(defaultPatch, ownPatch[facei]);
5070 }
5071 }
5072 }
5073 else if (ownRegion != -1 && neiRegion == -1)
5074 {
5075 label newPatchi = neiPatch[facei];
5076 if (newPatchi == -1)
5077 {
5078 newPatchi = max(defaultPatch, ownPatch[facei]);
5079 }
5080 forAll(f, fp)
5081 {
5082 if (!isFrozenPoint[f[fp]])
5083 {
5084 pointBaffle[f[fp]] = newPatchi;
5085 }
5086 }
5087 }
5088 }
5089 }
5090
5091 labelList neiCellRegion;
5092 syncTools::swapBoundaryCellList(mesh_, cellRegion, neiCellRegion);
5093 for
5094 (
5095 label facei = mesh_.nInternalFaces();
5096 facei < mesh_.nFaces();
5097 facei++
5098 )
5099 {
5100 if (!isFrozenFace[facei])
5101 {
5102 const face& f = mesh_.faces()[facei];
5103
5104 const label ownRegion = cellRegion[faceOwner[facei]];
5105 const label neiRegion =
5106 neiCellRegion[facei-mesh_.nInternalFaces()];
5107
5108 if (ownRegion == -1 && neiRegion != -1)
5109 {
5110 forAll(f, fp)
5111 {
5112 if (!isFrozenPoint[f[fp]])
5113 {
5114 pointBaffle[f[fp]] =
5115 max(defaultPatch, ownPatch[facei]);
5116 }
5117 }
5118 }
5119 }
5120 }
5121
5122 // Sync
5124 (
5125 mesh_,
5126 pointBaffle,
5127 maxEqOp<label>(),
5128 label(-1) // null value
5129 );
5130
5131
5132 // 2. From points back to faces
5133
5134 const labelListList& pointFaces = mesh_.pointFaces();
5135
5136 forAll(pointFaces, pointi)
5137 {
5138 if (pointBaffle[pointi] != -1)
5139 {
5140 const labelList& pFaces = pointFaces[pointi];
5141
5142 forAll(pFaces, pFacei)
5143 {
5144 const label facei = pFaces[pFacei];
5145
5146 if (!isFrozenFace[facei] && ownPatch[facei] == -1)
5147 {
5148 ownPatch[facei] = pointBaffle[pointi];
5149 }
5150 }
5151 }
5152 }
5153 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
5154
5155
5156 // 3. From faces to cells (cellRegion) and back to faces (ownPatch)
5157
5158 labelList newOwnPatch(ownPatch);
5159
5160 forAll(ownPatch, facei)
5161 {
5162 if (!isFrozenFace[facei] && ownPatch[facei] != -1)
5163 {
5164 const label own = faceOwner[facei];
5165
5166 if (cellRegion[own] == -1)
5167 {
5168 cellRegion[own] = labelMax;
5169
5170 const cell& ownFaces = mesh_.cells()[own];
5171 forAll(ownFaces, j)
5172 {
5173 const label ownFacei = ownFaces[j];
5174 if (!isFrozenFace[ownFacei] && ownPatch[ownFacei] == -1)
5175 {
5176 newOwnPatch[ownFacei] = ownPatch[facei];
5177 }
5178 }
5179 }
5180 if (mesh_.isInternalFace(facei))
5181 {
5182 const label nei = faceNeighbour[facei];
5183
5184 if (cellRegion[nei] == -1)
5185 {
5186 cellRegion[nei] = labelMax;
5187
5188 const cell& neiFaces = mesh_.cells()[nei];
5189 forAll(neiFaces, j)
5190 {
5191 const label neiFacei = neiFaces[j];
5192 const bool isFrozen = isFrozenFace[neiFacei];
5193 if (!isFrozen && ownPatch[neiFacei] == -1)
5194 {
5195 newOwnPatch[neiFacei] = ownPatch[facei];
5196 }
5197 }
5198 }
5199 }
5200 }
5201 }
5202
5203 ownPatch.transfer(newOwnPatch);
5204
5205 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
5206 }
5207
5208
5209 // Subset
5210 // ~~~~~~
5211
5212 // Get cells to remove
5213 DynamicList<label> cellsToRemove(mesh_.nCells());
5214 forAll(cellRegion, celli)
5215 {
5216 if (cellRegion[celli] == -1)
5217 {
5218 cellsToRemove.append(celli);
5219 }
5220 }
5221 cellsToRemove.shrink();
5222
5223 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
5224 reduce(nCellsToKeep, sumOp<label>());
5225
5226 Info<< "Keeping all cells containing inside points" << endl
5227 << "Selected for keeping : " << nCellsToKeep << " cells." << endl;
5228
5229
5230 // Remove cells
5231 removeCells cellRemover(mesh_);
5232
5233 // Pick up patches for exposed faces
5234 const labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
5235 labelList exposedPatches(exposedFaces.size());
5236
5237 label nUnpatched = 0;
5238
5239 forAll(exposedFaces, i)
5240 {
5241 label facei = exposedFaces[i];
5242
5243 if (ownPatch[facei] != -1)
5244 {
5245 exposedPatches[i] = ownPatch[facei];
5246 }
5247 else
5248 {
5249 const label fallbackPatch =
5250 (
5251 nearestOwnPatch.size()
5252 ? nearestOwnPatch[facei]
5253 : defaultPatch
5254 );
5255 if (nUnpatched == 0)
5256 {
5258 << "For exposed face " << facei
5259 << " fc:" << mesh_.faceCentres()[facei]
5260 << " found no patch." << endl
5261 << " Taking patch " << fallbackPatch
5262 << " instead. Suppressing future warnings" << endl;
5263 }
5264 nUnpatched++;
5265
5266 exposedPatches[i] = fallbackPatch;
5267 }
5268 }
5269
5270 reduce(nUnpatched, sumOp<label>());
5271 if (nUnpatched > 0)
5272 {
5273 Info<< "Detected " << nUnpatched << " faces out of "
5274 << returnReduce(exposedFaces.size(), sumOp<label>())
5275 << " for which the default patch " << defaultPatch
5276 << " will be used" << endl;
5277 }
5278
5279 return doRemoveCells
5280 (
5281 cellsToRemove,
5282 exposedFaces,
5283 exposedPatches,
5284 cellRemover
5285 );
5286}
5287
5288
5290(
5291 const label nBufferLayers,
5292 const label nErodeCellZones,
5293 const labelList& globalToMasterPatch,
5294 const labelList& globalToSlavePatch,
5295 const pointField& locationsInMesh,
5296 const wordList& zonesInMesh,
5297 const pointField& locationsOutsideMesh
5298)
5299{
5300 // Determine patches to put intersections into
5301 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5302
5303 // Swap neighbouring cell centres and cell level
5304 labelList neiLevel(mesh_.nBoundaryFaces());
5305 pointField neiCc(mesh_.nBoundaryFaces());
5306 calcNeighbourData(neiLevel, neiCc);
5307
5308 // Find intersections with all unnamed(!) surfaces
5309 labelList ownPatch, neiPatch;
5310 getBafflePatches
5311 (
5312 nErodeCellZones,
5313 globalToMasterPatch,
5314
5315 locationsInMesh,
5316 zonesInMesh,
5317 locationsOutsideMesh,
5318 false, // do not exit. Use leak-closure instead.
5319 refPtr<coordSetWriter>(nullptr),
5320
5321 neiLevel,
5322 neiCc,
5323
5324 ownPatch,
5325 neiPatch
5326 );
5327
5328
5329 labelList cellRegion(mesh_.nCells(), Zero);
5330 // Find any cells inside a limit shell with minLevel -1
5331 labelList levelShell;
5332 limitShells_.findLevel
5333 (
5334 mesh_.cellCentres(),
5335 labelList(mesh_.nCells(), -1), // pick up only shells with -1
5336 levelShell
5337 );
5338 forAll(levelShell, celli)
5339 {
5340 if (levelShell[celli] != -1)
5341 {
5342 // Mark cell region so it gets deleted
5343 cellRegion[celli] = -1;
5344 }
5345 }
5346
5347 autoPtr<mapPolyMesh> mapPtr = splitMesh
5348 (
5349 nBufferLayers,
5350 globalToMasterPatch,
5351 globalToSlavePatch,
5352 cellRegion,
5353 ownPatch,
5354 neiPatch
5355 );
5356
5357 if (debug&meshRefinement::MESH)
5358 {
5359 const_cast<Time&>(mesh_.time())++;
5360 Pout<< "Writing mesh after removing limitShells"
5361 << " to time " << timeName() << endl;
5362 write
5363 (
5364 debugType(debug),
5365 writeType
5366 (
5367 writeLevel()
5368 | WRITEMESH
5369 ),
5370 mesh_.time().path()/timeName()
5371 );
5372 }
5373 return mapPtr;
5374}
5375
5376
5378(
5380)
5381{
5382 // Topochange container
5383 polyTopoChange meshMod(mesh_);
5384
5385 label nNonManifPoints = returnReduce
5386 (
5387 regionSide.meshPointMap().size(),
5388 sumOp<label>()
5389 );
5390
5391 Info<< "dupNonManifoldPoints : Found : " << nNonManifPoints
5392 << " non-manifold points (out of "
5393 << mesh_.globalData().nTotalPoints()
5394 << ')' << endl;
5395
5396
5397 autoPtr<mapPolyMesh> mapPtr;
5398
5399 if (nNonManifPoints)
5400 {
5401 // Topo change engine
5402 duplicatePoints pointDuplicator(mesh_);
5403
5404 // Insert changes into meshMod
5405 pointDuplicator.setRefinement(regionSide, meshMod);
5406
5407 // Remove any unnecessary fields
5408 mesh_.clearOut();
5409 mesh_.moving(false);
5410
5411 // Change the mesh (no inflation, parallel sync)
5412 mapPtr = meshMod.changeMesh(mesh_, false, true);
5413 mapPolyMesh& map = *mapPtr;
5414
5415 // Update fields
5416 mesh_.updateMesh(map);
5417
5418 // Move mesh if in inflation mode
5419 if (map.hasMotionPoints())
5420 {
5421 mesh_.movePoints(map.preMotionPoints());
5422 }
5423 else
5424 {
5425 // Delete mesh volumes.
5426 mesh_.clearOut();
5427 }
5428
5429 // Reset the instance for if in overwrite mode
5430 mesh_.setInstance(timeName());
5431
5432 // Update intersections. Is mapping only (no faces created, positions
5433 // stay same) so no need to recalculate intersections.
5434 updateMesh(map, labelList());
5435 }
5436
5437 return mapPtr;
5438}
5439
5440
5442{
5443 // Analyse which points need to be duplicated
5445
5446 return dupNonManifoldPoints(regionSide);
5447}
5448
5449
5451(
5452 const labelList& pointToDuplicate
5453)
5454{
5455 label nPointPairs = 0;
5456 forAll(pointToDuplicate, pointI)
5457 {
5458 label otherPointI = pointToDuplicate[pointI];
5459 if (otherPointI != -1)
5460 {
5461 nPointPairs++;
5462 }
5463 }
5464
5465 autoPtr<mapPolyMesh> mapPtr;
5466
5467 if (returnReduce(nPointPairs, sumOp<label>()))
5468 {
5469 Map<label> pointToMaster(2*nPointPairs);
5470 forAll(pointToDuplicate, pointI)
5471 {
5472 label otherPointI = pointToDuplicate[pointI];
5473 if (otherPointI != -1)
5474 {
5475 // Slave point
5476 pointToMaster.insert(pointI, otherPointI);
5477 }
5478 }
5479
5480 // Topochange container
5481 polyTopoChange meshMod(mesh_);
5482
5483 // Insert changes
5484 polyMeshAdder::mergePoints(mesh_, pointToMaster, meshMod);
5485
5486 // Remove any unnecessary fields
5487 mesh_.clearOut();
5488 mesh_.moving(false);
5489
5490 // Change the mesh (no inflation, parallel sync)
5491 mapPtr = meshMod.changeMesh(mesh_, false, true);
5492 mapPolyMesh& map = *mapPtr;
5493
5494 // Update fields
5495 mesh_.updateMesh(map);
5496
5497 // Move mesh if in inflation mode
5498 if (map.hasMotionPoints())
5499 {
5500 mesh_.movePoints(map.preMotionPoints());
5501 }
5502 else
5503 {
5504 // Delete mesh volumes.
5505 mesh_.clearOut();
5506 }
5507
5508 // Reset the instance for if in overwrite mode
5509 mesh_.setInstance(timeName());
5510
5511 // Update intersections. Is mapping only (no faces created, positions
5512 // stay same) so no need to recalculate intersections.
5513 updateMesh(map, labelList());
5514 }
5515
5516 return mapPtr;
5517}
5518
5519
5520// Duplicate points on 'boundary' zones. Do not duplicate points on
5521// 'internal' or 'baffle' zone. Whether points are on normal patches does
5522// not matter
5525{
5526 const labelList boundaryFaceZones
5527 (
5528 getZones
5529 (
5531 (
5532 1,
5534 )
5535 )
5536 );
5537 labelList internalOrBaffleFaceZones;
5538 {
5540 fzTypes[0] = surfaceZonesInfo::INTERNAL;
5541 fzTypes[1] = surfaceZonesInfo::BAFFLE;
5542 internalOrBaffleFaceZones = getZones(fzTypes);
5543 }
5544
5545
5546
5547 // 0 : point used by normal, unzoned boundary faces
5548 // 1 : point used by 'boundary' zone
5549 // 2 : point used by internal/baffle zone
5550 PackedList<2> pointStatus(mesh_.nPoints(), 0u);
5551
5552 forAll(boundaryFaceZones, j)
5553 {
5554 const faceZone& fZone = mesh_.faceZones()[boundaryFaceZones[j]];
5555 forAll(fZone, i)
5556 {
5557 const face& f = mesh_.faces()[fZone[i]];
5558 forAll(f, fp)
5559 {
5560 pointStatus[f[fp]] = max(pointStatus[f[fp]], 1u);
5561 }
5562 }
5563 }
5564 forAll(internalOrBaffleFaceZones, j)
5565 {
5566 const faceZone& fZone = mesh_.faceZones()[internalOrBaffleFaceZones[j]];
5567 forAll(fZone, i)
5568 {
5569 const face& f = mesh_.faces()[fZone[i]];
5570 forAll(f, fp)
5571 {
5572 pointStatus[f[fp]] = max(pointStatus[f[fp]], 2u);
5573 }
5574 }
5575 }
5576
5578 (
5579 mesh_,
5580 pointStatus,
5581 maxEqOp<unsigned int>(), // combine op
5582 0u // null value
5583 );
5584
5585 // Pick up points on boundary zones that are not on internal/baffle zones
5586 label n = 0;
5587 forAll(pointStatus, pointI)
5588 {
5589 if (pointStatus[pointI] == 1u)
5590 {
5591 n++;
5592 }
5593 }
5594
5595 label globalNPoints = returnReduce(n, sumOp<label>());
5596 Info<< "Duplicating " << globalNPoints << " points on"
5597 << " faceZones of type "
5599 << endl;
5600
5602
5603 if (globalNPoints)
5604 {
5605 labelList candidatePoints(n);
5606 n = 0;
5607 forAll(pointStatus, pointI)
5608 {
5609 if (pointStatus[pointI] == 1u)
5610 {
5611 candidatePoints[n++] = pointI;
5612 }
5613 }
5614 localPointRegion regionSide(mesh_, candidatePoints);
5615 map = dupNonManifoldPoints(regionSide);
5616 }
5617 return map;
5618}
5619
5620
5621// Zoning
5622Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
5623(
5624 const bool allowFreeStandingZoneFaces,
5625 const label nErodeCellZones,
5626 const pointField& locationsInMesh,
5627 const wordList& zonesInMesh,
5628 const pointField& locationsOutsideMesh,
5629 const bool exitIfLeakPath,
5630 const refPtr<coordSetWriter>& leakPathFormatter,
5631 wordPairHashTable& zonesToFaceZone
5632)
5633{
5634 if (locationsInMesh.size() != zonesInMesh.size())
5635 {
5636 FatalErrorInFunction << "problem" << abort(FatalError);
5637 }
5638
5639 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
5640 const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
5641
5642
5643 // Swap neighbouring cell centres and cell level
5644 labelList neiLevel(mesh_.nBoundaryFaces());
5645 pointField neiCc(mesh_.nBoundaryFaces());
5646 calcNeighbourData(neiLevel, neiCc);
5647
5648
5649 // Add any faceZones, cellZones originating from surface to the mesh
5650 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5651 labelList surfaceToCellZone;
5652 labelListList surfaceToFaceZones;
5653
5654 labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
5655 if (namedSurfaces.size())
5656 {
5657 Info<< "Setting cellZones according to named surfaces:" << endl;
5658 forAll(namedSurfaces, i)
5659 {
5660 label surfI = namedSurfaces[i];
5661
5662 Info<< "Surface : " << surfaces_.names()[surfI] << nl
5663 << " faceZones : " << surfZones[surfI].faceZoneNames() << nl
5664 << " cellZone : " << surfZones[surfI].cellZoneName()
5665 << endl;
5666 }
5667 Info<< endl;
5668
5669 // Add zones to mesh
5670 surfaceToCellZone = surfaceZonesInfo::addCellZonesToMesh
5671 (
5672 surfZones,
5673 namedSurfaces,
5674 mesh_
5675 );
5676 surfaceToFaceZones = surfaceZonesInfo::addFaceZonesToMesh
5677 (
5678 surfZones,
5679 namedSurfaces,
5680 mesh_
5681 );
5682 }
5683
5684
5685
5686 // Put the cells into the correct zone
5687 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5688
5689 // Zone per cell:
5690 // -2 : unset : not allowed!
5691 // -1 : not in any zone (zone 'none')
5692 // >=0: zoneID
5693 // namedSurfaceRegion: zero sized or:
5694 // -1 : face not intersecting a named surface
5695 // >=0 : index of named surface
5696 labelList cellToZone;
5697 labelList namedSurfaceRegion;
5698 bitSet posOrientation;
5699 {
5700 labelList unnamedRegion1;
5701 labelList unnamedRegion2;
5702
5703 zonify
5704 (
5705 allowFreeStandingZoneFaces,
5706 nErodeCellZones,// Use erosion (>0) or regionSplit to clean up
5707 -1, // Set all cells with cellToZone -2 to -1
5708 locationsInMesh,
5709 zonesInMesh,
5710 locationsOutsideMesh,
5711 exitIfLeakPath,
5712 leakPathFormatter,
5713
5714 cellToZone,
5715 unnamedRegion1,
5716 unnamedRegion2,
5717 namedSurfaceRegion,
5718 posOrientation
5719 );
5720 }
5721
5722
5723 // Convert namedSurfaceRegion (index of named surfaces) to
5724 // actual faceZone index
5725
5726 //- Per face index of faceZone or -1
5727 labelList faceToZone(mesh_.nFaces(), -1);
5728
5729 forAll(namedSurfaceRegion, faceI)
5730 {
5731 //label surfI = namedSurfaceIndex[faceI];
5732 label globalI = namedSurfaceRegion[faceI];
5733 if (globalI != -1)
5734 {
5735 const labelPair spr = surfaces_.whichSurface(globalI);
5736 faceToZone[faceI] = surfaceToFaceZones[spr.first()][spr.second()];
5737 }
5738 }
5739
5740
5741
5742 // Allocate and assign faceZones from cellZones
5743 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5744
5745 {
5746 // 1. Detect inter-region face and allocate names
5747
5748 LabelPairMap<word> zoneIDsToFaceZone;
5749
5750 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
5751 {
5752 if (faceToZone[faceI] == -1) // Not named surface
5753 {
5754 // Face not yet in a faceZone. (it might already have been
5755 // done so by a 'named' surface). Check if inbetween different
5756 // cellZones
5757 allocateInterRegionFaceZone
5758 (
5759 cellToZone[mesh_.faceOwner()[faceI]],
5760 cellToZone[mesh_.faceNeighbour()[faceI]],
5761 zonesToFaceZone,
5762 zoneIDsToFaceZone
5763 );
5764 }
5765 }
5766
5767 labelList neiCellZone;
5768 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
5769
5770 forAll(neiCellZone, bFaceI)
5771 {
5772 label faceI = bFaceI + mesh_.nInternalFaces();
5773 if (faceToZone[faceI] == -1)
5774 {
5775 allocateInterRegionFaceZone
5776 (
5777 cellToZone[mesh_.faceOwner()[faceI]],
5778 neiCellZone[bFaceI],
5779 zonesToFaceZone,
5780 zoneIDsToFaceZone
5781 );
5782 }
5783 }
5784
5785
5786 // 2.Combine faceZoneNames allocated on different processors
5787
5788 Pstream::mapCombineAllGather(zonesToFaceZone, eqOp<word>());
5789
5790
5791 // 3. Allocate faceZones from (now synchronised) faceZoneNames
5792 // Note: the faceZoneNames contain the same data but in different
5793 // order. We could sort the contents but instead just loop
5794 // in sortedToc order.
5795
5796 Info<< "Setting faceZones according to neighbouring cellZones:"
5797 << endl;
5798
5799 // From cellZone indices to faceZone index
5800 LabelPairMap<label> fZoneLookup(zonesToFaceZone.size());
5801
5802 const cellZoneMesh& cellZones = mesh_.cellZones();
5803
5804 {
5805 List<Pair<word>> czs(zonesToFaceZone.sortedToc());
5806
5807 forAll(czs, i)
5808 {
5809 const Pair<word>& cz = czs[i];
5810 const word& fzName = zonesToFaceZone[cz];
5811
5812 Info<< indent<< "cellZones : "
5813 << cz[0] << ' ' << cz[1] << nl
5814 << " faceZone : " << fzName << endl;
5815
5816 label faceZoneI = surfaceZonesInfo::addFaceZone
5817 (
5818 fzName, // name
5819 labelList(0), // addressing
5820 boolList(0), // flipMap
5821 mesh_
5822 );
5823
5824 label cz0 = cellZones.findZoneID(cz[0]);
5825 label cz1 = cellZones.findZoneID(cz[1]);
5826
5827 fZoneLookup.insert(labelPair(cz0, cz1), faceZoneI);
5828 }
5829 }
5830
5831
5832 // 4. Set faceToZone with new faceZones
5833
5834
5835 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
5836 {
5837 if (faceToZone[faceI] == -1)
5838 {
5839 // Face not yet in a faceZone. (it might already have been
5840 // done so by a 'named' surface). Check if inbetween different
5841 // cellZones
5842
5843 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
5844 label neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
5845 if (ownZone != neiZone)
5846 {
5847 const bool swap =
5848 (
5849 ownZone == -1
5850 || (neiZone != -1 && ownZone > neiZone)
5851 );
5852 labelPair key(ownZone, neiZone);
5853 if (swap)
5854 {
5855 key.flip();
5856 }
5857 faceToZone[faceI] = fZoneLookup[key];
5858 }
5859 }
5860 }
5861 forAll(neiCellZone, bFaceI)
5862 {
5863 label faceI = bFaceI + mesh_.nInternalFaces();
5864 if (faceToZone[faceI] == -1)
5865 {
5866 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
5867 label neiZone = neiCellZone[bFaceI];
5868 if (ownZone != neiZone)
5869 {
5870 const bool swap =
5871 (
5872 ownZone == -1
5873 || (neiZone != -1 && ownZone > neiZone)
5874 );
5875 labelPair key(ownZone, neiZone);
5876 if (swap)
5877 {
5878 key.flip();
5879 }
5880 faceToZone[faceI] = fZoneLookup[key];
5881 }
5882 }
5883 }
5884 Info<< endl;
5885 }
5886
5887
5888
5889
5890 // Get coupled neighbour cellZone. Set to -1 on non-coupled patches.
5891 labelList neiCellZone;
5892 syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
5893 forAll(patches, patchI)
5894 {
5895 const polyPatch& pp = patches[patchI];
5896
5897 if (!pp.coupled())
5898 {
5899 label bFaceI = pp.start()-mesh_.nInternalFaces();
5900 forAll(pp, i)
5901 {
5902 neiCellZone[bFaceI++] = -1;
5903 }
5904 }
5905 }
5906
5907
5908
5909 // Get per face whether is it master (of a coupled set of faces)
5910 const bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
5911
5912
5913 // faceZones
5914 // ~~~~~~~~~
5915 // Faces on faceZones come in two variants:
5916 // - faces on the outside of a cellZone. They will be oriented to
5917 // point out of the maximum cellZone.
5918 // - free-standing faces. These will be oriented according to the
5919 // local surface normal. We do this in a two step algorithm:
5920 // - do a consistent orientation
5921 // - check number of faces with consistent orientation
5922 // - if <0 flip the whole patch
5923 bitSet meshFlipMap(mesh_.nFaces(), false);
5924 {
5925 // Collect all data on zone faces without cellZones on either side.
5926 const indirectPrimitivePatch patch
5927 (
5929 (
5930 mesh_.faces(),
5931 freeStandingBaffleFaces
5932 (
5933 faceToZone,
5934 cellToZone,
5935 neiCellZone
5936 )
5937 ),
5938 mesh_.points()
5939 );
5940
5941 label nFreeStanding = returnReduce(patch.size(), sumOp<label>());
5942 if (nFreeStanding > 0)
5943 {
5944 Info<< "Detected " << nFreeStanding << " free-standing zone faces"
5945 << endl;
5946
5947 if (debug)
5948 {
5949 OBJstream str(mesh_.time().path()/"freeStanding.obj");
5950 Pout<< "meshRefinement::zonify : dumping faceZone faces to "
5951 << str.name() << endl;
5952 str.write(patch.localFaces(), patch.localPoints(), false);
5953 }
5954
5955
5956 // Detect non-manifold edges
5957 labelList nMasterFacesPerEdge;
5958 calcPatchNumMasterFaces(isMasterFace, patch, nMasterFacesPerEdge);
5959
5960 // Mark zones. Even a single original surface might create multiple
5961 // disconnected/non-manifold-connected zones
5962 labelList faceToConnectedZone;
5963 const label nZones = markPatchZones
5964 (
5965 patch,
5966 nMasterFacesPerEdge,
5967 faceToConnectedZone
5968 );
5969
5970 Map<label> nPosOrientation(2*nZones);
5971 for (label zoneI = 0; zoneI < nZones; zoneI++)
5972 {
5973 nPosOrientation.insert(zoneI, 0);
5974 }
5975
5976 // Make orientations consistent in a topological way. This just
5977 // checks the first face per zone for whether nPosOrientation
5978 // is negative (which it never is at this point)
5979 consistentOrientation
5980 (
5981 isMasterFace,
5982 patch,
5983 nMasterFacesPerEdge,
5984 faceToConnectedZone,
5985 nPosOrientation,
5986
5987 meshFlipMap
5988 );
5989
5990 // Count per region the number of orientations (taking the new
5991 // flipMap into account)
5992 forAll(patch.addressing(), faceI)
5993 {
5994 label meshFaceI = patch.addressing()[faceI];
5995
5996 if (isMasterFace.test(meshFaceI))
5997 {
5998 label n = 1;
5999 if
6000 (
6001 posOrientation.test(meshFaceI)
6002 == meshFlipMap.test(meshFaceI)
6003 )
6004 {
6005 n = -1;
6006 }
6007
6008 nPosOrientation.find(faceToConnectedZone[faceI])() += n;
6009 }
6010 }
6012
6013
6014 Info<< "Split " << nFreeStanding << " free-standing zone faces"
6015 << " into " << nZones << " disconnected regions with size"
6016 << " (negative denotes wrong orientation) :"
6017 << endl;
6018
6019 for (label zoneI = 0; zoneI < nZones; zoneI++)
6020 {
6021 Info<< " " << zoneI << "\t" << nPosOrientation[zoneI]
6022 << endl;
6023 }
6024 Info<< endl;
6025
6026
6027 // Re-apply with new counts (in nPosOrientation). This will cause
6028 // zones with a negative count to be flipped.
6029 consistentOrientation
6030 (
6031 isMasterFace,
6032 patch,
6033 nMasterFacesPerEdge,
6034 faceToConnectedZone,
6035 nPosOrientation,
6036
6037 meshFlipMap
6038 );
6039 }
6040 }
6041
6042
6043
6044
6045 // Topochange container
6046 polyTopoChange meshMod(mesh_);
6047
6048 // Insert changes to put cells and faces into zone
6049 zonify
6050 (
6051 isMasterFace,
6052 cellToZone,
6053 neiCellZone,
6054 faceToZone,
6055 meshFlipMap,
6056 meshMod
6057 );
6058
6059 // Remove any unnecessary fields
6060 mesh_.clearOut();
6061 mesh_.moving(false);
6062
6063 // Change the mesh (no inflation, parallel sync)
6064 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
6065
6066 // Update fields
6067 mesh_.updateMesh(map());
6068
6069 // Move mesh if in inflation mode
6070 if (map().hasMotionPoints())
6071 {
6072 mesh_.movePoints(map().preMotionPoints());
6073 }
6074 else
6075 {
6076 // Delete mesh volumes.
6077 mesh_.clearOut();
6078 }
6079
6080 // Reset the instance for if in overwrite mode
6081 mesh_.setInstance(timeName());
6082
6083 // Print some stats (note: zones are synchronised)
6084 if (mesh_.cellZones().size() > 0)
6085 {
6086 Info<< "CellZones:" << endl;
6087 forAll(mesh_.cellZones(), zoneI)
6088 {
6089 const cellZone& cz = mesh_.cellZones()[zoneI];
6090 Info<< " " << cz.name()
6091 << "\tsize:" << returnReduce(cz.size(), sumOp<label>())
6092 << endl;
6093 }
6094 Info<< endl;
6095 }
6096 if (mesh_.faceZones().size() > 0)
6097 {
6098 Info<< "FaceZones:" << endl;
6099 forAll(mesh_.faceZones(), zoneI)
6100 {
6101 const faceZone& fz = mesh_.faceZones()[zoneI];
6102 Info<< " " << fz.name()
6103 << "\tsize:" << returnReduce(fz.size(), sumOp<label>())
6104 << endl;
6105 }
6106 Info<< endl;
6107 }
6108
6109 // None of the faces has changed, only the zones. Still...
6110 updateMesh(map(), labelList());
6111
6112 return map;
6113}
6114
6115
6116// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
label n
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
T & first() noexcept
The first element of the list, position [0].
Definition: FixedListI.H:207
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
A HashTable similar to std::unordered_map.
Definition: HashTable.H:123
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition: HashTable.C:137
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:122
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: HashTableI.H:114
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:65
A List with indirect addressing.
Definition: IndirectList.H:119
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:330
void transfer(List< T > &list)
Definition: List.C:447
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
A HashTable to objects of type <T> with a label key.
Definition: Map.H:60
OFstream that keeps track of vertices.
Definition: OBJstream.H:61
virtual Ostream & write(const char c)
Write character.
Definition: OBJstream.C:78
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
A dynamic list of packed unsigned integers, with the number of bits per item specified by the <Width>...
Definition: PackedList.H:129
const T & second() const noexcept
Return second element, which is also the last element.
Definition: PairI.H:120
A list of faces which address into the list of points.
static void listCombineAllGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
static void mapCombineAllGather(const List< commsStruct > &comms, Container &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: PtrList.H:73
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
fileName path() const
Return path.
Definition: Time.H:358
T & first()
Return the first element of the list.
Definition: UListI.H:202
bool found(const T &val, label pos=0) const
True if the value if found in the list.
Definition: UListI.H:265
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type test(const label i) const
Definition: UList.H:518
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:212
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:525
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:288
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:66
bool test(const label pos) const
Test value at specified position, never auto-vivify entries.
Definition: bitSetI.H:521
A subset of mesh cells.
Definition: cellZone.H:65
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:57
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTimeCxx.C:75
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Particle-size distribution model wherein random samples are drawn from the doubly-truncated uniform p...
Definition: uniform.H:164
Duplicate points.
void setRefinement(const localPointRegion &regionSide, polyTopoChange &)
Play commands into polyTopoChange to duplicate points. Gets.
A list of face labels.
Definition: faceSet.H:54
virtual void sync(const polyMesh &mesh)
Sync faceSet across coupled patches.
Definition: faceSet.C:130
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:67
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:372
const boolList & flipMap() const noexcept
Return face flip map.
Definition: faceZone.H:272
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static autoPtr< mapDistribute > calcClosure(const polyMesh &mesh, const List< pointField > &zonePoints, const labelList &blockedFaces, const globalIndex &globalBlockedFaces, const bool erode, labelList &closureFaces, labelList &closureToBlocked)
Optional direct use to generate the set of faces and the method to.
Definition: holeToFace.C:1194
Takes mesh with 'baffles' (= boundary faces sharing points). Determines for selected points on bounda...
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
const labelList & faceMap() const
Old face map.
Definition: mapPolyMesh.H:410
const pointField & preMotionPoints() const
Pre-motion point positions.
Definition: mapPolyMesh.H:613
const labelList & reverseFaceMap() const
Reverse face map.
Definition: mapPolyMesh.H:501
bool hasMotionPoints() const
Has valid preMotionPoints?
Definition: mapPolyMesh.H:619
labelList getZones(const List< surfaceZonesInfo::faceZoneType > &fzTypes) const
Get zones of given type.
autoPtr< mapPolyMesh > removeLimitShells(const label nBufferLayers, const label nErodeCellZones, const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const pointField &locationsInMesh, const wordList &regionsInMesh, const pointField &locationsOutsideMesh)
Remove cells from limitRegions if level -1.
static List< labelPair > subsetBaffles(const polyMesh &mesh, const labelList &zoneIDs, const List< labelPair > &baffles)
Subset baffles according to zones.
writeType
Enumeration for what to write. Used as a bit-pattern.
autoPtr< mapPolyMesh > mergePoints(const labelList &pointToDuplicate)
Merge duplicate points.
autoPtr< mapPolyMesh > dupNonManifoldPoints()
Find boundary points that connect to more than one cell.
autoPtr< mapPolyMesh > dupNonManifoldBoundaryPoints()
Find boundary points that are on faceZones of type boundary.
void getZoneFaces(const labelList &zoneIDs, labelList &faceZoneID, labelList &ownPatch, labelList &neiPatch, labelList &nBaffles) const
Get per-face information (faceZone, master/slave patch)
autoPtr< mapPolyMesh > mergeBaffles(const List< labelPair > &, const Map< label > &faceToPatch)
Merge baffles. Gets pairs of faces and boundary faces to move.
void baffleAndSplitMesh(const bool handleSnapProblems, const snapParameters &snapParams, const bool useTopologicalSnapDetection, const bool removeEdgeConnectedCells, const scalarField &perpendicularAngle, const label nErodeCellZones, const dictionary &motionDict, Time &runTime, const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const pointField &locationsInMesh, const wordList &regionsInMesh, const pointField &locationsOutsideMesh, const bool exitIfLeakPath, const refPtr< coordSetWriter > &leakPathFormatter)
Split off unreachable areas of mesh.
debugType
Enumeration for what to debug. Used as a bit-pattern.
autoPtr< mapPolyMesh > mergeZoneBaffles(const bool doInternalZones, const bool doBaffleZones)
Merge all baffles on faceZones.
autoPtr< mapPolyMesh > createBaffles(const labelList &ownPatch, const labelList &neiPatch)
Create baffle for every internal face where ownPatch != -1.
autoPtr< mapPolyMesh > createZoneBaffles(const labelList &zoneIDs, List< labelPair > &baffles, labelList &originatingFaceZone)
Create baffles for faces on faceZones. Return created baffles.
void mergeFreeStandingBaffles(const snapParameters &snapParams, const bool useTopologicalSnapDetection, const bool removeEdgeConnectedCells, const scalarField &perpendicularAngle, const scalar planarAngle, const dictionary &motionDict, Time &runTime, const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const pointField &locationsInMesh, const pointField &locationsOutsideMesh)
Merge free-standing baffles.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
label start() const noexcept
The start label of boundary faces in the polyMesh face list.
static void mergePoints(const polyMesh &, const Map< label > &pointToMaster, polyTopoChange &meshMod)
Helper: Merge points.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
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
Class describing modification of a face.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:380
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:364
Class containing data for face removal.
Direct mesh changes based on v1.3 polyTopoChange syntax.
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.
autoPtr< mapPolyMesh > changeMesh(polyMesh &mesh, const labelUList &patchMap, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
const vectorField & faceCentres() const
label nFaces() const noexcept
Number of mesh faces.
A class for managing references or pointers (no reference counting)
Definition: refPtr.H:58
static List< pointField > zonePoints(const pointField &locationsInMesh, const wordList &zonesInMesh, const pointField &locationsOutsideMesh)
Helper: per zone (entry in zonesInMesh) the locations with.
Determines the 'side' for every face and connected to a singly-connected (through edges) region of fa...
Definition: regionSide.H:64
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:144
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:294
Simple container to keep together snap specific information.
static labelList getInsidePointNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of surfaces with a cellZone that have 'insidePoint'.
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
static labelList getStandaloneNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces without a cellZone.
faceZoneType
What to do with faceZone faces.
static label addFaceZone(const word &name, const labelList &addressing, const boolList &flipMap, polyMesh &mesh)
static const Enum< faceZoneType > faceZoneTypeNames
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
static labelList addCellZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
static labelListList addFaceZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
static labelList getClosedNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList, const searchableSurfaces &allGeometry, const labelList &surfaces)
Get indices of surfaces with a cellZone that are closed and.
static bitSet getMasterFaces(const polyMesh &mesh)
Definition: syncTools.C:126
static bitSet getInternalOrCoupledFaces(const polyMesh &mesh)
Get per face whether it is internal or coupled.
Definition: syncTools.C:176
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
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition: word.H:68
const word & name() const noexcept
The zone name.
volScalarField & p
const polyBoundaryMesh & patches
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
dynamicFvMesh & mesh
engineTime & runTime
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
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))
const labelIOList & zoneIDs
Definition: correctPhi.H:59
label nZones
const labelIOList & zoneID
word timeName
Definition: getTimeIndex.H:3
#define WarningInFunction
Report a warning using Foam::Warning.
labelList findIndices(const ListType &input, const UnaryPredicate &pred, label start=0)
Linear search to find all occurences of given element.
const wordList area
Standard area field types (scalar, vector, tensor, etc)
const std::string patch
OpenFOAM patch number as a std::string.
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:108
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:57
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
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:169
const dimensionSet dimless
Dimensionless.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
List< label > labelList
A List of labels.
Definition: List.H:66
dimensionedSymmTensor sqr(const dimensionedVector &dv)
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:515
ZoneMesh< cellZone, polyMesh > cellZoneMesh
A ZoneMesh with the type cellZone.
line< point, const point & > linePointRef
A line using referred points.
Definition: linePointRef.H:47
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:82
void reverse(UList< T > &list, const label n)
Reverse the first n elements of the list.
Definition: UListI.H:449
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
ZoneMesh< pointZone, polyMesh > pointZoneMesh
A ZoneMesh with the type pointZone.
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
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
constexpr label labelMax
Definition: label.H:61
HashTable< word, wordPair, Foam::Hash< wordPair > > wordPairHashTable
HashTable of wordPair.
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:342
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
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)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
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
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
label checkData(const fvMesh &mesh, const instantList &timeDirs, wordList &objectNames)
Check if fields are good to use (available at all times)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
DynamicID< faceZoneMesh > faceZoneID
Foam::faceZoneID.
Definition: ZoneIDs.H:46
Type gMax(const FieldField< Field, Type > &f)
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:68
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar cos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:158
runTime write()
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
labelList f(nPoints)
insidePoints((1 2 3))
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278
Definition: ops.H:71
Unit conversion functions.