layerAdditionRemoval.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) 2020 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
30#include "polyTopoChanger.H"
31#include "polyMesh.H"
32#include "Time.H"
33#include "primitiveMesh.H"
34#include "polyTopoChange.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39namespace Foam
40{
43 (
47 );
48}
49
50
51const Foam::scalar Foam::layerAdditionRemoval::addDelta_ = 0.3;
52const Foam::scalar Foam::layerAdditionRemoval::removeDelta_ = 0.1;
53
54
55// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
56
57void Foam::layerAdditionRemoval::checkDefinition()
58{
59 if (!faceZoneID_.active())
60 {
62 << "Master face zone named " << faceZoneID_.name()
63 << " cannot be found."
64 << abort(FatalError);
65 }
66
67 if
68 (
69 minLayerThickness_ < VSMALL
70 || maxLayerThickness_ < minLayerThickness_
71 )
72 {
74 << "Incorrect layer thickness definition."
75 << abort(FatalError);
76 }
77
78 label nFaces = topoChanger().mesh().faceZones()[faceZoneID_.index()].size();
79
80 reduce(nFaces, sumOp<label>());
81
82 if (nFaces == 0)
83 {
85 << "Face extrusion zone contains no faces. "
86 << "Please check your mesh definition."
87 << abort(FatalError);
88 }
89
90 if (debug)
91 {
92 Pout<< "Cell layer addition/removal object " << name() << " :" << nl
93 << " faceZoneID: " << faceZoneID_ << endl;
94 }
95}
96
97
98void Foam::layerAdditionRemoval::clearAddressing() const
99{
100 pointsPairingPtr_.reset(nullptr);
101 facesPairingPtr_.reset(nullptr);
102}
103
104
105// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
106
108(
109 const word& name,
110 const label index,
111 const polyTopoChanger& ptc,
112 const word& zoneName,
113 const scalar minThickness,
114 const scalar maxThickness,
115 const bool thicknessFromVolume
116)
117:
118 polyMeshModifier(name, index, ptc, true),
119 faceZoneID_(zoneName, ptc.mesh().faceZones()),
120 minLayerThickness_(minThickness),
121 maxLayerThickness_(maxThickness),
122 thicknessFromVolume_(thicknessFromVolume),
123 oldLayerThickness_(-1.0),
124 pointsPairingPtr_(nullptr),
125 facesPairingPtr_(nullptr),
126 triggerRemoval_(-1),
127 triggerAddition_(-1)
128{
129 checkDefinition();
130}
131
132
134(
135 const word& name,
136 const dictionary& dict,
137 const label index,
138 const polyTopoChanger& ptc
139)
140:
141 polyMeshModifier(name, index, ptc, dict.get<bool>("active")),
142 faceZoneID_(dict.lookup("faceZoneName"), ptc.mesh().faceZones()),
143 minLayerThickness_(dict.get<scalar>("minLayerThickness")),
144 maxLayerThickness_(dict.get<scalar>("maxLayerThickness")),
145 thicknessFromVolume_(dict.getOrDefault("thicknessFromVolume", true)),
146 oldLayerThickness_(dict.getOrDefault<scalar>("oldLayerThickness", -1)),
147 pointsPairingPtr_(nullptr),
148 facesPairingPtr_(nullptr),
149 triggerRemoval_(-1),
150 triggerAddition_(-1)
151{
152 checkDefinition();
153}
154
155
156// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
157
159{
160 // Protect from multiple calculation in the same time-step
161 if (triggerRemoval_ > -1 || triggerAddition_ > -1)
162 {
163 return true;
164 }
165
166 // Go through all the cells in the master layer and calculate
167 // approximate layer thickness as the ratio of the cell volume and
168 // face area in the face zone.
169 // Layer addition:
170 // When the max thickness exceeds the threshold, trigger refinement.
171 // Layer removal:
172 // When the min thickness falls below the threshold, trigger removal.
173
174 const polyMesh& mesh = topoChanger().mesh();
175
176 const faceZone& fz = mesh.faceZones()[faceZoneID_.index()];
177 const labelList& mc = fz.masterCells();
178
179 const scalarField& V = mesh.cellVolumes();
180 const vectorField& S = mesh.faceAreas();
181
182 if (min(V) < -VSMALL)
183 {
185 << "negative cell volume. Error in mesh motion before "
186 << "topological change.\n V: " << V
187 << abort(FatalError);
188 }
189
190 scalar avgDelta = 0;
191 scalar minDelta = GREAT;
192 scalar maxDelta = 0;
193 label nDelta = 0;
194
195 if (thicknessFromVolume_)
196 {
197 // Thickness calculated from cell volume/face area
198 forAll(fz, facei)
199 {
200 scalar curDelta = V[mc[facei]]/mag(S[fz[facei]]);
201 avgDelta += curDelta;
202 minDelta = min(minDelta, curDelta);
203 maxDelta = max(maxDelta, curDelta);
204 }
205
206 nDelta = fz.size();
207 }
208 else
209 {
210 // Thickness calculated from edges on layer
211 const Map<label>& zoneMeshPointMap = fz().meshPointMap();
212
213 // Edges with only one point on zone
214 forAll(mc, facei)
215 {
216 const cell& cFaces = mesh.cells()[mc[facei]];
217 const edgeList cellEdges(cFaces.edges(mesh.faces()));
218
219 forAll(cellEdges, i)
220 {
221 const edge& e = cellEdges[i];
222
223 if (zoneMeshPointMap.found(e[0]))
224 {
225 if (!zoneMeshPointMap.found(e[1]))
226 {
227 scalar curDelta = e.mag(mesh.points());
228 avgDelta += curDelta;
229 nDelta++;
230 minDelta = min(minDelta, curDelta);
231 maxDelta = max(maxDelta, curDelta);
232 }
233 }
234 else
235 {
236 if (zoneMeshPointMap.found(e[1]))
237 {
238 scalar curDelta = e.mag(mesh.points());
239 avgDelta += curDelta;
240 nDelta++;
241 minDelta = min(minDelta, curDelta);
242 maxDelta = max(maxDelta, curDelta);
243 }
244 }
245 }
246 }
247 }
248
249 reduce(minDelta, minOp<scalar>());
250 reduce(maxDelta, maxOp<scalar>());
251 reduce(avgDelta, sumOp<scalar>());
252 reduce(nDelta, sumOp<label>());
253
254 avgDelta /= nDelta;
255
256 if (debug)
257 {
258 Pout<< "bool layerAdditionRemoval::changeTopology() const "
259 << " for object " << name() << " : " << nl
260 << "Layer thickness: min: " << minDelta
261 << " max: " << maxDelta << " avg: " << avgDelta
262 << " old thickness: " << oldLayerThickness_ << nl
263 << "Removal threshold: " << minLayerThickness_
264 << " addition threshold: " << maxLayerThickness_ << endl;
265 }
266
267 bool topologicalChange = false;
268
269 // If the thickness is decreasing and crosses the min thickness,
270 // trigger removal
271 if (oldLayerThickness_ < 0)
272 {
273 if (debug)
274 {
275 Pout<< "First step. No addition/removal" << endl;
276 }
277
278 // No topological changes allowed before first mesh motion
279 oldLayerThickness_ = avgDelta;
280
281 topologicalChange = false;
282 }
283 else if (avgDelta < oldLayerThickness_)
284 {
285 // Layers moving towards removal
286 if (minDelta < minLayerThickness_)
287 {
288 // Check layer pairing
289 if (setLayerPairing())
290 {
291 // A mesh layer detected. Check that collapse is valid
292 if (validCollapse())
293 {
294 // At this point, info about moving the old mesh
295 // in a way to collapse the cells in the removed
296 // layer is available. Not sure what to do with
297 // it.
298
299 if (debug)
300 {
301 Pout<< "bool layerAdditionRemoval::changeTopology() "
302 << " const for object " << name() << " : "
303 << "Triggering layer removal" << endl;
304 }
305
306 triggerRemoval_ = mesh.time().timeIndex();
307
308 // Old thickness looses meaning.
309 // Set it up to indicate layer removal
310 oldLayerThickness_ = GREAT;
311
312 topologicalChange = true;
313 }
314 else
315 {
316 // No removal, clear addressing
317 clearAddressing();
318 }
319 }
320 }
321 else
322 {
323 oldLayerThickness_ = avgDelta;
324 }
325 }
326 else
327 {
328 // Layers moving towards addition
329 if (maxDelta > maxLayerThickness_)
330 {
331 if (debug)
332 {
333 Pout<< "bool layerAdditionRemoval::changeTopology() const "
334 << " for object " << name() << " : "
335 << "Triggering layer addition" << endl;
336 }
337
338 triggerAddition_ = mesh.time().timeIndex();
339
340 // Old thickness looses meaning.
341 // Set it up to indicate layer removal
342 oldLayerThickness_ = 0;
343
344 topologicalChange = true;
345 }
346 else
347 {
348 oldLayerThickness_ = avgDelta;
349 }
350 }
351
352 return topologicalChange;
353}
354
355
357{
358 // Insert the layer addition/removal instructions
359 // into the topological change
360
361 if (triggerRemoval_ == topoChanger().mesh().time().timeIndex())
362 {
363 removeCellLayer(ref);
364
365 // Clear addressing. This also resets the addition/removal data
366 if (debug)
367 {
368 Pout<< "layerAdditionRemoval::setRefinement(polyTopoChange&) "
369 << "for object " << name() << " : "
370 << "Clearing addressing after layer removal" << endl;
371 }
372
373 triggerRemoval_ = -1;
374 clearAddressing();
375 }
376
377 if (triggerAddition_ == topoChanger().mesh().time().timeIndex())
378 {
379 addCellLayer(ref);
380
381 // Clear addressing. This also resets the addition/removal data
382 if (debug)
383 {
384 Pout<< "layerAdditionRemoval::setRefinement(polyTopoChange&) "
385 << "for object " << name() << " : "
386 << "Clearing addressing after layer addition" << endl;
387 }
388
389 triggerAddition_ = -1;
390 clearAddressing();
391 }
392}
393
394
396{
397 if (debug)
398 {
399 Pout<< "layerAdditionRemoval::updateMesh(const mapPolyMesh&) "
400 << "for object " << name() << " : "
401 << "Clearing addressing on external request";
402
403 if (pointsPairingPtr_ || facesPairingPtr_)
404 {
405 Pout<< "Pointers set." << endl;
406 }
407 else
408 {
409 Pout<< "Pointers not set." << endl;
410 }
411 }
412
413 // Mesh has changed topologically. Update local topological data
414 faceZoneID_.update(topoChanger().mesh().faceZones());
415
416 clearAddressing();
417}
418
419
421{
422 if (t < VSMALL || maxLayerThickness_ < t)
423 {
425 << "Incorrect layer thickness definition."
426 << abort(FatalError);
427 }
428
429 minLayerThickness_ = t;
430}
431
432
434{
435 if (t < minLayerThickness_)
436 {
438 << "Incorrect layer thickness definition."
439 << abort(FatalError);
440 }
441
442 maxLayerThickness_ = t;
443}
444
445
447{
448 os << nl << type() << nl
449 << name()<< nl
450 << faceZoneID_ << nl
451 << minLayerThickness_ << nl
452 << oldLayerThickness_ << nl
453 << maxLayerThickness_ << nl
454 << thicknessFromVolume_ << endl;
455}
456
457
459{
460 os << nl << name() << nl << token::BEGIN_BLOCK << nl
461 << " type " << type()
463 << " faceZoneName " << faceZoneID_.name()
465 << " minLayerThickness " << minLayerThickness_
467 << " maxLayerThickness " << maxLayerThickness_
469 << " thicknessFromVolume " << thicknessFromVolume_
471 << " oldLayerThickness " << oldLayerThickness_
473 << " active " << active()
476}
477
478
479// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
label index() const
The index of the first matching items, -1 if no matches.
Definition: DynamicID.H:123
bool active() const noexcept
Has the zone been found.
Definition: DynamicID.H:129
const wordRe & name() const noexcept
The selector name.
Definition: DynamicID.H:111
bool found(const Key &key) const
Return true if hashed entry is found in table.
Definition: HashTableI.H:100
A HashTable to objects of type <T> with a label key.
Definition: Map.H:60
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
label timeIndex() const noexcept
Return current time index.
Definition: TimeStateI.H:37
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:57
edgeList edges(const faceUList &meshFaces) const
Return cell edges.
Definition: cell.C:111
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:66
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:67
const labelList & masterCells() const
Definition: faceZone.C:389
virtual bool write()
Write the output fields.
Foam::dictionary writeDict() const
Write to dictionary.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:290
Cell layer addition mesh modifier.
void setMaxLayerThickness(const scalar t) const
Set max layer thickness which triggers removal.
virtual bool changeTopology() const
Check for topology change.
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
void setMinLayerThickness(const scalar t) const
Set min layer thickness which triggers removal.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
void updateMesh()
Update for new mesh topology.
Virtual base class for mesh modifiers.
const word & name() const
Return name of this modifier.
const polyTopoChanger & topoChanger() const
Return reference to morph engine.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
Direct mesh changes based on v1.3 polyTopoChange syntax.
List of mesh modifiers defining the mesh dynamics.
const polyMesh & mesh() const
Return the mesh reference.
const scalarField & cellVolumes() const
const vectorField & faceAreas() const
const cellList & cells() const
Lookup type of boundary radiation properties.
Definition: lookup.H:66
@ BEGIN_BLOCK
Begin block [isseparator].
Definition: token.H:159
@ END_BLOCK
End block [isseparator].
Definition: token.H:160
@ END_STATEMENT
End entry [isseparator].
Definition: token.H:154
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
rDeltaT ref()
bool
Definition: EEqn.H:20
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
errorManip< error > abort(error &err)
Definition: errorManip.H:144
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
label timeIndex
Definition: getTimeIndex.H:30
dictionary dict
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333