Loading...
Searching...
No Matches
meshRefinement.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-2017 OpenFOAM Foundation
9 Copyright (C) 2015-2025 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 "volMesh.H"
31#include "volFields.H"
32#include "surfaceMesh.H"
33#include "syncTools.H"
34#include "Time.H"
35#include "refinementSurfaces.H"
36#include "refinementFeatures.H"
37#include "decompositionMethod.H"
38#include "regionSplit.H"
39#include "fvMeshDistribute.H"
41#include "polyTopoChange.H"
42#include "removeCells.H"
44#include "localPointRegion.H"
45#include "pointMesh.H"
46#include "pointFields.H"
51#include "processorPointPatch.H"
52#include "globalIndex.H"
53#include "meshTools.H"
54#include "OFstream.H"
55#include "Random.H"
56#include "searchableSurfaces.H"
57#include "treeBoundBox.H"
59#include "fvMeshTools.H"
60#include "motionSmoother.H"
61#include "faceSet.H"
62#include "topoDistanceData.H"
63#include "FaceCellWave.H"
64
65// Leak path
67#include "meshSearch.H"
68
69// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
70
71namespace Foam
72{
74}
75
76
77const Foam::Enum
78<
80>
82({
83 { MeshType::CASTELLATED, "castellated" },
84 { MeshType::CASTELLATEDBUFFERLAYER, "castellatedBufferLayer" },
85 { MeshType::CASTELLATEDBUFFERLAYER2, "castellatedBufferLayer2" }
86});
87
88
89const Foam::Enum
90<
92>
94({
95 { debugType::MESH, "mesh" },
96 { debugType::OBJINTERSECTIONS, "intersections" },
97 { debugType::FEATURESEEDS, "featureSeeds" },
98 { debugType::ATTRACTION, "attraction" },
99 { debugType::LAYERINFO, "layerInfo" },
100});
101
102
103//const Foam::Enum
104//<
105// Foam::meshRefinement::outputType
106//>
107//Foam::meshRefinement::outputTypeNames
108//({
109// { outputType::OUTPUTLAYERINFO, "layerInfo" }
110//});
111
112
113const Foam::Enum
114<
116>
118({
119 { writeType::WRITEMESH, "mesh" },
120 { writeType::NOWRITEREFINEMENT, "noRefinement" },
121 { writeType::WRITELEVELS, "scalarLevels" },
122 { writeType::WRITELAYERSETS, "layerSets" },
123 { writeType::WRITELAYERFIELDS, "layerFields" },
124});
125
126
127Foam::meshRefinement::writeType Foam::meshRefinement::writeLevel_;
128
129//Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel_;
130
131// Inside/outside test for polyMesh:.findCell()
132// 2.4.x : default = polyMesh::FACE_DIAG_TRIS
133// 1712 : default = polyMesh::CELL_TETS
134//
135// - CELL_TETS is better with concave cells, but much slower.
136// - use faster method (FACE_DIAG_TRIS) here
137
140
141
142// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
143
144Foam::label Foam::meshRefinement::globalFaceCount(const labelList& elems) const
145{
146 //- Check for duplicates
147 const bitSet isElem(mesh_.nFaces(), elems);
148 if (label(isElem.count()) != elems.size())
149 {
150 FatalErrorInFunction << "Problem Duplicates:"
151 << " isElem:" << isElem.count()
152 << " elems:" << elems.size()
153 << exit(FatalError);
154 }
155
156 //- Check for same entries on coupled faces
157 {
158 bitSet isElem2(isElem);
159 syncTools::swapFaceList(mesh_, isElem2);
160
161 for
162 (
163 label facei = mesh_.nInternalFaces();
164 facei < mesh_.nFaces();
165 facei++
166 )
167 {
168 if (isElem2[facei] != isElem[facei])
169 {
171 << "at face:" << facei
172 << " at:" << mesh_.faceCentres()[facei]
173 << " patch:" << mesh_.boundaryMesh().whichPatch(facei)
174 << " isElem:" << isElem[facei]
175 << " isElem2:" << isElem2[facei]
176 << exit(FatalError);
177 }
178 }
179 }
180
181 //- Count number of master elements
182 const bitSet isMaster(syncTools::getMasterFaces(mesh_));
183 label count = 0;
184 for (const label i : isElem)
185 {
186 if (isMaster[i])
187 {
188 count++;
189 }
190 }
191 return returnReduce(count, sumOp<label>());
192}
193
194
195void Foam::meshRefinement::calcNeighbourData
196(
197 labelList& neiLevel,
198 pointField& neiCc
199) const
200{
201 const labelList& cellLevel = meshCutter_.cellLevel();
202 const pointField& cellCentres = mesh_.cellCentres();
203
204 const label nBoundaryFaces = mesh_.nBoundaryFaces();
205
206 if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
207 {
209 << nBoundaryFaces << " neiLevel:" << neiLevel.size()
210 << abort(FatalError);
211 }
212
213 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
214
215 labelHashSet addedPatchIDSet(meshedPatches());
216
217 forAll(patches, patchi)
218 {
219 const polyPatch& pp = patches[patchi];
220
221 const labelUList& faceCells = pp.faceCells();
222 const vectorField::subField faceCentres = pp.faceCentres();
223 const vectorField::subField faceAreas = pp.faceAreas();
224
225 label bFacei = pp.start()-mesh_.nInternalFaces();
226
227 if (pp.coupled())
228 {
229 forAll(faceCells, i)
230 {
231 neiLevel[bFacei] = cellLevel[faceCells[i]];
232 neiCc[bFacei] = cellCentres[faceCells[i]];
233 bFacei++;
234 }
235 }
236 else if (addedPatchIDSet.found(patchi))
237 {
238 // Face was introduced from cell-cell intersection. Try to
239 // reconstruct other side cell(centre). Three possibilities:
240 // - cells same size.
241 // - preserved cell smaller. Not handled.
242 // - preserved cell larger.
243 forAll(faceCells, i)
244 {
245 // Extrapolate the face centre.
246 const vector fn = normalised(faceAreas[i]);
247
248 label own = faceCells[i];
249 label ownLevel = cellLevel[own];
250 label faceLevel = meshCutter_.faceLevel(pp.start()+i);
251 if (faceLevel < 0)
252 {
253 // Due to e.g. face merging no longer a consistent
254 // refinementlevel of face. Assume same as cell
255 faceLevel = ownLevel;
256 }
257
258 // Normal distance from face centre to cell centre
259 scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
260 if (faceLevel > ownLevel)
261 {
262 // Other cell more refined. Adjust normal distance
263 d *= 0.5;
264 }
265 neiLevel[bFacei] = faceLevel;
266 // Calculate other cell centre by extrapolation
267 neiCc[bFacei] = faceCentres[i] + d*fn;
268 bFacei++;
269 }
270 }
271 else
272 {
273 forAll(faceCells, i)
274 {
275 neiLevel[bFacei] = cellLevel[faceCells[i]];
276 neiCc[bFacei] = faceCentres[i];
277 bFacei++;
278 }
279 }
280 }
281
282 // Swap coupled boundaries. Apply separation to cc since is coordinate.
284 syncTools::swapBoundaryFaceList(mesh_, neiLevel);
285}
286
287
288void Foam::meshRefinement::calcCellCellRays
289(
290 const pointField& neiCc,
291 const labelUList& neiLevel,
292 const labelUList& testFaces,
293 pointField& start,
294 pointField& end,
295 labelList& minLevel
296) const
297{
298 const labelList& cellLevel = meshCutter_.cellLevel();
299 const pointField& cellCentres = mesh_.cellCentres();
300
301
302 // Mark all non-coupled or coupled+master faces. Leaves only slave of
303 // coupled unset.
304 bitSet isMaster(mesh_.nBoundaryFaces(), true);
305 {
306 for (const polyPatch& pp : mesh_.boundaryMesh())
307 {
308 if (pp.coupled() && !refCast<const coupledPolyPatch>(pp).owner())
309 {
310 isMaster.unset(labelRange(pp.offset(), pp.size()));
311 }
312 }
313 }
314
315
316 start.setSize(testFaces.size());
317 end.setSize(testFaces.size());
318 minLevel.setSize(testFaces.size());
319
320 forAll(testFaces, i)
321 {
322 const label facei = testFaces[i];
323 const label own = mesh_.faceOwner()[facei];
324
325 if (mesh_.isInternalFace(facei))
326 {
327 const label nei = mesh_.faceNeighbour()[facei];
328
329 start[i] = cellCentres[own];
330 end[i] = cellCentres[nei];
331 minLevel[i] = min(cellLevel[own], cellLevel[nei]);
332 }
333 else
334 {
335 const label bFacei = facei - mesh_.nInternalFaces();
336
337 if (isMaster[bFacei])
338 {
339 start[i] = cellCentres[own];
340 end[i] = neiCc[bFacei];
341 }
342 else
343 {
344 // Slave face
345 start[i] = neiCc[bFacei];
346 end[i] = cellCentres[own];
347 }
348 minLevel[i] = min(cellLevel[own], neiLevel[bFacei]);
349 }
350 }
351
352 // Extend segments a bit
353 {
354 const vectorField smallVec(ROOTSMALL*(end-start));
355 start -= smallVec;
356 end += smallVec;
357 }
358}
359
362{
363 // Stats on edges to test. Count proc faces only once.
364 bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
365
366 {
367 const label nMasterFaces =
368 returnReduce(isMasterFace.count(), sumOp<label>());
369
370 label nChangedFaces = 0;
371 forAll(changedFaces, i)
372 {
373 if (isMasterFace.test(changedFaces[i]))
374 {
375 ++nChangedFaces;
376 }
377 }
378 reduce(nChangedFaces, sumOp<label>());
379
380 if (!dryRun_)
381 {
382 Info<< "Edge intersection testing:" << nl
383 << " Number of edges : " << nMasterFaces << nl
384 << " Number of edges to retest : " << nChangedFaces
385 << endl;
386 }
387 }
388
389
390 // Get boundary face centre and level. Coupled aware.
391 labelList neiLevel(mesh_.nBoundaryFaces());
392 pointField neiCc(mesh_.nBoundaryFaces());
393 calcNeighbourData(neiLevel, neiCc);
394
395 // Collect segments we want to test for
396 pointField start(changedFaces.size());
397 pointField end(changedFaces.size());
398 {
399 labelList minLevel;
400 calcCellCellRays
401 (
402 neiCc,
403 neiLevel,
404 changedFaces,
405 start,
406 end,
407 minLevel
408 );
409 }
410
411
412 // Do tests in one go
413 labelList surfaceHit;
414 {
415 labelList surfaceLevel;
416 surfaces_.findHigherIntersection
417 (
418 shells_,
419 start,
420 end,
421 labelList(start.size(), -1), // accept any intersection
422 surfaceHit,
423 surfaceLevel
424 );
425 }
426
427 // Keep just surface hit
428 forAll(surfaceHit, i)
429 {
430 surfaceIndex_[changedFaces[i]] = surfaceHit[i];
431 }
432
433 // Make sure both sides have same information. This should be
434 // case in general since same vectors but just to make sure.
435 syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>());
436
437 label nTotHits = returnReduce(countHits(), sumOp<label>());
438
439 if (!dryRun_)
440 {
441 Info<< " Number of intersected edges : " << nTotHits << endl;
442 }
443
444 // Set files to same time as mesh
445 setInstance(mesh_.facesInstance());
446}
447
448
449void Foam::meshRefinement::nearestFace
450(
451 const labelUList& startFaces,
452 const bitSet& isBlockedFace,
453
455 labelList& faceToStart,
456 const label nIter
457) const
458{
459 // From startFaces walk out (but not through isBlockedFace). Returns
460 // faceToStart which is the index into startFaces (or rather distributed
461 // version of it). E.g.
462 // pointField startFc(mesh.faceCentres(), startFaces);
463 // mapPtr().distribute(startFc);
464 // forAll(faceToStart, facei)
465 // {
466 // const label sloti = faceToStart[facei];
467 // if (sloti != -1)
468 // {
469 // Pout<< "face:" << mesh.faceCentres()[facei]
470 // << " nearest:" << startFc[sloti]
471 // << endl;
472 // }
473 // }
474
475
476 // Consecutive global numbering for start elements
477 const globalIndex globalStart(startFaces.size());
478
479 // Field on cells and faces.
480 List<topoDistanceData<label>> cellData(mesh_.nCells());
481 List<topoDistanceData<label>> faceData(mesh_.nFaces());
482
483 // Mark blocked faces to there not visited
484 for (const label facei : isBlockedFace)
485 {
486 faceData[facei] = topoDistanceData<label>(0, -1);
487 }
488
489 List<topoDistanceData<label>> startData(startFaces.size());
490 forAll(startFaces, i)
491 {
492 const label facei = startFaces[i];
493 if (isBlockedFace[facei])
494 {
495 FatalErrorInFunction << "Start face:" << facei
496 << " at:" << mesh_.faceCentres()[facei]
497 << " is also blocked" << exit(FatalError);
498 }
499 startData[i] = topoDistanceData<label>(0, globalStart.toGlobal(i));
500 }
501
502
503 // Propagate information inwards
505 (
506 mesh_,
507 startFaces,
508 startData,
509 faceData,
510 cellData,
511 0
512 );
513 deltaCalc.iterate(nIter);
514
515 // And extract
516
517 faceToStart.setSize(mesh_.nFaces());
518 faceToStart = -1;
519 bool haveWarned = false;
520 forAll(faceData, facei)
521 {
522 if (!faceData[facei].valid(deltaCalc.data()))
523 {
524 if (!haveWarned)
525 {
527 << "Did not visit some faces, e.g. face " << facei
528 << " at " << mesh_.faceCentres()[facei]
529 << endl;
530 haveWarned = true;
531 }
532 }
533 else
534 {
535 faceToStart[facei] = faceData[facei].data();
536 }
537 }
538
539 // Compact
540 List<Map<label>> compactMap;
541 mapPtr.reset(new mapDistribute(globalStart, faceToStart, compactMap));
542}
543
544
545void Foam::meshRefinement::nearestPatch
546(
547 const labelList& adaptPatchIDs,
548 labelList& nearestPatch,
549 labelList& nearestZone
550) const
551{
552 // Determine nearest patch for all mesh faces. Used when removing cells
553 // to give some reasonable patch to exposed faces.
554
555 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
556
557 nearestZone.setSize(mesh_.nFaces(), -1);
558
559 if (adaptPatchIDs.size())
560 {
561 nearestPatch.setSize(mesh_.nFaces(), adaptPatchIDs[0]);
562
563
564 // Get per-face the zone or -1
565 labelList faceToZone(mesh_.nFaces(), -1);
566 {
567 for (const faceZone& fz : mesh_.faceZones())
568 {
569 UIndirectList<label>(faceToZone, fz) = fz.index();
570 }
571 }
572
573
574 // Count number of faces in adaptPatchIDs
575 label nFaces = 0;
576 forAll(adaptPatchIDs, i)
577 {
578 const polyPatch& pp = patches[adaptPatchIDs[i]];
579 nFaces += pp.size();
580 }
581
582 // Field on cells and faces.
583 List<topoDistanceData<labelPair>> cellData(mesh_.nCells());
584 List<topoDistanceData<labelPair>> faceData(mesh_.nFaces());
585
586 // Start of changes
587 labelList patchFaces(nFaces);
588 List<topoDistanceData<labelPair>> patchData(nFaces);
589 nFaces = 0;
590 forAll(adaptPatchIDs, i)
591 {
592 label patchi = adaptPatchIDs[i];
593 const polyPatch& pp = patches[patchi];
594
595 forAll(pp, i)
596 {
597 patchFaces[nFaces] = pp.start()+i;
598 patchData[nFaces] = topoDistanceData<labelPair>
599 (
600 0,
602 (
603 patchi,
604 faceToZone[pp.start()+i]
605 )
606 );
607 nFaces++;
608 }
609 }
610
611 // Propagate information inwards
613 (
614 mesh_,
615 patchFaces,
616 patchData,
617 faceData,
618 cellData,
619 mesh_.globalData().nTotalCells()+1
620 );
621
622 // And extract
623
624 bool haveWarned = false;
625 forAll(faceData, facei)
626 {
627 if (!faceData[facei].valid(deltaCalc.data()))
628 {
629 if (!haveWarned)
630 {
632 << "Did not visit some faces, e.g. face " << facei
633 << " at " << mesh_.faceCentres()[facei] << endl
634 << "Assigning these faces to patch "
635 << adaptPatchIDs[0]
636 << endl;
637 haveWarned = true;
638 }
639 }
640 else
641 {
642 const labelPair& data = faceData[facei].data();
643 nearestPatch[facei] = data.first();
644 nearestZone[facei] = data.second();
645 }
646 }
647 }
648 else
649 {
650 // Use patch 0
651 nearestPatch.setSize(mesh_.nFaces(), 0);
652 }
653}
654
655
656Foam::labelList Foam::meshRefinement::nearestPatch
657(
658 const labelList& adaptPatchIDs
659) const
660{
661 labelList nearestAdaptPatch;
662 labelList nearestAdaptZone;
663 nearestPatch(adaptPatchIDs, nearestAdaptPatch, nearestAdaptZone);
664 return nearestAdaptPatch;
665}
666
668void Foam::meshRefinement::nearestIntersection
669(
670 const labelList& surfacesToTest,
671 const labelList& testFaces,
672
673 labelList& surface1,
675 labelList& region1,
676 labelList& surface2,
678 labelList& region2
679) const
680{
681 // Swap neighbouring cell centres and cell level
682 labelList neiLevel(mesh_.nBoundaryFaces());
683 pointField neiCc(mesh_.nBoundaryFaces());
684 calcNeighbourData(neiLevel, neiCc);
685
686
687 // Collect segments
688
689 pointField start(testFaces.size());
690 pointField end(testFaces.size());
691 labelList minLevel(testFaces.size());
692
693 calcCellCellRays
694 (
695 neiCc,
696 neiLevel,
697 testFaces,
698 start,
699 end,
700 minLevel
701 );
702
703 // Do tests in one go
704
705 surfaces_.findNearestIntersection
706 (
707 surfacesToTest,
708 start,
709 end,
710
711 surface1,
712 hit1,
713 region1,
714 surface2,
715 hit2,
716 region2
717 );
718}
719
720
721Foam::labelList Foam::meshRefinement::nearestIntersection
722(
723 const labelList& surfacesToTest,
724 const label defaultRegion
725) const
726{
727 // Determine nearest intersection for all mesh faces. Used when removing
728 // cells to give some reasonable patch to exposed faces. Use this
729 // function instead of nearestPatch if you don't have patches yet.
730
731
732 // All faces with any intersection
733 const labelList testFaces(intersectedFaces());
734
735 // Find intersection (if any)
736 labelList surface1;
738 labelList region1;
739 labelList surface2;
741 labelList region2;
742 nearestIntersection
743 (
744 surfacesToTest,
745 testFaces,
746
747 surface1,
748 hit1,
749 region1,
750 surface2,
751 hit2,
752 region2
753 );
754
755
756 labelList nearestRegion(mesh_.nFaces(), defaultRegion);
757
758 // Field on cells and faces.
759 List<topoDistanceData<label>> cellData(mesh_.nCells());
760 List<topoDistanceData<label>> faceData(mesh_.nFaces());
761
762 // Start walking from all intersected faces
763 DynamicList<label> patchFaces(testFaces.size());
764 DynamicList<topoDistanceData<label>> patchData(testFaces.size());
765 forAll(testFaces, i)
766 {
767 label facei = testFaces[i];
768 if (surface1[i] != -1)
769 {
770 patchFaces.append(facei);
771 label regioni = surfaces_.globalRegion(surface1[i], region1[i]);
772 patchData.append(topoDistanceData<label>(0, regioni));
773 }
774 else if (surface2[i] != -1)
775 {
776 patchFaces.append(facei);
777 label regioni = surfaces_.globalRegion(surface2[i], region2[i]);
778 patchData.append(topoDistanceData<label>(0, regioni));
779 }
780 }
781
782 // Propagate information inwards
784 (
785 mesh_,
786 patchFaces,
787 patchData,
788 faceData,
789 cellData,
790 mesh_.globalData().nTotalCells()+1
791 );
792
793 // And extract
794
795 bool haveWarned = false;
796 forAll(faceData, facei)
797 {
798 if (!faceData[facei].valid(deltaCalc.data()))
799 {
800 if (!haveWarned)
801 {
803 << "Did not visit some faces, e.g. face " << facei
804 << " at " << mesh_.faceCentres()[facei] << endl
805 << "Assigning these faces to global region "
806 << defaultRegion << endl;
807 haveWarned = true;
808 }
809 }
810 else
811 {
812 nearestRegion[facei] = faceData[facei].data();
813 }
814 }
815
816 return nearestRegion;
817}
818
821(
822 const string& msg,
823 const polyMesh& mesh,
824 const List<scalar>& fld
825)
826{
827 if (fld.size() != mesh.nPoints())
828 {
830 << msg << endl
831 << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
832 << abort(FatalError);
833 }
834
835 Pout<< "Checking field " << msg << endl;
836 scalarField minFld(fld);
838 (
839 mesh,
840 minFld,
842 GREAT
843 );
844 scalarField maxFld(fld);
846 (
847 mesh,
848 maxFld,
850 -GREAT
851 );
852 forAll(minFld, pointi)
853 {
854 const scalar& minVal = minFld[pointi];
855 const scalar& maxVal = maxFld[pointi];
856 if (mag(minVal-maxVal) > SMALL)
857 {
858 Pout<< msg << " at:" << mesh.points()[pointi] << nl
859 << " minFld:" << minVal << nl
860 << " maxFld:" << maxVal << nl
861 << endl;
862 }
863 }
864}
865
868(
869 const string& msg,
870 const polyMesh& mesh,
871 const List<point>& fld
872)
873{
874 if (fld.size() != mesh.nPoints())
875 {
877 << msg << endl
878 << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
879 << abort(FatalError);
880 }
881
882 Pout<< "Checking field " << msg << endl;
883 pointField minFld(fld);
885 (
886 mesh,
887 minFld,
889 point(GREAT, GREAT, GREAT)
890 );
891 pointField maxFld(fld);
893 (
894 mesh,
895 maxFld,
898 );
899 forAll(minFld, pointi)
900 {
901 const point& minVal = minFld[pointi];
902 const point& maxVal = maxFld[pointi];
903 if (mag(minVal-maxVal) > SMALL)
904 {
905 Pout<< msg << " at:" << mesh.points()[pointi] << nl
906 << " minFld:" << minVal << nl
907 << " maxFld:" << maxVal << nl
908 << endl;
909 }
910 }
911}
912
915{
916 Pout<< "meshRefinement::checkData() : Checking refinement structure."
917 << endl;
918 meshCutter_.checkMesh();
919
920 Pout<< "meshRefinement::checkData() : Checking refinement levels."
921 << endl;
922 meshCutter_.checkRefinementLevels(1, labelList(0));
923
924
925 const label nBnd = mesh_.nBoundaryFaces();
926
927 Pout<< "meshRefinement::checkData() : Checking synchronization."
928 << endl;
929
930 // Check face centres
931 {
932 // Boundary face centres
933 pointField::subList boundaryFc
934 (
935 mesh_.faceCentres(),
936 nBnd,
937 mesh_.nInternalFaces()
938 );
939
940 // Get neighbouring face centres
941 pointField neiBoundaryFc(boundaryFc);
943 (
944 mesh_,
945 neiBoundaryFc,
947 );
948
949 // Compare
951 (
952 mergeDistance_,
953 "testing faceCentres : ",
954 boundaryFc,
955 neiBoundaryFc
956 );
957 }
958
959 // Check meshRefinement
960 const labelList& surfIndex = surfaceIndex();
961
962
963 {
964 // Get boundary face centre and level. Coupled aware.
965 labelList neiLevel(nBnd);
966 pointField neiCc(nBnd);
967 calcNeighbourData(neiLevel, neiCc);
968
969 // Collect segments we want to test for
970 pointField start(mesh_.nFaces());
971 pointField end(mesh_.nFaces());
972
973 forAll(start, facei)
974 {
975 start[facei] = mesh_.cellCentres()[mesh_.faceOwner()[facei]];
976
977 if (mesh_.isInternalFace(facei))
978 {
979 end[facei] = mesh_.cellCentres()[mesh_.faceNeighbour()[facei]];
980 }
981 else
982 {
983 end[facei] = neiCc[facei-mesh_.nInternalFaces()];
984 }
985 }
986
987 // Extend segments a bit
988 {
989 const vectorField smallVec(ROOTSMALL*(end-start));
990 start -= smallVec;
991 end += smallVec;
992 }
993
994
995 // Do tests in one go
996 labelList surfaceHit;
997 {
998 labelList surfaceLevel;
999 surfaces_.findHigherIntersection
1000 (
1001 shells_,
1002 start,
1003 end,
1004 labelList(start.size(), -1), // accept any intersection
1005 surfaceHit,
1006 surfaceLevel
1007 );
1008 }
1009 // Get the coupled hit
1010 labelList neiHit
1011 (
1013 (
1014 surfaceHit,
1015 nBnd,
1016 mesh_.nInternalFaces()
1017 )
1018 );
1019 syncTools::swapBoundaryFaceList(mesh_, neiHit);
1020
1021 // Check
1022 forAll(surfaceHit, facei)
1023 {
1024 if (surfIndex[facei] != surfaceHit[facei])
1025 {
1026 if (mesh_.isInternalFace(facei))
1027 {
1029 << "Internal face:" << facei
1030 << " fc:" << mesh_.faceCentres()[facei]
1031 << " cached surfaceIndex_:" << surfIndex[facei]
1032 << " current:" << surfaceHit[facei]
1033 << " ownCc:"
1034 << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
1035 << " neiCc:"
1036 << mesh_.cellCentres()[mesh_.faceNeighbour()[facei]]
1037 << endl;
1038 }
1039 else if
1040 (
1041 surfIndex[facei]
1042 != neiHit[facei-mesh_.nInternalFaces()]
1043 )
1044 {
1046 << "Boundary face:" << facei
1047 << " fc:" << mesh_.faceCentres()[facei]
1048 << " cached surfaceIndex_:" << surfIndex[facei]
1049 << " current:" << surfaceHit[facei]
1050 << " ownCc:"
1051 << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
1052 << " neiCc:"
1053 << neiCc[facei-mesh_.nInternalFaces()]
1054 << " end:" << end[facei]
1055 << " ownLevel:"
1056 << meshCutter_.cellLevel()[mesh_.faceOwner()[facei]]
1057 << " faceLevel:"
1058 << meshCutter_.faceLevel(facei)
1059 << endl;
1060 }
1061 }
1062 }
1063 }
1064 {
1065 labelList::subList boundarySurface
1066 (
1067 surfaceIndex_,
1068 mesh_.nBoundaryFaces(),
1069 mesh_.nInternalFaces()
1070 );
1071
1072 labelList neiBoundarySurface(boundarySurface);
1074 (
1075 mesh_,
1076 neiBoundarySurface
1077 );
1078
1079 // Compare
1081 (
1082 0, // tolerance
1083 "testing surfaceIndex() : ",
1084 boundarySurface,
1085 neiBoundarySurface
1086 );
1087 }
1088
1089
1090 // Find duplicate faces
1091 Pout<< "meshRefinement::checkData() : Counting duplicate faces."
1092 << endl;
1093
1094 labelList duplicateFace
1095 (
1097 (
1098 mesh_,
1099 identity(mesh_.nBoundaryFaces(), mesh_.nInternalFaces())
1100 )
1101 );
1102
1103 // Count
1104 {
1105 label nDup = 0;
1106
1107 forAll(duplicateFace, i)
1108 {
1109 if (duplicateFace[i] != -1)
1110 {
1111 nDup++;
1112 }
1113 }
1114 nDup /= 2; // will have counted both faces of duplicate
1115 Pout<< "meshRefinement::checkData() : Found " << nDup
1116 << " duplicate pairs of faces." << endl;
1117 }
1118}
1119
1122{
1123 meshCutter_.setInstance(inst);
1124 surfaceIndex_.instance() = inst;
1125}
1126
1129(
1130 const labelList& cellsToRemove,
1131 const labelList& exposedFaces,
1132 const labelList& exposedPatchIDs,
1133 removeCells& cellRemover
1134)
1135{
1136 polyTopoChange meshMod(mesh_);
1137
1138 // Arbitrary: put exposed faces into last patch.
1139 cellRemover.setRefinement
1140 (
1141 cellsToRemove,
1142 exposedFaces,
1143 exposedPatchIDs,
1144 meshMod
1145 );
1146
1147 // Remove any unnecessary fields
1148 mesh_.clearOut();
1149 mesh_.moving(false);
1150
1151 // Change the mesh (no inflation)
1152 autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1153 mapPolyMesh& map = *mapPtr;
1154
1155 // Update fields
1156 mesh_.updateMesh(map);
1157
1158 // Move mesh (since morphing might not do this)
1159 if (map.hasMotionPoints())
1160 {
1161 mesh_.movePoints(map.preMotionPoints());
1162 }
1163 else
1164 {
1165 // Delete mesh volumes. No other way to do this?
1166 mesh_.clearOut();
1167 }
1168
1169 // Reset the instance for if in overwrite mode
1170 mesh_.setInstance(timeName());
1171 setInstance(mesh_.facesInstance());
1172
1173 // Update local mesh data
1174 cellRemover.updateMesh(map);
1175
1176 // Update intersections. Recalculate intersections for exposed faces.
1177 labelList newExposedFaces = renumber
1178 (
1179 map.reverseFaceMap(),
1180 exposedFaces
1181 );
1182
1183 //Pout<< "removeCells : updating intersections for "
1184 // << newExposedFaces.size() << " newly exposed faces." << endl;
1185
1186 updateMesh(map, newExposedFaces);
1187
1188 return mapPtr;
1189}
1190
1193(
1194 const face& f,
1195 const labelPair& split,
1196
1197 face& f0,
1198 face& f1
1199)
1200{
1201 if (split.find(-1) != -1)
1202 {
1203 FatalErrorInFunction<< "Illegal split " << split
1204 << " on face " << f << exit(FatalError);
1205 }
1206
1207 label nVerts = split[1]-split[0];
1208 if (nVerts < 0)
1209 {
1210 nVerts += f.size();
1211 }
1212 nVerts += 1;
1213
1214
1215 // Split into f0, f1
1216 f0.resize_nocopy(nVerts);
1217
1218 label fp = split[0];
1219 forAll(f0, i)
1220 {
1221 f0[i] = f[fp];
1222 fp = f.fcIndex(fp);
1223 }
1224
1225 f1.resize_nocopy(f.size()-f0.size()+2);
1226 fp = split[1];
1227 forAll(f1, i)
1228 {
1229 f1[i] = f[fp];
1230 fp = f.fcIndex(fp);
1231 }
1232}
1233
1236(
1237 const labelList& splitFaces,
1238 const labelPairList& splits,
1239 const labelPairList& splitPatches,
1240 //const List<Pair<point>>& splitPoints,
1241 polyTopoChange& meshMod
1242) const
1243{
1244 face f0, f1;
1245
1246 forAll(splitFaces, i)
1247 {
1248 const label facei = splitFaces[i];
1249 const auto& split = splits[i];
1250 const auto& twoPatches = splitPatches[i];
1251
1252 const face& f = mesh_.faces()[facei];
1253
1254 // Split as start and end index in face
1255 splitFace(f, split, f0, f1);
1256
1257 // Determine face properties
1258 label own = mesh_.faceOwner()[facei];
1259 label nei = -1;
1260 label patch0 = -1;
1261 label patch1 = -1;
1262 if (facei >= mesh_.nInternalFaces())
1263 {
1264 patch0 =
1265 (
1266 twoPatches[0] != -1
1267 ? twoPatches[0]
1268 : mesh_.boundaryMesh().whichPatch(facei)
1269 );
1270 patch1 =
1271 (
1272 twoPatches[1] != -1
1273 ? twoPatches[1]
1274 : mesh_.boundaryMesh().whichPatch(facei)
1275 );
1276 }
1277 else
1278 {
1279 nei = mesh_.faceNeighbour()[facei];
1280 }
1281
1282 label zonei = mesh_.faceZones().whichZone(facei);
1283 bool zoneFlip = false;
1284 if (zonei != -1)
1285 {
1286 const faceZone& fz = mesh_.faceZones()[zonei];
1287 zoneFlip = fz.flipMap()[fz.whichFace(facei)];
1288 }
1289
1290
1291 if (debug)
1292 {
1293 Pout<< "face:" << facei << " verts:" << f
1294 << " split into f0:" << f0
1295 << " f1:" << f1 << endl;
1296 }
1297
1298 // Change/add faces
1299 meshMod.modifyFace
1300 (
1301 f0, // modified face
1302 facei, // label of face
1303 own, // owner
1304 nei, // neighbour
1305 false, // face flip
1306 patch0, // patch for face
1307 zonei, // zone for face
1308 zoneFlip // face flip in zone
1309 );
1310
1311 meshMod.addFace
1312 (
1313 f1, // modified face
1314 own, // owner
1315 nei, // neighbour
1316 -1, // master point
1317 -1, // master edge
1318 facei, // master face
1319 false, // face flip
1320 patch1, // patch for face
1321 zonei, // zone for face
1322 zoneFlip // face flip in zone
1323 );
1324
1325
1327 //meshMod.modifyPoint
1328 //(
1329 // f[split[0]],
1330 // splitPoints[i][0],
1331 // -1,
1332 // true
1333 //);
1334 //meshMod.modifyPoint
1335 //(
1336 // f[split[1]],
1337 // splitPoints[i][1],
1338 // -1,
1339 // true
1340 //);
1341 }
1342}
1343
1346(
1347 const labelList& splitFaces,
1348 const labelPairList& splits,
1349 const labelPairList& splitPatches,
1350 const dictionary& motionDict,
1351
1352 labelList& duplicateFace,
1353 List<labelPair>& baffles
1354)
1355{
1356 label nSplit = returnReduce(splitFaces.size(), sumOp<label>());
1357 Info<< nl
1358 << "Splitting " << nSplit
1359 << " faces across diagonals" << "." << nl << endl;
1360
1361 // To undo: store original faces
1362 faceList originalFaces(UIndirectList<face>(mesh_.faces(), splitFaces));
1363 labelPairList facePairs(splitFaces.size(), labelPair(-1, -1));
1364
1365
1366 {
1367 polyTopoChange meshMod(mesh_);
1368 meshMod.setCapacity
1369 (
1370 meshMod.points().size(),
1371 meshMod.faces().size()+splitFaces.size(),
1372 mesh_.nCells()
1373 );
1374
1375 // Insert the mesh changes
1376 doSplitFaces(splitFaces, splits, splitPatches, meshMod);
1377
1378 // Remove any unnecessary fields
1379 mesh_.clearOut();
1380 mesh_.moving(false);
1381
1382 // Change the mesh (no inflation)
1383 autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1384 mapPolyMesh& map = *mapPtr;
1385
1386 // Update fields
1387 mesh_.updateMesh(map);
1388
1389 // Move mesh (since morphing might not do this)
1390 if (map.hasMotionPoints())
1391 {
1392 mesh_.movePoints(map.preMotionPoints());
1393 }
1394 else
1395 {
1396 mesh_.clearOut();
1397 }
1398
1399 // Reset the instance for if in overwrite mode
1400 mesh_.setInstance(timeName());
1401 setInstance(mesh_.facesInstance());
1402
1403
1404 // Update local mesh data
1405 // ~~~~~~~~~~~~~~~~~~~~~~
1406
1407 forAll(originalFaces, i)
1408 {
1409 inplaceRenumber(map.reversePointMap(), originalFaces[i]);
1410 }
1411
1412 {
1413 Map<label> splitFaceToIndex(invertToMap(splitFaces));
1414
1415 forAll(map.faceMap(), facei)
1416 {
1417 label oldFacei = map.faceMap()[facei];
1418
1419 const auto oldFaceFnd = splitFaceToIndex.cfind(oldFacei);
1420
1421 if (oldFaceFnd.good())
1422 {
1423 labelPair& twoFaces = facePairs[oldFaceFnd.val()];
1424 if (twoFaces[0] == -1)
1425 {
1426 twoFaces[0] = facei;
1427 }
1428 else if (twoFaces[1] == -1)
1429 {
1430 twoFaces[1] = facei;
1431 }
1432 else
1433 {
1435 << "problem: twoFaces:" << twoFaces
1436 << exit(FatalError);
1437 }
1438 }
1439 }
1440 }
1441
1442
1443 // Update baffle data
1444 // ~~~~~~~~~~~~~~~~~~
1445
1446 if (duplicateFace.size())
1447 {
1449 (
1450 map.faceMap(),
1451 label(-1),
1452 duplicateFace
1453 );
1454 }
1455
1456 const labelList& oldToNewFaces = map.reverseFaceMap();
1457 forAll(baffles, i)
1458 {
1459 labelPair& baffle = baffles[i];
1460 baffle.first() = oldToNewFaces[baffle.first()];
1461 baffle.second() = oldToNewFaces[baffle.second()];
1462
1463 if (baffle.first() == -1 || baffle.second() == -1)
1464 {
1466 << "Removed baffle : faces:" << baffle
1467 << exit(FatalError);
1468 }
1469 }
1470
1471
1472 // Update intersections
1473 // ~~~~~~~~~~~~~~~~~~~~
1474
1475 {
1476 DynamicList<label> changedFaces(facePairs.size());
1477 forAll(facePairs, i)
1478 {
1479 changedFaces.append(facePairs[i].first());
1480 changedFaces.append(facePairs[i].second());
1481 }
1482
1483 // Update intersections on changed faces
1484 updateMesh(map, growFaceCellFace(changedFaces));
1485 }
1486 }
1487
1488
1489
1490 // Undo loop
1491 // ~~~~~~~~~
1492 // Maintains two bits of information:
1493 // facePairs : two faces originating from the same face
1494 // originalFaces : original face in current vertices
1495
1496
1497 for (label iteration = 0; iteration < 100; iteration++)
1498 {
1499 Info<< nl
1500 << "Undo iteration " << iteration << nl
1501 << "----------------" << endl;
1502
1503
1504 // Check mesh for errors
1505 // ~~~~~~~~~~~~~~~~~~~~~
1506
1507 faceSet errorFaces(mesh_, "errorFaces", mesh_.nBoundaryFaces());
1508 bool hasErrors = motionSmoother::checkMesh
1509 (
1510 false, // report
1511 mesh_,
1512 motionDict,
1513 errorFaces,
1514 dryRun_
1515 );
1516 if (!hasErrors)
1517 {
1518 break;
1519 }
1520
1521 // Extend faces
1522 {
1523 const labelList grownFaces(growFaceCellFace(errorFaces));
1524 errorFaces.clear();
1525 errorFaces.insert(grownFaces);
1526 }
1527
1528
1529 // Merge face pairs
1530 // ~~~~~~~~~~~~~~~~
1531 // (if one of the faces is in the errorFaces set)
1532
1533 polyTopoChange meshMod(mesh_);
1534
1535 // Indices (in facePairs) of merged faces
1536 labelHashSet mergedIndices(facePairs.size());
1537 forAll(facePairs, index)
1538 {
1539 const labelPair& twoFaces = facePairs[index];
1540
1541 if
1542 (
1543 errorFaces.found(twoFaces.first())
1544 || errorFaces.found(twoFaces.second())
1545 )
1546 {
1547 const face& originalFace = originalFaces[index];
1548
1549
1550 // Determine face properties
1551 label own = mesh_.faceOwner()[twoFaces[0]];
1552 label nei = -1;
1553 label patchi = -1;
1554 if (twoFaces[0] >= mesh_.nInternalFaces())
1555 {
1556 patchi = mesh_.boundaryMesh().whichPatch(twoFaces[0]);
1557 }
1558 else
1559 {
1560 nei = mesh_.faceNeighbour()[twoFaces[0]];
1561 }
1562
1563 label zonei = mesh_.faceZones().whichZone(twoFaces[0]);
1564 bool zoneFlip = false;
1565 if (zonei != -1)
1566 {
1567 const faceZone& fz = mesh_.faceZones()[zonei];
1568 zoneFlip = fz.flipMap()[fz.whichFace(twoFaces[0])];
1569 }
1570
1571 // Modify first face
1572 meshMod.modifyFace
1573 (
1574 originalFace, // modified face
1575 twoFaces[0], // label of face
1576 own, // owner
1577 nei, // neighbour
1578 false, // face flip
1579 patchi, // patch for face
1580 zonei, // zone for face
1581 zoneFlip // face flip in zone
1582 );
1583 // Merge second face into first
1584 meshMod.removeFace(twoFaces[1], twoFaces[0]);
1585
1586 mergedIndices.insert(index);
1587 }
1588 }
1589
1590 label n = returnReduce(mergedIndices.size(), sumOp<label>());
1591
1592 Info<< "Detected " << n
1593 << " split faces that will be restored to their original faces."
1594 << nl << endl;
1595
1596 if (n == 0)
1597 {
1598 // Nothing to be restored
1599 break;
1600 }
1601
1602 nSplit -= n;
1603
1604
1605 // Remove any unnecessary fields
1606 mesh_.clearOut();
1607 mesh_.moving(false);
1608
1609 // Change the mesh (no inflation)
1610 autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1611 mapPolyMesh& map = *mapPtr;
1612
1613 // Update fields
1614 mesh_.updateMesh(map);
1615
1616 // Move mesh (since morphing might not do this)
1617 if (map.hasMotionPoints())
1618 {
1619 mesh_.movePoints(map.preMotionPoints());
1620 }
1621 else
1622 {
1623 mesh_.clearOut();
1624 }
1625
1626 // Reset the instance for if in overwrite mode
1627 mesh_.setInstance(timeName());
1628 setInstance(mesh_.facesInstance());
1629
1630
1631 // Update local mesh data
1632 // ~~~~~~~~~~~~~~~~~~~~~~
1633
1634 {
1635 const labelList& oldToNewFaces = map.reverseFaceMap();
1636 const labelList& oldToNewPoints = map.reversePointMap();
1637
1638 // Compact out merged faces
1639 DynamicList<label> changedFaces(mergedIndices.size());
1640
1641 label newIndex = 0;
1642 forAll(facePairs, index)
1643 {
1644 const labelPair& oldSplit = facePairs[index];
1645 label new0 = oldToNewFaces[oldSplit[0]];
1646 label new1 = oldToNewFaces[oldSplit[1]];
1647
1648 if (!mergedIndices.found(index))
1649 {
1650 // Faces still split
1651 if (new0 < 0 || new1 < 0)
1652 {
1654 << "Problem: oldFaces:" << oldSplit
1655 << " newFaces:" << labelPair(new0, new1)
1656 << exit(FatalError);
1657 }
1658
1659 facePairs[newIndex] = labelPair(new0, new1);
1660 originalFaces[newIndex] = renumber
1661 (
1662 oldToNewPoints,
1663 originalFaces[index]
1664 );
1665 newIndex++;
1666 }
1667 else
1668 {
1669 // Merged face. Only new0 kept.
1670 if (new0 < 0 || new1 == -1)
1671 {
1673 << "Problem: oldFaces:" << oldSplit
1674 << " newFace:" << labelPair(new0, new1)
1675 << exit(FatalError);
1676 }
1677 changedFaces.append(new0);
1678 }
1679 }
1680
1681 facePairs.setSize(newIndex);
1682 originalFaces.setSize(newIndex);
1683
1684
1685 // Update intersections
1686 updateMesh(map, growFaceCellFace(changedFaces));
1687 }
1688
1689 // Update baffle data
1690 // ~~~~~~~~~~~~~~~~~~
1691 {
1692 if (duplicateFace.size())
1693 {
1695 (
1696 map.faceMap(),
1697 label(-1),
1698 duplicateFace
1699 );
1700 }
1701
1702 const labelList& reverseFaceMap = map.reverseFaceMap();
1703 forAll(baffles, i)
1704 {
1705 labelPair& baffle = baffles[i];
1706 baffle.first() = reverseFaceMap[baffle.first()];
1707 baffle.second() = reverseFaceMap[baffle.second()];
1708
1709 if (baffle.first() == -1 || baffle.second() == -1)
1710 {
1712 << "Removed baffle : faces:" << baffle
1713 << exit(FatalError);
1714 }
1715 }
1716 }
1717
1718 }
1719
1720 return nSplit;
1721}
1722
1723
1724// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1726Foam::meshRefinement::meshRefinement
1727(
1728 fvMesh& mesh,
1729 const scalar mergeDistance,
1730 const bool overwrite,
1733 const shellSurfaces& shells,
1735 const labelUList& checkFaces,
1736 const MeshType meshType,
1737 const bool dryRun
1738)
1739:
1740 mesh_(mesh),
1741 mergeDistance_(mergeDistance),
1742 overwrite_(overwrite),
1743 oldInstance_(mesh.pointsInstance()),
1744 surfaces_(surfaces),
1745 features_(features),
1746 shells_(shells),
1747 limitShells_(limitShells),
1748 meshType_(meshType),
1749 dryRun_(dryRun),
1750 meshCutter_
1751 (
1752 mesh,
1753 false // do not try to read history.
1754 ),
1755 surfaceIndex_
1756 (
1757 IOobject
1758 (
1759 "surfaceIndex",
1760 mesh_.facesInstance(),
1761 polyMesh::meshSubDir,
1762 mesh_,
1763 IOobject::NO_READ,
1764 IOobject::NO_WRITE,
1765 IOobject::NO_REGISTER
1766 ),
1767 labelList(mesh_.nFaces(), -1)
1768 ),
1769 userFaceData_(0)
1770{
1771 // recalculate intersections for all faces
1772 updateIntersections(checkFaces);
1773}
1774
1775
1776// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1779{
1780 if (surfaceIndex_.size() != mesh_.nFaces())
1781 {
1782 const_cast<meshRefinement&>(*this).updateIntersections
1783 (
1784 identity(mesh_.nFaces())
1785 );
1786 }
1787 return surfaceIndex_;
1788}
1789
1792{
1793 if (surfaceIndex_.size() != mesh_.nFaces())
1794 {
1795 updateIntersections(identity(mesh_.nFaces()));
1796 }
1797 return surfaceIndex_;
1798}
1799
1801Foam::label Foam::meshRefinement::countHits() const
1802{
1803 // Stats on edges to test. Count proc faces only once.
1804 bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
1805
1806 label nHits = 0;
1807
1808 const labelList& surfIndex = surfaceIndex();
1809
1810 forAll(surfIndex, facei)
1811 {
1812 if (surfIndex[facei] >= 0 && isMasterFace.test(facei))
1813 {
1814 ++nHits;
1815 }
1816 }
1817 return nHits;
1818}
1819
1822(
1823 const bool keepZoneFaces,
1824 const bool keepBaffles,
1825 const labelList& singleProcPoints,
1826 const scalarField& cellWeights,
1827 decompositionMethod& decomposer,
1828 fvMeshDistribute& distributor
1829)
1830{
1832
1833 if (Pstream::parRun())
1834 {
1835 // Wanted distribution
1837
1838
1839 // Faces where owner and neighbour are not 'connected' so can
1840 // go to different processors.
1841 boolList blockedFace;
1842 label nUnblocked = 0;
1843
1844 // Faces that move as block onto single processor
1845 PtrList<labelList> specifiedProcessorFaces;
1846 labelList specifiedProcessor;
1847
1848 // Pairs of baffles
1849 List<labelPair> couples;
1850
1851 // Constraints from decomposeParDict
1852 decomposer.setConstraints
1853 (
1854 mesh_,
1855 blockedFace,
1856 specifiedProcessorFaces,
1857 specifiedProcessor,
1858 couples
1859 );
1860
1861
1862 if (keepZoneFaces || keepBaffles)
1863 {
1864 if (keepZoneFaces)
1865 {
1866 // Determine decomposition to keep/move surface zones
1867 // on one processor. The reason is that snapping will make these
1868 // into baffles, move and convert them back so if they were
1869 // proc boundaries after baffling&moving the points might be no
1870 // longer synchronised so recoupling will fail. To prevent this
1871 // keep owner&neighbour of such a surface zone on the same
1872 // processor.
1873
1874 const faceZoneMesh& fZones = mesh_.faceZones();
1875 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
1876
1877 // Get faces whose owner and neighbour should stay together,
1878 // i.e. they are not 'blocked'.
1879
1880 forAll(fZones, zonei)
1881 {
1882 const faceZone& fZone = fZones[zonei];
1883
1884 forAll(fZone, i)
1885 {
1886 label facei = fZone[i];
1887 if (blockedFace[facei])
1888 {
1889 if
1890 (
1891 mesh_.isInternalFace(facei)
1892 || pbm[pbm.whichPatch(facei)].coupled()
1893 )
1894 {
1895 blockedFace[facei] = false;
1896 nUnblocked++;
1897 }
1898 }
1899 }
1900 }
1901
1902
1903 // If the faceZones are not synchronised the blockedFace
1904 // might not be synchronised. If you are sure the faceZones
1905 // are synchronised remove below check.
1907 (
1908 mesh_,
1909 blockedFace,
1910 andEqOp<bool>() // combine operator
1911 );
1912 }
1913 reduce(nUnblocked, sumOp<label>());
1914
1915 if (keepZoneFaces)
1916 {
1917 Info<< "Found " << nUnblocked
1918 << " zoned faces to keep together." << endl;
1919 }
1920
1921
1922 // Extend un-blockedFaces with any cyclics
1923 {
1924 boolList separatedCoupledFace(mesh_.nFaces(), false);
1925 selectSeparatedCoupledFaces(separatedCoupledFace);
1926
1927 label nSeparated = 0;
1928 forAll(separatedCoupledFace, facei)
1929 {
1930 if (separatedCoupledFace[facei])
1931 {
1932 if (blockedFace[facei])
1933 {
1934 blockedFace[facei] = false;
1935 nSeparated++;
1936 }
1937 }
1938 }
1939 reduce(nSeparated, sumOp<label>());
1940 Info<< "Found " << nSeparated
1941 << " separated coupled faces to keep together." << endl;
1942
1943 nUnblocked += nSeparated;
1944 }
1945
1946
1947 if (keepBaffles)
1948 {
1949 const label nBnd = mesh_.nBoundaryFaces();
1950
1951 labelList coupledFace(mesh_.nFaces(), -1);
1952 {
1953 // Get boundary baffles that need to stay together
1954 List<labelPair> allCouples
1955 (
1957 );
1958
1959 // Merge with any couples from
1960 // decompositionMethod::setConstraints
1961 forAll(couples, i)
1962 {
1963 const labelPair& baffle = couples[i];
1964 coupledFace[baffle.first()] = baffle.second();
1965 coupledFace[baffle.second()] = baffle.first();
1966 }
1967 forAll(allCouples, i)
1968 {
1969 const labelPair& baffle = allCouples[i];
1970 coupledFace[baffle.first()] = baffle.second();
1971 coupledFace[baffle.second()] = baffle.first();
1972 }
1973 }
1974
1975 couples.setSize(nBnd);
1976 label nCpl = 0;
1977 forAll(coupledFace, facei)
1978 {
1979 if (coupledFace[facei] != -1 && facei < coupledFace[facei])
1980 {
1981 couples[nCpl++] = labelPair(facei, coupledFace[facei]);
1982 }
1983 }
1984 couples.setSize(nCpl);
1985 }
1986 label nCouples = returnReduce(couples.size(), sumOp<label>());
1987
1988 if (keepBaffles)
1989 {
1990 Info<< "Found " << nCouples << " baffles to keep together."
1991 << endl;
1992 }
1993 }
1994
1995
1996 // Make sure blockedFace not set on couples
1997 forAll(couples, i)
1998 {
1999 const labelPair& baffle = couples[i];
2000 blockedFace[baffle.first()] = false;
2001 blockedFace[baffle.second()] = false;
2002 }
2003
2004 if (returnReduceOr(singleProcPoints.size()))
2005 {
2006 // Modify couples to force all selected points be on the same
2007 // processor
2008
2009 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2010
2011 label nPointFaces = 0;
2012 for (const label pointi : singleProcPoints)
2013 {
2014 for (const label facei : mesh_.pointFaces()[pointi])
2015 {
2016 if (blockedFace[facei])
2017 {
2018 if
2019 (
2020 mesh_.isInternalFace(facei)
2021 || pbm[pbm.whichPatch(facei)].coupled()
2022 )
2023 {
2024 blockedFace[facei] = false;
2025 nPointFaces++;
2026 }
2027 }
2028 }
2029 }
2030 reduce(nPointFaces, sumOp<label>());
2031 Info<< "Found " << nPointFaces
2032 << " additional point-coupled faces to keep together." << endl;
2033
2034 nUnblocked += nPointFaces;
2035 }
2036
2037
2038 distribution = decomposer.decompose
2039 (
2040 mesh_,
2041 cellWeights,
2042 blockedFace,
2043 specifiedProcessorFaces,
2044 specifiedProcessor,
2045 couples // explicit connections
2046 );
2047
2048 if (debug)
2049 {
2050 labelList nProcCells(distributor.countCells(distribution));
2051 Pout<< "Wanted distribution:" << nProcCells << endl;
2052
2053 Pstream::listReduce(nProcCells, sumOp<label>());
2054
2055 Pout<< "Wanted resulting decomposition:" << endl;
2056 forAll(nProcCells, proci)
2057 {
2058 Pout<< " " << proci << '\t' << nProcCells[proci] << endl;
2059 }
2060 Pout<< endl;
2061 }
2062
2063 // Do actual sending/receiving of mesh
2064 map = distributor.distribute(distribution);
2065
2066 // Update numbering of meshRefiner
2067 distribute(map());
2068
2069 // Set correct instance (for if overwrite)
2070 mesh_.setInstance(timeName());
2071 setInstance(mesh_.facesInstance());
2072
2073
2074 if (debug && keepZoneFaces)
2075 {
2076 const faceZoneMesh& fZones = mesh_.faceZones();
2077 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2078
2079 // Check that faceZone faces are indeed internal
2080 forAll(fZones, zonei)
2081 {
2082 const faceZone& fZone = fZones[zonei];
2083
2084 forAll(fZone, i)
2085 {
2086 label facei = fZone[i];
2087 label patchi = pbm.whichPatch(facei);
2088
2089 if (patchi >= 0 && pbm[patchi].coupled())
2090 {
2092 << "Face at " << mesh_.faceCentres()[facei]
2093 << " on zone " << fZone.name()
2094 << " is on coupled patch " << pbm[patchi].name()
2095 << endl;
2096 }
2097 }
2098 }
2099 }
2100 }
2101
2102 return map;
2103}
2104
2107{
2108 label nBoundaryFaces = 0;
2109
2110 const labelList& surfIndex = surfaceIndex();
2111
2112 forAll(surfIndex, facei)
2113 {
2114 if (surfIndex[facei] != -1)
2115 {
2116 nBoundaryFaces++;
2117 }
2118 }
2119
2120 labelList surfaceFaces(nBoundaryFaces);
2121 nBoundaryFaces = 0;
2122
2123 forAll(surfIndex, facei)
2124 {
2125 if (surfIndex[facei] != -1)
2126 {
2127 surfaceFaces[nBoundaryFaces++] = facei;
2128 }
2129 }
2130 return surfaceFaces;
2131}
2132
2135{
2136 const faceList& faces = mesh_.faces();
2137
2138 // Mark all points on faces that will become baffles
2139 bitSet isBoundaryPoint(mesh_.nPoints());
2140
2141 const labelList& surfIndex = surfaceIndex();
2142
2143 forAll(surfIndex, facei)
2144 {
2145 if (surfIndex[facei] != -1)
2146 {
2147 isBoundaryPoint.set(faces[facei]);
2148 }
2149 }
2150
2152 //labelList adaptPatchIDs(meshedPatches());
2153 //forAll(adaptPatchIDs, i)
2154 //{
2155 // label patchi = adaptPatchIDs[i];
2156 //
2157 // if (patchi != -1)
2158 // {
2159 // const polyPatch& pp = mesh_.boundaryMesh()[patchi];
2160 // forAll(pp, i)
2161 // {
2162 // isBoundaryPoint.set(faces[pp.start()+i]);
2163 // }
2164 // }
2165 //}
2166
2167 // Make sure all processors have the same data
2168 syncTools::syncPointList(mesh_, isBoundaryPoint, orEqOp<unsigned int>(), 0);
2169
2170 return isBoundaryPoint.sortedToc();
2171}
2172
2173
2174//- Create patch from set of patches
2177 const polyMesh& mesh,
2178 const labelList& patchIDs
2179)
2180{
2181 const polyBoundaryMesh& patches = mesh.boundaryMesh();
2182
2183 // Count faces.
2184 label nFaces = 0;
2185
2186 forAll(patchIDs, i)
2187 {
2188 const polyPatch& pp = patches[patchIDs[i]];
2189
2190 nFaces += pp.size();
2191 }
2192
2193 // Collect faces.
2194 labelList addressing(nFaces);
2195 nFaces = 0;
2196
2197 forAll(patchIDs, i)
2198 {
2199 const polyPatch& pp = patches[patchIDs[i]];
2200
2201 label meshFacei = pp.start();
2202
2203 forAll(pp, i)
2204 {
2205 addressing[nFaces++] = meshFacei++;
2206 }
2207 }
2208
2210 (
2211 IndirectList<face>(mesh.faces(), addressing),
2212 mesh.points()
2213 );
2214}
2215
2216
2219 const pointMesh& pMesh,
2220 const labelList& adaptPatchIDs
2221)
2222{
2223 const polyMesh& mesh = pMesh();
2224
2225 // Construct displacement field.
2226 const pointBoundaryMesh& pointPatches = pMesh.boundary();
2227
2228 wordList patchFieldTypes
2229 (
2230 pointPatches.size(),
2231 slipPointPatchVectorField::typeName
2232 );
2233
2234 forAll(adaptPatchIDs, i)
2235 {
2236 patchFieldTypes[adaptPatchIDs[i]] =
2237 fixedValuePointPatchVectorField::typeName;
2238 }
2239
2240 forAll(pointPatches, patchi)
2241 {
2242 if (isA<processorPointPatch>(pointPatches[patchi]))
2243 {
2244 patchFieldTypes[patchi] = calculatedPointPatchVectorField::typeName;
2245 }
2246 else if (isA<cyclicPointPatch>(pointPatches[patchi]))
2247 {
2248 patchFieldTypes[patchi] = cyclicSlipPointPatchVectorField::typeName;
2249 }
2250 }
2251
2252 // Note: time().timeName() instead of meshRefinement::timeName() since
2253 // postprocessable field.
2255 (
2256 IOobject
2257 (
2258 "pointDisplacement",
2259 mesh.time().timeName(),
2260 mesh,
2263 ),
2264 pMesh,
2266 patchFieldTypes
2267 );
2268}
2269
2270
2273 const faceZoneMesh& fZones = mesh.faceZones();
2274
2275 // Check any zones are present anywhere and in same order
2276
2277 {
2278 List<wordList> zoneNames(Pstream::nProcs());
2279 zoneNames[Pstream::myProcNo()] = fZones.names();
2280 Pstream::allGatherList(zoneNames);
2281
2282 // All have same data now. Check.
2283 forAll(zoneNames, proci)
2284 {
2285 if
2286 (
2287 proci != Pstream::myProcNo()
2288 && (zoneNames[proci] != zoneNames[Pstream::myProcNo()])
2289 )
2290 {
2292 << "faceZones are not synchronised on processors." << nl
2293 << "Processor " << proci << " has faceZones "
2294 << zoneNames[proci] << nl
2295 << "Processor " << Pstream::myProcNo()
2296 << " has faceZones "
2297 << zoneNames[Pstream::myProcNo()] << nl
2298 << exit(FatalError);
2299 }
2300 }
2301 }
2302
2303 // Check that coupled faces are present on both sides.
2304
2305 labelList faceToZone(mesh.nBoundaryFaces(), -1);
2306
2307 forAll(fZones, zonei)
2308 {
2309 const faceZone& fZone = fZones[zonei];
2310
2311 forAll(fZone, i)
2312 {
2313 label bFacei = fZone[i]-mesh.nInternalFaces();
2314
2315 if (bFacei >= 0)
2316 {
2317 if (faceToZone[bFacei] == -1)
2318 {
2319 faceToZone[bFacei] = zonei;
2320 }
2321 else if (faceToZone[bFacei] == zonei)
2322 {
2324 << "Face " << fZone[i] << " in zone "
2325 << fZone.name()
2326 << " is twice in zone!"
2327 << abort(FatalError);
2328 }
2329 else
2330 {
2332 << "Face " << fZone[i] << " in zone "
2333 << fZone.name()
2334 << " is also in zone "
2335 << fZones[faceToZone[bFacei]].name()
2336 << abort(FatalError);
2337 }
2338 }
2339 }
2340 }
2341
2342 labelList neiFaceToZone(faceToZone);
2343 syncTools::swapBoundaryFaceList(mesh, neiFaceToZone);
2344
2345 forAll(faceToZone, i)
2346 {
2347 if (faceToZone[i] != neiFaceToZone[i])
2348 {
2350 << "Face " << mesh.nInternalFaces()+i
2351 << " is in zone " << faceToZone[i]
2352 << ", its coupled face is in zone " << neiFaceToZone[i]
2353 << abort(FatalError);
2354 }
2355 }
2356}
2357
2358
2361 const polyMesh& mesh,
2362 const bitSet& isMasterEdge,
2363 const labelList& meshPoints,
2364 const edgeList& edges,
2365 scalarField& edgeWeights,
2366 scalarField& invSumWeight
2367)
2368{
2369 const pointField& pts = mesh.points();
2370
2371 // Calculate edgeWeights and inverse sum of edge weights
2372 edgeWeights.setSize(isMasterEdge.size());
2373 invSumWeight.setSize(meshPoints.size());
2374
2375 forAll(edges, edgei)
2376 {
2377 const edge& e = edges[edgei];
2378 scalar eMag = max
2379 (
2380 SMALL,
2381 mag
2382 (
2383 pts[meshPoints[e[1]]]
2384 - pts[meshPoints[e[0]]]
2385 )
2386 );
2387 edgeWeights[edgei] = 1.0/eMag;
2388 }
2389
2390 // Sum per point all edge weights
2392 (
2393 mesh,
2394 isMasterEdge,
2395 meshPoints,
2396 edges,
2397 edgeWeights,
2398 scalarField(meshPoints.size(), 1.0), // data
2399 invSumWeight
2400 );
2401
2402 // Inplace invert
2403 forAll(invSumWeight, pointi)
2404 {
2405 scalar w = invSumWeight[pointi];
2406
2407 if (w > 0.0)
2408 {
2409 invSumWeight[pointi] = 1.0/w;
2410 }
2411 }
2412}
2413
2414
2417 fvMesh& mesh,
2418 const label insertPatchi,
2419 const word& patchName,
2420 const dictionary& patchDict
2421)
2422{
2423 // Clear local fields and e.g. polyMesh parallelInfo.
2424 mesh.clearOut();
2425
2426 polyBoundaryMesh& polyPatches =
2427 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
2428 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
2429
2430 // The new location (at the end)
2431 const label patchi = polyPatches.size();
2432
2433 // Add polyPatch at the end
2434 polyPatches.push_back
2435 (
2437 (
2438 patchName,
2439 patchDict,
2440 insertPatchi,
2441 polyPatches
2442 )
2443 );
2444
2445 fvPatches.push_back
2446 (
2448 (
2449 polyPatches[patchi], // point to newly added polyPatch
2450 mesh.boundary()
2451 )
2452 );
2453
2454 addPatchFields<volScalarField>
2455 (
2456 mesh,
2458 );
2459 addPatchFields<volVectorField>
2460 (
2461 mesh,
2463 );
2464 addPatchFields<volSphericalTensorField>
2465 (
2466 mesh,
2468 );
2469 addPatchFields<volSymmTensorField>
2470 (
2471 mesh,
2473 );
2474 addPatchFields<volTensorField>
2475 (
2476 mesh,
2478 );
2479
2480 // Surface fields
2481
2482 addPatchFields<surfaceScalarField>
2483 (
2484 mesh,
2486 );
2487 addPatchFields<surfaceVectorField>
2488 (
2489 mesh,
2491 );
2492 addPatchFields<surfaceSphericalTensorField>
2493 (
2494 mesh,
2496 );
2497 addPatchFields<surfaceSymmTensorField>
2498 (
2499 mesh,
2501 );
2502 addPatchFields<surfaceTensorField>
2503 (
2504 mesh,
2506 );
2507 return patchi;
2508}
2509
2510
2513 fvMesh& mesh,
2514 const word& patchName,
2515 const dictionary& patchInfo
2516)
2517{
2518 polyBoundaryMesh& polyPatches =
2519 const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
2520 fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
2521
2522 const label patchi = polyPatches.findPatchID(patchName);
2523 if (patchi != -1)
2524 {
2525 // Already there
2526 return patchi;
2527 }
2528
2529
2530 label insertPatchi = polyPatches.size();
2531 label startFacei = mesh.nFaces();
2532
2533 forAll(polyPatches, patchi)
2534 {
2535 const polyPatch& pp = polyPatches[patchi];
2536
2538 {
2539 insertPatchi = patchi;
2540 startFacei = pp.start();
2541 break;
2542 }
2543 }
2544
2545 dictionary patchDict(patchInfo);
2546 patchDict.set("nFaces", 0);
2547 patchDict.set("startFace", startFacei);
2548
2549 // Below is all quite a hack. Feel free to change once there is a better
2550 // mechanism to insert and reorder patches.
2551
2552 label addedPatchi = appendPatch(mesh, insertPatchi, patchName, patchDict);
2553
2554
2555 // Create reordering list
2556 // patches before insert position stay as is
2557 labelList oldToNew(addedPatchi+1);
2558 for (label i = 0; i < insertPatchi; i++)
2559 {
2560 oldToNew[i] = i;
2561 }
2562 // patches after insert position move one up
2563 for (label i = insertPatchi; i < addedPatchi; i++)
2564 {
2565 oldToNew[i] = i+1;
2566 }
2567 // appended patch gets moved to insert position
2568 oldToNew[addedPatchi] = insertPatchi;
2569
2570 // Shuffle into place
2571 polyPatches.reorder(oldToNew, true);
2572 fvPatches.reorder(oldToNew);
2573
2574 reorderPatchFields<volScalarField>(mesh, oldToNew);
2575 reorderPatchFields<volVectorField>(mesh, oldToNew);
2576 reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
2577 reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
2578 reorderPatchFields<volTensorField>(mesh, oldToNew);
2579 reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
2580 reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
2581 reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
2582 reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
2583 reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
2584
2585 return insertPatchi;
2586}
2587
2588
2591 const word& name,
2592 const dictionary& patchInfo
2593)
2594{
2595 label meshedi = meshedPatches_.find(name);
2596
2597 if (meshedi != -1)
2598 {
2599 // Already there. Get corresponding polypatch
2600 return mesh_.boundaryMesh().findPatchID(name);
2601 }
2602 else
2603 {
2604 // Add patch
2605 label patchi = addPatch(mesh_, name, patchInfo);
2606
2607// dictionary patchDict(patchInfo);
2608// patchDict.set("nFaces", 0);
2609// patchDict.set("startFace", 0);
2610// autoPtr<polyPatch> ppPtr
2611// (
2612// polyPatch::New
2613// (
2614// name,
2615// patchDict,
2616// 0,
2617// mesh_.boundaryMesh()
2618// )
2619// );
2620// label patchi = fvMeshTools::addPatch
2621// (
2622// mesh_,
2623// ppPtr(),
2624// dictionary(), // optional field values
2625// fvPatchFieldBase::calculatedType(),
2626// true
2627// );
2628
2629 // Store
2630 meshedPatches_.append(name);
2631
2632 // Clear patch based addressing
2633 faceToCoupledPatch_.clear();
2634
2635 return patchi;
2636 }
2637}
2638
2639
2642 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2643
2644 DynamicList<label> patchIDs(meshedPatches_.size());
2645 forAll(meshedPatches_, i)
2646 {
2647 label patchi = patches.findPatchID(meshedPatches_[i]);
2648
2649 if (patchi == -1)
2650 {
2652 << "Problem : did not find patch " << meshedPatches_[i]
2653 << endl << "Valid patches are " << patches.names()
2654 << endl; //abort(FatalError);
2655 }
2656 else if (!polyPatch::constraintType(patches[patchi].type()))
2657 {
2658 patchIDs.append(patchi);
2659 }
2660 }
2661
2662 return patchIDs;
2663}
2664
2665
2668 const word& fzName,
2669 const word& masterPatch,
2670 const word& slavePatch,
2671 const surfaceZonesInfo::faceZoneType& fzType
2672)
2673{
2674 label zonei = surfaceZonesInfo::addFaceZone
2675 (
2676 fzName, //name
2677 labelList(0), //addressing
2678 boolList(0), //flipmap
2679 mesh_
2680 );
2681
2682 faceZoneToMasterPatch_.insert(fzName, masterPatch);
2683 faceZoneToSlavePatch_.insert(fzName, slavePatch);
2684 faceZoneToType_.insert(fzName, fzType);
2685
2686 return zonei;
2687}
2688
2689
2692 const word& fzName,
2693 label& masterPatchID,
2694 label& slavePatchID,
2696) const
2697{
2698 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2699
2700 if (!faceZoneToMasterPatch_.found(fzName))
2701 {
2702 return false;
2703 }
2704 else
2705 {
2706 const word& masterName = faceZoneToMasterPatch_[fzName];
2707 masterPatchID = pbm.findPatchID(masterName);
2708
2709 const word& slaveName = faceZoneToSlavePatch_[fzName];
2710 slavePatchID = pbm.findPatchID(slaveName);
2711
2712 fzType = faceZoneToType_[fzName];
2713
2714 return true;
2715 }
2716}
2717
2718
2721 pointZoneMesh& pointZones = mesh_.pointZones();
2722
2723 label zoneI = pointZones.findZoneID(name);
2724
2725 if (zoneI == -1)
2726 {
2727 zoneI = pointZones.size();
2728 pointZones.clearAddressing();
2729
2730 pointZones.emplace_back
2731 (
2732 name, // name
2733 zoneI, // index
2734 pointZones // pointZoneMesh
2735 );
2736 }
2737 return zoneI;
2738}
2739
2740
2743 for (const polyPatch& pp : mesh_.boundaryMesh())
2744 {
2745 // Check all coupled. Avoid using .coupled() so we also pick up AMI.
2746 const auto* cpp = isA<coupledPolyPatch>(pp);
2747
2748 if (cpp && (cpp->separated() || !cpp->parallel()))
2749 {
2750 SubList<bool>(selected, pp.size(), pp.start()) = true;
2751 }
2752 }
2753}
2754
2755
2759) const
2760{
2761 // Count number of faces per edge. Parallel consistent.
2762
2763 const labelListList& edgeFaces = pp.edgeFaces();
2764 labelList nEdgeFaces(edgeFaces.size());
2765 forAll(edgeFaces, edgei)
2766 {
2767 nEdgeFaces[edgei] = edgeFaces[edgei].size();
2768 }
2769
2770 // Sync across processor patches
2771 if (Pstream::parRun())
2772 {
2773 const globalMeshData& globalData = mesh_.globalData();
2774 const mapDistribute& map = globalData.globalEdgeSlavesMap();
2775 const indirectPrimitivePatch& cpp = globalData.coupledPatch();
2776
2777 // Match pp edges to coupled edges
2778 labelList patchEdges;
2779 labelList coupledEdges;
2780 bitSet sameEdgeOrientation;
2782 (
2783 pp,
2784 cpp,
2785 patchEdges,
2786 coupledEdges,
2787 sameEdgeOrientation
2788 );
2789
2790 // Convert patch-edge data into cpp-edge data
2791 labelList coupledNEdgeFaces(map.constructSize(), Zero);
2792 UIndirectList<label>(coupledNEdgeFaces, coupledEdges) =
2793 UIndirectList<label>(nEdgeFaces, patchEdges);
2794
2795 // Synchronise
2796 globalData.syncData
2797 (
2798 coupledNEdgeFaces,
2799 globalData.globalEdgeSlaves(),
2800 globalData.globalEdgeTransformedSlaves(),
2801 map,
2803 );
2804
2805 // Convert back from cpp-edge to patch-edge
2806 UIndirectList<label>(nEdgeFaces, patchEdges) =
2807 UIndirectList<label>(coupledNEdgeFaces, coupledEdges);
2808 }
2809 return nEdgeFaces;
2810}
2811
2812
2815 const polyMesh& mesh,
2816 const vector& perturbVec,
2817 const point& p
2818)
2819{
2820 // Force calculation of base points (needs to be synchronised)
2821 (void)mesh.tetBasePtIs();
2822
2823 label celli = mesh.findCell(p, findCellMode);
2824
2825 if (returnReduceAnd(celli < 0))
2826 {
2827 // See if we can perturb a bit
2828 celli = mesh.findCell(p+perturbVec, findCellMode);
2829 }
2830 return celli;
2831}
2832
2833
2836 const polyMesh& mesh,
2837 const labelList& cellToRegion,
2838 const vector& perturbVec,
2839 const point& p
2840)
2841{
2842 label regioni = -1;
2843
2844 // Force calculation of base points (needs to be synchronised)
2845 (void)mesh.tetBasePtIs();
2846
2847 label celli = mesh.findCell(p, findCellMode);
2848 if (celli != -1)
2849 {
2850 regioni = cellToRegion[celli];
2851 }
2852 reduce(regioni, maxOp<label>());
2853
2854 if (regioni == -1)
2855 {
2856 // See if we can perturb a bit
2857 celli = mesh.findCell(p+perturbVec, findCellMode);
2858 if (celli != -1)
2859 {
2860 regioni = cellToRegion[celli];
2861 }
2862 reduce(regioni, maxOp<label>());
2863 }
2864 return regioni;
2865}
2866
2867
2868Foam::fileName Foam::meshRefinement::writeLeakPath
2869(
2870 const polyMesh& mesh,
2871 const pointField& locationsInMesh,
2872 const pointField& locationsOutsideMesh,
2873 const boolList& blockedFace,
2875)
2876{
2877 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
2878
2879 fileName outputDir
2880 (
2881 mesh.time().globalPath()
2883 / mesh.pointsInstance()
2884 );
2885 outputDir.clean(); // Remove unneeded ".."
2886
2887 // Write the leak path
2888
2889 meshSearch searchEngine(mesh);
2890 shortestPathSet leakPath
2891 (
2892 "leakPath",
2893 mesh,
2894 searchEngine,
2896 false, //true,
2897 50, // tbd. Number of iterations
2898 pbm.groupPatchIDs()["wall"],
2899 locationsInMesh,
2900 locationsOutsideMesh,
2901 blockedFace
2902 );
2903
2904 // Split leak path according to segment. Note: segment index
2905 // is global (= index in locationsInsideMesh)
2906 List<pointList> segmentPoints;
2907 List<scalarList> segmentDist;
2908 {
2909 label nSegments = 0;
2910 if (leakPath.segments().size())
2911 {
2912 nSegments = max(leakPath.segments())+1;
2913 }
2914 reduce(nSegments, maxOp<label>());
2915
2916 labelList nElemsPerSegment(nSegments, Zero);
2917 for (label segmenti : leakPath.segments())
2918 {
2919 nElemsPerSegment[segmenti]++;
2920 }
2921 segmentPoints.setSize(nElemsPerSegment.size());
2922 segmentDist.setSize(nElemsPerSegment.size());
2923 forAll(nElemsPerSegment, i)
2924 {
2925 segmentPoints[i].setSize(nElemsPerSegment[i]);
2926 segmentDist[i].setSize(nElemsPerSegment[i]);
2927 }
2928 nElemsPerSegment = 0;
2929
2930 forAll(leakPath, elemi)
2931 {
2932 label segmenti = leakPath.segments()[elemi];
2933 pointList& points = segmentPoints[segmenti];
2934 scalarList& dist = segmentDist[segmenti];
2935 label& n = nElemsPerSegment[segmenti];
2936
2937 points[n] = leakPath[elemi];
2938 dist[n] = leakPath.distance()[elemi];
2939 n++;
2940 }
2941 }
2942
2943 PtrList<coordSet> allLeakPaths(segmentPoints.size());
2944 forAll(allLeakPaths, segmenti)
2945 {
2946 // Collect data from all processors
2947 List<pointList> gatheredPts(Pstream::nProcs());
2948 gatheredPts[Pstream::myProcNo()] = std::move(segmentPoints[segmenti]);
2949 Pstream::gatherList(gatheredPts);
2950
2951 List<scalarList> gatheredDist(Pstream::nProcs());
2952 gatheredDist[Pstream::myProcNo()] = std::move(segmentDist[segmenti]);
2953 Pstream::gatherList(gatheredDist);
2954
2955 // Combine processor lists into one big list.
2956 pointList allPts
2957 (
2959 (
2960 gatheredPts, accessOp<pointList>()
2961 )
2962 );
2963 scalarList allDist
2964 (
2966 (
2967 gatheredDist, accessOp<scalarList>()
2968 )
2969 );
2970
2971 // Sort according to distance
2972 labelList indexSet(Foam::sortedOrder(allDist));
2973
2974 allLeakPaths.set
2975 (
2976 segmenti,
2977 new coordSet
2978 (
2979 leakPath.name(),
2980 leakPath.axis(),
2981 pointList(allPts, indexSet),
2982 //scalarList(allDist, indexSet)
2983 scalarList(allPts.size(), scalar(segmenti))
2984 )
2985 );
2986 }
2987
2988 fileName fName;
2989 if (Pstream::master())
2990 {
2991 List<scalarField> allLeakData(allLeakPaths.size());
2992 forAll(allLeakPaths, segmenti)
2993 {
2994 allLeakData[segmenti] = allLeakPaths[segmenti].distance();
2995 }
2996
2997 writer.nFields(1);
2998
2999 writer.open
3000 (
3001 allLeakPaths,
3002 (outputDir / allLeakPaths[0].name())
3003 );
3004
3005 fName = writer.write("leakPath", allLeakData);
3006
3007 // Force writing to finish before FatalError exit
3008 writer.close(true);
3009 }
3010
3011 // Probably do not need to broadcast name (only written on master anyhow)
3012 Pstream::broadcast(fName);
3013
3014 return fName;
3015}
3016
3017
3018// Modify cellRegion to be consistent with locationsInMesh.
3019// - all regions not in locationsInMesh are set to -1
3020// - check that all regions inside locationsOutsideMesh are set to -1
3023 const polyMesh& mesh,
3024 const vector& perturbVec,
3025 const pointField& locationsInMesh,
3026 const pointField& locationsOutsideMesh,
3027 const label nRegions,
3028 labelList& cellRegion,
3029 const boolList& blockedFace,
3030 // Leak-path
3031 const bool exitIfLeakPath,
3032 const refPtr<coordSetWriter>& leakPathFormatter
3033)
3034{
3035 bitSet insideCell(mesh.nCells());
3036
3037 // Mark all cells reachable from locationsInMesh
3038 labelList insideRegions(locationsInMesh.size());
3039 forAll(insideRegions, i)
3040 {
3041 // Find the region containing the point
3042 label regioni = findRegion
3043 (
3044 mesh,
3045 cellRegion,
3046 perturbVec,
3047 locationsInMesh[i]
3048 );
3049
3050 insideRegions[i] = regioni;
3051
3052 // Mark all cells in the region as being inside
3053 forAll(cellRegion, celli)
3054 {
3055 if (cellRegion[celli] == regioni)
3056 {
3057 insideCell.set(celli);
3058 }
3059 }
3060 }
3061
3062
3063
3064 // Check that all the locations outside the
3065 // mesh do not conflict with those inside
3066 forAll(locationsOutsideMesh, i)
3067 {
3068 // Find the region containing the point,
3069 // and the corresponding inside region index
3070
3071 label indexi;
3072 label regioni = findRegion
3073 (
3074 mesh,
3075 cellRegion,
3076 perturbVec,
3077 locationsOutsideMesh[i]
3078 );
3079
3080 if (regioni == -1 && (indexi = insideRegions.find(regioni)) != -1)
3081 {
3082 if (leakPathFormatter)
3083 {
3084 const fileName fName
3085 (
3086 writeLeakPath
3087 (
3088 mesh,
3089 locationsInMesh,
3090 locationsOutsideMesh,
3091 blockedFace,
3092 leakPathFormatter.constCast()
3093 )
3094 );
3095 Info<< "Dumped leak path to " << fName << endl;
3096 }
3097
3098 auto& err =
3099 (
3100 exitIfLeakPath
3103 );
3104
3105 err << "Location in mesh " << locationsInMesh[indexi]
3106 << " is inside same mesh region " << regioni
3107 << " as one of the locations outside mesh "
3108 << locationsOutsideMesh << endl;
3109
3110 if (exitIfLeakPath)
3111 {
3113 }
3114 }
3115 }
3116
3117
3118 label nRemove = 0;
3119
3120 // Now update cellRegion to -1 for unreachable cells
3121 forAll(insideCell, celli)
3122 {
3123 if (!insideCell.test(celli))
3124 {
3125 cellRegion[celli] = -1;
3126 ++nRemove;
3127 }
3128 else if (cellRegion[celli] == -1)
3129 {
3130 ++nRemove;
3131 }
3132 }
3133
3134 return nRemove;
3135}
3136
3137
3140 const labelList& globalToMasterPatch,
3141 const labelList& globalToSlavePatch,
3142 const pointField& locationsInMesh,
3143 const pointField& locationsOutsideMesh,
3144 const bool exitIfLeakPath,
3145 const refPtr<coordSetWriter>& leakPathFormatter
3146)
3147{
3148 // Force calculation of face decomposition (used in findCell)
3149 (void)mesh_.tetBasePtIs();
3150
3151 // Determine connected regions. regionSplit is the labelList with the
3152 // region per cell.
3153
3154 boolList blockedFace(mesh_.nFaces(), false);
3155 selectSeparatedCoupledFaces(blockedFace);
3156
3157 regionSplit cellRegion(mesh_, blockedFace);
3158
3159 label nRemove = findRegions
3160 (
3161 mesh_,
3162 vector::uniform(mergeDistance_), // perturbVec
3163 locationsInMesh,
3164 locationsOutsideMesh,
3165 cellRegion.nRegions(),
3166 cellRegion,
3167 blockedFace,
3168 // Leak-path
3169 exitIfLeakPath,
3170 leakPathFormatter
3171 );
3172
3173 // Subset
3174 // ~~~~~~
3175
3176 // Get cells to remove
3177 DynamicList<label> cellsToRemove(nRemove);
3178 forAll(cellRegion, celli)
3179 {
3180 if (cellRegion[celli] == -1)
3181 {
3182 cellsToRemove.append(celli);
3183 }
3184 }
3185 cellsToRemove.shrink();
3186
3187 label nTotCellsToRemove = returnReduce
3188 (
3189 cellsToRemove.size(),
3190 sumOp<label>()
3191 );
3192
3193
3194 autoPtr<mapPolyMesh> mapPtr;
3195 if (nTotCellsToRemove > 0)
3196 {
3197 label nCellsToKeep =
3198 mesh_.globalData().nTotalCells()
3199 - nTotCellsToRemove;
3200
3201 Info<< "Keeping all cells containing points " << locationsInMesh << endl
3202 << "Selected for keeping : "
3203 << nCellsToKeep
3204 << " cells." << endl;
3205
3206
3207 // Remove cells
3208 removeCells cellRemover(mesh_);
3209
3210 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
3211 labelList exposedPatch;
3212
3213 label nExposedFaces = returnReduce(exposedFaces.size(), sumOp<label>());
3214 if (nExposedFaces)
3215 {
3216 // FatalErrorInFunction
3217 // << "Removing non-reachable cells should only expose"
3218 // << " boundary faces" << nl
3219 // << "ExposedFaces:" << exposedFaces << abort(FatalError);
3220
3221 // Patch for exposed faces for lack of anything sensible.
3222 label defaultPatch = 0;
3223 if (globalToMasterPatch.size())
3224 {
3225 defaultPatch = globalToMasterPatch[0];
3226 }
3227
3229 << "Removing non-reachable cells exposes "
3230 << nExposedFaces << " internal or coupled faces." << endl
3231 << " These get put into patch " << defaultPatch << endl;
3232 exposedPatch.setSize(exposedFaces.size(), defaultPatch);
3233 }
3234
3235 mapPtr = doRemoveCells
3236 (
3237 cellsToRemove,
3238 exposedFaces,
3239 exposedPatch,
3240 cellRemover
3241 );
3242 }
3243 return mapPtr;
3244}
3245
3246
3249 // mesh_ already distributed; distribute my member data
3250
3251 // surfaceQueries_ ok.
3252
3253 // refinement
3254 meshCutter_.distribute(map);
3255
3256 // surfaceIndex is face data.
3257 map.distributeFaceData(surfaceIndex_);
3258
3259 // faceToPatch (baffles that were on coupled faces) is not maintained
3260 // (since baffling also disconnects points)
3261 faceToCoupledPatch_.clear();
3262
3263 // maintainedFaces are indices of faces.
3264 forAll(userFaceData_, i)
3265 {
3266 map.distributeFaceData(userFaceData_[i].second());
3267 }
3268
3269 // Redistribute surface and any fields on it.
3270 {
3271 Random rndGen(653213);
3272
3273 // Get local mesh bounding box. Single box for now.
3275 (
3276 1,
3277 treeBoundBox(mesh_.points()).extend(rndGen, 1e-4)
3278 );
3279
3280 // Distribute all geometry (so refinementSurfaces and shellSurfaces)
3281 searchableSurfaces& geometry =
3282 const_cast<searchableSurfaces&>(surfaces_.geometry());
3283
3284 forAll(geometry, i)
3285 {
3287 autoPtr<mapDistribute> pointMap;
3288 geometry[i].distribute
3289 (
3290 meshBb,
3291 false, // do not keep outside triangles
3292 faceMap,
3293 pointMap
3294 );
3295
3296 if (faceMap)
3297 {
3298 // (ab)use the instance() to signal current modification time
3299 geometry[i].instance() = geometry[i].time().timeName();
3300 }
3301
3302 faceMap.clear();
3303 pointMap.clear();
3304 }
3305 }
3306}
3307
3308
3311 const mapPolyMesh& map,
3312 const labelList& changedFaces
3313)
3314{
3315 Map<label> dummyMap(0);
3316
3317 updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
3318}
3319
3320
3323 const labelList& pointsToStore,
3324 const labelList& facesToStore,
3325 const labelList& cellsToStore
3326)
3327{
3328 // For now only meshCutter has storable/retrievable data.
3329 meshCutter_.storeData
3330 (
3331 pointsToStore,
3332 facesToStore,
3333 cellsToStore
3334 );
3335}
3336
3337
3340 const mapPolyMesh& map,
3341 const labelList& changedFaces,
3342 const Map<label>& pointsToRestore,
3343 const Map<label>& facesToRestore,
3344 const Map<label>& cellsToRestore
3345)
3346{
3347 // For now only meshCutter has storable/retrievable data.
3348
3349 // Update numbering of cells/vertices.
3350 meshCutter_.updateMesh
3351 (
3352 map,
3353 pointsToRestore,
3354 facesToRestore,
3355 cellsToRestore
3356 );
3357
3358 // Update surfaceIndex
3359 updateList(map.faceMap(), label(-1), surfaceIndex_);
3360
3361 // Update faceToCoupledPatch_
3362 {
3363 Map<label> newFaceToPatch(faceToCoupledPatch_.size());
3364 forAllConstIters(faceToCoupledPatch_, iter)
3365 {
3366 const label newFacei = map.reverseFaceMap()[iter.key()];
3367
3368 if (newFacei >= 0)
3369 {
3370 newFaceToPatch.insert(newFacei, iter.val());
3371 }
3372 }
3373 faceToCoupledPatch_.transfer(newFaceToPatch);
3374 }
3375
3376
3377 // Update cached intersection information
3378 updateIntersections(changedFaces);
3379
3380 // Update maintained faces
3381 forAll(userFaceData_, i)
3382 {
3383 labelList& data = userFaceData_[i].second();
3384
3385 if (userFaceData_[i].first() == KEEPALL)
3386 {
3387 // extend list with face-from-face data
3388 updateList(map.faceMap(), label(-1), data);
3389 }
3390 else if (userFaceData_[i].first() == MASTERONLY)
3391 {
3392 // keep master only
3393 labelList newFaceData(map.faceMap().size(), -1);
3394
3395 forAll(newFaceData, facei)
3396 {
3397 label oldFacei = map.faceMap()[facei];
3398
3399 if (oldFacei >= 0 && map.reverseFaceMap()[oldFacei] == facei)
3400 {
3401 newFaceData[facei] = data[oldFacei];
3402 }
3403 }
3404 data.transfer(newFaceData);
3405 }
3406 else
3407 {
3408 // remove any face that has been refined i.e. referenced more than
3409 // once.
3410
3411 // 1. Determine all old faces that get referenced more than once.
3412 // These get marked with -1 in reverseFaceMap
3413 labelList reverseFaceMap(map.reverseFaceMap());
3414
3415 forAll(map.faceMap(), facei)
3416 {
3417 label oldFacei = map.faceMap()[facei];
3418
3419 if (oldFacei >= 0)
3420 {
3421 if (reverseFaceMap[oldFacei] != facei)
3422 {
3423 // facei is slave face. Mark old face.
3424 reverseFaceMap[oldFacei] = -1;
3425 }
3426 }
3427 }
3428
3429 // 2. Map only faces with intact reverseFaceMap
3430 labelList newFaceData(map.faceMap().size(), -1);
3431 forAll(newFaceData, facei)
3432 {
3433 label oldFacei = map.faceMap()[facei];
3434
3435 if (oldFacei >= 0)
3436 {
3437 if (reverseFaceMap[oldFacei] == facei)
3438 {
3439 newFaceData[facei] = data[oldFacei];
3440 }
3441 }
3442 }
3443 data.transfer(newFaceData);
3444 }
3445 }
3446}
3447
3448
3449bool Foam::meshRefinement::write() const
3451 bool writeOk = mesh_.write();
3452
3453 // Make sure that any distributed surfaces (so ones which probably have
3454 // been changed) get written as well.
3455 // Note: should ideally have some 'modified' flag to say whether it
3456 // has been changed or not.
3457 searchableSurfaces& geometry =
3458 const_cast<searchableSurfaces&>(surfaces_.geometry());
3459
3460 forAll(geometry, i)
3461 {
3462 searchableSurface& s = geometry[i];
3463
3464 // Check if instance() of surface is not constant or system.
3465 // Is good hint that surface is distributed.
3466 if
3467 (
3468 s.instance() != s.time().system()
3469 && s.instance() != s.time().caseSystem()
3470 && s.instance() != s.time().constant()
3471 && s.instance() != s.time().caseConstant()
3472 )
3473 {
3474 // Make sure it gets written to current time, not constant.
3475 s.instance() = s.time().timeName();
3476 writeOk = writeOk && s.write();
3477 }
3478 }
3479
3480 return writeOk;
3481}
3482
3483
3486 const polyMesh& mesh,
3487 const labelList& meshPoints
3488)
3489{
3490 const label myProci = UPstream::myProcNo();
3491 const globalIndex globalPoints(meshPoints.size());
3492
3493 labelList myPoints
3494 (
3495 Foam::identity(globalPoints.range(myProci))
3496 );
3497
3499 (
3500 mesh,
3501 meshPoints,
3502 myPoints,
3504 labelMax
3505 );
3506
3507
3508 bitSet isPatchMasterPoint(meshPoints.size());
3509 forAll(meshPoints, pointi)
3510 {
3511 if (myPoints[pointi] == globalPoints.toGlobal(myProci, pointi))
3512 {
3513 isPatchMasterPoint.set(pointi);
3514 }
3515 }
3516
3517 return isPatchMasterPoint;
3518}
3519
3520
3523 const polyMesh& mesh,
3524 const labelList& meshEdges
3525)
3526{
3527 const label myProci = UPstream::myProcNo();
3528 const globalIndex globalEdges(meshEdges.size());
3529
3530 labelList myEdges
3531 (
3532 Foam::identity(globalEdges.range(myProci))
3533 );
3534
3536 (
3537 mesh,
3538 meshEdges,
3539 myEdges,
3541 labelMax
3542 );
3543
3544
3545 bitSet isMasterEdge(meshEdges.size());
3546 forAll(meshEdges, edgei)
3547 {
3548 if (myEdges[edgei] == globalEdges.toGlobal(myProci, edgei))
3549 {
3550 isMasterEdge.set(edgei);
3551 }
3552 }
3553
3554 return isMasterEdge;
3555}
3556
3557
3560 const bool debug,
3561 const string& msg,
3562 const bool printCellLevel
3563)
3564const
3565{
3566 const globalMeshData& pData = mesh_.globalData();
3567
3568 if (debug)
3569 {
3570 Pout<< msg.c_str()
3571 << " : cells(local):" << mesh_.nCells()
3572 << " faces(local):" << mesh_.nFaces()
3573 << " points(local):" << mesh_.nPoints()
3574 << endl;
3575 }
3576
3577 {
3578 bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
3579 label nMasterFaces = isMasterFace.count();
3580
3581 bitSet isMeshMasterPoint(syncTools::getMasterPoints(mesh_));
3582 label nMasterPoints = isMeshMasterPoint.count();
3583
3584 Info<< msg.c_str()
3585 << " : cells:" << pData.nTotalCells()
3586 << " faces:" << returnReduce(nMasterFaces, sumOp<label>())
3587 << " points:" << returnReduce(nMasterPoints, sumOp<label>());
3588
3589 if (UPstream::parRun())
3590 {
3591 const scalar nIdealCells =
3592 scalar(pData.nTotalCells())/Pstream::nProcs();
3593 const scalar unbalance = returnReduce
3594 (
3595 mag(1.0-mesh_.nCells()/nIdealCells),
3597 );
3598 Info<< " unbalance:" << unbalance;
3599 }
3600 Info<< endl;
3601 }
3602
3603 if (printCellLevel)
3604 {
3605 const labelList& cellLevel = meshCutter_.cellLevel();
3606
3607 labelList nCells(gMax(cellLevel)+1, Zero);
3608
3609 forAll(cellLevel, celli)
3610 {
3611 nCells[cellLevel[celli]]++;
3612 }
3613
3615
3617 if (Pstream::master())
3618 {
3619 Info<< "Cells per refinement level:" << endl;
3620 forAll(nCells, leveli)
3621 {
3622 Info<< " " << leveli << '\t' << nCells[leveli]
3623 << endl;
3624 }
3625 }
3626 }
3627}
3628
3629
3632 if (overwrite_ && mesh_.time().timeIndex() == 0)
3633 {
3634 return oldInstance_;
3635 }
3636
3637 return mesh_.time().timeName();
3638}
3639
3640
3643 // Note: use time().timeName(), not meshRefinement::timeName()
3644 // so as to dump the fields to 0, not to constant.
3645 {
3646 volScalarField volRefLevel
3647 (
3648 IOobject
3649 (
3650 "cellLevel",
3651 mesh_.time().timeName(),
3652 mesh_,
3656 ),
3657 mesh_,
3660 );
3661
3662 const labelList& cellLevel = meshCutter_.cellLevel();
3663
3664 forAll(volRefLevel, celli)
3665 {
3666 volRefLevel[celli] = cellLevel[celli];
3667 }
3668
3669 volRefLevel.write();
3670 }
3671
3672 // Dump pointLevel
3673 {
3674 const pointMesh& pMesh = pointMesh::New(mesh_);
3675
3676 pointScalarField pointRefLevel
3677 (
3678 IOobject
3679 (
3680 "pointLevel",
3681 mesh_.time().timeName(),
3682 mesh_,
3686 ),
3687 pMesh,
3689 );
3690
3691 const labelList& pointLevel = meshCutter_.pointLevel();
3692
3693 forAll(pointRefLevel, pointi)
3694 {
3695 pointRefLevel[pointi] = pointLevel[pointi];
3696 }
3697
3698 pointRefLevel.write();
3699 }
3700}
3701
3702
3703void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
3705 {
3706 OFstream str(prefix + "_edges.obj");
3707 label verti = 0;
3708 Pout<< "meshRefinement::dumpIntersections :"
3709 << " Writing cellcentre-cellcentre intersections to file "
3710 << str.name() << endl;
3711
3712
3713 // Redo all intersections
3714 // ~~~~~~~~~~~~~~~~~~~~~~
3715
3716 // Get boundary face centre and level. Coupled aware.
3717 labelList neiLevel(mesh_.nBoundaryFaces());
3718 pointField neiCc(mesh_.nBoundaryFaces());
3719 calcNeighbourData(neiLevel, neiCc);
3720
3721 labelList intersectionFaces(intersectedFaces());
3722
3723 // Collect segments we want to test for
3724 pointField start(intersectionFaces.size());
3725 pointField end(intersectionFaces.size());
3726 {
3727 labelList minLevel;
3728 calcCellCellRays
3729 (
3730 neiCc,
3731 labelList(neiCc.size(), -1),
3732 intersectionFaces,
3733 start,
3734 end,
3735 minLevel
3736 );
3737 }
3738
3739
3740 // Do tests in one go
3741 labelList surfaceHit;
3742 List<pointIndexHit> surfaceHitInfo;
3743 surfaces_.findAnyIntersection
3744 (
3745 start,
3746 end,
3747 surfaceHit,
3748 surfaceHitInfo
3749 );
3750
3751 forAll(intersectionFaces, i)
3752 {
3753 if (surfaceHit[i] != -1)
3754 {
3755 meshTools::writeOBJ(str, start[i]);
3756 verti++;
3757 meshTools::writeOBJ(str, surfaceHitInfo[i].point());
3758 verti++;
3759 meshTools::writeOBJ(str, end[i]);
3760 verti++;
3761 str << "l " << verti-2 << ' ' << verti-1 << nl
3762 << "l " << verti-1 << ' ' << verti << nl;
3763 }
3764 }
3765 }
3766
3767 Pout<< endl;
3768}
3769
3770
3773 const debugType debugFlags,
3774 const writeType writeFlags,
3775 const fileName& prefix
3776) const
3777{
3778 if (writeFlags & WRITEMESH)
3779 {
3780 write();
3781 }
3782
3783 if (writeFlags && !(writeFlags & NOWRITEREFINEMENT))
3784 {
3785 meshCutter_.write();
3786
3787 // Force calculation before writing
3788 (void)surfaceIndex();
3789 surfaceIndex_.write();
3790 }
3791
3792 if (writeFlags & WRITELEVELS)
3793 {
3795 }
3796
3797 if ((debugFlags & OBJINTERSECTIONS) && prefix.size())
3798 {
3799 dumpIntersections(prefix);
3800 }
3801}
3802
3803
3806 IOobject io
3807 (
3808 "dummy",
3809 mesh.facesInstance(),
3811 mesh
3812 );
3813 fileName setsDir(io.path());
3814
3815 if (topoSet::debug) DebugVar(setsDir);
3816
3817 // Remove local files
3818 if (exists(setsDir/"surfaceIndex"))
3819 {
3820 rm(setsDir/"surfaceIndex");
3821 }
3822
3823 // Remove other files
3825}
3826
3827
3830 return writeLevel_;
3831}
3832
3833
3834void Foam::meshRefinement::writeLevel(const writeType flags)
3836 writeLevel_ = flags;
3837}
3838
3839
3840//Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel()
3841//{
3842// return outputLevel_;
3843//}
3844//
3845//
3846//void Foam::meshRefinement::outputLevel(const outputType flags)
3847//{
3848// outputLevel_ = flags;
3849//}
3850
3851
3854 const dictionary& dict,
3855 const word& keyword,
3856 const bool noExit,
3857 enum keyType::option matchOpt
3858)
3859{
3860 const dictionary* dictptr = dict.findDict(keyword, matchOpt);
3861
3862 if (!dictptr)
3863 {
3865 << "Entry '" << keyword
3866 << "' not found (or not a dictionary) in dictionary "
3867 << dict.relativeName() << nl;
3868
3869 if (noExit)
3870 {
3871 // Dummy return
3872 return dictionary::null;
3873 }
3874 else
3875 {
3877 }
3878 }
3879
3880 return *dictptr;
3881}
3882
3883
3886 const dictionary& dict,
3887 const word& keyword,
3888 const bool noExit,
3889 enum keyType::option matchOpt
3890)
3891{
3892 const entry* eptr = dict.findEntry(keyword, matchOpt);
3893
3894 if (!eptr)
3895 {
3897 << "Entry '" << keyword << "' not found in dictionary "
3898 << dict.relativeName() << nl;
3899
3900 if (noExit)
3901 {
3902 // Dummy return
3903 return ITstream::empty_stream();
3904 }
3905 else
3906 {
3908 }
3909 }
3910
3911 return eptr->stream();
3912}
3913
3914
3915// ************************************************************************* //
label n
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edgesCentres")))
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
labelList patchIDs
const polyBoundaryMesh & pbm
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
DynamicList< T, SizeMin > & shrink()
Calls shrink_to_fit() and returns a reference to the DynamicList.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition Enum.H:57
Wave propagation of information through grid. Every iteration information goes through one layer of c...
SubField< vector > subField
Definition Field.H:183
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
bool found(const Key &key) const
Same as contains().
Definition HashTable.H:1370
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition HashTableI.H:113
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition HashTableI.H:152
label size() const noexcept
The number of elements in table.
Definition HashTable.H:358
void clear()
Remove all entries from table.
Definition HashTable.C:742
@ NO_REGISTER
Do not request registration (bool: false).
@ NO_READ
Nothing to be read.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
@ AUTO_WRITE
Automatically write from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
const word & name() const noexcept
Return the object name.
Definition IOobjectI.H:205
An input stream of tokens.
Definition ITstream.H:56
static ITstream & empty_stream()
Return reference to an empty ITstream, for functions needing to return an ITstream reference but whic...
Definition ITstream.C:63
label size() const noexcept
The number of elements in the list.
A List with indirect addressing.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition List.C:347
SubList< vector > subList
Definition List.H:129
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void setSize(label n)
Alias for resize().
Definition List.H:536
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
static FOAM_NO_DANGLING_REFERENCE const pointMesh & New(const polyMesh &mesh, Args &&... args)
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition OSstream.H:134
label size() const noexcept
Number of entries.
Definition PackedList.H:392
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const T & second() const noexcept
Access the second element.
Definition Pair.H:147
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
const Field< point_type > & faceAreas() const
Return face area vectors for patch.
const Field< point_type > & faceCentres() const
Return face centres for patch.
static void listGather(UList< T > &values, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather (reduce) list elements, applying bop to each list element.
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
static void listReduce(UList< T > &values, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce list elements (list must be equal size on all ranks), applying bop to each list element.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
void setSize(const label n)
Same as resize().
Definition PtrList.H:357
void push_back(T *ptr)
Append an element to the end of the list.
Definition PtrListI.H:131
T & emplace_back(Args &&... args)
Construct and append an element to the end of the list, return reference to the new list element.
Definition PtrListI.H:122
Random number generator.
Definition Random.H:56
A non-owning sub-view of a List (allocated or unallocated storage).
Definition SubList.H:61
A List with indirect addressing. Like IndirectList but does not store addressing.
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition UListI.H:274
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label find(const T &val) const
Find index of the first occurrence of the value.
Definition UList.C:160
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
Definition UPstream.H:1697
@ gatherList
gatherList [manual algorithm]
Definition UPstream.H:194
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
void reorder(const labelUList &oldToNew, const bool check=false)
Reorder elements. Reordering must be unique (ie, shuffle).
Definition UPtrList.C:62
label size() const noexcept
The number of entries in the list.
Definition UPtrListI.H:106
static const Form zero
static Form uniform(const Cmpt &s)
Return a VectorSpace with all elements = s.
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition ZoneMesh.C:757
void clearAddressing()
Clear addressing.
Definition ZoneMesh.C:944
wordList names() const
A list of the zone names.
Definition ZoneMesh.C:463
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
void clear() noexcept
Same as reset(nullptr).
Definition autoPtr.H:255
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition autoPtrI.H:37
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition autoPtr.H:178
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
unsigned int count(const bool on=true) const
Count number of bits set.
Definition bitSetI.H:420
labelList sortedToc() const
The indices of the on bits as a sorted labelList.
Definition bitSetI.H:441
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition bitSet.H:334
Base class for writing coordSet(s) and tracks with fields.
Holds list of sampling positions.
Definition coordSet.H:52
static const Enum< coordFormat > coordFormatNames
String representation of coordFormat enum.
Definition coordSet.H:74
@ DISTANCE
Use additional distance field for (scalar) axis.
Definition coordSet.H:66
Abstract base class for domain decomposition.
void setConstraints(const polyMesh &mesh, boolList &blockedFace, PtrList< labelList > &specifiedProcessorFaces, labelList &specifiedProcessor, List< labelPair > &explicitConnections) const
Helper: extract constraints:
virtual labelList decompose(const pointField &points, const scalarField &pointWeights=scalarField::null()) const
Return the wanted processor number for every coordinate, using uniform or specified point weights.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition dictionary.C:765
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition dictionary.H:487
Accumulating histogram of values. Specified bin resolution automatic generation of bins.
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
Smooth ATC in cells next to a set of patches supplied by type.
Definition faceCells.H:55
A list of face labels.
Definition faceSet.H:50
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
label whichFace(const label meshFaceID) const
The local index of the given mesh face, -1 if not in the zone.
Definition faceZone.H:394
const boolList & flipMap() const noexcept
Return face flip map.
Definition faceZone.H:389
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
A class for handling file names.
Definition fileName.H:75
static word outputPrefix
Directory prefix.
A fvBoundaryMesh is a fvPatch list with a reference to the associated fvMesh, with additional search ...
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
static labelList countCells(const labelList &)
Helper function: count cells per processor in wanted distribution.
autoPtr< mapDistributePolyMesh > distribute(const labelList &dist)
Send cells to neighbours according to distribution.
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
static const word & calculatedType() noexcept
The type name for calculated patch fields.
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
static autoPtr< fvPatch > New(const polyPatch &, const fvBoundaryMesh &)
Return a pointer to a new patch created on freestore from polyPatch.
Definition fvPatchNew.C:28
static const word & calculatedType() noexcept
The type name for calculated patch fields.
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
labelRange range(label proci) const noexcept
Return start/size range of proci data.
label toGlobal(const label proci, const label i) const
From local to global on proci.
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const labelListList & globalEdgeTransformedSlaves() const
const mapDistribute & globalEdgeSlavesMap() const
static void syncData(List< Type > &elems, const labelListList &slaves, const labelListList &transformedSlaves, const mapDistribute &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
label nTotalCells() const noexcept
Total global number of mesh cells.
const labelListList & globalEdgeSlaves() const
Calculates points shared by more than two processor patches or cyclic patches.
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
Definition hexRef8.C:5828
option
Enumeration for the data type and search/match modes (bitmask).
Definition keyType.H:80
A range or interval of labels defined by a start and a size.
Definition labelRange.H:66
static labelList findDuplicateFaces(const primitiveMesh &, const labelList &)
Helper routine to find baffles (two boundary faces using the.
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
label constructSize() const noexcept
Constructed data size.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
void distributeFaceData(List< T > &values) const
Distribute list of face data.
Class containing processor-to-processor mapping information.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const pointField & preMotionPoints() const noexcept
Pre-motion point positions.
const labelList & reverseFaceMap() const noexcept
Reverse face map.
const labelList & faceMap() const noexcept
Old face map.
bool hasMotionPoints() const noexcept
Has valid preMotionPoints?
const labelList & reversePointMap() const noexcept
Reverse point map.
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
static void calculateEdgeWeights(const polyMesh &mesh, const bitSet &isMasterEdge, const labelList &meshPoints, const edgeList &edges, scalarField &edgeWeights, scalarField &invSumWeight)
Helper: calculate edge weights (1/length).
label addFaceZone(const word &fzName, const word &masterPatch, const word &slavePatch, const surfaceZonesInfo::faceZoneType &fzType)
Add/lookup faceZone and update information. Return index of.
bool getFaceZoneInfo(const word &fzName, label &masterPatchID, label &slavePatchID, surfaceZonesInfo::faceZoneType &fzType) const
Lookup faceZone information. Return false if no information.
labelList intersectedFaces() const
Get faces with intersection.
labelList intersectedPoints() const
Get points on surfaces with intersection and boundary faces.
static ITstream & lookup(const dictionary &dict, const word &keyword, const bool noExit, enum keyType::option matchOpt=keyType::REGEX)
Wrapper around dictionary::lookup which does not exit.
void printMeshInfo(const bool debug, const string &msg, const bool printCellLevel) const
Print some mesh stats.
MeshType
Enumeration for how to operate.
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
static bitSet getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
static const Enum< MeshType > MeshTypeNames
static void testSyncPointList(const string &msg, const polyMesh &mesh, const List< scalar > &fld)
void checkData()
Debugging: check that all faces still obey start()>end().
void updateIntersections(const labelUList &changedFaces)
Find any intersection of surface. Store in surfaceIndex_.
void updateMesh(const mapPolyMesh &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
writeType
Enumeration for what to write. Used as a bit-pattern.
void doSplitFaces(const labelList &splitFaces, const labelPairList &splits, const labelPairList &splitPatches, polyTopoChange &meshMod) const
Split faces into two.
const labelList & surfaceIndex() const
Per start-end edge the index of the surface hit.
const shellSurfaces & limitShells() const
Reference to limit shells (regions).
labelList growFaceCellFace(const labelUList &set) const
void dumpRefinementLevel() const
Write refinement level as volScalarFields for postprocessing.
static const Enum< writeType > writeTypeNames
void distribute(const mapDistributePolyMesh &)
Update local numbering for mesh redistribution.
static void splitFace(const face &f, const labelPair &split, face &f0, face &f1)
Helper: split face into:
static label addPatch(fvMesh &, const word &name, const dictionary &)
Helper:add patch to mesh. Update all registered fields.
label countHits() const
Count number of intersections (local).
autoPtr< mapPolyMesh > doRemoveCells(const labelList &cellsToRemove, const labelList &exposedFaces, const labelList &exposedPatchIDs, removeCells &cellRemover)
Remove cells. Put exposedFaces into exposedPatchIDs.
@ KEEPALL
have slaves (upon refinement) from master
@ MASTERONLY
maintain master only
static FOAM_NO_DANGLING_REFERENCE const dictionary & subDict(const dictionary &dict, const word &keyword, const bool noExit, enum keyType::option matchOpt=keyType::REGEX)
Wrapper around dictionary::subDict which does not exit.
static label findCell(const polyMesh &, const vector &perturbVec, const point &p)
Find cell point is in. Uses optional perturbation to re-test.
const refinementSurfaces & surfaces() const
Reference to surface search engines.
word timeName() const
Replacement for Time::timeName() that returns oldInstance (if overwrite_).
debugType
Enumeration for what to debug. Used as a bit-pattern.
static bitSet getMasterEdges(const polyMesh &mesh, const labelList &meshEdges)
Determine master edge for subset of edges. If coupled.
const shellSurfaces & shells() const
Reference to refinement shells (regions).
labelList meshedPatches() const
Get patchIDs for patches added in addMeshedPatch.
static void checkCoupledFaceZones(const polyMesh &)
Helper function: check that face zones are synced.
labelList countEdgeFaces(const uindirectPrimitivePatch &pp) const
Count number of faces per patch edge. Parallel consistent.
autoPtr< mapPolyMesh > splitMeshRegions(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const pointField &locationsInMesh, const pointField &locationsOutsideMesh, const bool exitIfLeakPath, const refPtr< coordSetWriter > &leakPathFormatter)
Split mesh. Keep part containing point. Return empty map if.
label addMeshedPatch(const word &name, const dictionary &)
Add patch originating from meshing. Update meshedPatches_.
const fvMesh & mesh() const
Reference to mesh.
const refinementFeatures & features() const
Reference to feature edge mesh.
void testSyncBoundaryFaceList(const scalar mergeDistance, const string &, const UList< T > &, const UList< T > &) const
Compare two lists over all boundary faces.
void selectSeparatedCoupledFaces(boolList &) const
Select coupled faces that are not collocated.
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
static label findRegion(const polyMesh &, const labelList &cellRegion, const vector &perturbVec, const point &p)
Find region point is in. Uses optional perturbation to re-test.
label addPointZone(const word &name)
Add pointZone if does not exist. Return index of zone.
static label findRegions(const polyMesh &, const vector &perturbVec, const pointField &locationsInMesh, const pointField &locationsOutsideMesh, const label nRegions, labelList &cellRegion, const boolList &blockedFace, const bool exitIfLeakPath, const refPtr< coordSetWriter > &leakPathFormatter)
Find regions points are in.
scalar mergeDistance() const
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
void storeData(const labelList &pointsToStore, const labelList &facesToStore, const labelList &cellsToStore)
Signal points/face/cells for which to store data.
static void updateList(const labelList &newToOld, const T &nullValue, List< T > &elems)
Helper: reorder list according to map.
bool overwrite() const
Overwrite the mesh?
bool write() const
Write mesh and all data.
autoPtr< mapDistributePolyMesh > balance(const bool keepZoneFaces, const bool keepBaffles, const labelList &singleProcPoints, const scalarField &cellWeights, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Redecompose according to cell count.
label splitFacesUndo(const labelList &splitFaces, const labelPairList &splits, const labelPairList &splitPatches, const dictionary &motionDict, labelList &duplicateFace, List< labelPair > &baffles)
Split faces along diagonal. Maintain mesh quality. Return.
void setInstance(const fileName &)
Set instance of all local IOobjects.
static const Enum< debugType > debugTypeNames
static label appendPatch(fvMesh &, const label insertPatchi, const word &, const dictionary &)
Helper:append patch to end of mesh.
MeshType meshType() const
Mode of meshing.
static writeType writeLevel()
Get/set write level.
void dumpIntersections(const fileName &prefix) const
Debug: Write intersection information to OBJ format.
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search.
Definition meshSearch.H:57
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
A pointBoundaryMesh is a pointPatch list with registered IO, a reference to the associated pointMesh,...
Mesh representing a set of points created from polyMesh.
Definition pointMesh.H:49
const pointBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition pointMesh.H:177
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
void reorder(const labelUList &oldToNew, const bool validBoundary)
Reorders patches. Ordering does not have to be done in.
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
cellDecomposition
Enumeration defining the decomposition of the cell for.
Definition polyMesh.H:105
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh").
Definition polyMesh.H:411
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return pointer to a new patch created on freestore from components.
static bool constraintType(const word &patchType)
Return true if the given type is a constraint type.
Definition polyPatch.C:255
Direct mesh changes based on v1.3 polyTopoChange syntax.
const DynamicList< face > & faces() const
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip, const bool multiZone=false)
Modify vertices or cell of face.
void setCapacity(const label nPoints, const label nFaces, const label nCells)
Explicitly pre-size the dynamic storage for expected mesh size for if construct-without-mesh.
void removeFace(const label facei, const label mergeFacei)
Remove/merge face.
label addFace(const face &f, const label own, const label nei, const label masterPointID, const label masterEdgeID, const label masterFaceID, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip)
Add face to cells. Return new face label.
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.
const DynamicList< point > & points() const
Points. Shrunk after constructing mesh (or calling of compact()).
label nFaces() const noexcept
Number of mesh faces.
A class for managing references or pointers (no reference counting).
Definition refPtr.H:54
T & constCast() const
Return non-const reference to the object or to the contents of a (non-null) managed pointer,...
Definition refPtr.H:278
Encapsulates queries for features.
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
label nRegions() const
Return total number of regions.
Given list of cells to remove, insert all the topology changes.
Definition removeCells.H:60
labelList getExposedFaces(const bitSet &removedCell) const
Get labels of faces exposed after cells removal.
Definition removeCells.C:77
void setRefinement(const bitSet &removedCell, const labelUList &facesToExpose, const labelUList &patchIDs, polyTopoChange &) const
Play commands into polyTopoChange to remove cells.
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
Container for searchableSurfaces. The collection is specified as a dictionary. For example,...
Encapsulates queries for volume refinement ('refine all cells within shell').
Finds shortest path (in terms of cell centres) to walk on mesh from any point in insidePoints to any ...
faceZoneType
What to do with faceZone faces.
static label addFaceZone(const word &name, const labelList &addressing, const boolList &flipMap, polyMesh &mesh)
static bitSet getMasterFaces(const polyMesh &mesh)
Get per face whether it is uncoupled or a master of a coupled set of faces.
Definition syncTools.C:119
static void swapBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions, const bool parRun=UPstream::parRun())
Swap coupled positions. Uses eqOp.
Definition syncTools.H:545
static bitSet getMasterPoints(const polyMesh &mesh)
Get per point whether it is uncoupled or a master of a coupled set of points.
Definition syncTools.C:61
static void swapFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled face values. Uses eqOp.
Definition syncTools.H:567
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition syncTools.H:465
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 syncBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions, const CombineOp &cop)
Synchronize locations on boundary faces only.
Definition syncTools.H:445
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 class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
For use with FaceCellWave. Determines topological distance to starting faces. Templated on passive tr...
virtual bool found(const label id) const
Has the given index?
Definition topoSet.C:539
Standard boundBox with extra functionality for use in octree.
treeBoundBox extend(Random &rndGen, const scalar s) const
Return slightly wider bounding box.
void close()
End the file contents and close the file after writing.
virtual bool open(const fileName &file, bool parallel=UPstream::parRun())
Open file for writing (creates parent directory).
void write(const word &fieldName, const UList< Type > &field)
Write primitive field of CellData (Poly or Line) or PointData values.
A class for handling words, derived from Foam::string.
Definition word.H:66
const word & name() const noexcept
The zone name.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
volScalarField & p
const polyBoundaryMesh & patches
static bool split(const std::string &line, std::string &key, std::string &val)
Definition cpuInfo.C:32
bool coupled
dynamicFvMesh & mesh
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const auto & io
auto & name
const pointField & points
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const bitSet isBlockedFace(intersectedFaces())
static const Foam::polyMesh::cellDecomposition findCellMode(Foam::polyMesh::FACE_DIAG_TRIS)
word timeName
Definition getTimeIndex.H:3
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugVar(var)
Report a variable name and value.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
AccessType combine(const UList< T > &lists, AccessOp aop=accessOp< T >())
Combines sub-lists into a single list.
Definition ListListOps.C:62
const char * end
Definition SVGTools.H:223
Namespace for handling debugging switches.
Definition debug.C:45
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition meshTools.C:196
Namespace for OpenFOAM.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition POSIX.C:1406
List< edge > edgeList
List of edge.
Definition edgeList.H:32
Type weightedSum(const UList< scalar > &weights, const UList< Type > &fld)
The local weighted sum (integral) of a field, using the mag() of the weights.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
List< word > wordList
List of word.
Definition fileName.H:60
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
const dimensionSet dimless
Dimensionless.
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values within a list.
ZoneMesh< pointZone, polyMesh > pointZoneMesh
A ZoneMesh with pointZone content on a polyMesh.
List< labelPair > labelPairList
List of labelPair.
Definition labelPair.H:33
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
GeometricField< scalar, pointPatchField, pointMesh > pointScalarField
Map< label > invertToMap(const labelUList &values)
Create inverse mapping, which is a lookup table into the given list.
Definition ListOps.C:105
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition POSIX.C:837
List< label > labelList
A List of labels.
Definition List.H:62
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
GeometricField< scalar, fvPatchField, volMesh > volScalarField
messageStream Info
Information stream (stdout output on master, null elsewhere).
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with faceZone content on a polyMesh.
List< face > faceList
List of faces.
Definition faceListFwd.H:41
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
constexpr label labelMax
Definition label.H:55
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
List< point > pointList
List of point.
Definition pointList.H:32
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
errorManip< error > abort(error &err)
Definition errorManip.H:139
Field< vector > vectorField
Specialisation of Field<T> for vector.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
vector point
Point is a vector.
Definition point.H:37
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
vectorField pointField
pointField is a vectorField.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Vector< scalar > vector
Definition vector.H:57
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
List< scalar > scalarList
List of scalar.
Definition scalarList.H:32
Type gMax(const FieldField< Field, Type > &f)
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
runTime write()
labelList f(nPoints)
dictionary dict
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))
const pointField & pts
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
Object access operator or list access operator (default is pass-through).
Definition UList.H:1120
Random rndGen