multiDirRefinement.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "multiDirRefinement.H"
30 #include "polyMesh.H"
31 #include "Time.H"
32 #include "undoableMeshCutter.H"
33 #include "hexCellLooper.H"
34 #include "geomCellLooper.H"
35 #include "directions.H"
36 #include "hexRef8.H"
37 #include "mapPolyMesh.H"
38 #include "polyTopoChange.H"
39 #include "cellModel.H"
40 
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45  defineTypeNameAndDebug(multiDirRefinement, 0);
46 }
47 
48 
49 // * * * * * * * * * * * * * Private Statc Functions * * * * * * * * * * * * //
50 
51 // Update refCells pattern for split cells. Note refCells is current
52 // list of cells to refine (these should all have been refined)
53 void Foam::multiDirRefinement::addCells
54 (
55  const Map<label>& splitMap,
56  List<refineCell>& refCells
57 )
58 {
59  label newRefI = refCells.size();
60 
61  label oldSize = refCells.size();
62 
63  refCells.setSize(newRefI + splitMap.size());
64 
65  for (label refI = 0; refI < oldSize; refI++)
66  {
67  const refineCell& refCell = refCells[refI];
68 
69  const auto iter = splitMap.cfind(refCell.cellNo());
70 
71  if (!iter.good())
72  {
74  << "Problem : cannot find added cell for cell "
75  << refCell.cellNo() << endl
76  << abort(FatalError);
77  }
78 
79  refCells[newRefI++] = refineCell(iter.val(), refCell.direction());
80  }
81 }
82 
83 
84 // Update vectorField for all the new cells. Takes over value of
85 // original cell.
86 void Foam::multiDirRefinement::update
87 (
88  const Map<label>& splitMap,
90 )
91 {
92  field.setSize(field.size() + splitMap.size());
93 
94  forAllConstIters(splitMap, iter)
95  {
96  field[iter.val()] = field[iter.key()];
97  }
98 }
99 
100 
101 // Add added cells to labelList
102 void Foam::multiDirRefinement::addCells
103 (
104  const Map<label>& splitMap,
105  labelList& labels
106 )
107 {
108  label newCelli = labels.size();
109 
110  labels.setSize(labels.size() + splitMap.size());
111 
112  forAllConstIters(splitMap, iter)
113  {
114  labels[newCelli++] = iter.val();
115  }
116 }
117 
118 
119 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
120 
121 void Foam::multiDirRefinement::addCells
122 (
123  const primitiveMesh& mesh,
124  const Map<label>& splitMap
125 )
126 {
127  // Construct inverse addressing: from new to original cell.
128  labelList origCell(mesh.nCells(), -1);
129 
130  forAll(addedCells_, celli)
131  {
132  const labelList& added = addedCells_[celli];
133 
134  forAll(added, i)
135  {
136  label slave = added[i];
137 
138  if (origCell[slave] == -1)
139  {
140  origCell[slave] = celli;
141  }
142  else if (origCell[slave] != celli)
143  {
145  << "Added cell " << slave << " has two different masters:"
146  << origCell[slave] << " , " << celli
147  << abort(FatalError);
148  }
149  }
150  }
151 
152 
153  forAllConstIters(splitMap, iter)
154  {
155  label masterI = iter.key();
156  const label newCelli = iter.val();
157 
158  while (origCell[masterI] != -1 && origCell[masterI] != masterI)
159  {
160  masterI = origCell[masterI];
161  }
162 
163  if (masterI >= addedCells_.size())
164  {
166  << "Map of added cells contains master cell " << masterI
167  << " which is not a valid cell number" << endl
168  << "This means that the mesh is not consistent with the"
169  << " done refinement" << endl
170  << "newCell:" << newCelli << abort(FatalError);
171  }
172 
173  labelList& added = addedCells_[masterI];
174 
175  if (added.empty())
176  {
177  added.setSize(2);
178  added[0] = masterI;
179  added[1] = newCelli;
180  }
181  else if (!added.found(newCelli))
182  {
183  const label sz = added.size();
184  added.setSize(sz + 1);
185  added[sz] = newCelli;
186  }
187  }
188 }
189 
190 
191 Foam::labelList Foam::multiDirRefinement::splitOffHex(const primitiveMesh& mesh)
192 {
193  const cellModel& hex = cellModel::ref(cellModel::HEX);
194 
196 
197  // Split cellLabels_ into two lists.
198 
199  labelList nonHexLabels(cellLabels_.size());
200  label nonHexI = 0;
201 
202  labelList hexLabels(cellLabels_.size());
203  label hexI = 0;
204 
205  forAll(cellLabels_, i)
206  {
207  label celli = cellLabels_[i];
208 
209  if (cellShapes[celli].model() == hex)
210  {
211  hexLabels[hexI++] = celli;
212  }
213  else
214  {
215  nonHexLabels[nonHexI++] = celli;
216  }
217  }
218 
219  nonHexLabels.setSize(nonHexI);
220 
221  cellLabels_.transfer(nonHexLabels);
222 
223  hexLabels.setSize(hexI);
224 
225  return hexLabels;
226 }
227 
228 
229 void Foam::multiDirRefinement::refineHex8
230 (
231  polyMesh& mesh,
232  const labelList& hexCells,
233  const bool writeMesh
234 )
235 {
236  if (debug)
237  {
238  Pout<< "multiDirRefinement : Refining hexes " << hexCells.size()
239  << endl;
240  }
241 
242  hexRef8 hexRefiner
243  (
244  mesh,
245  labelList(mesh.nCells(), Zero), // cellLevel
246  labelList(mesh.nPoints(), Zero), // pointLevel
247  refinementHistory
248  (
249  IOobject
250  (
251  "refinementHistory",
254  mesh,
258  ),
259  List<refinementHistory::splitCell8>(),
260  labelList(),
261  false
262  ) // refinement history
263  );
264 
265  polyTopoChange meshMod(mesh);
266 
267  labelList consistentCells
268  (
269  hexRefiner.consistentRefinement
270  (
271  hexCells,
272  true // buffer layer
273  )
274  );
275 
276  // Check that consistentRefinement hasn't added cells
277  {
278  // Create count 1 for original cells
279  Map<label> hexCellSet(2*hexCells.size());
280  for (const label celli : hexCells)
281  {
282  hexCellSet.insert(celli, 1);
283  }
284 
285  // Increment count
286  for (const label celli : consistentCells)
287  {
288  auto iter = hexCellSet.find(celli);
289 
290  if (iter.good())
291  {
292  iter.val() = 2;
293  }
294  else
295  {
297  << "Resulting mesh would not satisfy 2:1 ratio"
298  << " when refining cell " << celli << abort(FatalError);
299  }
300  }
301 
302  // Check if all been visited (should always be since
303  // consistentRefinement set up to extend set.
304  forAllConstIters(hexCellSet, iter)
305  {
306  if (iter.val() != 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, no inflation
320  autoPtr<mapPolyMesh> morphMapPtr = meshMod.changeMesh(mesh, false, true);
321  const mapPolyMesh& morphMap = morphMapPtr();
322 
323  if (morphMap.hasMotionPoints())
324  {
325  mesh.movePoints(morphMap.preMotionPoints());
326  }
327 
328  if (writeMesh)
329  {
330  mesh.write();
331  }
332 
333  if (debug)
334  {
335  Pout<< "multiDirRefinement : updated mesh at time "
336  << mesh.time().timeName() << endl;
337  }
338 
339  hexRefiner.updateMesh(morphMap);
340 
341  // Collect all cells originating from same old cell (original + 7 extra)
342 
343  forAll(consistentCells, i)
344  {
345  addedCells_[consistentCells[i]].setSize(8);
346  }
347  labelList nAddedCells(addedCells_.size(), Zero);
348 
349  const labelList& cellMap = morphMap.cellMap();
350 
351  forAll(cellMap, celli)
352  {
353  const label oldCelli = cellMap[celli];
354 
355  if (addedCells_[oldCelli].size())
356  {
357  addedCells_[oldCelli][nAddedCells[oldCelli]++] = celli;
358  }
359  }
360 }
361 
362 
363 void Foam::multiDirRefinement::refineAllDirs
364 (
365  polyMesh& mesh,
366  List<vectorField>& cellDirections,
367  const cellLooper& cellWalker,
368  undoableMeshCutter& cutter,
369  const bool writeMesh
370 )
371 {
372  // Iterator
373  refinementIterator refiner(mesh, cutter, cellWalker, writeMesh);
374 
375  forAll(cellDirections, dirI)
376  {
377  if (debug)
378  {
379  Pout<< "multiDirRefinement : Refining " << cellLabels_.size()
380  << " cells in direction " << dirI << endl
381  << endl;
382  }
383 
384  const vectorField& dirField = cellDirections[dirI];
385 
386  // Combine cell to be cut with direction to cut in.
387  // If dirField is only one element use this for all cells.
388 
389  List<refineCell> refCells(cellLabels_.size());
390 
391  if (dirField.size() == 1)
392  {
393  // Uniform directions.
394  if (debug)
395  {
396  Pout<< "multiDirRefinement : Uniform refinement:"
397  << dirField[0] << endl;
398  }
399 
400  forAll(refCells, refI)
401  {
402  const label celli = cellLabels_[refI];
403 
404  refCells[refI] = refineCell(celli, dirField[0]);
405  }
406  }
407  else
408  {
409  // Non uniform directions.
410  forAll(refCells, refI)
411  {
412  const label celli = cellLabels_[refI];
413 
414  refCells[refI] = refineCell(celli, dirField[celli]);
415  }
416  }
417 
418  // Do refine mesh (multiple iterations). Remember added cells.
419  Map<label> splitMap = refiner.setRefinement(refCells);
420 
421  // Update overall map of added cells
422  addCells(mesh, splitMap);
423 
424  // Add added cells to list of cells to refine in next iteration
425  addCells(splitMap, cellLabels_);
426 
427  // Update refinement direction for added cells.
428  if (dirField.size() != 1)
429  {
430  forAll(cellDirections, i)
431  {
432  update(splitMap, cellDirections[i]);
433  }
434  }
435 
436  if (debug)
437  {
438  Pout<< "multiDirRefinement : Done refining direction " << dirI
439  << " resulting in " << cellLabels_.size() << " cells" << nl
440  << endl;
441  }
442  }
443 }
444 
445 
446 void Foam::multiDirRefinement::refineFromDict
447 (
448  polyMesh& mesh,
449  List<vectorField>& cellDirections,
450  const dictionary& dict,
451  const bool writeMesh
452 )
453 {
454  // How to walk cell circumference.
455  const bool pureGeomCut(dict.get<bool>("geometricCut"));
456 
457  autoPtr<cellLooper> cellWalker;
458  if (pureGeomCut)
459  {
460  cellWalker.reset(new geomCellLooper(mesh));
461  }
462  else
463  {
464  cellWalker.reset(new hexCellLooper(mesh));
465  }
466 
467  // Construct undoable refinement topology modifier.
468  //Note: undoability switched off.
469  // Might want to reconsider if needs to be possible. But then can always
470  // use other constructor.
471  undoableMeshCutter cutter(mesh, false);
472 
473  refineAllDirs(mesh, cellDirections, cellWalker(), cutter, writeMesh);
474 }
476 
477 
478 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
479 
480 // Construct from dictionary
481 Foam::multiDirRefinement::multiDirRefinement
482 (
483  polyMesh& mesh,
484  const labelList& cellLabels, // list of cells to refine
485  const dictionary& dict
486 )
487 :
488  cellLabels_(cellLabels),
489  addedCells_(mesh.nCells())
490 {
491  const bool useHex(dict.get<bool>("useHexTopology"));
492 
493  const bool writeMesh(dict.get<bool>("writeMesh"));
494 
495  const wordList dirNames(dict.get<wordList>("directions"));
496 
497  if (useHex && dirNames.size() == 3)
498  {
499  // Filter out hexes from cellLabels_
500  labelList hexCells(splitOffHex(mesh));
501 
502  refineHex8(mesh, hexCells, writeMesh);
503  }
504 
505  if (returnReduceOr(cellLabels_.size()))
506  {
507  // Any cells to refine using meshCutter
508 
509  // Determine directions for every cell. Can either be uniform
510  // (size = 1) or non-uniform (one vector per cell)
511  directions cellDirections(mesh, dict);
512 
513  refineFromDict(mesh, cellDirections, dict, writeMesh);
514  }
515 }
516 
517 
518 // Construct from dictionary and directions to refine.
519 Foam::multiDirRefinement::multiDirRefinement
520 (
521  polyMesh& mesh,
522  const labelList& cellLabels, // list of cells to refine
523  const List<vectorField>& cellDirs, // Explicitly provided directions
524  const dictionary& dict
525 )
526 :
527  cellLabels_(cellLabels),
528  addedCells_(mesh.nCells())
529 {
530  const bool useHex(dict.get<bool>("useHexTopology"));
531 
532  const bool writeMesh(dict.get<bool>("writeMesh"));
533 
534  const wordList dirNames(dict.get<wordList>("directions"));
535 
536  if (useHex && dirNames.size() == 3)
537  {
538  // Filter out hexes from cellLabels_
539  labelList hexCells(splitOffHex(mesh));
540 
541  refineHex8(mesh, hexCells, writeMesh);
542  }
543 
544  if (returnReduceOr(cellLabels_.size()))
545  {
546  // Any cells to refine using meshCutter
547 
548  // Working copy of cells to refine
549  List<vectorField> cellDirections(cellDirs);
550 
551  refineFromDict(mesh, cellDirections, dict, writeMesh);
552  }
553 }
554 
555 
556 // Construct from components. Implies meshCutter since directions provided.
557 Foam::multiDirRefinement::multiDirRefinement
558 (
559  polyMesh& mesh,
560  undoableMeshCutter& cutter, // actual mesh modifier
561  const cellLooper& cellWalker, // how to cut a single cell with
562  // a plane
563  const labelList& cellLabels, // list of cells to refine
564  const List<vectorField>& cellDirs,
565  const bool writeMesh // write intermediate meshes
566 )
567 :
568  cellLabels_(cellLabels),
569  addedCells_(mesh.nCells())
570 {
571  // Working copy of cells to refine
572  List<vectorField> cellDirections(cellDirs);
573 
574  refineAllDirs(mesh, cellDirections, cellWalker, cutter, writeMesh);
575 }
576 
577 
578 // ************************************************************************* //
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
rDeltaTY field()
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:859
label nPoints() const noexcept
Number of mesh points.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
IOstream & hex(IOstream &io)
Definition: IOstream.H:560
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
const cellShapeList & cellShapes() const
Return cell shapes.
Set of directions for each cell in the mesh. Either uniform and size=1 or one set of directions per c...
Definition: directions.H:63
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:411
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
virtual void movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: fvMesh.C:929
List< cellShape > cellShapeList
List of cellShape.
Definition: cellShapeList.H:32
Ignore writing from objectRegistry::writeObject()
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static const cellModel & ref(const modelType model)
Look up reference to cellModel by enumeration. Fatal on failure.
Definition: cellModels.C:150
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
cellShapeList cellShapes
errorManip< error > abort(error &err)
Definition: errorManip.H:139
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:173
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1113
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
int debug
Static debugging option.
mesh update()
defineTypeNameAndDebug(combustionModel, 0)
List< word > wordList
List of word.
Definition: fileName.H:59
label nCells() const noexcept
Number of mesh cells.
Nothing to be read.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
List< label > labelList
A List of labels.
Definition: List.H:62
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Do not request registration (bool: false)
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127