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