multiDirRefinement.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-2025 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 
26 #include "multiDirRefinement.H"
27 #include "polyMesh.H"
28 #include "Time.H"
29 #include "undoableMeshCutter.H"
30 #include "hexCellLooper.H"
31 #include "geomCellLooper.H"
32 #include "topoSet.H"
33 #include "directions.H"
34 #include "hexRef8.H"
35 #include "polyTopoChangeMap.H"
36 #include "polyTopoChange.H"
37 #include "ListOps.H"
38 #include "cellModeller.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
45 }
46 
47 
48 // * * * * * * * * * * * * * Private Statc Functions * * * * * * * * * * * * //
49 
50 void Foam::multiDirRefinement::addCells
51 (
52  const Map<label>& splitMap,
53  List<refineCell>& refCells
54 )
55 {
56  label newRefI = refCells.size();
57 
58  label oldSize = refCells.size();
59 
60  refCells.setSize(newRefI + splitMap.size());
61 
62  for (label refI = 0; refI < oldSize; refI++)
63  {
64  const refineCell& refCell = refCells[refI];
65 
66  Map<label>::const_iterator iter = splitMap.find(refCell.cellNo());
67 
68  if (iter == splitMap.end())
69  {
71  << "Problem : cannot find added cell for cell "
72  << refCell.cellNo() << abort(FatalError);
73  }
74 
75  refCells[newRefI++] = refineCell(iter(), refCell.direction());
76  }
77 }
78 
79 
80 void Foam::multiDirRefinement::update
81 (
82  const Map<label>& splitMap,
83  vectorField& field
84 )
85 {
86  field.setSize(field.size() + splitMap.size());
87 
88  forAllConstIter(Map<label>, splitMap, iter)
89  {
90  field[iter()] = field[iter.key()];
91  }
92 }
93 
94 
95 void Foam::multiDirRefinement::addCells
96 (
97  const Map<label>& splitMap,
98  labelList& labels
99 )
100 {
101  label newCelli = labels.size();
102 
103  labels.setSize(labels.size() + splitMap.size());
104 
105  forAllConstIter(Map<label>, splitMap, iter)
106  {
107  labels[newCelli++] = iter();
108  }
109 }
110 
111 
112 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
113 
114 void Foam::multiDirRefinement::addCells
115 (
116  const primitiveMesh& mesh,
117  const Map<label>& splitMap
118 )
119 {
120  // Construct inverse addressing: from new to original cell.
121  labelList origCell(mesh.nCells(), -1);
122 
123  forAll(addedCells_, celli)
124  {
125  const labelList& added = addedCells_[celli];
126 
127  forAll(added, i)
128  {
129  label slave = added[i];
130 
131  if (origCell[slave] == -1)
132  {
133  origCell[slave] = celli;
134  }
135  else if (origCell[slave] != celli)
136  {
138  << "Added cell " << slave << " has two different masters:"
139  << origCell[slave] << " , " << celli
140  << abort(FatalError);
141  }
142  }
143  }
144 
145 
146  forAllConstIter(Map<label>, splitMap, iter)
147  {
148  label masterI = iter.key();
149  label newCelli = iter();
150 
151  while (origCell[masterI] != -1 && origCell[masterI] != masterI)
152  {
153  masterI = origCell[masterI];
154  }
155 
156  if (masterI >= addedCells_.size())
157  {
159  << "Map of added cells contains master cell " << masterI
160  << " which is not a valid cell number" << endl
161  << "This means that the mesh is not consistent with the"
162  << " done refinement" << endl
163  << "newCell:" << newCelli << abort(FatalError);
164  }
165 
166  labelList& added = addedCells_[masterI];
167 
168  if (added.empty())
169  {
170  added.setSize(2);
171  added[0] = masterI;
172  added[1] = newCelli;
173  }
174  else if (findIndex(added, newCelli) == -1)
175  {
176  label sz = added.size();
177  added.setSize(sz + 1);
178  added[sz] = newCelli;
179  }
180  }
181 }
182 
183 
184 Foam::labelList Foam::multiDirRefinement::splitOffHex(const primitiveMesh& mesh)
185 {
186  const cellModel& hex = *(cellModeller::lookup("hex"));
187 
189 
190  // Split cellLabels_ into two lists.
191 
192  labelList nonHexLabels(cellLabels_.size());
193  label nonHexI = 0;
194 
195  labelList hexLabels(cellLabels_.size());
196  label hexI = 0;
197 
198  forAll(cellLabels_, i)
199  {
200  label celli = cellLabels_[i];
201 
202  if (cellShapes[celli].model() == hex)
203  {
204  hexLabels[hexI++] = celli;
205  }
206  else
207  {
208  nonHexLabels[nonHexI++] = celli;
209  }
210  }
211 
212  nonHexLabels.setSize(nonHexI);
213 
214  cellLabels_.transfer(nonHexLabels);
215 
216  hexLabels.setSize(hexI);
217 
218  return hexLabels;
219 }
220 
221 
222 void Foam::multiDirRefinement::refineHex8
223 (
224  polyMesh& mesh,
225  const labelList& hexCells,
226  const bool writeMesh
227 )
228 {
229  if (debug)
230  {
231  Pout<< "multiDirRefinement : Refining hexes " << hexCells.size()
232  << endl;
233  }
234 
235  hexRef8 hexRefiner
236  (
237  mesh,
238  labelList(mesh.nCells(), 0), // cellLevel
239  labelList(mesh.nPoints(), 0), // pointLevel
240  refinementHistory
241  (
242  IOobject
243  (
244  "refinementHistory",
247  mesh,
250  false
251  ),
252  List<refinementHistory::splitCell8>(0),
253  labelList(0),
254  false
255  ) // refinement history
256  );
257 
258  polyTopoChange meshMod(mesh);
259 
260  labelList consistentCells
261  (
262  hexRefiner.consistentRefinement
263  (
264  hexCells,
265  true // buffer layer
266  )
267  );
268 
269  // Check that consistentRefinement hasn't added cells
270  {
271  // Create count 1 for original cells
272  Map<label> hexCellSet(2*hexCells.size());
273  forAll(hexCells, i)
274  {
275  hexCellSet.insert(hexCells[i], 1);
276  }
277 
278  // Increment count
279  forAll(consistentCells, i)
280  {
281  const label celli = consistentCells[i];
282 
283  Map<label>::iterator iter = hexCellSet.find(celli);
284 
285  if (iter == hexCellSet.end())
286  {
288  << "Resulting mesh would not satisfy 2:1 ratio"
289  << " when refining cell " << celli << abort(FatalError);
290  }
291  else
292  {
293  iter() = 2;
294  }
295  }
296 
297  // Check if all been visited (should always be since
298  // consistentRefinement set up to extend set.
299  forAllConstIter(Map<label>, hexCellSet, iter)
300  {
301  if (iter() != 2)
302  {
304  << "Resulting mesh would not satisfy 2:1 ratio"
305  << " when refining cell " << iter.key()
306  << abort(FatalError);
307  }
308  }
309  }
310 
311 
312  hexRefiner.setRefinement(consistentCells, meshMod);
313 
314  // Change mesh
315  autoPtr<polyTopoChangeMap> mapPtr = meshMod.changeMesh(mesh, true);
316  const polyTopoChangeMap& map = mapPtr();
317 
318  if (writeMesh)
319  {
320  mesh.write();
321  }
322 
323  if (debug)
324  {
325  Pout<< "multiDirRefinement : updated mesh at time "
326  << mesh.time().name() << endl;
327  }
328 
329  hexRefiner.topoChange(map);
330 
331  // Collect all cells originating from same old cell (original + 7 extra)
332 
333  forAll(consistentCells, i)
334  {
335  addedCells_[consistentCells[i]].setSize(8);
336  }
337  labelList nAddedCells(addedCells_.size(), 0);
338 
339  const labelList& cellMap = map.cellMap();
340 
341  forAll(cellMap, celli)
342  {
343  const label oldCelli = cellMap[celli];
344 
345  if (addedCells_[oldCelli].size())
346  {
347  addedCells_[oldCelli][nAddedCells[oldCelli]++] = celli;
348  }
349  }
350 }
351 
352 
353 void Foam::multiDirRefinement::refineAllDirs
354 (
355  polyMesh& mesh,
356  List<vectorField>& cellDirections,
357  const cellLooper& cellWalker,
358  undoableMeshCutter& cutter,
359  const bool writeMesh
360 )
361 {
362  // Iterator
363  refinementIterator refiner(mesh, cutter, cellWalker, writeMesh);
364 
365  forAll(cellDirections, dirI)
366  {
367  if (debug)
368  {
369  Pout<< "multiDirRefinement : Refining " << cellLabels_.size()
370  << " cells in direction " << dirI << endl
371  << endl;
372  }
373 
374  const vectorField& dirField = cellDirections[dirI];
375 
376  // Combine cell to be cut with direction to cut in.
377  // If dirField is only one element use this for all cells.
378 
379  List<refineCell> refCells(cellLabels_.size());
380 
381  if (dirField.size() == 1)
382  {
383  // Uniform directions.
384  if (debug)
385  {
386  Pout<< "multiDirRefinement : Uniform refinement:"
387  << dirField[0] << endl;
388  }
389 
390  forAll(refCells, refI)
391  {
392  label celli = cellLabels_[refI];
393 
394  refCells[refI] = refineCell(celli, dirField[0]);
395  }
396  }
397  else
398  {
399  // Non uniform directions.
400  forAll(refCells, refI)
401  {
402  const label celli = cellLabels_[refI];
403 
404  refCells[refI] = refineCell(celli, dirField[celli]);
405  }
406  }
407 
408  // Do refine mesh (multiple iterations). Remember added cells.
409  Map<label> splitMap = refiner.setRefinement(refCells);
410 
411  // Update overall map of added cells
412  addCells(mesh, splitMap);
413 
414  // Add added cells to list of cells to refine in next iteration
415  addCells(splitMap, cellLabels_);
416 
417  // Update refinement direction for added cells.
418  if (dirField.size() != 1)
419  {
420  forAll(cellDirections, i)
421  {
422  update(splitMap, cellDirections[i]);
423  }
424  }
425 
426  if (debug)
427  {
428  Pout<< "multiDirRefinement : Done refining direction " << dirI
429  << " resulting in " << cellLabels_.size() << " cells" << nl
430  << endl;
431  }
432  }
433 }
434 
435 
436 void Foam::multiDirRefinement::refineFromDict
437 (
438  polyMesh& mesh,
439  List<vectorField>& cellDirections,
440  const dictionary& dict,
441  const bool writeMesh
442 )
443 {
444  // How to walk cell circumference.
445  Switch pureGeomCut(dict.lookupOrDefault("geometricCut", false));
446 
447  autoPtr<cellLooper> cellWalker(nullptr);
448  if (pureGeomCut)
449  {
450  cellWalker.reset(new geomCellLooper(mesh));
451  }
452  else
453  {
454  cellWalker.reset(new hexCellLooper(mesh));
455  }
456 
457  // Construct undoable refinement topology modifier.
458  // Note: undoability switched off.
459  // Might want to reconsider if needs to be possible. But then can always
460  // use other constructor.
461  undoableMeshCutter cutter(mesh, false);
462 
463  refineAllDirs(mesh, cellDirections, cellWalker(), cutter, writeMesh);
464 }
465 
466 
467 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
468 
470 (
471  polyMesh& mesh,
472  const labelList& cellLabels, // list of cells to refine
473  const dictionary& dict,
474  const dictionary& coordinatesDict
475 )
476 :
477  cellLabels_(cellLabels),
478  addedCells_(mesh.nCells())
479 {
480  Switch useHex(dict.lookupOrDefault("useHexTopology", false));
481 
482  Switch writeMesh(dict.lookupOrDefault("writeMesh", false));
483 
484  wordList dirNames(coordinatesDict.lookup("directions"));
485 
486  if (useHex && dirNames.size() == 3)
487  {
488  // Filter out hexes from cellLabels_
489  labelList hexCells(splitOffHex(mesh));
490 
491  refineHex8(mesh, hexCells, writeMesh);
492  }
493 
494  label nRemainingCells = cellLabels_.size();
495 
496  reduce(nRemainingCells, sumOp<label>());
497 
498  if (nRemainingCells > 0)
499  {
500  // Any cells to refine using meshCutter
501 
502  // Determine directions for every cell. Can either be uniform
503  // (size = 1) or non-uniform (one vector per cell)
504  directions cellDirections(mesh, coordinatesDict);
505 
506  refineFromDict(mesh, cellDirections, dict, writeMesh);
507  }
508 }
509 
510 
512 (
513  polyMesh& mesh,
514  const labelList& cellLabels, // list of cells to refine
515  const List<vectorField>& cellDirs, // Explicitly provided directions
516  const dictionary& dict,
517  const dictionary& coordinatesDict
518 )
519 :
520  cellLabels_(cellLabels),
521  addedCells_(mesh.nCells())
522 {
523  Switch useHex(dict.lookupOrDefault("useHexTopology", false));
524 
525  Switch writeMesh(dict.lookupOrDefault("writeMesh", false));
526 
527  wordList dirNames(coordinatesDict.lookup("directions"));
528 
529  if (useHex && dirNames.size() == 3)
530  {
531  // Filter out hexes from cellLabels_
532  labelList hexCells(splitOffHex(mesh));
533 
534  refineHex8(mesh, hexCells, writeMesh);
535  }
536 
537  label nRemainingCells = cellLabels_.size();
538 
539  reduce(nRemainingCells, sumOp<label>());
540 
541  if (nRemainingCells > 0)
542  {
543  // Any cells to refine using meshCutter
544 
545  // Working copy of cells to refine
546  List<vectorField> cellDirections(cellDirs);
547 
548  refineFromDict(mesh, cellDirections, dict, writeMesh);
549  }
550 }
551 
552 
554 (
555  polyMesh& mesh,
556  undoableMeshCutter& cutter, // actual mesh modifier
557  const cellLooper& cellWalker, // how to cut a single cell with
558  // a plane
559  const labelList& cellLabels, // list of cells to refine
560  const List<vectorField>& cellDirs,
561  const bool writeMesh // write intermediate meshes
562 )
563 :
564  cellLabels_(cellLabels),
565  addedCells_(mesh.nCells())
566 {
567  // Working copy of cells to refine
568  List<vectorField> cellDirections(cellDirs);
569 
570  refineAllDirs(mesh, cellDirections, cellWalker, cutter, writeMesh);
571 }
572 
573 
574 // ************************************************************************* //
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
friend class iterator
Declare friendship with the iterator.
Definition: HashTable.H:194
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:197
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
Abstract base class. Concrete implementations know how to cut a cell (i.e. determine a loop around th...
Definition: cellLooper.H:72
static const cellModel * lookup(const word &)
Look up a model by name and return a pointer to the model or nullptr.
Definition: cellModeller.C:100
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
T lookupOrDefault(const word &, const T &, const bool writeDefault=writeOptionalEntries > 0) const
Find and return a T, if not found return the given default.
const word & name() const
Return const reference to name.
Set of directions for each cell in the mesh. Either uniform and size=1 or one set of directions per c...
Definition: directions.H:67
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:420
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1785
Does multiple pass refinement to refine cells in multiple directions.
multiDirRefinement(polyMesh &mesh, const labelList &cellLabels, const dictionary &dict, const dictionary &coordinatesDict)
Construct from dictionary. After construction all refinement will.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:994
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:273
const cellShapeList & cellShapes() const
Return cell shapes.
label nCells() const
label nPoints() const
The main refinement handler. Gets cellCuts which is structure that describes which cells are to be cu...
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
const cellShapeList & cellShapes
Namespace for OpenFOAM.
List< cellShape > cellShapeList
List of cellShapes and PtrList of List of cellShape.
Definition: cellShapeList.H:43
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:258
errorManip< error > abort(error &err)
Definition: errorManip.H:131
IOstream & hex(IOstream &io)
Definition: IOstream.H:576
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
defineTypeNameAndDebug(combustionModel, 0)
Field< vector > vectorField
Specialisation of Field<T> for vector.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
static const char nl
Definition: Ostream.H:267
dictionary dict