Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
10License
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
34using 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
57namespace Foam
58{
59
60// Read porosity, change to blockage. Clamp values [0-1] silently
61
62// Volume porosity -> blockage
63inline scalar getPorosity(const dictionary& dict)
64{
65 return 1 - clamp(dict.getOrDefault<scalar>("porosity", 0), zero_one{});
66}
67
68// Direction porosities -> blockage
69inline 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
92static const Foam::Enum<Foam::vector::components>
93vectorComponentsNames
94({
95 { vector::components::X, "x" },
96 { vector::components::Y, "y" },
97 { vector::components::Z, "z" },
98});
99
100
101enum 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
111static const Foam::Enum<inletDirnType>
112inletDirnNames
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
133addObstacleReader(cylinder, cyl);
134addObstacleReader(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
172addObstacleReader(diagbeam, diag);
173addObstacleReader(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
274addObstacleReader(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
305addObstacleReader(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
327addObstacleReader(grating, grating);
328addObstacleReader(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
383addObstacleReader(louver, louver);
384addObstacleReader(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
467addObstacleReader(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// ************************************************************************* //
Macros for easy insertion into member function selection tables.
Obstacle definitions for PDR.
Definition PDRobstacle.H:71
scalar sortBias
Bias for position sorting.
point pt
The obstacle location.
direction orient
The x/y/z orientation (0,1,2).
scalar theta() const
scalar len() const
scalar dia() const
vector span
The obstacle dimensions (for boxes).
int typeId
The obstacle type-id.
void flip()
Flip the Pair in-place.
Definition PairI.H:137
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const T & second() const noexcept
Access the second element.
Definition Pair.H:147
static const Form one
const Cmpt & x() const noexcept
Access to the vector x component.
Definition Vector.H:135
const Cmpt & y() const noexcept
Access to the vector y component.
Definition Vector.H:140
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
static std::string::size_type length(const char *s)
Length of the character sequence (with nullptr protection).
Definition string.H:259
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition word.C:39
Represents 0/1 range or concept. Used for tagged dispatch or clamping.
Definition pTraits.H:51
PtrList< volScalarField > & Y
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
#define WarningInFunction
Report a warning using Foam::Warning.
Different types of constants.
Namespace for OpenFOAM.
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
constexpr scalar barToPa(const scalar bar) noexcept
Conversion from bar to Pa.
dimensionedScalar sin(const dimensionedScalar &ds)
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition label.H:180
messageStream Info
Information stream (stdout output on master, null elsewhere).
dimensionSet clamp(const dimensionSet &a, const dimensionSet &range)
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
Vector< scalar > vector
Definition vector.H:57
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
dimensionedScalar cos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
A cuboid, selectable as box.
static void read(PDRobstacle &obs, const dictionary &dict)
static constexpr int enumTypeId
static void read(PDRobstacle &obs, const dictionary &dict)
static constexpr int enumTypeId
A diagonal beam, which is cylinder-like, selectable as diag or diagbeam.
static void read(PDRobstacle &obs, const dictionary &dict)
A grating, selectable as grate or grating.
static void read(PDRobstacle &obs, const dictionary &dict)
Louver blowoff, selectable as louver or louvre.
static void read(PDRobstacle &obs, const dictionary &dict)
Rectangular patch, selectable as patch.
static void read(PDRobstacle &obs, const dictionary &dict)
A wallbeam, selectable as wallbeam which is currently identical to a box (PDRobstacles::cuboid).
static void read(PDRobstacle &obs, const dictionary &dict)
Unit conversion functions.