layerParameters.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-2026 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 "layerParameters.H"
27 #include "polyBoundaryMesh.H"
28 #include "refinementSurfaces.H"
29 #include "searchableSurfaceList.H"
30 #include "medialAxisMeshMover.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 const Foam::scalar Foam::layerParameters::defaultConcaveAngle =
35  Foam::degToRad(90);
36 
37 
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 
40 Foam::scalar Foam::layerParameters::layerExpansionRatio
41 (
42  const label n,
43  const scalar totalOverFirst
44 ) const
45 {
46  if (n <= 1)
47  {
48  return 1;
49  }
50 
51  const scalar tol = 1e-8;
52 
53  if (mag(n - totalOverFirst) < tol)
54  {
55  return 1;
56  }
57 
58  const label maxIters = 100;
59 
60  // Calculate the bounds of the solution
61  scalar minR;
62  scalar maxR;
63 
64  if (totalOverFirst < n)
65  {
66  minR = 0;
67  maxR = pow(totalOverFirst/n, 1/(n-1));
68  }
69  else
70  {
71  minR = pow(totalOverFirst/n, 1/(n-1));
72  maxR = totalOverFirst/(n - 1);
73  }
74 
75  // Starting guess
76  scalar r = 0.5*(minR + maxR);
77 
78  for (label i = 0; i < maxIters; ++i)
79  {
80  const scalar prevr = r;
81  const scalar fx = pow(r, n) - totalOverFirst*r - (1 - totalOverFirst);
82  const scalar dfx = n*pow(r, n - 1) - totalOverFirst;
83 
84  r -= fx/dfx;
85 
86  if (mag(r - prevr) < tol)
87  {
88  break;
89  }
90  }
91 
92  return r;
93 }
94 
95 
96 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
97 
99 (
100  const dictionary& dict,
101  const polyBoundaryMesh& boundaryMesh
102 )
103 :
104  dict_(dict),
105  numLayers_(boundaryMesh.size(), -1),
106  relativeSizes_(dict.lookup("relativeSizes")),
107  layerSpec_(ILLEGAL),
108  firstLayerThickness_(boundaryMesh.size(), -123),
109  finalLayerThickness_(boundaryMesh.size(), -123),
110  thickness_(boundaryMesh.size(), -123),
111  expansionRatio_(boundaryMesh.size(), -123),
112  minThickness_
113  (
114  boundaryMesh.size(),
115  dict.lookup<scalar>("minThickness")
116  ),
117  mergeFaces_
118  (
119  boundaryMesh.size(),
120  dict.found("mergeFaces")
121  ? (
122  dict.lookup<bool>("mergeFaces")
123  ? mergeFace::yes
124  : mergeFace::no
125  )
126  : mergeFace::ifOnMeshedPatch
127  ),
128  featureAngle_(dict.lookup<scalar>("featureAngle", units::degrees)),
129  concaveAngle_
130  (
131  dict.lookupOrDefault
132  (
133  "concaveAngle",
134  units::degrees,
135  defaultConcaveAngle
136  )
137  ),
138  nGrow_(dict.lookup<label>("nGrow")),
139  maxFaceThicknessRatio_
140  (
141  dict.lookup<scalar>("maxFaceThicknessRatio")
142  ),
143  nBufferCellsNoExtrude_
144  (
145  dict.lookup<label>("nBufferCellsNoExtrude")
146  ),
147  nLayerIter_(dict.lookup<label>("nLayerIter")),
148  nRelaxedIter_(labelMax),
149  additionalReporting_(dict.lookupOrDefault("additionalReporting", false)),
150  meshShrinker_
151  (
152  dict.lookupOrDefault
153  (
154  "meshShrinker",
156  )
157  )
158 {
159  // Detect layer specification mode
160 
161  label nSpec = 0;
162 
163  bool haveFirst = dict.found("firstLayerThickness");
164  if (haveFirst)
165  {
166  firstLayerThickness_ = scalarField
167  (
168  boundaryMesh.size(),
169  dict.lookup<scalar>("firstLayerThickness")
170  );
171  nSpec++;
172  }
173  bool haveFinal = dict.found("finalLayerThickness");
174  if (haveFinal)
175  {
176  finalLayerThickness_ = scalarField
177  (
178  boundaryMesh.size(),
179  dict.lookup<scalar>("finalLayerThickness")
180  );
181  nSpec++;
182  }
183  bool haveTotal = dict.found("thickness");
184  if (haveTotal)
185  {
186  thickness_ = scalarField
187  (
188  boundaryMesh.size(),
189  dict.lookup<scalar>("thickness")
190  );
191  nSpec++;
192  }
193  bool haveExp = dict.found("expansionRatio");
194  if (haveExp)
195  {
196  expansionRatio_ = scalarField
197  (
198  boundaryMesh.size(),
199  dict.lookup<scalar>("expansionRatio")
200  );
201  nSpec++;
202  }
203 
204 
205  if (haveFirst && haveTotal)
206  {
207  layerSpec_ = FIRST_AND_TOTAL;
208  Info<< "Layer thickness specified as first layer and overall thickness."
209  << endl;
210  }
211  else if (haveFirst && haveExp)
212  {
213  layerSpec_ = FIRST_AND_EXPANSION;
214  Info<< "Layer thickness specified as first layer and expansion ratio."
215  << endl;
216  }
217  else if (haveFinal && haveTotal)
218  {
219  layerSpec_ = FINAL_AND_TOTAL;
220  Info<< "Layer thickness specified as final layer and overall thickness."
221  << endl;
222  }
223  else if (haveFinal && haveExp)
224  {
225  layerSpec_ = FINAL_AND_EXPANSION;
226  Info<< "Layer thickness specified as final layer and expansion ratio."
227  << endl;
228  }
229  else if (haveTotal && haveExp)
230  {
231  layerSpec_ = TOTAL_AND_EXPANSION;
232  Info<< "Layer thickness specified as overall thickness"
233  << " and expansion ratio." << endl;
234  }
235 
236 
237  if (layerSpec_ == ILLEGAL || nSpec != 2)
238  {
240  (
241  dict
242  ) << "Over- or underspecified layer thickness."
243  << " Please specify" << nl
244  << " first layer thickness ('firstLayerThickness')"
245  << " and overall thickness ('thickness') or" << nl
246  << " first layer thickness ('firstLayerThickness')"
247  << " and expansion ratio ('expansionRatio') or" << nl
248  << " final layer thickness ('finalLayerThickness')"
249  << " and expansion ratio ('expansionRatio') or" << nl
250  << " final layer thickness ('finalLayerThickness')"
251  << " and overall thickness ('thickness') or" << nl
252  << " overall thickness ('thickness')"
253  << " and expansion ratio ('expansionRatio'"
254  << exit(FatalIOError);
255  }
256 
257 
258  dict.readIfPresent("nRelaxedIter", nRelaxedIter_);
259 
260  if (nLayerIter_ < 0 || nRelaxedIter_ < 0)
261  {
263  << "Layer iterations should be >= 0." << endl
264  << "nLayerIter:" << nLayerIter_
265  << " nRelaxedIter:" << nRelaxedIter_
266  << exit(FatalIOError);
267  }
268 
269 
270  const dictionary& layersDict = dict.subDict("layers");
271 
272  forAllConstIter(dictionary, layersDict, iter)
273  {
274  if (iter().isDict())
275  {
276  const keyType& key = iter().keyword();
277  const labelHashSet patchIDs
278  (
279  boundaryMesh.patchSet(List<wordRe>(1, wordRe(key)))
280  );
281 
282  if (patchIDs.size() == 0)
283  {
284  IOWarningInFunction(layersDict)
285  << "Layer specification for " << key
286  << " does not match any patch." << endl
287  << "Valid patches are " << boundaryMesh.names() << endl;
288  }
289  else
290  {
291  const dictionary& layerDict = iter().dict();
292 
293  forAllConstIter(labelHashSet, patchIDs, patchiter)
294  {
295  const label patchi = patchiter.key();
296 
297  numLayers_[patchi] =
298  layerDict.lookup<label>("nSurfaceLayers");
299 
300  switch (layerSpec_)
301  {
302  case FIRST_AND_TOTAL:
303  layerDict.readIfPresent
304  (
305  "firstLayerThickness",
306  firstLayerThickness_[patchi]
307  );
308  layerDict.readIfPresent
309  (
310  "thickness",
311  thickness_[patchi]
312  );
313  break;
314 
315  case FIRST_AND_EXPANSION:
316  layerDict.readIfPresent
317  (
318  "firstLayerThickness",
319  firstLayerThickness_[patchi]
320  );
321  layerDict.readIfPresent
322  (
323  "expansionRatio",
324  expansionRatio_[patchi]
325  );
326  break;
327 
328  case FINAL_AND_TOTAL:
329  layerDict.readIfPresent
330  (
331  "finalLayerThickness",
332  finalLayerThickness_[patchi]
333  );
334  layerDict.readIfPresent
335  (
336  "thickness",
337  thickness_[patchi]
338  );
339  break;
340 
341  case FINAL_AND_EXPANSION:
342  layerDict.readIfPresent
343  (
344  "finalLayerThickness",
345  finalLayerThickness_[patchi]
346  );
347  layerDict.readIfPresent
348  (
349  "expansionRatio",
350  expansionRatio_[patchi]
351  );
352  break;
353 
354  case TOTAL_AND_EXPANSION:
355  layerDict.readIfPresent
356  (
357  "thickness",
358  thickness_[patchi]
359  );
360  layerDict.readIfPresent
361  (
362  "expansionRatio",
363  expansionRatio_[patchi]
364  );
365  break;
366 
367  default:
369  (
370  dict
371  ) << "problem." << exit(FatalIOError);
372  break;
373  }
374 
375  layerDict.readIfPresent
376  (
377  "minThickness",
378  minThickness_[patchi]
379  );
380 
381  if (layerDict.found("mergeFaces"))
382  {
383  mergeFaces_[patchi] =
384  layerDict.lookup<bool>("mergeFaces")
386  : mergeFace::no;
387  }
388  }
389  }
390  }
391  }
392 }
393 
394 
395 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
396 
398 (
399  const label nLayers,
400  const scalar firstLayerThickness,
401  const scalar finalLayerThickness,
402  const scalar totalThickness,
403  const scalar expansionRatio
404 ) const
405 {
406  switch (layerSpec_)
407  {
408  case FIRST_AND_TOTAL:
409  case FINAL_AND_TOTAL:
410  case TOTAL_AND_EXPANSION:
411  {
412  return totalThickness;
413  }
414  break;
415 
416  case FIRST_AND_EXPANSION:
417  {
418  if (mag(expansionRatio-1) < small)
419  {
420  return firstLayerThickness * nLayers;
421  }
422  else
423  {
424  return firstLayerThickness
425  *(1 - pow(expansionRatio, nLayers))
426  /(1 - expansionRatio);
427  }
428  }
429  break;
430 
431  case FINAL_AND_EXPANSION:
432  {
433  if (mag(expansionRatio-1) < small)
434  {
435  return finalLayerThickness * nLayers;
436  }
437  else
438  {
439  const scalar invExpansion = 1.0/expansionRatio;
440 
441  return finalLayerThickness
442  *(1 - pow(invExpansion, nLayers))
443  /(1 - invExpansion);
444  }
445  }
446  break;
447 
448  default:
449  {
451  << exit(FatalError);
452  return -vGreat;
453  }
454  }
455 }
456 
457 
458 Foam::scalar Foam::layerParameters::layerExpansionRatio
459 (
460  const label nLayers,
461  const scalar firstLayerThickness,
462  const scalar finalLayerThickness,
463  const scalar totalThickness,
464  const scalar expansionRatio
465 ) const
466 {
467  switch (layerSpec_)
468  {
469  case FIRST_AND_EXPANSION:
470  case FINAL_AND_EXPANSION:
471  case TOTAL_AND_EXPANSION:
472  {
473  return expansionRatio;
474  }
475  break;
476 
477  case FIRST_AND_TOTAL:
478  {
479  return layerExpansionRatio
480  (
481  nLayers,
482  totalThickness/firstLayerThickness
483  );
484  }
485  break;
486 
487  case FINAL_AND_TOTAL:
488  {
489  return
490  1.0
491  /layerExpansionRatio
492  (
493  nLayers,
494  totalThickness/finalLayerThickness
495  );
496  }
497  break;
498 
499  default:
500  {
502  << "Illegal thickness specification" << exit(FatalError);
503  return -vGreat;
504  }
505  }
506 }
507 
508 
510 (
511  const label nLayers,
512  const scalar firstLayerThickness,
513  const scalar finalLayerThickness,
514  const scalar totalThickness,
515  const scalar expansionRatio
516 ) const
517 {
518  switch (layerSpec_)
519  {
520  case FIRST_AND_EXPANSION:
521  case FIRST_AND_TOTAL:
522  {
523  return firstLayerThickness;
524  }
525 
526  case FINAL_AND_EXPANSION:
527  {
528  return finalLayerThickness*pow(1.0/expansionRatio, nLayers-1);
529  }
530  break;
531 
532  case FINAL_AND_TOTAL:
533  {
534  const scalar r = layerExpansionRatio
535  (
536  nLayers,
537  firstLayerThickness,
538  finalLayerThickness,
539  totalThickness,
540  expansionRatio
541  );
542 
543  return finalLayerThickness/pow(r, nLayers-1);
544  }
545  break;
546 
547  case TOTAL_AND_EXPANSION:
548  {
549  const scalar r = finalLayerThicknessRatio
550  (
551  nLayers,
552  expansionRatio
553  );
554 
555  const scalar finalThickness = r*totalThickness;
556 
557  return finalThickness/pow(expansionRatio, nLayers-1);
558  }
559  break;
560 
561  default:
562  {
564  << "Illegal thickness specification" << exit(FatalError);
565  return -vGreat;
566  }
567  }
568 }
569 
570 
572 (
573  const label nLayers,
574  const scalar expansionRatio
575 ) const
576 {
577  if (nLayers > 0)
578  {
579  if (mag(expansionRatio-1) < small)
580  {
581  return 1.0/nLayers;
582  }
583  else
584  {
585  return
586  pow(expansionRatio, nLayers - 1)
587  *(1 - expansionRatio)
588  /(1 - pow(expansionRatio, nLayers));
589  }
590  }
591  else
592  {
593  return 0;
594  }
595 }
596 
597 
598 // ************************************************************************* //
bool found
label n
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
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:669
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:778
bool readIfPresent(const word &, T &, bool recursive=false, bool patternMatch=true) const
Find an entry if present, and assign to T.
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:468
A class for handling keywords in dictionaries.
Definition: keyType.H:69
layerParameters(const dictionary &dict, const polyBoundaryMesh &)
Construct from dictionary.
scalar finalLayerThicknessRatio(const label nLayers, const scalar expansionRatio) const
Determine ratio of final layer thickness to.
const dictionary & dict() const
mergeFace
Enumeration defining whether to merge faces on a given patch. Read.
const scalarField & firstLayerThickness() const
Wanted thickness of the layer nearest to the wall.
scalar layerThickness(const label nLayers, const scalar firstLayerThickness, const scalar finalLayerThickness, const scalar totalThickness, const scalar expansionRatio) const
Determine overall thickness. Uses two of the four parameters.
Mesh motion solver that uses a medial axis algorithm to work out a fraction between the (nearest poin...
Foam::polyBoundaryMesh.
labelHashSet patchSet(const UList< wordRe > &patchNames, const bool warnNotFound=true, const bool usePatchGroups=true) const
Return the patch set corresponding to the given names.
wordList names() const
Return the list of patch names.
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A wordRe is a word, but can also have a regular expression for matching words.
Definition: wordRe.H:77
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
const unitSet degrees
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
scalar degToRad(const scalar deg)
Convert degrees to radians.
Definition: units.C:364
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:288
messageStream Info
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
IOerror FatalIOError
tmp< DimensionedField< typename powProduct< Type, r >::type, GeoMesh, Field > > pow(const DimensionedField< Type, GeoMesh, PrimitiveField > &df, typename powProduct< Type, r >::type)
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
error FatalError
static const label labelMax
Definition: label.H:62
static const char nl
Definition: Ostream.H:297
dictionary dict