PDRobstacleTypes.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) 2019-2021 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "PDRobstacleTypes.H"
29 #include "PDRobstacleTypes.H"
30 #include "Enum.H"
31 #include "unitConversion.H"
33 
34 using namespace Foam::constant;
35 
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 
38 #define addObstacleReader(obsType, obsName) \
39  namespace Foam \
40  { \
41  namespace PDRobstacles \
42  { \
43  addNamedToMemberFunctionSelectionTable \
44  ( \
45  PDRobstacle, \
46  obsType, \
47  read, \
48  dictionary, \
49  obsName \
50  ); \
51  } \
52  }
53 
54 
55 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
56 
57 namespace Foam
58 {
59 
60 // Read porosity, change to blockage. Clamp values [0-1] silently
61 
62 // Volume porosity -> blockage
63 inline scalar getPorosity(const dictionary& dict)
64 {
65  return 1 - clamp(dict.getOrDefault<scalar>("porosity", 0), zero_one{});
66 }
67 
68 // Direction porosities -> blockage
69 inline vector getPorosities(const dictionary& dict)
70 {
71  vector blockage(vector::one);
72 
73  if (dict.readIfPresent("porosities", blockage))
74  {
75  for (scalar& val : blockage)
76  {
77  val = 1 - clamp(val, zero_one{});
78  }
79  }
80 
81  return blockage;
82 }
83 
84 
85 // Check for "porosity", or "porosities"
86 // inline static bool hasPorosity(const dictionary& dict)
87 // {
88 // return dict.found("porosity") || dict.found("porosities");
89 // }
90 
91 
93 vectorComponentsNames
94 ({
95  { vector::components::X, "x" },
96  { vector::components::Y, "y" },
97  { vector::components::Z, "z" },
98 });
99 
100 
101 enum inletDirnType
102 {
103  _X = -1, // -ve x
104  _Y = -2, // -ve y
105  _Z = -3, // -ve z
106  X = 1, // +ve x
107  Y = 2, // +ve y
108  Z = 3, // +ve z
109 };
110 
111 static const Foam::Enum<inletDirnType>
112 inletDirnNames
113 ({
114  { inletDirnType::_X, "-x" },
115  { inletDirnType::_Y, "-y" },
116  { inletDirnType::_Z, "-z" },
117  { inletDirnType::_X, "_x" },
118  { inletDirnType::_Y, "_y" },
119  { inletDirnType::_Z, "_z" },
120  { inletDirnType::X, "+x" },
121  { inletDirnType::Y, "+y" },
122  { inletDirnType::Z, "+z" },
123  { inletDirnType::X, "x" },
124  { inletDirnType::Y, "y" },
125  { inletDirnType::Z, "z" },
126 });
127 
128 } // End namespace Foam
129 
130 
131 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
132 
133 addObstacleReader(cylinder, cyl);
134 addObstacleReader(cylinder, cylinder);
135 
137 (
138  PDRobstacle& obs,
139  const dictionary& dict
140 )
141 {
142  obs.PDRobstacle::readProperties(dict);
143  obs.typeId = enumTypeId;
144 
145  // Enforce complete blockage
146  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
147  // if (hasPorosity(dict)) ... warn?
148 
149 
150  dict.readEntry("point", obs.pt);
151  dict.readEntry("length", obs.len());
152  dict.readEntry("diameter", obs.dia());
153 
154  obs.orient = vectorComponentsNames.get("direction", dict);
155 
156  // The sortBias for later position sorting
157  switch (obs.orient)
158  {
159  case vector::X:
160  obs.sortBias = obs.len();
161  break;
162 
163  default:
164  obs.sortBias = 0.5*obs.dia();
165  break;
166  }
167 }
168 
169 
170 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
171 
172 addObstacleReader(diagbeam, diag);
173 addObstacleReader(diagbeam, diagbeam);
174 
176 (
177  PDRobstacle& obs,
178  const dictionary& dict
179 )
180 {
181  obs.PDRobstacle::readProperties(dict);
182  obs.typeId = enumTypeId;
183 
184  // Enforce complete blockage
185  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
186  // if (hasPorosity(dict)) ... warn?
187 
188 
189  dict.readEntry("point", obs.pt);
190  dict.readEntry("length", obs.len());
191  obs.dia() = Zero;
192  obs.theta() = Zero; // Fix later on
193 
194  obs.orient = vectorComponentsNames.get("direction", dict);
195 
196  // Angle (degrees) on input, limit to range [0, PI]
197  scalar angle = dict.get<scalar>("angle");
198 
199  while (angle > 180) angle -= 180;
200  while (angle < 0) angle += 180;
201 
202  labelPair dims;
203  dict.readEntry("width", dims);
204 
205  // Swap axes when theta > PI/2
206  // For 89-90 degrees it becomes -ve, which is picked up in following section
207  if (angle > 89)
208  {
209  angle -= 90;
210  dims.flip(); // Swap dimensions
211  }
212 
213  obs.theta() = degToRad(angle);
214 
215  obs.wa = dims.first();
216  obs.wb = dims.second();
217 
218  const scalar ctheta = cos(obs.theta());
219  const scalar stheta = sin(obs.theta());
220 
221  // The sortBias for later position sorting
222  switch (obs.orient)
223  {
224  case vector::X:
225  obs.sortBias = obs.len();
226  break;
227 
228  case vector::Y:
229  obs.sortBias = 0.5*(obs.wa * stheta + obs.wb * ctheta);
230  break;
231 
232  case vector::Z:
233  obs.sortBias = 0.5*(obs.wa * ctheta + obs.wb * stheta);
234  break;
235  }
236 
237  // If very nearly aligned with axis, turn it into normal block,
238  // to avoid 1/tan(theta) blowing up
239  if (angle < 1)
240  {
241  Info<< "... changed diag-beam to box" << nl;
242 
243  switch (obs.orient)
244  {
245  case vector::X:
246  obs.span = vector(obs.len(), obs.wa, obs.wb);
247  break;
248 
249  case vector::Y:
250  obs.span = vector(obs.wb, obs.len(), obs.wa);
251  break;
252 
253  case vector::Z:
254  obs.span = vector(obs.wa, obs.wb, obs.len());
255  break;
256  }
257 
258  // The pt was end centre (cylinder), now lower corner
259  vector adjustPt = -0.5*obs.span;
260  adjustPt[obs.orient] = 0;
261 
262  obs.pt -= adjustPt;
263 
265  obs.sortBias = 0;
266  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1.0;
267  obs.blowoff_type = 0;
268  }
269 }
270 
271 
272 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
273 
274 addObstacleReader(cuboid, box);
275 
277 (
278  PDRobstacle& obs,
279  const dictionary& dict
280 )
281 {
282  obs.PDRobstacle::readProperties(dict);
283  obs.typeId = enumTypeId;
284 
285  // Default - full blockage
286  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
287 
288 
289  dict.readEntry("point", obs.pt);
290  dict.readEntry("size", obs.span);
291 
292  // Optional
293  obs.vbkge = getPorosity(dict);
294 
295  // Optional
296  const vector blockages = getPorosities(dict);
297  obs.xbkge = blockages.x();
298  obs.ybkge = blockages.y();
299  obs.zbkge = blockages.z();
300 }
301 
302 
303 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
304 
305 addObstacleReader(wallbeam, wallbeam);
306 
308 (
309  PDRobstacle& obs,
310  const dictionary& dict
311 )
312 {
314  obs.typeId = enumTypeId;
315 
316  // Enforce complete blockage
317  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
318 
319  // if (hasPorosity(dict)) ... warn?
320 
321  // Additional adjustment for drag etc.
322 }
323 
324 
325 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
326 
327 addObstacleReader(grating, grating);
328 addObstacleReader(grating, grate);
329 
331 (
332  PDRobstacle& obs,
333  const dictionary& dict
334 )
335 {
336  obs.PDRobstacle::readProperties(dict);
337  obs.typeId = enumTypeId;
338 
339  // Initialize to full blockage
340  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
341 
342  dict.readEntry("point", obs.pt);
343  dict.readEntry("size", obs.span);
344 
345  // TODO: better error handling
346  // if (!equal(cmptProduct(obs.span), 0))
347  // {
348  // Info<< "Type " << typeId << " has non-zero thickness.";
349  // ReportLineInfo(lineNo, inputFile);
350  // }
351 
352  obs.vbkge = getPorosity(dict);
353 
354  const vector blockages = getPorosities(dict);
355  obs.xbkge = blockages.x();
356  obs.ybkge = blockages.y();
357  obs.zbkge = blockages.z();
358 
359  // TODO: Warning if porosity was not specified?
360 
361 
362  // TBD: Default slat width from PDR.params
363  obs.slat_width = dict.getOrDefault<scalar>("slats", Zero);
364 
365  // Determine the orientation
366  if (equal(obs.span.x(), 0))
367  {
368  obs.orient = vector::X;
369  }
370  else if (equal(obs.span.y(), 0))
371  {
372  obs.orient = vector::Y;
373  }
374  else
375  {
376  obs.orient = vector::Z;
377  }
378 }
379 
380 
381 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
382 
383 addObstacleReader(louver, louver);
384 addObstacleReader(louver, louvre);
385 
387 (
388  PDRobstacle& obs,
389  const dictionary& dict
390 )
391 {
392  obs.PDRobstacle::readProperties(dict);
393  obs.typeId = enumTypeId;
394 
395  // Initialize to full blockage
396  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
397 
398  dict.readEntry("point", obs.pt);
399  dict.readEntry("size", obs.span);
400 
401  // TODO: better error handling
402  // if (!equal(cmptProduct(obs.span), 0))
403  // {
404  // Info<< "Type " << typeId << " has non-zero thickness.";
405  // ReportLineInfo(lineNo, inputFile);
406  // }
407 
408  obs.vbkge = getPorosity(dict);
409 
410  const vector blockages = getPorosities(dict);
411  obs.xbkge = blockages.x();
412  obs.ybkge = blockages.y();
413  obs.zbkge = blockages.z();
414 
415  // TODO: Warning if porosity was not specified?
416 
417 
418  // Blowoff pressure [bar]
419  const scalar blowoffPress = dict.get<scalar>("pressure");
420 
421  obs.blowoff_press = barToPa(blowoffPress);
422  obs.blowoff_time = dict.getOrDefault<scalar>("time", 0);
423  obs.blowoff_type = dict.getOrDefault<label>("type", 2);
424 
425  if (obs.blowoff_type == 1)
426  {
427  Info<< "Louver : blowoff-type 1 not yet implemented." << nl;
428  // ReportLineInfo(lineNo, inputFile);
429 
430  if (obs.blowoff_time != 0)
431  {
432  Info<< "Louver : has blowoff time set,"
433  << " not set to blow off cell-by-cell" << nl;
434  // ReportLineInfo(lineNo, inputFile);
435  }
436  }
437  else
438  {
439  if
440  (
441  (obs.blowoff_type == 1 || obs.blowoff_type == 2)
442  && (blowoffPress > 0)
443  )
444  {
445  if (blowoffPress > maxBlowoffPressure)
446  {
447  Info<< "Blowoff pressure (" << blowoffPress
448  << ") too high for blowoff type "
449  << obs.blowoff_type << nl;
450  // ReportLineInfo(lineNo, inputFile);
451  }
452  }
453  else
454  {
455  Info<< "Problem with blowoff parameters" << nl;
456  // ReportLineInfo(lineNo, inputFile);
457  Info<< "Pressure[bar] " << blowoffPress
458  << " Blowoff type " << obs.blowoff_type
459  << ", blowoff pressure " << obs.blowoff_press << nl;
460  }
461  }
462 }
463 
464 
465 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
466 
467 addObstacleReader(patch, patch);
468 
470 (
471  PDRobstacle& obs,
472  const dictionary& dict
473 )
474 {
475  obs.PDRobstacle::readProperties(dict);
476  obs.typeId = enumTypeId;
477 
478  const auto nameLen = obs.identifier.length();
479 
480  word patchName = word::validate(obs.identifier);
481 
482  if (patchName.empty())
483  {
485  << "RECT_PATCH without a patch name"
486  << exit(FatalError);
487  }
488  else if (patchName.length() != nameLen)
489  {
491  << "RECT_PATCH stripped invalid characters from patch name: "
492  << obs.identifier
493  << exit(FatalError);
494 
495  obs.identifier = std::move(patchName);
496  }
497 
498  // Enforce complete blockage
499  obs.xbkge = obs.ybkge = obs.zbkge = obs.vbkge = 1;
500 
501  dict.readEntry("point", obs.pt);
502  dict.readEntry("size", obs.span);
503  obs.inlet_dirn = inletDirnNames.get("direction", dict);
504 }
505 
506 
507 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
508 
509 #undef addObstacleReader
510 
511 // ************************************************************************* //
Different types of constants.
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:39
dictionary dict
static void read(PDRobstacle &obs, const dictionary &dict)
constexpr scalar barToPa(const scalar bar) noexcept
Conversion from bar to Pa.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition: label.H:164
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
static void read(PDRobstacle &obs, const dictionary &dict)
Unit conversion functions.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static void read(PDRobstacle &obs, const dictionary &dict)
static void read(PDRobstacle &obs, const dictionary &dict)
static constexpr int enumTypeId
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
dimensionedScalar cos(const dimensionedScalar &ds)
static void read(PDRobstacle &obs, const dictionary &dict)
Vector< scalar > vector
Definition: vector.H:57
static void read(PDRobstacle &obs, const dictionary &dict)
dimensionedScalar sin(const dimensionedScalar &ds)
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
static void read(PDRobstacle &obs, const dictionary &dict)
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
PtrList< volScalarField > & Y
const std::string patch
OpenFOAM patch number as a std::string.
Macros for easy insertion into member function selection tables.
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Namespace for OpenFOAM.
dimensionSet clamp(const dimensionSet &a, const dimensionSet &range)
Definition: dimensionSet.C:271
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127