fvMeshTopoChangersRefiner.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "surfaceInterpolate.H"
28 #include "polyTopoChange.H"
29 #include "syncTools.H"
30 #include "pointFields.H"
31 #include "sigFpe.H"
32 #include "cellSet.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace fvMeshTopoChangers
40 {
41  defineTypeNameAndDebug(refiner, 0);
42  addToRunTimeSelectionTable(fvMeshTopoChanger, refiner, fvMesh);
43 }
44 }
45 
46 
47 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
48 
49 Foam::label Foam::fvMeshTopoChangers::refiner::count
50 (
51  const PackedBoolList& l,
52  const unsigned int val
53 )
54 {
55  label n = 0;
56  forAll(l, i)
57  {
58  if (l.get(i) == val)
59  {
60  n++;
61  }
62 
63  // Debug also serves to get-around Clang compiler trying to optimise
64  // out this forAll loop under O3 optimisation
65  if (debug)
66  {
67  Info<< "n=" << n << endl;
68  }
69  }
70 
71  return n;
72 }
73 
74 
75 void Foam::fvMeshTopoChangers::refiner::calculateProtectedCells
76 (
77  PackedBoolList& unrefineableCells
78 ) const
79 {
80  if (protectedCells_.empty())
81  {
82  unrefineableCells.clear();
83  return;
84  }
85 
86  const labelList& cellLevel = meshCutter_.cellLevel();
87 
88  unrefineableCells = protectedCells_;
89 
90  // Get neighbouring cell level
91  labelList neiLevel(mesh().nFaces() - mesh().nInternalFaces());
92 
93  for
94  (
95  label facei = mesh().nInternalFaces();
96  facei < mesh().nFaces();
97  facei++
98  )
99  {
100  neiLevel[facei - mesh().nInternalFaces()] =
101  cellLevel[mesh().faceOwner()[facei]];
102  }
104 
105 
106  while (true)
107  {
108  // Pick up faces on border of protected cells
109  boolList seedFace(mesh().nFaces(), false);
110 
111  forAll(mesh().faceNeighbour(), facei)
112  {
113  const label own = mesh().faceOwner()[facei];
114  const bool ownProtected = unrefineableCells.get(own);
115  const label nei = mesh().faceNeighbour()[facei];
116  const bool neiProtected = unrefineableCells.get(nei);
117 
118  if (ownProtected && (cellLevel[nei] > cellLevel[own]))
119  {
120  seedFace[facei] = true;
121  }
122  else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
123  {
124  seedFace[facei] = true;
125  }
126  }
127 
128  for
129  (
130  label facei = mesh().nInternalFaces();
131  facei < mesh().nFaces();
132  facei++
133  )
134  {
135  const label own = mesh().faceOwner()[facei];
136  const bool ownProtected = unrefineableCells.get(own);
137 
138  if
139  (
140  ownProtected
141  && (neiLevel[facei-mesh().nInternalFaces()] > cellLevel[own])
142  )
143  {
144  seedFace[facei] = true;
145  }
146  }
147 
148  syncTools::syncFaceList(mesh(), seedFace, orEqOp<bool>());
149 
150 
151  // Extend unrefineableCells
152  bool hasExtended = false;
153 
154  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
155  {
156  if (seedFace[facei])
157  {
158  const label own = mesh().faceOwner()[facei];
159  if (unrefineableCells.get(own) == 0)
160  {
161  unrefineableCells.set(own, 1);
162  hasExtended = true;
163  }
164 
165  const label nei = mesh().faceNeighbour()[facei];
166  if (unrefineableCells.get(nei) == 0)
167  {
168  unrefineableCells.set(nei, 1);
169  hasExtended = true;
170  }
171  }
172  }
173 
174  for
175  (
176  label facei = mesh().nInternalFaces();
177  facei < mesh().nFaces();
178  facei++
179  )
180  {
181  if (seedFace[facei])
182  {
183  const label own = mesh().faceOwner()[facei];
184 
185  if (unrefineableCells.get(own) == 0)
186  {
187  unrefineableCells.set(own, 1);
188  hasExtended = true;
189  }
190  }
191  }
192 
193  if (!returnReduce(hasExtended, orOp<bool>()))
194  {
195  break;
196  }
197  }
198 }
199 
200 
201 void Foam::fvMeshTopoChangers::refiner::readDict()
202 {
203  refineInterval_ = dict_.lookup<label>("refineInterval");
204 
205  if (refineInterval_ < 0)
206  {
208  << "Illegal refineInterval " << refineInterval_ << nl
209  << "The refineInterval setting in the dynamicMeshDict should"
210  << " be >= 1." << nl
211  << exit(FatalIOError);
212  }
213 
214  maxCells_ = dict_.lookup<label>("maxCells");
215 
216  if (maxCells_ <= 0)
217  {
219  << "Illegal maximum number of cells " << maxCells_ << nl
220  << "The maxCells setting in the dynamicMeshDict should"
221  << " be > 0." << nl
222  << exit(FatalIOError);
223  }
224 
225  nBufferLayers_ = dict_.lookup<label>("nBufferLayers");
226 
227  const List<Pair<word>> fluxVelocities = List<Pair<word>>
228  (
229  dict_.lookup("correctFluxes")
230  );
231 
232  // Rework into hashtable.
233  correctFluxes_.resize(fluxVelocities.size());
234  forAll(fluxVelocities, i)
235  {
236  correctFluxes_.insert(fluxVelocities[i][0], fluxVelocities[i][1]);
237  }
238 
239  dumpLevel_ = Switch(dict_.lookup("dumpLevel"));
240 }
241 
242 
244 Foam::fvMeshTopoChangers::refiner::refine
245 (
246  const labelList& cellsToRefine
247 )
248 {
249  // Mesh changing engine.
250  polyTopoChange meshMod(mesh());
251 
252  // Play refinement commands into mesh changer.
253  meshCutter_.setRefinement(cellsToRefine, meshMod);
254 
255  // Create mesh (with inflation), return map from old to new mesh.
256  // autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(*this, true);
257  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh(), false);
258 
259  Info<< "Refined from "
260  << returnReduce(map().nOldCells(), sumOp<label>())
261  << " to " << mesh().globalData().nTotalCells() << " cells." << endl;
262 
263  if (debug)
264  {
265  // Check map.
266  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
267  {
268  const label oldFacei = map().faceMap()[facei];
269 
270  if (oldFacei >= mesh().nInternalFaces())
271  {
273  << "New internal face:" << facei
274  << " fc:" << mesh().faceCentres()[facei]
275  << " originates from boundary oldFace:" << oldFacei
276  << abort(FatalError);
277  }
278  }
279  }
280 
281  // Update fields
282  mesh().topoChange(map);
283 
284  {
285  // Correct the flux for modified/added faces. All the faces which only
286  // have been renumbered will already have been handled by the mapping.
287  const labelList& faceMap = map().faceMap();
288  const labelList& reverseFaceMap = map().reverseFaceMap();
289 
290  // Storage for any master faces. These will be the original faces
291  // on the coarse cell that get split into four (or rather the
292  // master face gets modified and three faces get added from the master)
293  labelHashSet masterFaces(4*cellsToRefine.size());
294 
295  forAll(faceMap, facei)
296  {
297  const label oldFacei = faceMap[facei];
298 
299  if (oldFacei >= 0)
300  {
301  const label masterFacei = reverseFaceMap[oldFacei];
302 
303  if (masterFacei < 0)
304  {
306  << "Problem: should not have removed faces"
307  << " when refining."
308  << nl << "face:" << facei << abort(FatalError);
309  }
310  else if (masterFacei != facei)
311  {
312  masterFaces.insert(masterFacei);
313  }
314  }
315  }
316  if (debug)
317  {
318  Pout<< "Found " << masterFaces.size() << " split faces " << endl;
319  }
320 
321  refineFluxes(masterFaces, map());
322  refineUfs(masterFaces, map());
323  }
324 
325  // Update numbering of protectedCells_
326  if (protectedCells_.size())
327  {
328  PackedBoolList newProtectedCell(mesh().nCells());
329 
330  forAll(newProtectedCell, celli)
331  {
332  const label oldCelli = map().cellMap()[celli];
333  newProtectedCell.set(celli, protectedCells_.get(oldCelli));
334  }
335  protectedCells_.transfer(newProtectedCell);
336  }
337 
338  // Debug: Check refinement levels (across faces only)
339  meshCutter_.checkRefinementLevels(-1, labelList(0));
340 
341  return map;
342 }
343 
344 
346 Foam::fvMeshTopoChangers::refiner::unrefine
347 (
348  const labelList& splitPoints
349 )
350 {
351  polyTopoChange meshMod(mesh());
352 
353  // Play refinement commands into mesh changer.
354  meshCutter_.setUnrefinement(splitPoints, meshMod);
355 
356 
357  // Save information on faces that will be combined
358  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359 
360  // Find the faceMidPoints on cells to be combined.
361  // for each face resulting of split of face into four store the
362  // midpoint
363  Map<label> faceToSplitPoint(3*splitPoints.size());
364 
365  {
366  forAll(splitPoints, i)
367  {
368  const label pointi = splitPoints[i];
369  const labelList& pEdges = mesh().pointEdges()[pointi];
370 
371  forAll(pEdges, j)
372  {
373  const label otherPointi =
374  mesh().edges()[pEdges[j]].otherVertex(pointi);
375 
376  const labelList& pFaces = mesh().pointFaces()[otherPointi];
377 
378  forAll(pFaces, pFacei)
379  {
380  faceToSplitPoint.insert(pFaces[pFacei], otherPointi);
381  }
382  }
383  }
384  }
385 
386 
387  // Change mesh and generate map.
388  // autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh(), true);
389  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh(), false);
390 
391  Info<< "Unrefined from "
392  << returnReduce(map().nOldCells(), sumOp<label>())
393  << " to " << mesh().globalData().nTotalCells() << " cells."
394  << endl;
395 
396  // Update fields
397  mesh().topoChange(map);
398 
399  // Correct the fluxes for modified faces
400  unrefineFluxes(faceToSplitPoint, map());
401 
402  // Correct the face velocities for modified faces
403  unrefineUfs(faceToSplitPoint, map());
404 
405  // Update numbering of protectedCells_
406  if (protectedCells_.size())
407  {
408  PackedBoolList newProtectedCell(mesh().nCells());
409 
410  forAll(newProtectedCell, celli)
411  {
412  const label oldCelli = map().cellMap()[celli];
413  if (oldCelli >= 0)
414  {
415  newProtectedCell.set(celli, protectedCells_.get(oldCelli));
416  }
417  }
418  protectedCells_.transfer(newProtectedCell);
419  }
420 
421  // Debug: Check refinement levels (across faces only)
422  meshCutter_.checkRefinementLevels(-1, labelList(0));
423 
424  return map;
425 }
426 
427 
428 Foam::word Foam::fvMeshTopoChangers::refiner::Uname
429 (
430  const surfaceVectorField& Uf
431 ) const
432 {
433  const word UfName(Uf.member());
434 
435  return
437  (
438  UfName.back() == 'f'
439  ? word(UfName(UfName.size() - 1))
440  : UfName.compare(UfName.size() - 3, 3, "f_0") == 0
441  ? word(UfName(UfName.size() - 3) + "_0")
442  : word::null,
443  Uf.group()
444  );
445 }
446 
447 
448 void Foam::fvMeshTopoChangers::refiner::refineFluxes
449 (
450  const labelHashSet& masterFaces,
451  const polyTopoChangeMap& map
452 )
453 {
454  // Correct the flux for modified/added faces. All the faces which only
455  // have been renumbered will already have been handled by the mapping.
456  const labelList& faceMap = map.faceMap();
457  const labelList& reverseFaceMap = map.reverseFaceMap();
458 
459  HashTable<surfaceScalarField*> fluxes
460  (
461  mesh().lookupClass<surfaceScalarField>()
462  );
463  forAllIter(HashTable<surfaceScalarField*>, fluxes, iter)
464  {
465  if (!correctFluxes_.found(iter.key()))
466  {
468  << "Cannot find surfaceScalarField " << iter.key()
469  << " in user-provided flux mapping table "
470  << correctFluxes_ << endl
471  << " The flux mapping table is used to recreate the"
472  << " flux on newly created faces." << endl
473  << " Either add the entry if it is a flux or use ("
474  << iter.key() << " none) to suppress this warning."
475  << endl;
476  continue;
477  }
478 
479  const word& Uname = correctFluxes_[iter.key()];
480 
481  if (Uname == "none")
482  {
483  continue;
484  }
485 
486  if (Uname == "NaN")
487  {
488  Pout<< "Setting surfaceScalarField " << iter.key()
489  << " to NaN" << endl;
490 
491  surfaceScalarField& phi = *iter();
492 
493  sigFpe::fillNan(phi.primitiveFieldRef());
494 
495  continue;
496  }
497 
498  if (debug)
499  {
500  Pout<< "Mapping flux " << iter.key()
501  << " using interpolated flux " << Uname
502  << endl;
503  }
504 
505  surfaceScalarField& phi = *iter();
506  const surfaceScalarField phiU
507  (
508  fvc::interpolate(mesh().lookupObject<volVectorField>(Uname))
509  & mesh().Sf()
510  );
511 
512  // Recalculate new internal faces.
513  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
514  {
515  const label oldFacei = faceMap[facei];
516 
517  if (oldFacei == -1)
518  {
519  // Inflated/appended
520  phi[facei] = phiU[facei];
521  }
522  else if (reverseFaceMap[oldFacei] != facei)
523  {
524  // face-from-masterface
525  phi[facei] = phiU[facei];
526  }
527  }
528 
529  // Recalculate new boundary faces.
530  surfaceScalarField::Boundary& phiBf = phi.boundaryFieldRef();
531 
532  forAll(phiBf, patchi)
533  {
534  fvsPatchScalarField& patchPhi = phiBf[patchi];
535 
536  const fvsPatchScalarField& patchPhiU =
537  phiU.boundaryField()[patchi];
538 
539  label facei = patchPhi.patch().start();
540 
541  forAll(patchPhi, i)
542  {
543  const label oldFacei = faceMap[facei];
544 
545  if (oldFacei == -1)
546  {
547  // Inflated/appended
548  patchPhi[i] = patchPhiU[i];
549  }
550  else if (reverseFaceMap[oldFacei] != facei)
551  {
552  // face-from-masterface
553  patchPhi[i] = patchPhiU[i];
554  }
555 
556  facei++;
557  }
558  }
559 
560  // Update master faces
561  forAllConstIter(labelHashSet, masterFaces, iter)
562  {
563  const label facei = iter.key();
564 
565  if (mesh().isInternalFace(facei))
566  {
567  phi[facei] = phiU[facei];
568  }
569  else
570  {
571  const label patchi =
572  mesh().boundaryMesh().whichPatch(facei);
573 
574  const label i =
575  facei - mesh().boundaryMesh()[patchi].start();
576 
577  phiBf[patchi][i] = phiU.boundaryField()[patchi][i];
578  }
579  }
580  }
581 }
582 
583 
584 void Foam::fvMeshTopoChangers::refiner::refineUfs
585 (
586  const labelHashSet& masterFaces,
587  const polyTopoChangeMap& map
588 )
589 {
590  const labelList& faceMap = map.faceMap();
591  const labelList& reverseFaceMap = map.reverseFaceMap();
592 
593  // Interpolate U to Uf for added faces
594  HashTable<surfaceVectorField*> Ufs
595  (
596  mesh().lookupClass<surfaceVectorField>()
597  );
598  forAllIter(HashTable<surfaceVectorField*>, Ufs, iter)
599  {
600  surfaceVectorField& Uf = *iter();
601 
602  const word Uname(this->Uname(Uf));
603 
604  if (Uname != word::null)
605  {
606  const surfaceVectorField UfU
607  (
609  (
610  mesh().lookupObject<volVectorField>(Uname)
611  )
612  );
613 
614  // Recalculate new internal faces.
615  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
616  {
617  label oldFacei = faceMap[facei];
618 
619  if (oldFacei == -1)
620  {
621  // Inflated/appended
622  Uf[facei] = UfU[facei];
623  }
624  else if (reverseFaceMap[oldFacei] != facei)
625  {
626  // face-from-masterface
627  Uf[facei] = UfU[facei];
628  }
629  }
630 
631  // Recalculate new boundary faces.
632  surfaceVectorField::Boundary& UfBf = Uf.boundaryFieldRef();
633  forAll(UfBf, patchi)
634  {
635  fvsPatchVectorField& patchUf = UfBf[patchi];
636  const fvsPatchVectorField& patchUfU =
637  UfU.boundaryField()[patchi];
638 
639  label facei = patchUf.patch().start();
640 
641  forAll(patchUf, i)
642  {
643  label oldFacei = faceMap[facei];
644 
645  if (oldFacei == -1)
646  {
647  // Inflated/appended
648  patchUf[i] = patchUfU[i];
649  }
650  else if (reverseFaceMap[oldFacei] != facei)
651  {
652  // face-from-masterface
653  patchUf[i] = patchUfU[i];
654  }
655 
656  facei++;
657  }
658  }
659 
660  // Update master faces
661  forAllConstIter(labelHashSet, masterFaces, iter)
662  {
663  label facei = iter.key();
664 
665  if (mesh().isInternalFace(facei))
666  {
667  Uf[facei] = UfU[facei];
668  }
669  else
670  {
671  const label patchi =
672  mesh().boundaryMesh().whichPatch(facei);
673  const label i =
674  facei - mesh().boundaryMesh()[patchi].start();
675 
676  const fvsPatchVectorField& patchUfU =
677  UfU.boundaryField()[patchi];
678 
679  fvsPatchVectorField& patchUf = UfBf[patchi];
680 
681  patchUf[i] = patchUfU[i];
682  }
683  }
684  }
685  }
686 }
687 
688 
689 void Foam::fvMeshTopoChangers::refiner::unrefineFluxes
690 (
691  const Map<label>& faceToSplitPoint,
692  const polyTopoChangeMap& map
693 )
694 {
695  const labelList& reversePointMap = map.reversePointMap();
696  const labelList& reverseFaceMap = map.reverseFaceMap();
697 
698  HashTable<surfaceScalarField*> fluxes
699  (
700  mesh().lookupClass<surfaceScalarField>()
701  );
702  forAllIter(HashTable<surfaceScalarField*>, fluxes, iter)
703  {
704  if (!correctFluxes_.found(iter.key()))
705  {
707  << "Cannot find surfaceScalarField " << iter.key()
708  << " in user-provided flux mapping table "
709  << correctFluxes_ << endl
710  << " The flux mapping table is used to recreate the"
711  << " flux on newly created faces." << endl
712  << " Either add the entry if it is a flux or use ("
713  << iter.key() << " none) to suppress this warning."
714  << endl;
715  continue;
716  }
717 
718  const word& Uname = correctFluxes_[iter.key()];
719 
720  if (Uname == "none")
721  {
722  continue;
723  }
724 
725  if (debug)
726  {
727  Info<< "Mapping flux " << iter.key()
728  << " using interpolated flux " << Uname
729  << endl;
730  }
731 
732  surfaceScalarField& phi = *iter();
733  surfaceScalarField::Boundary& phiBf = phi.boundaryFieldRef();
734 
735  const surfaceScalarField phiU
736  (
737  fvc::interpolate(mesh().lookupObject<volVectorField>(Uname))
738  & mesh().Sf()
739  );
740 
741  forAllConstIter(Map<label>, faceToSplitPoint, iter)
742  {
743  const label oldFacei = iter.key();
744  const label oldPointi = iter();
745 
746  if (reversePointMap[oldPointi] < 0)
747  {
748  // midpoint was removed. See if face still exists.
749  const label facei = reverseFaceMap[oldFacei];
750 
751  if (facei >= 0)
752  {
753  if (mesh().isInternalFace(facei))
754  {
755  phi[facei] = phiU[facei];
756  }
757  else
758  {
759  const label patchi =
760  mesh().boundaryMesh().whichPatch(facei);
761 
762  const label i =
763  facei - mesh().boundaryMesh()[patchi].start();
764 
765  phiBf[patchi][i] = phiU.boundaryField()[patchi][i];
766  }
767  }
768  }
769  }
770  }
771 }
772 
773 
774 void Foam::fvMeshTopoChangers::refiner::unrefineUfs
775 (
776  const Map<label>& faceToSplitPoint,
777  const polyTopoChangeMap& map
778 )
779 {
780  const labelList& reversePointMap = map.reversePointMap();
781  const labelList& reverseFaceMap = map.reverseFaceMap();
782 
783  // Interpolate U to Uf for added faces
784  HashTable<surfaceVectorField*> Ufs
785  (
786  mesh().lookupClass<surfaceVectorField>()
787  );
788  forAllIter(HashTable<surfaceVectorField*>, Ufs, iter)
789  {
790  surfaceVectorField& Uf = *iter();
791 
792  const word Uname(this->Uname(Uf));
793 
794  if (Uname != word::null)
795  {
796  surfaceVectorField::Boundary& UfBf = Uf.boundaryFieldRef();
797 
798  const surfaceVectorField UfU
799  (
800  fvc::interpolate(mesh().lookupObject<volVectorField>(Uname))
801  );
802 
803  forAllConstIter(Map<label>, faceToSplitPoint, iter)
804  {
805  const label oldFacei = iter.key();
806  const label oldPointi = iter();
807 
808  if (reversePointMap[oldPointi] < 0)
809  {
810  // midpoint was removed. See if face still exists.
811  const label facei = reverseFaceMap[oldFacei];
812 
813  if (facei >= 0)
814  {
815  if (mesh().isInternalFace(facei))
816  {
817  Uf[facei] = UfU[facei];
818  }
819  else
820  {
821  const label patchi =
822  mesh().boundaryMesh().whichPatch(facei);
823  const label i =
824  facei - mesh().boundaryMesh()[patchi].start();
825 
826  UfBf[patchi][i] = UfU.boundaryField()[patchi][i];
827  }
828  }
829  }
830  }
831  }
832  }
833 }
834 
835 
836 const Foam::cellZone& Foam::fvMeshTopoChangers::refiner::findCellZone
837 (
838  const word& cellZoneName
839 ) const
840 {
841  const label cellZoneID = mesh().cellZones().findZoneID(cellZoneName);
842 
843  bool cellZoneFound = (cellZoneID != -1);
844  reduce(cellZoneFound, orOp<bool>());
845 
846  if (!cellZoneFound)
847  {
849  << "cannot find cellZone " << cellZoneName
850  << exit(FatalError);
851  }
852 
853  return mesh().cellZones()[cellZoneID];
854 }
855 
856 
858 Foam::fvMeshTopoChangers::refiner::cellToPoint(const scalarField& vFld) const
859 {
860  scalarField pFld(mesh().nPoints());
861 
862  forAll(mesh().pointCells(), pointi)
863  {
864  const labelList& pCells = mesh().pointCells()[pointi];
865 
866  scalar sum = 0.0;
867  forAll(pCells, i)
868  {
869  sum += vFld[pCells[i]];
870  }
871  pFld[pointi] = sum/pCells.size();
872  }
873 
874  return pFld;
875 }
876 
877 
878 Foam::scalarField Foam::fvMeshTopoChangers::refiner::error
879 (
880  const scalarField& fld,
881  const scalar minLevel,
882  const scalar maxLevel
883 ) const
884 {
885  scalarField c(fld.size(), -1);
886 
887  forAll(c, celli)
888  {
889  scalar err = min(fld[celli] - minLevel, maxLevel - fld[celli]);
890 
891  if (err >= 0)
892  {
893  c[celli] = err;
894  }
895  }
896 
897  return c;
898 }
899 
900 
901 Foam::scalarField Foam::fvMeshTopoChangers::refiner::error
902 (
903  const scalarField& fld,
904  const labelList& cells,
905  const scalar minLevel,
906  const scalar maxLevel
907 ) const
908 {
909  scalarField c(fld.size(), -1);
910 
911  forAll(cells, i)
912  {
913  const label celli = cells[i];
914 
915  scalar err = min(fld[celli] - minLevel, maxLevel - fld[celli]);
916 
917  if (err >= 0)
918  {
919  c[celli] = err;
920  }
921  }
922 
923  return c;
924 }
925 
926 
927 void Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
928 (
929  PackedBoolList& candidateCells,
930  const scalar lowerRefineLevel,
931  const scalar upperRefineLevel,
932  const scalar maxRefinement,
933  const scalarField& vFld
934 ) const
935 {
936  // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
937  // higher more desirable to be refined).
938  const scalarField cellError
939  (
940  error(vFld, lowerRefineLevel, upperRefineLevel)
941  );
942 
943  // Mark cells that are candidates for refinement.
944  forAll(cellError, celli)
945  {
946  if (cellError[celli] > 0)
947  {
948  candidateCells.set(celli, 1);
949  }
950  }
951 }
952 
953 
954 void Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
955 (
956  PackedBoolList& candidateCells,
957  const scalar lowerRefineLevel,
958  const scalar upperRefineLevel,
959  const scalar maxRefinement,
960  const scalarField& vFld,
961  const labelList& cells
962 ) const
963 {
964  // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
965  // higher more desirable to be refined).
966  const scalarField cellError
967  (
968  error(vFld, cells, lowerRefineLevel, upperRefineLevel)
969  );
970 
971  // Mark cells that are candidates for refinement.
972  forAll(cellError, celli)
973  {
974  if (cellError[celli] > 0)
975  {
976  candidateCells.set(celli, 1);
977  }
978  }
979 }
980 
981 
982 Foam::scalar Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
983 (
984  PackedBoolList& candidateCells,
985  const dictionary& refineDict
986 ) const
987 {
988  const word fieldName(refineDict.lookup("field"));
989 
990  const volScalarField& vFld = mesh().lookupObject<volScalarField>(fieldName);
991 
992  const scalar lowerRefineLevel =
993  refineDict.lookup<scalar>("lowerRefineLevel");
994  const scalar upperRefineLevel =
995  refineDict.lookup<scalar>("upperRefineLevel");
996 
997  const label maxRefinement = refineDict.lookup<label>("maxRefinement");
998 
999  if (maxRefinement <= 0)
1000  {
1002  << "Illegal maximum refinement level " << maxRefinement << nl
1003  << "The maxCells setting in the dynamicMeshDict should"
1004  << " be > 0." << nl
1005  << exit(FatalError);
1006  }
1007 
1008  if (refineDict.found("cellZone"))
1009  {
1010  // Determine candidates for refinement (looking at field only)
1011  selectRefineCandidates
1012  (
1013  candidateCells,
1014  lowerRefineLevel,
1015  upperRefineLevel,
1016  maxRefinement,
1017  vFld,
1018  findCellZone(refineDict.lookup("cellZone"))
1019  );
1020  }
1021  else
1022  {
1023  // Determine candidates for refinement (looking at field only)
1024  selectRefineCandidates
1025  (
1026  candidateCells,
1027  lowerRefineLevel,
1028  upperRefineLevel,
1029  maxRefinement,
1030  vFld
1031  );
1032  }
1033 
1034  return maxRefinement;
1035 }
1036 
1037 
1038 Foam::labelList Foam::fvMeshTopoChangers::refiner::selectRefineCells
1039 (
1040  const label maxCells,
1041  const label maxRefinement,
1042  const PackedBoolList& candidateCells
1043 ) const
1044 {
1045  // Every refined cell causes 7 extra cells
1046  const label nTotToRefine = (maxCells - mesh().globalData().nTotalCells())/7;
1047 
1048  const labelList& cellLevel = meshCutter_.cellLevel();
1049 
1050  // Mark cells that cannot be refined since they would trigger refinement
1051  // of protected cells (since 2:1 cascade)
1052  PackedBoolList unrefineableCells;
1053  calculateProtectedCells(unrefineableCells);
1054 
1055  // Count current selection
1056  const label nLocalCandidates = count(candidateCells, 1);
1057  const label nCandidates = returnReduce(nLocalCandidates, sumOp<label>());
1058 
1059  // Collect all cells
1060  DynamicList<label> candidates(nLocalCandidates);
1061 
1062  if (nCandidates < nTotToRefine)
1063  {
1064  forAll(candidateCells, celli)
1065  {
1066  if
1067  (
1068  candidateCells.get(celli)
1069  && (
1070  unrefineableCells.empty()
1071  || !unrefineableCells.get(celli)
1072  )
1073  )
1074  {
1075  candidates.append(celli);
1076  }
1077  }
1078  }
1079  else
1080  {
1081  // Sort by error? For now just truncate.
1082  for (label level = 0; level < maxRefinement; level++)
1083  {
1084  forAll(candidateCells, celli)
1085  {
1086  if
1087  (
1088  cellLevel[celli] == level
1089  && candidateCells.get(celli)
1090  && (
1091  unrefineableCells.empty()
1092  || !unrefineableCells.get(celli)
1093  )
1094  )
1095  {
1096  candidates.append(celli);
1097  }
1098  }
1099 
1100  if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
1101  {
1102  break;
1103  }
1104  }
1105  }
1106 
1107  // Guarantee 2:1 refinement after refinement
1108  labelList consistentSet
1109  (
1110  meshCutter_.consistentRefinement
1111  (
1112  candidates.shrink(),
1113  true // Add to set to guarantee 2:1
1114  )
1115  );
1116 
1117  Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
1118  << " cells for refinement out of " << mesh().globalData().nTotalCells()
1119  << "." << endl;
1120 
1121  return consistentSet;
1122 }
1123 
1124 
1125 Foam::labelList Foam::fvMeshTopoChangers::refiner::selectUnrefinePoints
1126 (
1127  const PackedBoolList& markedCell
1128 ) const
1129 {
1130  // All points that can be unrefined
1131  const labelList splitPoints(meshCutter_.getSplitPoints());
1132 
1133  DynamicList<label> newSplitPoints(splitPoints.size());
1134 
1135  forAll(splitPoints, i)
1136  {
1137  const label pointi = splitPoints[i];
1138 
1139  // Check that all cells are not marked
1140  const labelList& pCells = mesh().pointCells()[pointi];
1141 
1142  bool hasMarked = false;
1143 
1144  forAll(pCells, pCelli)
1145  {
1146  if (markedCell.get(pCells[pCelli]))
1147  {
1148  hasMarked = true;
1149  break;
1150  }
1151  }
1152 
1153  if (!hasMarked)
1154  {
1155  newSplitPoints.append(pointi);
1156  }
1157  }
1158 
1159 
1160  newSplitPoints.shrink();
1161 
1162  // Guarantee 2:1 refinement after unrefinement
1163  labelList consistentSet
1164  (
1165  meshCutter_.consistentUnrefinement
1166  (
1167  newSplitPoints,
1168  false
1169  )
1170  );
1171 
1172  Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
1173  << " split points out of a possible "
1174  << returnReduce(splitPoints.size(), sumOp<label>())
1175  << "." << endl;
1176 
1177  return consistentSet;
1178 }
1179 
1180 
1181 void Foam::fvMeshTopoChangers::refiner::extendMarkedCells
1182 (
1183  PackedBoolList& markedCell
1184 ) const
1185 {
1186  // Mark faces using any marked cell
1187  boolList markedFace(mesh().nFaces(), false);
1188 
1189  forAll(markedCell, celli)
1190  {
1191  if (markedCell.get(celli))
1192  {
1193  const cell& cFaces = mesh().cells()[celli];
1194 
1195  forAll(cFaces, i)
1196  {
1197  markedFace[cFaces[i]] = true;
1198  }
1199  }
1200  }
1201 
1202  syncTools::syncFaceList(mesh(), markedFace, orEqOp<bool>());
1203 
1204  // Update cells using any markedFace
1205  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
1206  {
1207  if (markedFace[facei])
1208  {
1209  markedCell.set(mesh().faceOwner()[facei], 1);
1210  markedCell.set(mesh().faceNeighbour()[facei], 1);
1211  }
1212  }
1213 
1214  for
1215  (
1216  label facei = mesh().nInternalFaces();
1217  facei < mesh().nFaces();
1218  facei++
1219  )
1220  {
1221  if (markedFace[facei])
1222  {
1223  markedCell.set(mesh().faceOwner()[facei], 1);
1224  }
1225  }
1226 }
1227 
1228 
1229 void Foam::fvMeshTopoChangers::refiner::checkEightAnchorPoints
1230 (
1231  PackedBoolList& protectedCell,
1232  label& nProtected
1233 ) const
1234 {
1235  const labelList& cellLevel = meshCutter_.cellLevel();
1236  const labelList& pointLevel = meshCutter_.pointLevel();
1237 
1238  labelList nAnchorPoints(mesh().nCells(), 0);
1239 
1240  forAll(pointLevel, pointi)
1241  {
1242  const labelList& pCells = mesh().pointCells(pointi);
1243 
1244  forAll(pCells, pCelli)
1245  {
1246  const label celli = pCells[pCelli];
1247 
1248  if (pointLevel[pointi] <= cellLevel[celli])
1249  {
1250  // Check if cell has already 8 anchor points -> protect cell
1251  if (nAnchorPoints[celli] == 8)
1252  {
1253  if (protectedCell.set(celli, true))
1254  {
1255  nProtected++;
1256  }
1257  }
1258 
1259  if (!protectedCell[celli])
1260  {
1261  nAnchorPoints[celli]++;
1262  }
1263  }
1264  }
1265  }
1266 
1267  forAll(protectedCell, celli)
1268  {
1269  if (!protectedCell[celli] && nAnchorPoints[celli] != 8)
1270  {
1271  protectedCell.set(celli, true);
1272  nProtected++;
1273  }
1274  }
1275 }
1276 
1277 
1278 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1279 
1281 :
1282  fvMeshTopoChanger(mesh),
1283  dict_(dict),
1284  meshCutter_(mesh),
1285  dumpLevel_(false),
1286  nRefinementIterations_(0),
1287  protectedCells_(mesh.nCells(), 0),
1288  changedSinceWrite_(false),
1289  timeIndex_(-1)
1290 {
1291  // Read static part of dictionary
1292  readDict();
1293 
1294  const labelList& cellLevel = meshCutter_.cellLevel();
1295  const labelList& pointLevel = meshCutter_.pointLevel();
1296 
1297  // Set cells that should not be refined.
1298  // This is currently any cell which does not have 8 anchor points or
1299  // uses any face which does not have 4 anchor points.
1300  // Note: do not use cellPoint addressing
1301 
1302  // Count number of points <= cellLevel
1303  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1304 
1305  labelList nAnchors(mesh.nCells(), 0);
1306 
1307  label nProtected = 0;
1308 
1309  forAll(mesh.pointCells(), pointi)
1310  {
1311  const labelList& pCells = mesh.pointCells()[pointi];
1312 
1313  forAll(pCells, i)
1314  {
1315  const label celli = pCells[i];
1316 
1317  if (!protectedCells_.get(celli))
1318  {
1319  if (pointLevel[pointi] <= cellLevel[celli])
1320  {
1321  nAnchors[celli]++;
1322 
1323  if (nAnchors[celli] > 8)
1324  {
1325  protectedCells_.set(celli, 1);
1326  nProtected++;
1327  }
1328  }
1329  }
1330  }
1331  }
1332 
1333 
1334  // Count number of points <= faceLevel
1335  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1336  // Bit tricky since proc face might be one more refined than the owner since
1337  // the coupled one is refined.
1338 
1339  {
1340  labelList neiLevel(mesh.nFaces());
1341 
1342  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
1343  {
1344  neiLevel[facei] = cellLevel[mesh.faceNeighbour()[facei]];
1345  }
1346 
1347  for
1348  (
1349  label facei = mesh.nInternalFaces();
1350  facei < mesh.nFaces();
1351  facei++
1352  )
1353  {
1354  neiLevel[facei] = cellLevel[mesh.faceOwner()[facei]];
1355  }
1356  syncTools::swapFaceList(mesh, neiLevel);
1357 
1358 
1359  boolList protectedFace(mesh.nFaces(), false);
1360 
1361  forAll(mesh.faceOwner(), facei)
1362  {
1363  const label faceLevel = max
1364  (
1365  cellLevel[mesh.faceOwner()[facei]],
1366  neiLevel[facei]
1367  );
1368 
1369  const face& f = mesh.faces()[facei];
1370 
1371  label nAnchors = 0;
1372 
1373  forAll(f, fp)
1374  {
1375  if (pointLevel[f[fp]] <= faceLevel)
1376  {
1377  nAnchors++;
1378 
1379  if (nAnchors > 4)
1380  {
1381  protectedFace[facei] = true;
1382  break;
1383  }
1384  }
1385  }
1386  }
1387 
1388  syncTools::syncFaceList(mesh, protectedFace, orEqOp<bool>());
1389 
1390  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
1391  {
1392  if (protectedFace[facei])
1393  {
1394  protectedCells_.set(mesh.faceOwner()[facei], 1);
1395  nProtected++;
1396  protectedCells_.set(mesh.faceNeighbour()[facei], 1);
1397  nProtected++;
1398  }
1399  }
1400 
1401  for
1402  (
1403  label facei = mesh.nInternalFaces();
1404  facei < mesh.nFaces();
1405  facei++
1406  )
1407  {
1408  if (protectedFace[facei])
1409  {
1410  protectedCells_.set(mesh.faceOwner()[facei], 1);
1411  nProtected++;
1412  }
1413  }
1414 
1415  // Also protect any cells that are less than hex
1416  forAll(mesh.cells(), celli)
1417  {
1418  const cell& cFaces = mesh.cells()[celli];
1419 
1420  if (cFaces.size() < 6)
1421  {
1422  if (protectedCells_.set(celli, 1))
1423  {
1424  nProtected++;
1425  }
1426  }
1427  else
1428  {
1429  forAll(cFaces, cFacei)
1430  {
1431  if (mesh.faces()[cFaces[cFacei]].size() < 4)
1432  {
1433  if (protectedCells_.set(celli, 1))
1434  {
1435  nProtected++;
1436  }
1437  break;
1438  }
1439  }
1440  }
1441  }
1442 
1443  // Check cells for 8 corner points
1444  checkEightAnchorPoints(protectedCells_, nProtected);
1445  }
1446 
1447  if (returnReduce(nProtected, sumOp<label>()) == 0)
1448  {
1449  protectedCells_.clear();
1450  }
1451  else
1452  {
1453  cellSet protectedCells(mesh, "protectedCells", nProtected);
1454  forAll(protectedCells_, celli)
1455  {
1456  if (protectedCells_[celli])
1457  {
1458  protectedCells.insert(celli);
1459  }
1460  }
1461 
1462  Info<< "Detected " << returnReduce(nProtected, sumOp<label>())
1463  << " cells that are protected from refinement."
1464  << " Writing these to cellSet "
1465  << protectedCells.name()
1466  << "." << endl;
1467 
1468  protectedCells.write();
1469  }
1470 }
1471 
1472 
1473 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1474 
1476 {}
1477 
1478 
1479 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1480 
1482 {
1483  // Only refine on the first call in a time-step
1484  if (timeIndex_ != mesh().time().timeIndex())
1485  {
1486  timeIndex_ = mesh().time().timeIndex();
1487  }
1488  else
1489  {
1490  return false;
1491  }
1492 
1493  bool hasChanged = false;
1494 
1495  if (refineInterval_ == 0)
1496  {
1497  return hasChanged;
1498  }
1499 
1500  // Note: cannot refine at time 0 since no V0 present since mesh not
1501  // moved yet.
1502 
1503  if
1504  (
1505  mesh().time().timeIndex() > 0
1506  && mesh().time().timeIndex() % refineInterval_ == 0
1507  )
1508  {
1509  // Cells marked for refinement or otherwise protected from unrefinement.
1510  PackedBoolList refineCells(mesh().nCells());
1511 
1512  label maxRefinement = 0;
1513 
1514  if (dict_.isDict("refinementRegions"))
1515  {
1517  (
1518  dict_.subDict("refinementRegions")
1519  );
1520 
1522  {
1523  maxRefinement = max
1524  (
1525  selectRefineCandidates
1526  (
1527  refineCells,
1528  refinementRegions.subDict(iter().keyword())
1529  ),
1530  maxRefinement
1531  );
1532  }
1533  }
1534  else
1535  {
1536  maxRefinement = selectRefineCandidates(refineCells, dict_);
1537  }
1538 
1539  // Extend with a buffer layer to prevent neighbouring points
1540  // being unrefined.
1541  for (label i = 0; i < nBufferLayers_; i++)
1542  {
1543  extendMarkedCells(refineCells);
1544  }
1545 
1546  PackedBoolList refinableCells(refineCells);
1547 
1548  {
1549  const labelList& cellLevel = meshCutter_.cellLevel();
1550 
1551  // Mark cells that are candidates for refinement.
1552  forAll(cellLevel, celli)
1553  {
1554  if (cellLevel[celli] >= maxRefinement)
1555  {
1556  refinableCells.unset(celli);
1557  }
1558  }
1559  }
1560 
1561  if (mesh().globalData().nTotalCells() < maxCells_)
1562  {
1563  // Select subset of candidates. Take into account max allowable
1564  // cells, refinement level, protected cells.
1565  const labelList cellsToRefine
1566  (
1567  selectRefineCells
1568  (
1569  maxCells_,
1570  maxRefinement,
1571  refinableCells
1572  )
1573  );
1574 
1575  const label nCellsToRefine = returnReduce
1576  (
1577  cellsToRefine.size(), sumOp<label>()
1578  );
1579 
1580  if (nCellsToRefine > 0)
1581  {
1582  // Refine/update mesh and map fields
1583  autoPtr<polyTopoChangeMap> map = refine(cellsToRefine);
1584 
1585  // Update refinableCells. Note that some of the marked ones have
1586  // not been refined due to constraints.
1587  {
1588  const labelList& cellMap = map().cellMap();
1589  const labelList& reverseCellMap = map().reverseCellMap();
1590 
1591  PackedBoolList newRefineCell(cellMap.size());
1592 
1593  forAll(cellMap, celli)
1594  {
1595  const label oldCelli = cellMap[celli];
1596 
1597  if (oldCelli < 0)
1598  {
1599  newRefineCell.set(celli, 1);
1600  }
1601  else if (reverseCellMap[oldCelli] != celli)
1602  {
1603  newRefineCell.set(celli, 1);
1604  }
1605  else
1606  {
1607  newRefineCell.set
1608  (
1609  celli,
1610  refinableCells.get(oldCelli)
1611  );
1612  }
1613  }
1614  refinableCells.transfer(newRefineCell);
1615  }
1616 
1617  hasChanged = true;
1618  }
1619  }
1620 
1621  {
1622  // Select unrefineable points that are not marked in refineCells
1623  const labelList pointsToUnrefine(selectUnrefinePoints(refineCells));
1624 
1625  const label nSplitPoints = returnReduce
1626  (
1627  pointsToUnrefine.size(),
1628  sumOp<label>()
1629  );
1630 
1631  if (nSplitPoints > 0)
1632  {
1633  // Refine/update mesh
1634  unrefine(pointsToUnrefine);
1635 
1636  hasChanged = true;
1637  }
1638  }
1639 
1640 
1641  if ((nRefinementIterations_ % 10) == 0)
1642  {
1643  // Compact refinement history occasionally (how often?).
1644  // Unrefinement causes holes in the refinementHistory.
1645  const_cast<refinementHistory&>(meshCutter().history()).compact();
1646  }
1647  nRefinementIterations_++;
1648  }
1649 
1650  if (hasChanged)
1651  {
1652  changedSinceWrite_ = true;
1653  }
1654 
1655  return hasChanged;
1656 }
1657 
1658 
1660 {
1661  // Update numbering of cells/vertices.
1662  meshCutter_.topoChange(map);
1663 }
1664 
1665 
1667 {
1668  // meshCutter_ will need to be re-constructed from the new mesh
1669  // and protectedCells_ updated.
1670  // The constructor should be refactored for the protectedCells_ update.
1672 }
1673 
1674 
1677  const polyDistributionMap& map
1678 )
1679 {
1680  // Redistribute the mesh cutting engine
1681  meshCutter_.distribute(map);
1682 }
1683 
1684 
1686 {
1687  if (changedSinceWrite_)
1688  {
1689  // Force refinement data to go to the current time directory.
1690  const_cast<hexRef8&>(meshCutter_).setInstance(mesh().time().timeName());
1691 
1692  bool writeOk = meshCutter_.write(write);
1693 
1694  if (dumpLevel_)
1695  {
1696  volScalarField scalarCellLevel
1697  (
1698  IOobject
1699  (
1700  "cellLevel",
1701  mesh().time().timeName(),
1702  mesh(),
1705  false
1706  ),
1707  mesh(),
1709  );
1710 
1711  const labelList& cellLevel = meshCutter_.cellLevel();
1712 
1713  forAll(cellLevel, celli)
1714  {
1715  scalarCellLevel[celli] = cellLevel[celli];
1716  }
1717 
1718  writeOk = writeOk && scalarCellLevel.write();
1719  }
1720 
1721  changedSinceWrite_ = false;
1722 
1723  return writeOk;
1724  }
1725  else
1726  {
1727  return true;
1728  }
1729 }
1730 
1731 
1732 // ************************************************************************* //
const char *const group
Group name for atomic constants.
fvsPatchField< vector > fvsPatchVectorField
fvsPatchField< scalar > fvsPatchScalarField
const refinementHistory & history() const
Definition: hexRef8.H:413
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
const word & name() const
Return name.
Definition: IOobject.H:315
fvMesh & mesh()
Return the fvMesh.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
unsigned int get(const label) const
Get value at index I.
Definition: PackedListI.H:954
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
const labelIOList & pointLevel() const
Definition: hexRef8.H:408
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
label nInternalFaces() const
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1243
label nFaces() const
refiner(fvMesh &mesh, const dictionary &dict)
Construct from fvMesh and dictionary.
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:459
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
label nCells() const
GeometricField< vector, fvsPatchField, surfaceMesh > surfaceVectorField
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
label count(const ListType &l, typename ListType::const_reference x)
Count the number of occurrences of a value in a list.
Encapsulates queries for volume refinement (&#39;refine all cells within shell&#39;).
const cellList & cells() const
GeometricBoundaryField< scalar, fvsPatchField, surfaceMesh > Boundary
Type of the boundary field.
const dimensionSet dimless
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:372
addToRunTimeSelectionTable(fvMeshTopoChanger, list, fvMesh)
fvMesh & mesh
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
const dimensionedScalar c
Speed of light in a vacuum.
void distribute(const polyDistributionMap &)
Update local numbering for mesh redistribution.
Definition: hexRef8.C:4517
virtual bool write(const bool write=true) const
Write using given format, version and compression.
Macros for easy insertion into run-time selection tables.
void topoChange(const polyTopoChangeMap &)
Update local numbering for changed mesh.
Definition: hexRef8.C:4237
bool isDict(const word &) const
Check if entry is a sub-dictionary.
Definition: dictionary.C:956
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
DynamicID< meshCellZones > cellZoneID
Foam::cellZoneID.
Definition: ZoneIDs.H:41
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:1002
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:58
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:211
virtual bool update()
Update the mesh for both mesh motion and topology change.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
void set(const PackedList< 1 > &)
Set specified bits.
Pre-declare SubField and related Field type.
Definition: Field.H:56
static word timeName(const scalar, const int precision=curPrecision_)
Return time name of given scalar time.
Definition: Time.C:666
Refinement of (split) hexes using polyTopoChange.
Definition: hexRef8.H:64
A class for handling words, derived from string.
Definition: word.H:59
label nPoints
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static word groupName(Name name, const word &group)
bool write(const bool write=true) const
Force writing refinement+history to polyMesh directory.
Definition: hexRef8.C:5632
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1237
static const word null
An empty word.
Definition: word.H:77
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
word timeName
Definition: getTimeIndex.H:3
List< label > labelList
A List of labels.
Definition: labelList.H:56
static void swapFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled face values.
Definition: syncTools.H:469
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1224
static void fillNan(UList< scalar > &)
Fill block of data with NaN.
Definition: sigFpe.C:46
errorManip< error > abort(error &err)
Definition: errorManip.H:131
void clear()
Clear the list, i.e. set addressable size to zero.
Definition: PackedListI.H:889
const labelListList & pointCells() const
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("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]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< small) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &mergedCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
static const char nl
Definition: Ostream.H:260
labelList f(nPoints)
A subset of mesh cells.
Definition: cellZone.H:61
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
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.
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronise values on all mesh faces.
Definition: syncTools.H:387
A bit-packed bool list.
label timeIndex() const
Return current time index.
Definition: TimeStateI.H:28
label patchi
void transfer(PackedBoolList &)
Transfer the contents of the argument list into this list.
#define WarningInFunction
Report a warning using Foam::Warning.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:318
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:57
A collection of cell labels.
Definition: cellSet.H:48
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:95
label timeIndex
Definition: getTimeIndex.H:4
const hexRef8 & meshCutter() const
Direct access to the refinement engine.
void unset(const PackedList< 1 > &)
Unset specified bits.
messageStream Info
label n
virtual void topoChange(const polyTopoChangeMap &)
Update corresponding to the given map.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
virtual bool write(const bool write=true) const
Write using setting from DB.
All refinement history. Used in unrefinement.
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:50
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:353
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:98
virtual void distribute(const polyDistributionMap &)
Update corresponding to the given distribution map.
const labelIOList & cellLevel() const
Definition: hexRef8.H:403
Abstract base class for fvMesh movers.
Namespace for OpenFOAM.
IOerror FatalIOError