refiner_fvMeshTopoChanger.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-2026 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 {
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::calcProtectedCells
76 (
77  PackedBoolList& protectedCells
78 ) const
79 {
80  const label nFaces = mesh().nFaces();
81  const label nInternalFaces = mesh().nInternalFaces();
82 
83  const labelList& cellLevel = meshCutter_.cellLevel();
84  const labelList& pointLevel = meshCutter_.pointLevel();
85 
86  // Determine the number of parent anchors (i.e., pointLevel < cellLevel)
87  // and anchors (pointLevel <= cellLevel) in each cell
88  labelList cellNParentAnchors(mesh().nCells(), 0);
89  labelList cellNAnchors(mesh().nCells(), 0);
90  forAll(mesh().pointCells(), pointi)
91  {
92  const labelList& pCells = mesh().pointCells()[pointi];
93  forAll(pCells, pci)
94  {
95  const label celli = pCells[pci];
96  if (pointLevel[pointi] < cellLevel[celli])
97  {
98  cellNParentAnchors[celli] ++;
99  }
100  if (pointLevel[pointi] <= cellLevel[celli])
101  {
102  cellNAnchors[celli] ++;
103  }
104  }
105  }
106 
107  // A cell is (probably) refine-able if it has 8 anchors and 1 parent
108  // anchor, unless this is an original cell (i.e., cellLevel == 0), in which
109  // case it must have 0 parent anchors
110  forAll(mesh().cells(), celli)
111  {
112  protectedCells[celli] =
113  (cellNAnchors[celli] != 8)
114  || (cellLevel[celli] > 0 && cellNParentAnchors[celli] != 1)
115  || (cellLevel[celli] == 0 && cellNParentAnchors[celli] != 0);
116  }
117 
118  // Construct a list of face-neighbour levels. Requires communication.
119  labelList neiLevel(nFaces);
120  for (label facei = 0; facei < nInternalFaces; facei ++)
121  {
122  neiLevel[facei] = cellLevel[mesh().faceNeighbour()[facei]];
123  }
124  for (label facei = nInternalFaces; facei < nFaces; facei ++)
125  {
126  neiLevel[facei] = cellLevel[mesh().faceOwner()[facei]];
127  }
128  syncTools::swapFaceList(mesh(), neiLevel);
129 
130  // Count the number of parent anchors and anchors in each face
131  labelList faceNParentAnchors(nFaces, 0);
132  labelList faceNAnchors(nFaces, 0);
133  forAll(mesh().faces(), facei)
134  {
135  const label fLevel =
136  max(cellLevel[mesh()().faceOwner()[facei]], neiLevel[facei]);
137  const face& f = mesh().faces()[facei];
138  forAll(f, fpi)
139  {
140  if (pointLevel[f[fpi]] < fLevel)
141  {
142  faceNParentAnchors[facei] ++;
143  }
144  if (pointLevel[f[fpi]] <= fLevel)
145  {
146  faceNAnchors[facei] ++;
147  }
148  }
149  }
150 
151  // A face is (probably) refine-able if it has 4 anchors and no more than 1
152  // parent anchor (*), unless this is an original face (i.e., faceLevel ==
153  // 0), in which case it must have 0 parent anchors.
154  //
155  // (*) Note this is slightly different from the cell criteria. Faces
156  // constructed inside cells have no parent anchors.
157  //
158  boolList faceProtected(nFaces, false);
159  forAll(mesh().faces(), facei)
160  {
161  const label fLevel =
162  max(cellLevel[mesh().faceOwner()[facei]], neiLevel[facei]);
163 
164  faceProtected[facei] =
165  (faceNAnchors[facei] != 4)
166  || (fLevel > 0 && faceNParentAnchors[facei] > 1)
167  || (fLevel == 0 && faceNParentAnchors[facei] != 0);
168  }
169 
170  // Another criteria... Points are created when adjacent cells are refined.
171  // This means then should always be created along an edge in predictable
172  // patterns (e.g., with levels 1 4 3 4 2 4 3 4 1). No two adjacent points
173  // of a face should therefore have the same level, unless the edge is
174  // unrefined (e.g., 1 1). So, if we find two such adjacent points, then we
175  // also need to consider the face protected.
176  forAll(mesh().faces(), facei)
177  {
178  const face& f = mesh().faces()[facei];
179  const label fLevel =
180  max(cellLevel[mesh().faceOwner()[facei]], neiLevel[facei]);
181  forAll(f, fpi)
182  {
183  if
184  (
185  pointLevel[f[fpi]] > fLevel
186  && pointLevel[f[fpi]] == pointLevel[f[f.fcIndex(fpi)]]
187  )
188  {
189  faceProtected[facei] = true;
190  }
191  }
192  }
193 
194  syncTools::syncFaceList(mesh(), faceProtected, orEqOp<bool>());
195 
196  // Any cell which has a protected face is also protected
197  for (label facei = 0; facei < nFaces; facei ++)
198  {
199  const label own = mesh().faceOwner()[facei];
200  protectedCells[own] = protectedCells[own] || faceProtected[facei];
201  if (facei < nInternalFaces)
202  {
203  const label nei = mesh().faceNeighbour()[facei];
204  protectedCells[nei] = protectedCells[nei] || faceProtected[facei];
205  }
206  }
207 }
208 
209 
210 void Foam::fvMeshTopoChangers::refiner::calcAdditionallyProtectedCells
211 (
212  const PackedBoolList& protectedCells,
213  PackedBoolList& additionallyProtectedCells
214 ) const
215 {
216  if (protectedCells_.empty())
217  {
218  additionallyProtectedCells.clear();
219  return;
220  }
221 
222  const labelList& cellLevel = meshCutter_.cellLevel();
223 
224  additionallyProtectedCells = protectedCells_;
225 
226  // Get neighbouring cell level
227  labelList neiLevel(mesh().nFaces() - mesh().nInternalFaces());
228 
229  for
230  (
231  label facei = mesh().nInternalFaces();
232  facei < mesh().nFaces();
233  facei++
234  )
235  {
236  neiLevel[facei - mesh().nInternalFaces()] =
237  cellLevel[mesh().faceOwner()[facei]];
238  }
240 
241 
242  while (true)
243  {
244  // Pick up faces on border of protected cells
245  boolList seedFace(mesh().nFaces(), false);
246 
247  forAll(mesh().faceNeighbour(), facei)
248  {
249  const label own = mesh().faceOwner()[facei];
250  const bool ownProtected = additionallyProtectedCells.get(own);
251  const label nei = mesh().faceNeighbour()[facei];
252  const bool neiProtected = additionallyProtectedCells.get(nei);
253 
254  if (ownProtected && (cellLevel[nei] > cellLevel[own]))
255  {
256  seedFace[facei] = true;
257  }
258  else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
259  {
260  seedFace[facei] = true;
261  }
262  }
263 
264  for
265  (
266  label facei = mesh().nInternalFaces();
267  facei < mesh().nFaces();
268  facei++
269  )
270  {
271  const label own = mesh().faceOwner()[facei];
272  const bool ownProtected = additionallyProtectedCells.get(own);
273 
274  if
275  (
276  ownProtected
277  && (neiLevel[facei-mesh().nInternalFaces()] > cellLevel[own])
278  )
279  {
280  seedFace[facei] = true;
281  }
282  }
283 
284  syncTools::syncFaceList(mesh(), seedFace, orEqOp<bool>());
285 
286 
287  // Extend additionallyProtectedCells
288  bool hasExtended = false;
289 
290  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
291  {
292  if (seedFace[facei])
293  {
294  const label own = mesh().faceOwner()[facei];
295  if (additionallyProtectedCells.get(own) == 0)
296  {
297  additionallyProtectedCells.set(own, 1);
298  hasExtended = true;
299  }
300 
301  const label nei = mesh().faceNeighbour()[facei];
302  if (additionallyProtectedCells.get(nei) == 0)
303  {
304  additionallyProtectedCells.set(nei, 1);
305  hasExtended = true;
306  }
307  }
308  }
309 
310  for
311  (
312  label facei = mesh().nInternalFaces();
313  facei < mesh().nFaces();
314  facei++
315  )
316  {
317  if (seedFace[facei])
318  {
319  const label own = mesh().faceOwner()[facei];
320 
321  if (additionallyProtectedCells.get(own) == 0)
322  {
323  additionallyProtectedCells.set(own, 1);
324  hasExtended = true;
325  }
326  }
327  }
328 
329  if (!returnReduce(hasExtended, orOp<bool>()))
330  {
331  break;
332  }
333  }
334 }
335 
336 
337 void Foam::fvMeshTopoChangers::refiner::readDict()
338 {
339  refineInterval_ = dict_.lookup<label>("refineInterval");
340 
341  if (refineInterval_ < 0)
342  {
344  << "Illegal refineInterval " << refineInterval_ << nl
345  << "The refineInterval setting in the dynamicMeshDict should"
346  << " be >= 1." << nl
347  << exit(FatalIOError);
348  }
349 
350  maxCells_ = dict_.lookup<label>("maxCells");
351 
352  if (maxCells_ <= 0)
353  {
355  << "Illegal maximum number of cells " << maxCells_ << nl
356  << "The maxCells setting in the dynamicMeshDict should"
357  << " be > 0." << nl
358  << exit(FatalIOError);
359  }
360 
361  nBufferLayers_ = dict_.lookup<label>("nBufferLayers");
362 
363  if (dict_.found("correctFluxes"))
364  {
365  const List<Pair<word>> fluxVelocities = List<Pair<word>>
366  (
367  dict_.lookup("correctFluxes")
368  );
369 
370  // Rework into hashtable.
371  correctFluxes_.resize(fluxVelocities.size());
372  forAll(fluxVelocities, i)
373  {
374  correctFluxes_.insert(fluxVelocities[i][0], fluxVelocities[i][1]);
375  }
376  }
377 
378  dumpLevel_ = Switch(dict_.lookup("dumpLevel"));
379 }
380 
381 
383 Foam::fvMeshTopoChangers::refiner::refine
384 (
385  const labelList& cellsToRefine
386 )
387 {
388  mesh().preChange();
389 
390  // Mesh changing engine.
391  polyTopoChange meshMod(mesh());
392 
393  // Play refinement commands into mesh changer.
394  meshCutter_.setRefinement(cellsToRefine, meshMod);
395 
396  // Create mesh
397  // return map from old to new mesh.
398  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh());
399 
400  Info<< "Refined from "
401  << returnReduce(map().nOldCells(), sumOp<label>())
402  << " to " << mesh().globalData().nTotalCells() << " cells." << endl;
403 
404  if (debug)
405  {
406  // Check map.
407  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
408  {
409  const label oldFacei = map().faceMap()[facei];
410 
411  if (oldFacei >= mesh().nInternalFaces())
412  {
414  << "New internal face:" << facei
415  << " fc:" << mesh().faceCentres()[facei]
416  << " originates from boundary oldFace:" << oldFacei
417  << abort(FatalError);
418  }
419  }
420  }
421 
422  // Update fields
423  mesh().topoChange(map);
424 
425  {
426  // Correct the flux for modified/added faces. All the faces which only
427  // have been renumbered will already have been handled by the mapping.
428  const labelList& faceMap = map().faceMap();
429  const labelList& reverseFaceMap = map().reverseFaceMap();
430 
431  // Storage for any master faces. These will be the original faces
432  // on the coarse cell that get split into four (or rather the
433  // master face gets modified and three faces get added from the master)
434  labelHashSet masterFaces(4*cellsToRefine.size());
435 
436  forAll(faceMap, facei)
437  {
438  const label oldFacei = faceMap[facei];
439 
440  if (oldFacei >= 0)
441  {
442  const label masterFacei = reverseFaceMap[oldFacei];
443 
444  if (masterFacei < 0)
445  {
447  << "Problem: should not have removed faces"
448  << " when refining."
449  << nl << "face:" << facei << abort(FatalError);
450  }
451  else if (masterFacei != facei)
452  {
453  masterFaces.insert(masterFacei);
454  }
455  }
456  }
457  if (debug)
458  {
459  Pout<< "Found " << masterFaces.size() << " split faces " << endl;
460  }
461 
462  refineFluxes(masterFaces, map());
463  refineUfs(masterFaces, map());
464  }
465 
466  // Update numbering of protectedCells_
467  if (protectedCells_.size())
468  {
469  PackedBoolList newProtectedCell(mesh().nCells());
470 
471  forAll(newProtectedCell, celli)
472  {
473  const label oldCelli = map().cellMap()[celli];
474  newProtectedCell.set(celli, protectedCells_.get(oldCelli));
475  }
476  protectedCells_.transfer(newProtectedCell);
477  }
478 
479  // Debug: Check refinement levels (across faces only)
480  meshCutter_.checkRefinementLevels(-1, labelList(0));
481 
482  return map;
483 }
484 
485 
487 Foam::fvMeshTopoChangers::refiner::unrefine
488 (
489  const labelList& splitPoints
490 )
491 {
492  mesh().preChange();
493 
494  // Mesh changing engine.
495  polyTopoChange meshMod(mesh());
496 
497  // Play refinement commands into mesh changer.
498  meshCutter_.setUnrefinement(splitPoints, meshMod);
499 
500 
501  // Save information on faces that will be combined
502  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
503 
504  // Find the faceMidPoints on cells to be combined.
505  // for each face resulting of split of face into four store the
506  // midpoint
507  Map<label> faceToSplitPoint(3*splitPoints.size());
508 
509  {
510  forAll(splitPoints, i)
511  {
512  const label pointi = splitPoints[i];
513  const labelList& pEdges = mesh().pointEdges()[pointi];
514 
515  forAll(pEdges, j)
516  {
517  const label otherPointi =
518  mesh().edges()[pEdges[j]].otherVertex(pointi);
519 
520  const labelList& pFaces = mesh().pointFaces()[otherPointi];
521 
522  forAll(pFaces, pFacei)
523  {
524  faceToSplitPoint.insert(pFaces[pFacei], otherPointi);
525  }
526  }
527  }
528  }
529 
530 
531  // Change mesh and generate map.
532  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh());
533 
534  Info<< "Unrefined from "
535  << returnReduce(map().nOldCells(), sumOp<label>())
536  << " to " << mesh().globalData().nTotalCells() << " cells."
537  << endl;
538 
539  // Update fields
540  mesh().topoChange(map);
541 
542  // Correct the fluxes for modified faces
543  unrefineFluxes(faceToSplitPoint, map());
544 
545  // Correct the face velocities for modified faces
546  unrefineUfs(faceToSplitPoint, map());
547 
548  // Update numbering of protectedCells_
549  if (protectedCells_.size())
550  {
551  PackedBoolList newProtectedCell(mesh().nCells());
552 
553  forAll(newProtectedCell, celli)
554  {
555  const label oldCelli = map().cellMap()[celli];
556  if (oldCelli >= 0)
557  {
558  newProtectedCell.set(celli, protectedCells_.get(oldCelli));
559  }
560  }
561  protectedCells_.transfer(newProtectedCell);
562  }
563 
564  // Debug: Check refinement levels (across faces only)
565  meshCutter_.checkRefinementLevels(-1, labelList(0));
566 
567  return map;
568 }
569 
570 
571 Foam::word Foam::fvMeshTopoChangers::refiner::Uname
572 (
573  const surfaceVectorField& Uf
574 ) const
575 {
576  const word UfName(Uf.member());
577 
578  return
580  (
581  UfName.back() == 'f'
582  ? word(UfName(UfName.size() - 1))
583  : UfName.compare(UfName.size() - 3, 3, "f_0") == 0
584  ? word(UfName(UfName.size() - 3) + "_0")
585  : word::null,
586  Uf.group()
587  );
588 }
589 
590 
591 void Foam::fvMeshTopoChangers::refiner::refineFluxes
592 (
593  const labelHashSet& masterFaces,
594  const polyTopoChangeMap& map
595 )
596 {
597  if (correctFluxes_.size())
598  {
599  UPtrList<surfaceScalarField> fluxes
600  (
601  mesh().fields<surfaceScalarField>()
602  );
603 
604  forAll(fluxes, i)
605  {
606  surfaceScalarField& flux = fluxes[i];
607 
608  if (!correctFluxes_.found(flux.name()))
609  {
611  << "Cannot find surfaceScalarField " << flux.name()
612  << " in user-provided flux mapping table "
613  << correctFluxes_ << endl
614  << " The flux mapping table is used to recreate the"
615  << " flux on newly created faces." << endl
616  << " Either add the entry if it is a flux or use ("
617  << flux.name() << " none) to suppress this warning."
618  << endl;
619  }
620  else
621  {
622  const word& method = correctFluxes_[flux.name()];
623 
624  if (method == "none")
625  {}
626  else if (method == "NaN")
627  {
628  Pout<< "Setting surfaceScalarField " << flux.name()
629  << " to NaN" << endl;
630 
631  sigFpe::fillNan(flux.primitiveFieldRef());
632  }
633  else
634  {
636  << "Unknown refinement method " << method
637  << " for surfaceScalarField " << flux.name()
638  << " in user-provided flux mapping table "
639  << correctFluxes_
640  << exit(FatalError);
641  }
642  }
643  }
644  }
645 }
646 
647 
648 void Foam::fvMeshTopoChangers::refiner::unrefineFluxes
649 (
650  const Map<label>& faceToSplitPoint,
651  const polyTopoChangeMap& map
652 )
653 {
654  if (correctFluxes_.size())
655  {
656  UPtrList<surfaceScalarField> fluxes
657  (
658  mesh().fields<surfaceScalarField>()
659  );
660 
661  forAll(fluxes, i)
662  {
663  surfaceScalarField& flux = fluxes[i];
664 
665  if (!correctFluxes_.found(flux.name()))
666  {
668  << "Cannot find surfaceScalarField " << flux.name()
669  << " in user-provided flux mapping table "
670  << correctFluxes_ << endl
671  << " The flux mapping table is used to recreate the"
672  << " flux on newly created faces." << endl
673  << " Either add the entry if it is a flux or use ("
674  << flux.name() << " none) to suppress this warning."
675  << endl;
676  }
677  else
678  {
679  const word& method = correctFluxes_[flux.name()];
680 
681  if (method != "none")
682  {
684  << "Unknown unrefinement method " << method
685  << " for surfaceScalarField " << flux.name()
686  << " in user-provided flux mapping table "
687  << correctFluxes_
688  << exit(FatalError);
689  }
690  }
691  }
692  }
693 }
694 
695 
696 void Foam::fvMeshTopoChangers::refiner::refineUfs
697 (
698  const labelHashSet& masterFaces,
699  const polyTopoChangeMap& map
700 )
701 {
702  const labelList& faceMap = map.faceMap();
703  const labelList& reverseFaceMap = map.reverseFaceMap();
704 
705  // Interpolate U to Uf for added faces
706  UPtrList<surfaceVectorField> Ufs(mesh().fields<surfaceVectorField>());
707 
708  forAll(Ufs, i)
709  {
710  surfaceVectorField& Uf = Ufs[i];
711 
712  const word Uname(this->Uname(Uf));
713 
714  if (Uname != word::null)
715  {
716  const surfaceVectorField UfU
717  (
718  fvc::interpolate(mesh().lookupObject<volVectorField>(Uname))
719  );
720 
721  // Recalculate new internal faces.
722  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
723  {
724  label oldFacei = faceMap[facei];
725 
726  if (oldFacei == -1)
727  {
728  // Inserted
729  Uf[facei] = UfU[facei];
730  }
731  else if (reverseFaceMap[oldFacei] != facei)
732  {
733  // face-from-masterface
734  Uf[facei] = UfU[facei];
735  }
736  }
737 
738  // Recalculate new boundary faces.
739  surfaceVectorField::Boundary& UfBf = Uf.boundaryFieldRef();
740  forAll(UfBf, patchi)
741  {
742  fvsPatchVectorField& patchUf = UfBf[patchi];
743  const fvsPatchVectorField& patchUfU =
744  UfU.boundaryField()[patchi];
745 
746  label facei = patchUf.patch().start();
747 
748  forAll(patchUf, i)
749  {
750  label oldFacei = faceMap[facei];
751 
752  if (oldFacei == -1)
753  {
754  // Inserted/appended
755  patchUf[i] = patchUfU[i];
756  }
757  else if (reverseFaceMap[oldFacei] != facei)
758  {
759  // face-from-master-face
760  patchUf[i] = patchUfU[i];
761  }
762 
763  facei++;
764  }
765  }
766 
767  // Update master faces
768  forAllConstIter(labelHashSet, masterFaces, iter)
769  {
770  label facei = iter.key();
771 
772  if (mesh().isInternalFace(facei))
773  {
774  Uf[facei] = UfU[facei];
775  }
776  else
777  {
778  const label patchi =
779  mesh().poly().boundary().whichPatch(facei);
780  const label i =
781  facei - mesh().poly().boundary()[patchi].start();
782 
783  const fvsPatchVectorField& patchUfU =
784  UfU.boundaryField()[patchi];
785 
786  fvsPatchVectorField& patchUf = UfBf[patchi];
787 
788  patchUf[i] = patchUfU[i];
789  }
790  }
791  }
792  }
793 }
794 
795 
796 void Foam::fvMeshTopoChangers::refiner::unrefineUfs
797 (
798  const Map<label>& faceToSplitPoint,
799  const polyTopoChangeMap& map
800 )
801 {
802  const labelList& reversePointMap = map.reversePointMap();
803  const labelList& reverseFaceMap = map.reverseFaceMap();
804 
805  // Interpolate U to Uf for added faces
806  UPtrList<surfaceVectorField> Ufs(mesh().fields<surfaceVectorField>());
807 
808  forAll(Ufs, i)
809  {
810  surfaceVectorField& Uf = Ufs[i];
811 
812  const word Uname(this->Uname(Uf));
813 
814  if (Uname != word::null)
815  {
816  surfaceVectorField::Boundary& UfBf = Uf.boundaryFieldRef();
817 
818  const surfaceVectorField UfU
819  (
820  fvc::interpolate(mesh().lookupObject<volVectorField>(Uname))
821  );
822 
823  forAllConstIter(Map<label>, faceToSplitPoint, iter)
824  {
825  const label oldFacei = iter.key();
826  const label oldPointi = iter();
827 
828  if (reversePointMap[oldPointi] < 0)
829  {
830  // midpoint was removed. See if face still exists.
831  const label facei = reverseFaceMap[oldFacei];
832 
833  if (facei >= 0)
834  {
835  if (mesh().isInternalFace(facei))
836  {
837  Uf[facei] = UfU[facei];
838  }
839  else
840  {
841  const label patchi =
842  mesh().poly().boundary().whichPatch(facei);
843  const label i =
844  facei
845  - mesh().poly().boundary()[patchi].start();
846 
847  UfBf[patchi][i] = UfU.boundaryField()[patchi][i];
848  }
849  }
850  }
851  }
852  }
853  }
854 }
855 
856 
857 const Foam::cellZone& Foam::fvMeshTopoChangers::refiner::findCellZone
858 (
859  const word& cellZoneName
860 ) const
861 {
862  const label cellZoneID = mesh().cellZones().findIndex(cellZoneName);
863 
864  bool cellZoneFound = (cellZoneID != -1);
865  reduce(cellZoneFound, orOp<bool>());
866 
867  if (!cellZoneFound)
868  {
870  << "cannot find cellZone " << cellZoneName
871  << exit(FatalError);
872  }
873 
874  return mesh().cellZones()[cellZoneID];
875 }
876 
877 
879 Foam::fvMeshTopoChangers::refiner::cellToPoint(const scalarField& vFld) const
880 {
881  scalarField pFld(mesh().nPoints());
882 
883  forAll(mesh().pointCells(), pointi)
884  {
885  const labelList& pCells = mesh().pointCells()[pointi];
886 
887  scalar sum = 0.0;
888  forAll(pCells, i)
889  {
890  sum += vFld[pCells[i]];
891  }
892  pFld[pointi] = sum/pCells.size();
893  }
894 
895  return pFld;
896 }
897 
898 
899 Foam::scalarField Foam::fvMeshTopoChangers::refiner::error
900 (
901  const scalarField& fld,
902  const scalar minLevel,
903  const scalar maxLevel
904 ) const
905 {
906  scalarField c(fld.size(), -1);
907 
908  forAll(c, celli)
909  {
910  scalar err = min(fld[celli] - minLevel, maxLevel - fld[celli]);
911 
912  if (err >= 0)
913  {
914  c[celli] = err;
915  }
916  }
917 
918  return c;
919 }
920 
921 
922 Foam::scalarField Foam::fvMeshTopoChangers::refiner::error
923 (
924  const scalarField& fld,
925  const labelList& cells,
926  const scalar minLevel,
927  const scalar maxLevel
928 ) const
929 {
930  scalarField c(fld.size(), -1);
931 
932  forAll(cells, i)
933  {
934  const label celli = cells[i];
935 
936  scalar err = min(fld[celli] - minLevel, maxLevel - fld[celli]);
937 
938  if (err >= 0)
939  {
940  c[celli] = err;
941  }
942  }
943 
944  return c;
945 }
946 
947 
948 void Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
949 (
950  PackedBoolList& candidateCells,
951  const scalar lowerRefineLevel,
952  const scalar upperRefineLevel,
953  const scalar maxRefinement,
954  const scalarField& vFld
955 ) const
956 {
957  // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
958  // higher more desirable to be refined).
959  const scalarField cellError
960  (
961  error(vFld, lowerRefineLevel, upperRefineLevel)
962  );
963 
964  // Mark cells that are candidates for refinement.
965  forAll(cellError, celli)
966  {
967  if (cellError[celli] > 0)
968  {
969  candidateCells.set(celli, 1);
970  }
971  }
972 }
973 
974 
975 void Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
976 (
977  PackedBoolList& candidateCells,
978  const scalar lowerRefineLevel,
979  const scalar upperRefineLevel,
980  const scalar maxRefinement,
981  const scalarField& vFld,
982  const labelList& cells
983 ) const
984 {
985  // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
986  // higher more desirable to be refined).
987  const scalarField cellError
988  (
989  error(vFld, cells, lowerRefineLevel, upperRefineLevel)
990  );
991 
992  // Mark cells that are candidates for refinement.
993  forAll(cellError, celli)
994  {
995  if (cellError[celli] > 0)
996  {
997  candidateCells.set(celli, 1);
998  }
999  }
1000 }
1001 
1002 
1003 Foam::scalar Foam::fvMeshTopoChangers::refiner::selectRefineCandidates
1004 (
1005  PackedBoolList& candidateCells,
1006  const dictionary& refineDict
1007 ) const
1008 {
1009  const word fieldName(refineDict.lookup("field"));
1010 
1011  const volScalarField& vFld = mesh().lookupObject<volScalarField>(fieldName);
1012 
1013  const scalar lowerRefineLevel =
1014  refineDict.lookup<scalar>("lowerRefineLevel");
1015  const scalar upperRefineLevel =
1016  refineDict.lookup<scalar>("upperRefineLevel");
1017 
1018  const label maxRefinement = refineDict.lookup<label>("maxRefinement");
1019 
1020  if (maxRefinement <= 0)
1021  {
1023  << "Illegal maximum refinement level " << maxRefinement << nl
1024  << "The maxCells setting in the dynamicMeshDict should"
1025  << " be > 0." << nl
1026  << exit(FatalError);
1027  }
1028 
1029  if (refineDict.found("cellZone"))
1030  {
1031  // Determine candidates for refinement (looking at field only)
1032  selectRefineCandidates
1033  (
1034  candidateCells,
1035  lowerRefineLevel,
1036  upperRefineLevel,
1037  maxRefinement,
1038  vFld,
1039  findCellZone(refineDict.lookup("cellZone"))
1040  );
1041  }
1042  else
1043  {
1044  // Determine candidates for refinement (looking at field only)
1045  selectRefineCandidates
1046  (
1047  candidateCells,
1048  lowerRefineLevel,
1049  upperRefineLevel,
1050  maxRefinement,
1051  vFld
1052  );
1053  }
1054 
1055  return maxRefinement;
1056 }
1057 
1058 
1059 Foam::labelList Foam::fvMeshTopoChangers::refiner::selectRefineCells
1060 (
1061  const label maxCells,
1062  const label maxRefinement,
1063  const PackedBoolList& candidateCells
1064 ) const
1065 {
1066  // Every refined cell causes 7 extra cells
1067  const label nTotToRefine = (maxCells - mesh().globalData().nTotalCells())/7;
1068 
1069  const labelList& cellLevel = meshCutter_.cellLevel();
1070 
1071  // Calculate cells that are additionally protected, as their refinement
1072  // would trigger refinement of protectedCells due to the 2:1 limit
1073  PackedBoolList additionallyProtectedCells;
1074  calcAdditionallyProtectedCells(protectedCells_, additionallyProtectedCells);
1075 
1076  // Count current selection
1077  const label nLocalCandidates = count(candidateCells, 1);
1078  const label nCandidates = returnReduce(nLocalCandidates, sumOp<label>());
1079 
1080  // Collect all cells
1081  DynamicList<label> candidates(nLocalCandidates);
1082 
1083  if (nCandidates < nTotToRefine)
1084  {
1085  forAll(candidateCells, celli)
1086  {
1087  if
1088  (
1089  candidateCells.get(celli)
1090  && (
1091  additionallyProtectedCells.empty()
1092  || !additionallyProtectedCells.get(celli)
1093  )
1094  )
1095  {
1096  candidates.append(celli);
1097  }
1098  }
1099  }
1100  else
1101  {
1102  // Sort by error? For now just truncate.
1103  for (label level = 0; level < maxRefinement; level++)
1104  {
1105  forAll(candidateCells, celli)
1106  {
1107  if
1108  (
1109  cellLevel[celli] == level
1110  && candidateCells.get(celli)
1111  && (
1112  additionallyProtectedCells.empty()
1113  || !additionallyProtectedCells.get(celli)
1114  )
1115  )
1116  {
1117  candidates.append(celli);
1118  }
1119  }
1120 
1121  if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
1122  {
1123  break;
1124  }
1125  }
1126  }
1127 
1128  // Guarantee 2:1 refinement after refinement
1129  labelList consistentSet
1130  (
1131  meshCutter_.consistentRefinement
1132  (
1133  candidates.shrink(),
1134  true // Add to set to guarantee 2:1
1135  )
1136  );
1137 
1138  Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
1139  << " cells for refinement out of " << mesh().globalData().nTotalCells()
1140  << "." << endl;
1141 
1142  return consistentSet;
1143 }
1144 
1145 
1146 Foam::labelList Foam::fvMeshTopoChangers::refiner::selectUnrefinePoints
1147 (
1148  const PackedBoolList& markedCell
1149 ) const
1150 {
1151  // All points that can be unrefined
1152  const labelList splitPoints(meshCutter_.getSplitPoints());
1153 
1154  DynamicList<label> newSplitPoints(splitPoints.size());
1155 
1156  forAll(splitPoints, i)
1157  {
1158  const label pointi = splitPoints[i];
1159 
1160  // Check that all cells are not marked
1161  const labelList& pCells = mesh().pointCells()[pointi];
1162 
1163  bool hasMarked = false;
1164 
1165  forAll(pCells, pCelli)
1166  {
1167  if (markedCell.get(pCells[pCelli]))
1168  {
1169  hasMarked = true;
1170  break;
1171  }
1172  }
1173 
1174  if (!hasMarked)
1175  {
1176  newSplitPoints.append(pointi);
1177  }
1178  }
1179 
1180 
1181  newSplitPoints.shrink();
1182 
1183  // Guarantee 2:1 refinement after unrefinement
1184  labelList consistentSet
1185  (
1186  meshCutter_.consistentUnrefinement
1187  (
1188  newSplitPoints,
1189  false
1190  )
1191  );
1192 
1193  Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
1194  << " split points out of a possible "
1195  << returnReduce(splitPoints.size(), sumOp<label>())
1196  << "." << endl;
1197 
1198  return consistentSet;
1199 }
1200 
1201 
1202 void Foam::fvMeshTopoChangers::refiner::extendMarkedCells
1203 (
1204  PackedBoolList& markedCell
1205 ) const
1206 {
1207  // Mark faces using any marked cell
1208  boolList markedFace(mesh().nFaces(), false);
1209 
1210  forAll(markedCell, celli)
1211  {
1212  if (markedCell.get(celli))
1213  {
1214  const cell& cFaces = mesh().cells()[celli];
1215 
1216  forAll(cFaces, i)
1217  {
1218  markedFace[cFaces[i]] = true;
1219  }
1220  }
1221  }
1222 
1223  syncTools::syncFaceList(mesh(), markedFace, orEqOp<bool>());
1224 
1225  // Update cells using any markedFace
1226  for (label facei = 0; facei < mesh().nInternalFaces(); facei++)
1227  {
1228  if (markedFace[facei])
1229  {
1230  markedCell.set(mesh().faceOwner()[facei], 1);
1231  markedCell.set(mesh().faceNeighbour()[facei], 1);
1232  }
1233  }
1234 
1235  for
1236  (
1237  label facei = mesh().nInternalFaces();
1238  facei < mesh().nFaces();
1239  facei++
1240  )
1241  {
1242  if (markedFace[facei])
1243  {
1244  markedCell.set(mesh().faceOwner()[facei], 1);
1245  }
1246  }
1247 }
1248 
1249 
1250 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1251 
1253 :
1255  dict_(dict),
1256  meshCutter_(hexRef8::New(mesh)),
1257  dumpLevel_(false),
1258  nRefinementIterations_(0),
1259  protectedCells_(mesh.nCells(), 0),
1260  timeIndex_(-1)
1261 {
1262  // Read static part of dictionary
1263  readDict();
1264 
1265  // Calculate and report the protected cells
1266  calcProtectedCells(protectedCells_);
1267 
1268  // Report
1269  labelList protectedCellsSet = protectedCells_.used();
1270  const label nProtectedCells =
1271  returnReduce(protectedCellsSet.size(), sumOp<label>());
1272  if (nProtectedCells)
1273  {
1274  Info<< "Detected " << nProtectedCells << " cells that are protected "
1275  << "from refinement. Writing these to cell-set 'protectedCells'."
1276  << endl;
1277 
1278  cellSet(mesh, "protectedCells", protectedCellsSet).write();
1279  }
1280  else
1281  {
1282  protectedCells_.clear();
1283  }
1284 }
1285 
1286 
1287 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1288 
1290 {}
1291 
1292 
1293 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1294 
1296 {
1297  // Only refine on the first call in a time-step
1298  if (timeIndex_ != mesh().time().timeIndex())
1299  {
1300  timeIndex_ = mesh().time().timeIndex();
1301  }
1302  else
1303  {
1304  return false;
1305  }
1306 
1307  bool hasChanged = false;
1308 
1309  if (refineInterval_ == 0)
1310  {
1311  return hasChanged;
1312  }
1313 
1314  // Note: cannot refine at time 0 since no V0 present since mesh not
1315  // moved yet.
1316 
1317  if
1318  (
1319  mesh().time().timeIndex() > 0
1320  && mesh().time().timeIndex() % refineInterval_ == 0
1321  )
1322  {
1323  // Cells marked for refinement or otherwise protected from unrefinement.
1324  PackedBoolList refineCells(mesh().nCells());
1325 
1326  label maxRefinement = 0;
1327 
1328  if (dict_.isDict("refinementRegions"))
1329  {
1331  (
1332  dict_.subDict("refinementRegions")
1333  );
1334 
1336  {
1337  maxRefinement = max
1338  (
1339  selectRefineCandidates
1340  (
1341  refineCells,
1342  refinementRegions.subDict(iter().keyword())
1343  ),
1344  maxRefinement
1345  );
1346  }
1347  }
1348  else
1349  {
1350  maxRefinement = selectRefineCandidates(refineCells, dict_);
1351  }
1352 
1353  // Extend with a buffer layer to prevent neighbouring points
1354  // being unrefined.
1355  for (label i = 0; i < nBufferLayers_; i++)
1356  {
1357  extendMarkedCells(refineCells);
1358  }
1359 
1360  PackedBoolList refinableCells(refineCells);
1361 
1362  {
1363  const labelList& cellLevel = meshCutter_.cellLevel();
1364 
1365  // Mark cells that are candidates for refinement.
1366  forAll(cellLevel, celli)
1367  {
1368  if (cellLevel[celli] >= maxRefinement)
1369  {
1370  refinableCells.unset(celli);
1371  }
1372  }
1373  }
1374 
1375  if (mesh().globalData().nTotalCells() < maxCells_)
1376  {
1377  // Select subset of candidates. Take into account max allowable
1378  // cells, refinement level, protected cells.
1379  const labelList cellsToRefine
1380  (
1381  selectRefineCells
1382  (
1383  maxCells_,
1384  maxRefinement,
1385  refinableCells
1386  )
1387  );
1388 
1389  const label nCellsToRefine = returnReduce
1390  (
1391  cellsToRefine.size(), sumOp<label>()
1392  );
1393 
1394  if (nCellsToRefine > 0)
1395  {
1396  // Refine/update mesh and map fields
1397  autoPtr<polyTopoChangeMap> map = refine(cellsToRefine);
1398 
1399  // Update refinableCells. Note that some of the marked ones have
1400  // not been refined due to constraints.
1401  {
1402  const labelList& cellMap = map().cellMap();
1403  const labelList& reverseCellMap = map().reverseCellMap();
1404 
1405  PackedBoolList newRefineCell(cellMap.size());
1406 
1407  forAll(cellMap, celli)
1408  {
1409  const label oldCelli = cellMap[celli];
1410 
1411  if (oldCelli < 0)
1412  {
1413  newRefineCell.set(celli, 1);
1414  }
1415  else if (reverseCellMap[oldCelli] != celli)
1416  {
1417  newRefineCell.set(celli, 1);
1418  }
1419  else
1420  {
1421  newRefineCell.set
1422  (
1423  celli,
1424  refinableCells.get(oldCelli)
1425  );
1426  }
1427  }
1428  refinableCells.transfer(newRefineCell);
1429  }
1430 
1431  hasChanged = true;
1432  }
1433  }
1434 
1435  {
1436  // Select unrefineable points that are not marked in refineCells
1437  const labelList pointsToUnrefine(selectUnrefinePoints(refineCells));
1438 
1439  const label nSplitPoints = returnReduce
1440  (
1441  pointsToUnrefine.size(),
1442  sumOp<label>()
1443  );
1444 
1445  if (nSplitPoints > 0)
1446  {
1447  // Refine/update mesh
1448  unrefine(pointsToUnrefine);
1449 
1450  hasChanged = true;
1451  }
1452  }
1453 
1454 
1455  if ((nRefinementIterations_ % 10) == 0)
1456  {
1457  // Compact refinement history occasionally (how often?).
1458  // Unrefinement causes holes in the refinementHistory.
1459  const_cast<refinementHistory&>(meshCutter_.history()).compact();
1460  }
1461  nRefinementIterations_++;
1462  }
1463 
1464  return hasChanged;
1465 }
1466 
1467 
1469 {}
1470 
1471 
1473 {}
1474 
1475 
1477 (
1478  const polyDistributionMap& map
1479 )
1480 {}
1481 
1482 
1483 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
Macros for easy insertion into run-time selection tables.
GeometricBoundaryField< Type, GeoMesh, PrimitiveField > Boundary
Type of the boundary field.
static word groupName(Name name, const word &group)
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
A bit-packed bool list.
void set(const PackedList< 1 > &)
Set specified bits.
labelList used() const
Return indices of the used (true) elements as a list of labels.
void transfer(PackedBoolList &)
Transfer the contents of the argument list into this list.
void unset(const PackedList< 1 > &)
Unset specified bits.
unsigned int get(const label) const
Get value at index I.
Definition: PackedListI.H:938
void clear()
Clear the list, i.e. set addressable size to zero.
Definition: PackedListI.H:873
label findIndex(const word &key) const
Return the index of the given the key or -1 if not found.
label timeIndex() const
Return current time index.
Definition: TimeStateI.H:28
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A collection of cell labels.
Definition: cellSet.H:51
Named list of cell indices representing a sub-set of the mesh.
Definition: cellZone.H:61
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Abstract base class for fvMesh topology changers.
fvMesh & mesh()
Return the fvMesh.
Dynamic mesh refinement/unrefinement based on volScalarField values.
virtual void topoChange(const polyTopoChangeMap &)
Update corresponding to the given map.
virtual void distribute(const polyDistributionMap &)
Update corresponding to the given distribution map.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
virtual bool update()
Update the mesh for both mesh motion and topology change.
refiner(fvMesh &mesh, const dictionary &dict)
Construct from fvMesh and dictionary.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
void preChange()
Prepare for a mesh change.
Definition: fvMesh.C:1188
virtual void topoChange(const polyTopoChangeMap &map)
Update mesh corresponding to the given map.
Definition: fvMesh.C:1335
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
label nTotalCells() const
Return total number of cells in decomposed mesh.
Refinement of (split) hexes using polyTopoChange.
Definition: hexRef8.H:73
const Type & lookupObject(const word &name) const
Lookup and return the object of the given Type and name.
Motion of the mesh specified as a list of pointMeshMovers.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:51
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:438
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1471
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1327
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
const labelListList & pointCells() const
label nInternalFaces() const
const labelListList & pointFaces() const
const cellList & cells() const
label nFaces() const
All refinement history. Used in unrefinement.
Encapsulates queries for volume refinement ('refine all cells within shell').
virtual bool write(const bool write=true) const
Write using setting from DB.
static void fillNan(UList< scalar > &)
Fill block of data with NaN.
Definition: sigFpe.C:46
static void swapFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled face values.
Definition: syncTools.H:469
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronise values on all mesh faces.
Definition: syncTools.H:387
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
label nPoints
const cellShapeList & cells
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
const dimensionSet time
addToRunTimeSelectionTable(fvMeshTopoChanger, list, fvMesh)
tmp< SurfaceField< typename innerProduct< vector, Type >::type > > flux(const VolField< Type > &vf)
Return the face-flux field obtained from the given volVectorField.
static tmp< SurfaceField< Type > > interpolate(const VolField< Type > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
errorManip< error > abort(error &err)
Definition: errorManip.H:131
SurfaceField< scalar > surfaceScalarField
messageStream Info
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
VolField< scalar > volScalarField
Definition: volFieldsFwd.H:62
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
IOerror FatalIOError
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:213
error FatalError
label count(const ListType &l, typename ListType::const_reference x)
Count the number of occurrences of a value in a list.
SurfaceField< vector > surfaceVectorField
fvsPatchField< vector > fvsPatchVectorField
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
static const char nl
Definition: Ostream.H:297
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
label timeIndex
Definition: getTimeIndex.H:4
labelList f(nPoints)
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:229
dictionary dict