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