Loading...
Searching...
No Matches
dynamicRefineFvMesh.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) 2018-2023 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 "dynamicRefineFvMesh.H"
31#include "surfaceInterpolate.H"
32#include "volFields.H"
33#include "polyTopoChange.H"
34#include "surfaceFields.H"
35#include "syncTools.H"
36#include "pointFields.H"
37#include "sigFpe.H"
38#include "cellSet.H"
39#include "HashOps.H"
41// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42
43namespace Foam
44{
45 defineTypeNameAndDebug(dynamicRefineFvMesh, 0);
47 addToRunTimeSelectionTable(dynamicFvMesh, dynamicRefineFvMesh, doInit);
48}
49
50// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
51
53(
54 bitSet& unrefineableCell
55) const
56{
58 {
59 unrefineableCell.clear();
60 return;
61 }
62
63 const labelList& cellLevel = meshCutter_.cellLevel();
64
65 unrefineableCell = protectedCell_;
66
67 // Get neighbouring cell level
68 labelList neiLevel(nBoundaryFaces());
69
70 for (label facei = nInternalFaces(); facei < nFaces(); ++facei)
71 {
72 neiLevel[facei-nInternalFaces()] = cellLevel[faceOwner()[facei]];
73 }
74 syncTools::swapBoundaryFaceList(*this, neiLevel);
75
76
77 bitSet seedFace;
78
79 while (true)
80 {
81 // Pick up faces on border of protected cells
82 seedFace.reset();
83 seedFace.resize(nFaces());
84
85 for (label facei = 0; facei < nInternalFaces(); ++facei)
86 {
87 const label own = faceOwner()[facei];
88 const label nei = faceNeighbour()[facei];
89
90 if
91 (
92 // Protected owner
93 (
94 unrefineableCell.test(own)
95 && (cellLevel[nei] > cellLevel[own])
96 )
97 ||
98 // Protected neighbour
99 (
100 unrefineableCell.test(nei)
101 && (cellLevel[own] > cellLevel[nei])
102 )
103 )
104 {
105 seedFace.set(facei);
106 }
107 }
108 for (label facei = nInternalFaces(); facei < nFaces(); facei++)
109 {
110 const label own = faceOwner()[facei];
111
112 if
113 (
114 // Protected owner
115 (
116 unrefineableCell.test(own)
117 && (neiLevel[facei-nInternalFaces()] > cellLevel[own])
118 )
119 )
120 {
121 seedFace.set(facei);
122 }
123 }
124
125 syncTools::syncFaceList(*this, seedFace, orEqOp<unsigned int>());
126
127
128 // Extend unrefineableCell
129 bool hasExtended = false;
130
131 for (label facei = 0; facei < nInternalFaces(); ++facei)
132 {
133 if (seedFace.test(facei))
134 {
135 if (unrefineableCell.set(faceOwner()[facei]))
136 {
137 hasExtended = true;
138 }
139 if (unrefineableCell.set(faceNeighbour()[facei]))
140 {
141 hasExtended = true;
142 }
143 }
144 }
145 for (label facei = nInternalFaces(); facei < nFaces(); ++facei)
146 {
147 if (seedFace.test(facei))
148 {
149 const label own = faceOwner()[facei];
150
151 if (unrefineableCell.set(own))
152 {
153 hasExtended = true;
154 }
155 }
156 }
157
158 if (!returnReduceOr(hasExtended))
160 break;
161 }
162 }
163}
164
165
167{
168 const dictionary refineDict
169 (
171 (
173 (
174 "dynamicMeshDict",
175 time().constant(),
176 *this,
180 )
181 ).optionalSubDict(typeName + "Coeffs")
182 );
183
184 auto fluxVelocities = refineDict.get<List<Pair<word>>>("correctFluxes");
185
186 // Rework into hashtable.
187 correctFluxes_.reserve(fluxVelocities.size());
188 for (const auto& pr : fluxVelocities)
189 {
190 correctFluxes_.insert(pr.first(), pr.second());
191 }
192
193 refineDict.readEntry("dumpLevel", dumpLevel_);
194}
195
196
197void Foam::dynamicRefineFvMesh::mapFields(const mapPolyMesh& mpm)
198{
199 //dynamicFvMesh::mapFields(mpm);
201
202
203 // Correct old-time volumes for refined/unrefined cells. We know at this
204 // point that the points have not moved and the cells have only been split
205 // or merged. We hope that dynamicMotionSolverListFvMesh::mapFields
206 // does not use old-time volumes ...
207 {
208 const labelList& cellMap = mpm.cellMap();
209 const labelList& reverseCellMap = mpm.reverseCellMap();
210
211 // Each split cell becomes original + 7 additional
212 labelList nSubCells(mpm.nOldCells(), 0);
213
214 forAll(cellMap, celli)
215 {
216 const label oldCelli = cellMap[celli];
217 if (oldCelli >= 0 && reverseCellMap[oldCelli] >= 0)
218 {
219 // Found master cell.
220 nSubCells[oldCelli]++;
221 }
222 }
223
224 // Start off from mapped old volumes
225 scalarField correctedV0(this->V0());
226
227 // Correct any split cells
228 const auto& V = this->V();
229 forAll(cellMap, celli)
230 {
231 const label oldCelli = cellMap[celli];
232 if (oldCelli >= 0 && nSubCells[oldCelli] == 8)
233 {
234 // Found split cell. Use current volume instead of mapped
235 // old one
236 correctedV0[celli] = V[celli];
237 }
238 }
239
240 const auto& cellsFromCells = mpm.cellsFromCellsMap();
241 for (const auto& s : cellsFromCells)
242 {
243 // Reset unsplit cell
244 const label celli = s.index();
245 correctedV0[celli] = V[celli];
246 //? Or sum up old volumes?
247 //const labelList& oldCells = s.masterObjects();
248 //for (const label oldCelli : oldCells)
249 //{
250 //}
251 }
252
253 setV0().field() = correctedV0;
254 }
255
256
257 // Correct the flux for modified/added faces. All the faces which only
258 // have been renumbered will already have been handled by the mapping.
259 {
260 const labelList& faceMap = mpm.faceMap();
261 const labelList& reverseFaceMap = mpm.reverseFaceMap();
262
263 // Storage for any master faces. These will be the original faces
264 // on the coarse cell that get split into four (or rather the
265 // master face gets modified and three faces get added from the master)
266 // Estimate number of faces created
267
268 bitSet masterFaces(nFaces());
269
270 forAll(faceMap, facei)
271 {
272 const label oldFacei = faceMap[facei];
273
274 if (oldFacei >= 0)
275 {
276 const label masterFacei = reverseFaceMap[oldFacei];
277
278 if (masterFacei < 0)
279 {
281 << "Problem: should not have removed faces"
282 << " when refining."
283 << nl << "face:" << facei << endl
284 << abort(FatalError);
285 }
286 else if (masterFacei != facei)
287 {
288 masterFaces.set(masterFacei);
289 }
290 }
291 }
292
293 if (debug)
294 {
295 Pout<< "Found " << masterFaces.count() << " split faces " << endl;
296 }
297
299 (
301 );
302
303 // Remove surfaceInterpolation to allow re-calculation on demand
304 // This could be done in fvMesh::updateMesh but some dynamicFvMesh
305 // might need the old interpolation fields (weights, etc).
307
308 for (surfaceScalarField& phi : fluxes)
309 {
310 const word& UName = correctFluxes_.lookup(phi.name(), word::null);
311
312 if (UName.empty())
313 {
315 << "Cannot find surfaceScalarField " << phi.name()
316 << " in user-provided flux mapping table "
317 << correctFluxes_ << endl
318 << " The flux mapping table is used to recreate the"
319 << " flux on newly created faces." << endl
320 << " Either add the entry if it is a flux or use ("
321 << phi.name() << " none) to suppress this warning."
322 << endl;
323 continue;
324 }
325 if (UName == "none")
326 {
327 continue;
328 }
329 if (UName == "NaN")
330 {
331 Pout<< "Setting surfaceScalarField " << phi.name()
332 << " to NaN" << endl;
333
334 sigFpe::fillNan(phi.primitiveFieldRef());
335 continue;
336 }
337
338 if (debug)
339 {
340 Pout<< "Mapping flux " << phi.name()
341 << " using interpolated flux " << UName
342 << endl;
343 }
344
345 const surfaceScalarField phiU
346 (
348 (
349 lookupObject<volVectorField>(UName)
350 )
351 & Sf()
352 );
353
354 // Recalculate new internal faces.
355 for (label facei = 0; facei < nInternalFaces(); ++facei)
356 {
357 const label oldFacei = faceMap[facei];
358
359 if (oldFacei == -1)
360 {
361 // Inflated/appended
362 phi[facei] = phiU[facei];
363 }
364 else if (reverseFaceMap[oldFacei] != facei)
365 {
366 // face-from-masterface
367 phi[facei] = phiU[facei];
368 }
369 }
370
371 // Recalculate new boundary faces.
372 auto& phiBf = phi.boundaryFieldRef();
373
374 forAll(phiBf, patchi)
375 {
376 fvsPatchScalarField& patchPhi = phiBf[patchi];
377 const fvsPatchScalarField& patchPhiU =
378 phiU.boundaryField()[patchi];
379
380 label facei = patchPhi.patch().start();
381
382 forAll(patchPhi, i)
383 {
384 const label oldFacei = faceMap[facei];
385
386 if (oldFacei == -1)
387 {
388 // Inflated/appended
389 patchPhi[i] = patchPhiU[i];
390 }
391 else if (reverseFaceMap[oldFacei] != facei)
392 {
393 // face-from-masterface
394 patchPhi[i] = patchPhiU[i];
395 }
396
397 ++facei;
398 }
399 }
400
401 // Update master faces
402 for (const label facei : masterFaces)
403 {
404 if (isInternalFace(facei))
405 {
406 phi[facei] = phiU[facei];
407 }
408 else
409 {
410 const label patchi = boundaryMesh().whichPatch(facei);
411 const label i = facei - boundaryMesh()[patchi].start();
412
413 const fvsPatchScalarField& patchPhiU =
414 phiU.boundaryField()[patchi];
415
416 fvsPatchScalarField& patchPhi = phiBf[patchi];
417
418 patchPhi[i] = patchPhiU[i];
419 }
420 }
421 }
422 }
423
424 // Correct the flux for injected faces - these are the faces which have
425 // no correspondence to the old mesh (i.e. added without a masterFace, edge
426 // or point). An example is the internal faces from hexRef8.
427 {
428 const labelList& faceMap = mpm.faceMap();
429
430 mapNewInternalFaces<scalar>(this->Sf(), this->magSf(), faceMap);
431 mapNewInternalFaces<vector>(this->Sf(), this->magSf(), faceMap);
432
433 // No oriented fields of more complex type
434 mapNewInternalFaces<sphericalTensor>(faceMap);
435 mapNewInternalFaces<symmTensor>(faceMap);
437 }
438}
439
440
441// Refines cells, maps fields and recalculates (an approximate) flux
444(
445 const labelList& cellsToRefine
446)
447{
448 // Mesh changing engine.
449 polyTopoChange meshMod(*this);
450
451 // Play refinement commands into mesh changer.
452 meshCutter_.setRefinement(cellsToRefine, meshMod);
453
454 // Create mesh (with inflation), return map from old to new mesh.
455 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
456
457 // Clear moving flag. This is currently required since geometry calculation
458 // might get triggered when doing processor patches.
459 // (TBD: should be in changeMesh if no inflation?)
460 moving(false);
461 // Create mesh (no inflation), return map from old to new mesh.
462 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
463
464 Info<< "Refined from "
465 << returnReduce(map().nOldCells(), sumOp<label>())
466 << " to " << globalData().nTotalCells() << " cells." << endl;
467
468 if (debug)
469 {
470 // Check map.
471 for (label facei = 0; facei < nInternalFaces(); ++facei)
472 {
473 const label oldFacei = map().faceMap()[facei];
474
475 if (oldFacei >= nInternalFaces())
476 {
478 << "New internal face:" << facei
479 << " fc:" << faceCentres()[facei]
480 << " originates from boundary oldFace:" << oldFacei
481 << abort(FatalError);
482 }
483 }
484 }
485
486 // // Remove the stored tet base points
487 // tetBasePtIsPtr_.clear();
488 // // Remove the cell tree
489 // cellTreePtr_.clear();
490
491 // Update fields
492 updateMesh(*map);
493
494
495 // Move mesh
496 /*
497 pointField newPoints;
498 if (map().hasMotionPoints())
499 {
500 newPoints = map().preMotionPoints();
501 }
502 else
503 {
504 newPoints = points();
505 }
506 movePoints(newPoints);
507 */
508
509
510
511 // Update numbering of cells/vertices.
512 meshCutter_.updateMesh(*map);
513
514 // Update numbering of protectedCell_
515 if (protectedCell_.size())
516 {
517 bitSet newProtectedCell(nCells());
518
519 forAll(newProtectedCell, celli)
520 {
521 const label oldCelli = map().cellMap()[celli];
522 if (protectedCell_.test(oldCelli))
523 {
524 newProtectedCell.set(celli);
525 }
526 }
527 protectedCell_.transfer(newProtectedCell);
528 }
529
530 // Debug: Check refinement levels (across faces only)
531 meshCutter_.checkRefinementLevels(-1, labelList());
532
533 return map;
534}
535
536
539(
540 const labelList& splitPoints
541)
542{
543 polyTopoChange meshMod(*this);
544
545 // Play refinement commands into mesh changer.
546 meshCutter_.setUnrefinement(splitPoints, meshMod);
547
548
549 // Save information on faces that will be combined
550 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
551
552 // Find the faceMidPoints on cells to be combined.
553 // for each face resulting of split of face into four store the
554 // midpoint
555 Map<label> faceToSplitPoint(3*splitPoints.size());
556
557 {
558 for (const label pointi : splitPoints)
559 {
560 const labelList& pEdges = pointEdges()[pointi];
561
562 for (const label edgei : pEdges)
563 {
564 const label otherPointi = edges()[edgei].otherVertex(pointi);
565
566 const labelList& pFaces = pointFaces()[otherPointi];
567
568 for (const label facei : pFaces)
569 {
570 faceToSplitPoint.insert(facei, otherPointi);
571 }
572 }
573 }
574 }
575
576
577 // Change mesh and generate map.
578 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
579
580 // Clear moving flag. This is currently required since geometry calculation
581 // might get triggered when doing processor patches.
582 // (TBD: should be in changeMesh if no inflation?)
583 moving(false);
584 // Create mesh (no inflation), return map from old to new mesh.
585 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
586
587 Info<< "Unrefined from "
588 << returnReduce(map().nOldCells(), sumOp<label>())
589 << " to " << globalData().nTotalCells() << " cells."
590 << endl;
591
592 // Update fields
593 updateMesh(*map);
594
595
596 // Move mesh
597 /*
598 pointField newPoints;
599 if (map().hasMotionPoints())
600 {
601 newPoints = map().preMotionPoints();
602 }
603 else
604 {
605 newPoints = points();
606 }
607 movePoints(newPoints);
608 */
609
610 // Correct the flux for modified faces.
611 {
612 const labelList& reversePointMap = map().reversePointMap();
613 const labelList& reverseFaceMap = map().reverseFaceMap();
614
615 UPtrList<surfaceScalarField> fluxes
616 (
618 );
619
620 for (surfaceScalarField& phi : fluxes)
621 {
622 const word& UName = correctFluxes_.lookup(phi.name(), word::null);
623
624 if (UName.empty())
625 {
627 << "Cannot find surfaceScalarField " << phi.name()
628 << " in user-provided flux mapping table "
629 << correctFluxes_ << endl
630 << " The flux mapping table is used to recreate the"
631 << " flux on newly created faces." << endl
632 << " Either add the entry if it is a flux or use ("
633 << phi.name() << " none) to suppress this warning."
634 << endl;
635 continue;
636 }
637 if (UName == "none")
638 {
639 continue;
640 }
641
643 << "Mapping flux " << phi.name()
644 << " using interpolated flux " << UName
645 << endl;
646
647 auto& phiBf = phi.boundaryFieldRef();
648
649 const surfaceScalarField phiU
650 (
652 (
653 lookupObject<volVectorField>(UName)
654 )
655 & Sf()
656 );
657
658
659 forAllConstIters(faceToSplitPoint, iter)
660 {
661 const label oldFacei = iter.key();
662 const label oldPointi = iter.val();
663
664 if (reversePointMap[oldPointi] < 0)
665 {
666 // midpoint was removed. See if face still exists.
667 const label facei = reverseFaceMap[oldFacei];
668
669 if (facei >= 0)
670 {
671 if (isInternalFace(facei))
672 {
673 phi[facei] = phiU[facei];
674 }
675 else
676 {
677 label patchi = boundaryMesh().whichPatch(facei);
678 label i = facei - boundaryMesh()[patchi].start();
679
680 const fvsPatchScalarField& patchPhiU =
681 phiU.boundaryField()[patchi];
682 fvsPatchScalarField& patchPhi = phiBf[patchi];
683 patchPhi[i] = patchPhiU[i];
684 }
685 }
686 }
687 }
688 }
689 }
690
691
692 // Update numbering of cells/vertices.
693 meshCutter_.updateMesh(*map);
694
695 // Update numbering of protectedCell_
696 if (protectedCell_.size())
697 {
698 bitSet newProtectedCell(nCells());
699
700 forAll(newProtectedCell, celli)
701 {
702 const label oldCelli = map().cellMap()[celli];
703 if (protectedCell_.test(oldCelli))
704 {
705 newProtectedCell.set(celli);
706 }
707 }
708 protectedCell_.transfer(newProtectedCell);
709 }
710
711 // Debug: Check refinement levels (across faces only)
712 meshCutter_.checkRefinementLevels(-1, labelList());
713
714 return map;
715}
716
717
720{
721 scalarField vFld(nCells(), -GREAT);
722
723 forAll(pointCells(), pointi)
724 {
725 const labelList& pCells = pointCells()[pointi];
726
727 for (const label celli : pCells)
728 {
729 vFld[celli] = max(vFld[celli], pFld[pointi]);
731 }
732 return vFld;
733}
734
735
738{
739 scalarField pFld(nPoints(), -GREAT);
740
741 forAll(pointCells(), pointi)
742 {
743 const labelList& pCells = pointCells()[pointi];
744
745 for (const label celli : pCells)
746 {
747 pFld[pointi] = max(pFld[pointi], vFld[celli]);
749 }
750 return pFld;
751}
752
753
756{
757 scalarField pFld(nPoints());
758
759 forAll(pointCells(), pointi)
760 {
761 const labelList& pCells = pointCells()[pointi];
762
763 scalar sum = 0.0;
764 for (const label celli : pCells)
765 {
766 sum += vFld[celli];
768 pFld[pointi] = sum/pCells.size();
769 }
770 return pFld;
771}
772
773
775(
776 const scalarField& fld,
777 const scalar minLevel,
778 const scalar maxLevel
779) const
780{
781 scalarField c(fld.size(), scalar(-1));
782
783 forAll(fld, i)
784 {
785 scalar err = min(fld[i]-minLevel, maxLevel-fld[i]);
786
787 if (err >= 0)
788 {
789 c[i] = err;
790 }
791 }
792 return c;
793}
794
795
797(
798 const scalar lowerRefineLevel,
799 const scalar upperRefineLevel,
800 const scalarField& vFld,
801 bitSet& candidateCell
802) const
803{
804 // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
805 // higher more desirable to be refined).
806 scalarField cellError
807 (
808 maxPointField
809 (
810 error
811 (
812 cellToPoint(vFld),
813 lowerRefineLevel,
814 upperRefineLevel
815 )
816 )
817 );
818
819 // Mark cells that are candidates for refinement.
820 forAll(cellError, celli)
821 {
822 if (cellError[celli] > 0)
824 candidateCell.set(celli);
825 }
826 }
827}
828
829
831(
832 const label maxCells,
833 const label maxRefinement,
834 const bitSet& candidateCell
835) const
836{
837 // Every refined cell causes 7 extra cells
838 label nTotToRefine = (maxCells - globalData().nTotalCells()) / 7;
839
840 const labelList& cellLevel = meshCutter_.cellLevel();
841
842 // Mark cells that cannot be refined since they would trigger refinement
843 // of protected cells (since 2:1 cascade)
844 bitSet unrefineableCell;
845 calculateProtectedCells(unrefineableCell);
846
847 // Count current selection
848 label nLocalCandidates = candidateCell.count();
849 label nCandidates = returnReduce(nLocalCandidates, sumOp<label>());
850
851 // Collect all cells
852 DynamicList<label> candidates(nLocalCandidates);
853
854 if (nCandidates < nTotToRefine)
855 {
856 for (const label celli : candidateCell)
857 {
858 if
859 (
860 (!unrefineableCell.test(celli))
861 && cellLevel[celli] < maxRefinement
862 )
863 {
864 candidates.append(celli);
865 }
866 }
867 }
868 else
869 {
870 // Sort by error? For now just truncate.
871 for (label level = 0; level < maxRefinement; ++level)
872 {
873 for (const label celli : candidateCell)
874 {
875 if
876 (
877 (!unrefineableCell.test(celli))
878 && cellLevel[celli] == level
879 )
880 {
881 candidates.append(celli);
882 }
883 }
884
885 if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
886 {
887 break;
888 }
889 }
890 }
891
892 // Guarantee 2:1 refinement after refinement
893 labelList consistentSet
894 (
895 meshCutter_.consistentRefinement
896 (
897 candidates.shrink(),
898 true // Add to set to guarantee 2:1
899 )
900 );
901
902 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
903 << " cells for refinement out of " << globalData().nTotalCells()
904 << "." << endl;
905
906 return consistentSet;
907}
908
909
911(
912 const scalar unrefineLevel,
913 const bitSet& markedCell,
914 const scalarField& pFld
915) const
916{
917 // All points that can be unrefined
918 const labelList splitPoints(meshCutter_.getSplitPoints());
919
920
921 const labelListList& pointCells = this->pointCells();
922
923 // If we have any protected cells make sure they also are not being
924 // unrefined
925
926 bitSet protectedPoint(nPoints());
927
928 if (protectedCell_.size())
929 {
930 // Get all points on a protected cell
931 forAll(pointCells, pointi)
932 {
933 for (const label celli : pointCells[pointi])
934 {
935 if (protectedCell_.test(celli))
936 {
937 protectedPoint.set(pointi);
938 break;
939 }
940 }
941 }
942
944 (
945 *this,
946 protectedPoint,
948 0u
949 );
950
951 DebugInfo<< "From "
952 << returnReduce(protectedCell_.count(), sumOp<label>())
953 << " protected cells found "
954 << returnReduce(protectedPoint.count(), sumOp<label>())
955 << " protected points." << endl;
956 }
957
958
959 DynamicList<label> newSplitPoints(splitPoints.size());
960
961 for (const label pointi : splitPoints)
962 {
963 if (!protectedPoint[pointi] && pFld[pointi] < unrefineLevel)
964 {
965 // Check that all cells are not marked
966 bool hasMarked = false;
967
968 for (const label celli : pointCells[pointi])
969 {
970 if (markedCell.test(celli))
971 {
972 hasMarked = true;
973 break;
974 }
975 }
976
977 if (!hasMarked)
978 {
979 newSplitPoints.append(pointi);
980 }
981 }
982 }
983
984
985 newSplitPoints.shrink();
986
987 // Guarantee 2:1 refinement after unrefinement
988 labelList consistentSet
989 (
990 meshCutter_.consistentUnrefinement
991 (
992 newSplitPoints,
993 false
994 )
995 );
996 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
997 << " split points out of a possible "
998 << returnReduce(splitPoints.size(), sumOp<label>())
999 << "." << endl;
1000
1001 return consistentSet;
1002}
1003
1004
1006(
1007 bitSet& markedCell
1008) const
1009{
1010 // Mark faces using any marked cell
1011 bitSet markedFace(nFaces());
1012
1013 for (const label celli : markedCell)
1014 {
1015 markedFace.set(cells()[celli]); // set multiple faces
1016 }
1017
1018 syncTools::syncFaceList(*this, markedFace, orEqOp<unsigned int>());
1019
1020 // Update cells using any markedFace
1021 for (label facei = 0; facei < nInternalFaces(); ++facei)
1022 {
1023 if (markedFace.test(facei))
1024 {
1025 markedCell.set(faceOwner()[facei]);
1026 markedCell.set(faceNeighbour()[facei]);
1027 }
1028 }
1029 for (label facei = nInternalFaces(); facei < nFaces(); ++facei)
1030 {
1031 if (markedFace.test(facei))
1033 markedCell.set(faceOwner()[facei]);
1034 }
1035 }
1036}
1037
1038
1040(
1041 bitSet& protectedCell
1042) const
1043{
1044 const labelList& cellLevel = meshCutter_.cellLevel();
1045 const labelList& pointLevel = meshCutter_.pointLevel();
1046
1047 labelList nAnchorPoints(nCells(), Zero);
1048
1049 forAll(pointLevel, pointi)
1050 {
1051 const labelList& pCells = pointCells(pointi);
1052
1053 for (const label celli : pCells)
1054 {
1055 if (pointLevel[pointi] <= cellLevel[celli])
1056 {
1057 // Check if cell has already 8 anchor points -> protect cell
1058 if (nAnchorPoints[celli] == 8)
1059 {
1060 protectedCell.set(celli);
1061 }
1062
1063 if (!protectedCell.test(celli))
1064 {
1065 ++nAnchorPoints[celli];
1066 }
1067 }
1068 }
1069 }
1070
1071
1072 forAll(protectedCell, celli)
1073 {
1074 if (nAnchorPoints[celli] != 8)
1075 {
1076 protectedCell.set(celli);
1078 }
1079}
1080
1081
1082// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1083
1084Foam::dynamicRefineFvMesh::dynamicRefineFvMesh
1085(
1086 const IOobject& io,
1087 const bool doInit
1088)
1089:
1090 //dynamicFvMesh(io, doInit),
1092 meshCutter_(*this)
1093{
1094 if (doInit)
1095 {
1096 init(false); // do not initialise lower levels
1097 }
1098}
1099
1100
1101bool Foam::dynamicRefineFvMesh::init(const bool doInit)
1102{
1103 if (doInit)
1104 {
1105 //dynamicFvMesh::init(doInit);
1106 // Note: allow zero motion solvers
1108 }
1109
1110 protectedCell_.setSize(nCells());
1111 nRefinementIterations_ = 0;
1112 dumpLevel_ = false;
1113
1114 // Read static part of dictionary
1115 readDict();
1116
1117
1118 const labelList& cellLevel = meshCutter_.cellLevel();
1119 const labelList& pointLevel = meshCutter_.pointLevel();
1120
1121 // Set cells that should not be refined.
1122 // This is currently any cell which does not have 8 anchor points or
1123 // uses any face which does not have 4 anchor points.
1124 // Note: do not use cellPoint addressing
1125
1126 // Count number of points <= cellLevel
1127 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1128
1129 labelList nAnchors(nCells(), Zero);
1130
1131 forAll(pointCells(), pointi)
1132 {
1133 const labelList& pCells = pointCells()[pointi];
1134
1135 for (const label celli : pCells)
1136 {
1137 if (!protectedCell_.test(celli))
1138 {
1139 if (pointLevel[pointi] <= cellLevel[celli])
1140 {
1141 ++nAnchors[celli];
1142
1143 if (nAnchors[celli] > 8)
1144 {
1145 protectedCell_.set(celli);
1146 }
1147 }
1148 }
1149 }
1150 }
1151
1152
1153 // Count number of points <= faceLevel
1154 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1155 // Bit tricky since proc face might be one more refined than the owner since
1156 // the coupled one is refined.
1157
1158 {
1159 labelList neiLevel(nFaces());
1160
1161 for (label facei = 0; facei < nInternalFaces(); ++facei)
1162 {
1163 neiLevel[facei] = cellLevel[faceNeighbour()[facei]];
1164 }
1165 for (label facei = nInternalFaces(); facei < nFaces(); ++facei)
1166 {
1167 neiLevel[facei] = cellLevel[faceOwner()[facei]];
1168 }
1169 syncTools::swapFaceList(*this, neiLevel);
1170
1171
1172 bitSet protectedFace(nFaces());
1173
1174 forAll(faceOwner(), facei)
1175 {
1176 const label faceLevel = max
1177 (
1178 cellLevel[faceOwner()[facei]],
1179 neiLevel[facei]
1180 );
1181
1182 const face& f = faces()[facei];
1183
1184 label nAnchors = 0;
1185
1186 for (const label pointi : f)
1187 {
1188 if (pointLevel[pointi] <= faceLevel)
1189 {
1190 ++nAnchors;
1191
1192 if (nAnchors > 4)
1193 {
1194 protectedFace.set(facei);
1195 break;
1196 }
1197 }
1198 }
1199 }
1200
1201 syncTools::syncFaceList(*this, protectedFace, orEqOp<unsigned int>());
1202
1203 for (label facei = 0; facei < nInternalFaces(); ++facei)
1204 {
1205 if (protectedFace.test(facei))
1206 {
1207 protectedCell_.set(faceOwner()[facei]);
1208 protectedCell_.set(faceNeighbour()[facei]);
1209 }
1210 }
1211 for (label facei = nInternalFaces(); facei < nFaces(); ++facei)
1212 {
1213 if (protectedFace.test(facei))
1214 {
1215 protectedCell_.set(faceOwner()[facei]);
1216 }
1217 }
1218
1219 // Also protect any cells that are less than hex
1220 forAll(cells(), celli)
1221 {
1222 const cell& cFaces = cells()[celli];
1223
1224 if (cFaces.size() < 6)
1225 {
1226 protectedCell_.set(celli);
1227 }
1228 else
1229 {
1230 for (const label cfacei : cFaces)
1231 {
1232 if (faces()[cfacei].size() < 4)
1233 {
1234 protectedCell_.set(celli);
1235 break;
1236 }
1237 }
1238 }
1239 }
1240
1241 // Check cells for 8 corner points
1242 checkEightAnchorPoints(protectedCell_);
1243 }
1244
1245 if (!returnReduceOr(protectedCell_.any()))
1246 {
1247 protectedCell_.clear();
1248 }
1249 else
1250 {
1251 cellSet protectedCells
1252 (
1253 *this,
1254 "protectedCells",
1255 HashSetOps::used(protectedCell_)
1256 );
1257
1258 Info<< "Detected "
1259 << returnReduce(protectedCells.size(), sumOp<label>())
1260 << " cells that are protected from refinement."
1261 << " Writing these to cellSet "
1262 << protectedCells.name()
1263 << "." << endl;
1264
1265 protectedCells.write();
1266 }
1268 return true;
1269}
1270
1271
1272// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1273
1275{
1276 // Re-read dictionary. Chosen since usually -small so trivial amount
1277 // of time compared to actual refinement. Also very useful to be able
1278 // to modify on-the-fly.
1279 dictionary refineDict
1280 (
1282 (
1283 IOobject
1284 (
1285 "dynamicMeshDict",
1286 time().constant(),
1287 *this,
1291 )
1292 ).optionalSubDict(typeName + "Coeffs")
1293 );
1294
1295 const label refineInterval = refineDict.get<label>("refineInterval");
1296
1297 bool hasChanged = false;
1298
1299 if (refineInterval == 0)
1300 {
1301 topoChanging(hasChanged);
1302
1303 return false;
1304 }
1305 else if (refineInterval < 0)
1306 {
1308 << "Illegal refineInterval " << refineInterval << nl
1309 << "The refineInterval setting in the dynamicMeshDict should"
1310 << " be >= 1." << nl
1311 << exit(FatalError);
1312 }
1313
1314
1315 // Note: cannot refine at time 0 since no V0 present since mesh not
1316 // moved yet.
1317
1318 if (time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0)
1319 {
1320 const label maxCells = refineDict.get<label>("maxCells");
1321
1322 if (maxCells <= 0)
1323 {
1325 << "Illegal maximum number of cells " << maxCells << nl
1326 << "The maxCells setting in the dynamicMeshDict should"
1327 << " be > 0." << nl
1328 << exit(FatalError);
1329 }
1330
1331 const label maxRefinement = refineDict.get<label>("maxRefinement");
1332
1333 if (maxRefinement <= 0)
1334 {
1336 << "Illegal maximum refinement level " << maxRefinement << nl
1337 << "The maxCells setting in the dynamicMeshDict should"
1338 << " be > 0." << nl
1339 << exit(FatalError);
1340 }
1341
1342 const word fieldName(refineDict.get<word>("field"));
1343
1344 const volScalarField& vFld = lookupObject<volScalarField>(fieldName);
1345
1346 const scalar lowerRefineLevel =
1347 refineDict.get<scalar>("lowerRefineLevel");
1348 const scalar upperRefineLevel =
1349 refineDict.get<scalar>("upperRefineLevel");
1350 const scalar unrefineLevel = refineDict.getOrDefault<scalar>
1351 (
1352 "unrefineLevel",
1353 GREAT
1354 );
1355 const label nBufferLayers = refineDict.get<label>("nBufferLayers");
1356
1357 // Cells marked for refinement or otherwise protected from unrefinement.
1358 bitSet refineCell(nCells());
1359
1360 // Determine candidates for refinement (looking at field only)
1361 selectRefineCandidates
1362 (
1363 lowerRefineLevel,
1364 upperRefineLevel,
1365 vFld,
1367 );
1368
1369 if (globalData().nTotalCells() < maxCells)
1370 {
1371 // Select subset of candidates. Take into account max allowable
1372 // cells, refinement level, protected cells.
1373 labelList cellsToRefine
1374 (
1375 selectRefineCells
1376 (
1377 maxCells,
1378 maxRefinement,
1380 )
1381 );
1382
1383 if (returnReduceOr(cellsToRefine.size()))
1384 {
1385 // Refine/update mesh and map fields
1386 autoPtr<mapPolyMesh> map = refine(cellsToRefine);
1387
1388 // Update refineCell. Note that some of the marked ones have
1389 // not been refined due to constraints.
1390 {
1391 const labelList& cellMap = map().cellMap();
1392 const labelList& reverseCellMap = map().reverseCellMap();
1393
1394 bitSet newRefineCell(cellMap.size());
1395
1396 forAll(cellMap, celli)
1397 {
1398 const label oldCelli = cellMap[celli];
1399
1400 if
1401 (
1402 (oldCelli < 0)
1403 || (reverseCellMap[oldCelli] != celli)
1404 || (refineCell.test(oldCelli))
1405 )
1406 {
1407 newRefineCell.set(celli);
1408 }
1409 }
1410 refineCell.transfer(newRefineCell);
1411 }
1412
1413 // Extend with a buffer layer to prevent neighbouring points
1414 // being unrefined.
1415 for (label i = 0; i < nBufferLayers; ++i)
1416 {
1417 extendMarkedCells(refineCell);
1418 }
1419
1420 hasChanged = true;
1421 }
1422 }
1423
1424
1425 {
1426 // Select unrefineable points that are not marked in refineCell
1427 labelList pointsToUnrefine
1428 (
1429 selectUnrefinePoints
1430 (
1431 unrefineLevel,
1432 refineCell,
1433 maxCellField(vFld)
1434 )
1435 );
1436
1437 if (returnReduceOr(pointsToUnrefine.size()))
1438 {
1439 // Refine/update mesh
1440 unrefine(pointsToUnrefine);
1441
1442 hasChanged = true;
1443 }
1444 }
1445
1446
1447 if ((nRefinementIterations_ % 10) == 0)
1448 {
1449 // Compact refinement history occasionally (how often?).
1450 // Unrefinement causes holes in the refinementHistory.
1451 const_cast<refinementHistory&>(meshCutter().history()).compact();
1452 }
1453 nRefinementIterations_++;
1454 }
1455
1456 topoChanging(hasChanged);
1457 if (hasChanged)
1458 {
1459 // Reset moving flag (if any). If not using inflation we'll not move,
1460 // if are using inflation any follow on movePoints will set it.
1461 moving(false);
1462 }
1463
1464 return hasChanged;
1465}
1466
1467
1469{
1470 bool hasChanged = updateTopology();
1471 // Do any mesh motion (resets mesh.moving() if it does any mesh motion)
1472 hasChanged = dynamicMotionSolverListFvMesh::update() && hasChanged;
1473
1474 return hasChanged;
1475}
1476
1477
1479(
1480 IOstreamOption streamOpt,
1481 const bool writeOnProc
1482) const
1483{
1484 // Force refinement data to go to the current time directory.
1485 const_cast<hexRef8&>(meshCutter_).setInstance(time().timeName());
1486
1487 bool writeOk =
1488 (
1489 //dynamicFvMesh::writeObject(streamOpt, writeOnProc)
1490 dynamicMotionSolverListFvMesh::writeObject(streamOpt, writeOnProc)
1491 && meshCutter_.write(writeOnProc)
1492 );
1493
1494 if (dumpLevel_)
1495 {
1496 volScalarField scalarCellLevel
1497 (
1498 IOobject
1499 (
1500 "cellLevel",
1501 time().timeName(),
1502 *this,
1506 ),
1507 *this,
1509 );
1510
1511 const labelList& cellLevel = meshCutter_.cellLevel();
1512
1513 forAll(cellLevel, celli)
1514 {
1515 scalarCellLevel[celli] = cellLevel[celli];
1516 }
1517
1518 writeOk = writeOk && scalarCellLevel.write();
1519 }
1520
1521 return writeOk;
1522}
1523
1524
1525// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
const word UName(propsDict.getOrDefault< word >("U", "U"))
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
DynamicList< T, SizeMin > & shrink()
Calls shrink_to_fit() and returns a reference to the DynamicList.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition HashTableI.H:152
label size() const noexcept
Definition HashTable.H:358
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
@ NO_REGISTER
Do not request registration (bool: false).
@ NO_READ
Nothing to be read.
@ MUST_READ
Reading required.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
const word & name() const noexcept
Return the object name.
Definition IOobjectI.H:205
A simple container for options an IOstream can normally have.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition PackedList.H:387
void resize(const label numElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
void clear()
Clear the list, i.e. set addressable size to zero.
void reset()
Clear all bits but do not adjust the addressable size.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition UPtrList.H:101
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
unsigned int count(const bool on=true) const
Count number of bits set.
Definition bitSetI.H:420
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition bitSet.H:334
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
A collection of cell labels.
Definition cellSet.H:50
A topoSetPointSource to select all the points from given cellSet(s).
A cell is defined as a list of faces with extra functionality.
Definition cell.H:56
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
const dictionary & optionalSubDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary, otherwise return this dictionary.
Definition dictionary.C:560
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, IOobjectOption::readOption readOpt=IOobjectOption::MUST_READ) const
Find entry and assign to T val. FatalIOError if it is found and the number of tokens is incorrect,...
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
Abstract base class for geometry and/or topology changing fvMesh.
Dynamic mesh able to handle multiple motion solvers. NOTE: If the word entry "solvers" is not found i...
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
virtual bool update()
Update the mesh for both mesh motion and topology change.
virtual void mapFields(const mapPolyMesh &mpm)
Map all fields in time using given map. Triggered by topo change.
A fvMesh with built-in refinement.
virtual bool writeObject(IOstreamOption streamOpt, const bool writeOnProc) const
Write using stream options.
void readDict()
Read the projection parameters from dictionary.
scalarField error(const scalarField &fld, const scalar minLevel, const scalar maxLevel) const
scalarField cellToPoint(const scalarField &vFld) const
bool updateTopology()
Update topology (refinement, unrefinement).
void mapNewInternalFaces(const labelList &faceMap, GeometricField< T, fvsPatchField, surfaceMesh > &)
Map single non-flux surface<Type>Field.
hexRef8 meshCutter_
Mesh cutting engine.
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
const hexRef8 & meshCutter() const
Direct access to the refinement engine.
virtual autoPtr< mapPolyMesh > refine(const labelList &)
Refine cells. Update mesh and fields.
HashTable< word > correctFluxes_
Fluxes to map.
scalarField maxPointField(const scalarField &) const
Get per cell max of connected point.
bool dumpLevel_
Dump cellLevel for post-processing.
void calculateProtectedCells(bitSet &unrefineableCell) const
Calculate cells that cannot be refined since would trigger.
virtual labelList selectRefineCells(const label maxCells, const label maxRefinement, const bitSet &candidateCell) const
Subset candidate cells for refinement.
bitSet protectedCell_
Protected cells (usually since not hexes).
label nRefinementIterations_
Number of refinement/unrefinement steps done so far.
const bitSet & protectedCell() const
Cells which should not be refined/unrefined.
virtual bool update()
Update the mesh for both mesh motion and topology change.
virtual void selectRefineCandidates(const scalar lowerRefineLevel, const scalar upperRefineLevel, const scalarField &vFld, bitSet &candidateCell) const
Select candidate cells for refinement.
scalarField maxCellField(const volScalarField &) const
Get point max of connected cell.
virtual labelList selectUnrefinePoints(const scalar unrefineLevel, const bitSet &markedCell, const scalarField &pFld) const
Select points that can be unrefined.
void extendMarkedCells(bitSet &markedCell) const
Extend markedCell with cell-face-cell.
virtual void mapFields(const mapPolyMesh &mpm)
Map all fields in time using given map.
virtual autoPtr< mapPolyMesh > unrefine(const labelList &)
Unrefine cells. Gets passed in centre points of cells to combine.
void checkEightAnchorPoints(bitSet &protectedCell) const
Check all cells have 8 anchor points.
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition error.H:74
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
virtual bool writeObject(IOstreamOption streamOpt, const bool writeOnProc) const
Write the underlying polyMesh and other data.
Definition fvMesh.C:1045
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
DimensionedField< scalar, volMesh > & setV0()
Return old-time cell volumes.
const Time & time() const
Return the top-level database.
Definition fvMesh.H:360
const surfaceScalarField & phi() const
Return cell face motion fluxes.
const DimensionedField< scalar, volMesh > & V0() const
Return old-time cell volumes.
virtual void updateMesh(const mapPolyMesh &mpm)
Update mesh corresponding to the given map.
Definition fvMesh.C:960
const surfaceVectorField & Sf() const
Return cell face area vectors.
const surfaceScalarField & magSf() const
Return cell face area magnitudes.
label start() const noexcept
The patch start within the polyMesh face list.
Definition fvPatch.H:226
const fvPatch & patch() const noexcept
Return the patch.
Refinement of (split) hexes using polyTopoChange.
Definition hexRef8.H:63
const labelIOList & cellLevel() const
Definition hexRef8.H:481
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseCellMap() const noexcept
Reverse cell map.
label nOldCells() const noexcept
Number of old cells.
const List< objectMap > & cellsFromCellsMap() const noexcept
Cells originating from cells.
const labelList & reverseFaceMap() const noexcept
Reverse face map.
const labelList & faceMap() const noexcept
Old face map.
const labelList & cellMap() const noexcept
Old cell map.
Cuts (splits) cells.
Definition meshCutter.H:137
UPtrList< Type > sorted()
Return sorted list of objects with a class satisfying isA<Type> or isType<Type> (with Strict).
const Type & lookupObject(const word &name, const bool recursive=false) const
Lookup and return const reference to the object of the given Type. Fatal if not found or the wrong ty...
Smooth ATC in cells having a point to a set of patches supplied by type.
Definition pointCells.H:55
void setInstance(const fileName &instance, const IOobjectOption::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition polyMeshIO.C:29
virtual const faceList & faces() const
Return raw faces.
Definition polyMesh.C:1088
bool moving() const noexcept
Is mesh moving.
Definition polyMesh.H:732
virtual const labelList & faceOwner() const
Return face owner.
Definition polyMesh.C:1101
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
bool topoChanging() const noexcept
Is mesh topology changing.
Definition polyMesh.H:750
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition polyMesh.C:1107
Direct mesh changes based on v1.3 polyTopoChange syntax.
autoPtr< mapPolyMesh > changeMesh(polyMesh &mesh, const labelUList &patchMap, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces).
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
label nInternalFaces() const noexcept
Number of internal faces.
label nCells() const noexcept
Number of mesh cells.
label nFaces() const noexcept
Number of mesh faces.
const labelListList & pointFaces() const
Container with cells to refine. Refinement given as single direction.
Definition refineCell.H:53
All refinement history. Used in unrefinement.
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
static void fillNan(char *buf, size_t count)
Fill data block with signaling_NaN values. Does a reinterpret to Foam::scalar.
Definition sigFpe.H:209
void clearOut()
Clear all geometry and addressing.
static void swapFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled face values. Uses eqOp.
Definition syncTools.H:567
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition syncTools.H:465
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
A class for handling words, derived from Foam::string.
Definition word.H:66
static const word null
An empty word.
Definition word.H:84
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const auto & io
label nPoints
const cellShapeList & cells
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))
word timeName
Definition getTimeIndex.H:3
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
const expr V(m.psi().mesh().V())
labelHashSet used(const bitSet &select)
Convert a bitset to a labelHashSet of the indices used.
Definition HashOps.C:26
const dimensionedScalar c
Speed of light in a vacuum.
Different types of constants.
Namespace for handling debugging switches.
Definition debug.C:45
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
Namespace for OpenFOAM.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
const dimensionSet dimless
Dimensionless.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
GeometricField< scalar, fvPatchField, volMesh > volScalarField
messageStream Info
Information stream (stdout output on master, null elsewhere).
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
const word GlobalIOList< Tuple2< scalar, vector > >::typeName("scalarVectorTable")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
errorManip< error > abort(error &err)
Definition errorManip.H:139
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
fvsPatchField< scalar > fvsPatchScalarField
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
label timeIndex
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};constexpr label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< DynamicList< face > > pFaces[nBCs]
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
Foam::surfaceFields.