undoableMeshCutter.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) 2019 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "undoableMeshCutter.H"
30#include "polyMesh.H"
31#include "polyTopoChange.H"
32#include "DynamicList.H"
33#include "meshCutter.H"
34#include "cellCuts.H"
35#include "splitCell.H"
36#include "mapPolyMesh.H"
37#include "unitConversion.H"
38#include "meshTools.H"
39
40// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41
42namespace Foam
43{
45}
46
47
48// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49
50// For debugging
51void Foam::undoableMeshCutter::printCellRefTree
52(
53 Ostream& os,
54 const word& indent,
55 const splitCell* splitCellPtr
56) const
57{
58 if (splitCellPtr)
59 {
60 os << indent << splitCellPtr->cellLabel() << endl;
61
62 word subIndent = indent + "--";
63
64 printCellRefTree(os, subIndent, splitCellPtr->master());
65
66 printCellRefTree(os, subIndent, splitCellPtr->slave());
67 }
68}
69
70
71// For debugging
72void Foam::undoableMeshCutter::printRefTree(Ostream& os) const
73{
74 forAllConstIters(liveSplitCells_, iter)
75 {
76 const splitCell* splitPtr = iter.val();
77
78 // Walk to top (master path only)
79 while (splitPtr->parent())
80 {
81 if (!splitPtr->isMaster())
82 {
83 splitPtr = nullptr;
84
85 break;
86 }
87 else
88 {
89 splitPtr = splitPtr->parent();
90 }
91 }
92
93 // If we have reached top along master path start printing.
94 if (splitPtr)
95 {
96 // Print from top down
97 printCellRefTree(os, word(""), splitPtr);
98 }
99 }
100}
101
102
103// Update all (cell) labels on splitCell structure.
104// Do in two passes to prevent allocation if nothing changed.
105void Foam::undoableMeshCutter::updateLabels
106(
107 const labelList& map,
108 Map<splitCell*>& liveSplitCells
109)
110{
111 // Pass1 : check if changed
112
113 bool changed = false;
114
115 forAllConstIters(liveSplitCells, iter)
116 {
117 const splitCell* splitPtr = iter.val();
118
119 if (!splitPtr)
120 {
122 << "Problem: null pointer on liveSplitCells list"
123 << abort(FatalError);
124 }
125
126 label celli = splitPtr->cellLabel();
127
128 if (celli != map[celli])
129 {
130 changed = true;
131
132 break;
133 }
134 }
135
136
137 // Pass2: relabel
138
139 if (changed)
140 {
141 // Build new liveSplitCells
142 // since new labels (= keys in Map) might clash with existing ones.
143 Map<splitCell*> newLiveSplitCells(2*liveSplitCells.size());
144
145 forAllIters(liveSplitCells, iter)
146 {
147 splitCell* splitPtr = iter.val();
148
149 const label celli = splitPtr->cellLabel();
150
151 const label newCelli = map[celli];
152
153 if (debug && (celli != newCelli))
154 {
155 Pout<< "undoableMeshCutter::updateLabels :"
156 << " Updating live (split)cell from " << celli
157 << " to " << newCelli << endl;
158 }
159
160 if (newCelli >= 0)
161 {
162 // Update splitCell. Can do inplace since only one celli will
163 // refer to this structure.
164 splitPtr->cellLabel() = newCelli;
165
166 // Update liveSplitCells
167 newLiveSplitCells.insert(newCelli, splitPtr);
168 }
169 }
170 liveSplitCells = newLiveSplitCells;
171 }
172}
173
174
175// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
176
178(
179 const polyMesh& mesh,
180 const bool undoable
181)
182:
184 undoable_(undoable),
185 liveSplitCells_(mesh.nCells()/100 + 100),
186 faceRemover_
187 (
188 mesh,
189 Foam::cos(degToRad(30.0))
190 )
191{}
192
193
194// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
195
197{
198 // Clean split cell tree.
199
200 forAllIters(liveSplitCells_, iter)
201 {
202 splitCell* splitPtr = iter.val();
203
204 while (splitPtr)
205 {
206 splitCell* parentPtr = splitPtr->parent();
207
208 // Sever ties with parent. Also of other side of refinement since
209 // we are handling rest of tree so other side will not have to.
210 if (parentPtr)
211 {
212 splitCell* otherSidePtr = splitPtr->getOther();
213
214 otherSidePtr->parent() = nullptr;
215
216 splitPtr->parent() = nullptr;
217 }
218
219 // Delete splitCell (updates pointer on parent to itself)
220 delete splitPtr;
221
222 splitPtr = parentPtr;
223 }
224 }
225}
226
227
228// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
229
231(
232 const cellCuts& cuts,
233 polyTopoChange& meshMod
234)
235{
236 // Insert commands to actually cut cells
237 meshCutter::setRefinement(cuts, meshMod);
238
239 if (undoable_)
240 {
241 // Use cells cut in this iteration to update splitCell tree.
242 forAllConstIters(addedCells(), iter)
243 {
244 const label celli = iter.key();
245 const label addedCelli = iter.val();
246
247 // Newly created split cell. (celli -> celli + addedCelli)
248
249 // Check if celli already part of split.
250 auto findCell = liveSplitCells_.find(celli);
251
252 if (!findCell.found())
253 {
254 // Celli not yet split. It cannot be unlive split cell
255 // since that would be illegal to split in the first
256 // place.
257
258 // Create 0th level. Null parent to denote this.
259 splitCell* parentPtr = new splitCell(celli, nullptr);
260
261 splitCell* masterPtr = new splitCell(celli, parentPtr);
262
263 splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
264
265 // Store newly created cells on parent together with face
266 // that splits them
267 parentPtr->master() = masterPtr;
268 parentPtr->slave() = slavePtr;
269
270 // Insert master and slave into live splitcell list
271
272 if (liveSplitCells_.found(addedCelli))
273 {
275 << "problem addedCell:" << addedCelli
276 << abort(FatalError);
277 }
278
279 liveSplitCells_.insert(celli, masterPtr);
280 liveSplitCells_.insert(addedCelli, slavePtr);
281 }
282 else
283 {
284 // Cell that was split has been split again.
285 splitCell* parentPtr = findCell();
286
287 // It is no longer live
288 liveSplitCells_.erase(findCell);
289
290 splitCell* masterPtr = new splitCell(celli, parentPtr);
291
292 splitCell* slavePtr = new splitCell(addedCelli, parentPtr);
293
294 // Store newly created cells on parent together with face
295 // that splits them
296 parentPtr->master() = masterPtr;
297 parentPtr->slave() = slavePtr;
298
299 // Insert master and slave into live splitcell list
300
301 if (liveSplitCells_.found(addedCelli))
302 {
304 << "problem addedCell:" << addedCelli
305 << abort(FatalError);
306 }
307
308 liveSplitCells_.insert(celli, masterPtr);
309 liveSplitCells_.insert(addedCelli, slavePtr);
310 }
311 }
312
313 if (debug & 2)
314 {
315 Pout<< "** After refinement: liveSplitCells_:" << endl;
316
317 printRefTree(Pout);
318 }
319 }
320}
321
322
324{
325 // Update mesh cutter for new labels.
326 meshCutter::updateMesh(morphMap);
327
328 // No need to update cell walker for new labels since does not store any.
329
330 // Update faceRemover for new labels
331 faceRemover_.updateMesh(morphMap);
332
333 if (undoable_)
334 {
335 // Update all live split cells for mesh mapper.
336 updateLabels(morphMap.reverseCellMap(), liveSplitCells_);
337 }
338}
339
340
342{
343 if (!undoable_)
344 {
346 << "Only call if constructed with unrefinement capability"
347 << abort(FatalError);
348 }
349
350 DynamicList<label> liveSplitFaces(liveSplitCells_.size());
351
352 forAllConstIters(liveSplitCells_, iter)
353 {
354 const splitCell* splitPtr = iter.val();
355
356 if (!splitPtr->parent())
357 {
359 << "Live split cell without parent" << endl
360 << "splitCell:" << splitPtr->cellLabel()
361 << abort(FatalError);
362 }
363
364 // Check if not top of refinement and whether it is the master side
365 if (splitPtr->isMaster())
366 {
367 splitCell* slavePtr = splitPtr->getOther();
368
369 if
370 (
371 liveSplitCells_.found(slavePtr->cellLabel())
372 && splitPtr->isUnrefined()
373 && slavePtr->isUnrefined()
374 )
375 {
376 // Both master and slave are live and are not refined.
377 // Find common face.
378
379 label celli = splitPtr->cellLabel();
380
381 label slaveCelli = slavePtr->cellLabel();
382
383 label commonFacei =
385 (
386 mesh(),
387 celli,
388 slaveCelli
389 );
390
391 liveSplitFaces.append(commonFacei);
392 }
393 }
394 }
395
396 return liveSplitFaces.shrink();
397}
398
399
401{
402 // (code copied from getSplitFaces)
403
404 if (!undoable_)
405 {
407 << "Only call if constructed with unrefinement capability"
408 << abort(FatalError);
409 }
410
411 Map<label> addedCells(liveSplitCells_.size());
412
413 forAllConstIters(liveSplitCells_, iter)
414 {
415 const splitCell* splitPtr = iter.val();
416
417 if (!splitPtr->parent())
418 {
420 << "Live split cell without parent" << endl
421 << "splitCell:" << splitPtr->cellLabel()
422 << abort(FatalError);
423 }
424
425 // Check if not top of refinement and whether it is the master side
426 if (splitPtr->isMaster())
427 {
428 splitCell* slavePtr = splitPtr->getOther();
429
430 if
431 (
432 liveSplitCells_.found(slavePtr->cellLabel())
433 && splitPtr->isUnrefined()
434 && slavePtr->isUnrefined()
435 )
436 {
437 // Both master and slave are live and are not refined.
438 addedCells.insert(splitPtr->cellLabel(), slavePtr->cellLabel());
439 }
440 }
441 }
442 return addedCells;
443}
444
445
447(
448 const labelList& splitFaces,
449 polyTopoChange& meshMod
450)
451{
452 if (!undoable_)
453 {
455 << "Only call if constructed with unrefinement capability"
456 << abort(FatalError);
457 }
458
459 // Check with faceRemover what faces will get removed. Note that this can
460 // be more (but never less) than splitFaces provided.
461 labelList cellRegion;
462 labelList cellRegionMaster;
463 labelList facesToRemove;
464
465 faceRemover().compatibleRemoves
466 (
467 splitFaces, // pierced faces
468 cellRegion, // per cell -1 or region it is merged into
469 cellRegionMaster, // per region the master cell
470 facesToRemove // new faces to be removed.
471 );
472
473 if (facesToRemove.size() != splitFaces.size())
474 {
475 Pout<< "cellRegion:" << cellRegion << endl;
476 Pout<< "cellRegionMaster:" << cellRegionMaster << endl;
477
479 << "Faces to remove:" << splitFaces << endl
480 << "to be removed:" << facesToRemove
481 << abort(FatalError);
482 }
483
484
485 // Every face removed will result in neighbour and owner being merged
486 // into owner.
487 forAll(facesToRemove, facesToRemoveI)
488 {
489 label facei = facesToRemove[facesToRemoveI];
490
491 if (!mesh().isInternalFace(facei))
492 {
494 << "Trying to remove face that is not internal"
495 << abort(FatalError);
496 }
497
498 label own = mesh().faceOwner()[facei];
499 label nbr = mesh().faceNeighbour()[facei];
500
501 auto ownFind = liveSplitCells_.find(own);
502 auto nbrFind = liveSplitCells_.find(nbr);
503
504 if (ownFind.found() && nbrFind.found())
505 {
506 // Face is original splitFace.
507
508 splitCell* ownPtr = ownFind.val();
509
510 splitCell* nbrPtr = nbrFind.val();
511
512 splitCell* parentPtr = ownPtr->parent();
513
514 // Various checks on sanity.
515
516 if (debug)
517 {
518 Pout<< "Updating for removed splitFace " << facei
519 << " own:" << own << " nbr:" << nbr
520 << " ownPtr:" << ownPtr->cellLabel()
521 << " nbrPtr:" << nbrPtr->cellLabel()
522 << endl;
523 }
524 if (!parentPtr)
525 {
527 << "No parent for owner " << ownPtr->cellLabel()
528 << abort(FatalError);
529 }
530
531 if (!nbrPtr->parent())
532 {
534 << "No parent for neighbour " << nbrPtr->cellLabel()
535 << abort(FatalError);
536 }
537
538 if (parentPtr != nbrPtr->parent())
539 {
541 << "Owner and neighbour liveSplitCell entries do not have"
542 << " same parent. facei:" << facei << " owner:" << own
543 << " ownparent:" << parentPtr->cellLabel()
544 << " neighbour:" << nbr
545 << " nbrparent:" << nbrPtr->parent()->cellLabel()
546 << abort(FatalError);
547 }
548
549 if
550 (
551 !ownPtr->isUnrefined()
552 || !nbrPtr->isUnrefined()
553 || parentPtr->isUnrefined()
554 )
555 {
556 // Live owner and neighbour are refined themselves.
558 << "Owner and neighbour liveSplitCell entries are"
559 << " refined themselves or the parent is not refined"
560 << endl
561 << "owner unrefined:" << ownPtr->isUnrefined()
562 << " neighbour unrefined:" << nbrPtr->isUnrefined()
563 << " master unrefined:" << parentPtr->isUnrefined()
564 << abort(FatalError);
565 }
566
567 // Delete from liveSplitCell
568 liveSplitCells_.erase(ownFind);
569
571 liveSplitCells_.erase(liveSplitCells_.find(nbr));
572
573 // Delete entries themselves
574 delete ownPtr;
575 delete nbrPtr;
576
577 // Update parent:
578 // - has parent itself: is part of split cell. Update cellLabel
579 // with merged cell one.
580 // - has no parent: is start of tree. Completely remove.
581
582 if (parentPtr->parent())
583 {
584 // Update parent cell label to be new merged cell label
585 // (will be owner)
586 parentPtr->cellLabel() = own;
587
588 // And insert into live cells (is ok since old entry with
589 // own as key has been removed above)
590 liveSplitCells_.insert(own, parentPtr);
591 }
592 else
593 {
594 // No parent so is start of tree. No need to keep splitCell
595 // tree.
596 delete parentPtr;
597 }
598 }
599 }
600
601 // Insert all commands to combine cells. Never fails so don't have to
602 // test for success.
603 faceRemover().setRefinement
604 (
605 facesToRemove,
606 cellRegion,
607 cellRegionMaster,
608 meshMod
609 );
610
611 return facesToRemove;
612}
613
614
615// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
DynamicList< T, SizeMin > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:434
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
A HashTable to objects of type <T> with a label key.
Definition: Map.H:60
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:212
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Description of cuts across cells.
Definition: cellCuts.H:113
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
const labelList & reverseCellMap() const
Reverse cell map.
Definition: mapPolyMesh.H:532
Cuts (splits) cells.
Definition: meshCutter.H:141
void setRefinement(const cellCuts &cuts, polyTopoChange &meshMod)
Do actual cutting with cut description. Inserts mesh changes.
Definition: meshCutter.C:522
void updateMesh()
Update for new mesh topology.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
Direct mesh changes based on v1.3 polyTopoChange syntax.
Description of cell after splitting. Contains cellLabel and pointers to cells it it split in....
Definition: splitCell.H:52
bool isMaster() const
Check if this is master cell of split.
Definition: splitCell.C:71
bool isUnrefined() const
Check if this is unrefined (i.e. has no master or slave)
Definition: splitCell.C:101
splitCell * parent() const
Definition: splitCell.H:103
splitCell * master() const
Definition: splitCell.H:113
splitCell * getOther() const
Returns other half of split cell. I.e. slave if this is master.
Definition: splitCell.C:107
splitCell * slave() const
Definition: splitCell.H:123
label cellLabel() const
Definition: splitCell.H:93
The main refinement handler. Gets cellCuts which is structure that describes which cells are to be cu...
labelList getSplitFaces() const
Calculate split faces from current liveCells. Only.
Map< label > getAddedCells() const
Like getSplitFaces but returns map from original to added cell.
void setRefinement(const cellCuts &cuts, polyTopoChange &)
Refine cells acc. to cellCuts. Plays topology changes.
labelList removeSplitFaces(const labelList &splitFaces, polyTopoChange &)
Remove some refinement. Needs to be supplied subset of.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
label getSharedFace(const primitiveMesh &mesh, const label cell0, const label cell1)
Return face shared by two cells. Throws error if none found.
Definition: meshTools.C:441
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition: List.H:66
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:342
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
errorManip< error > abort(error &err)
Definition: errorManip.H:144
error FatalError
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
dimensionedScalar cos(const dimensionedScalar &ds)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:260
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278
Unit conversion functions.