MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
lbrb.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "lbrb.h"
8
10#include "IO/parallelio.h"
11#include "MEMORY/alloc.h"
12#include "UTIL/functions.h"
13#include "globals.h"
14#include "globalvariables.h"
15
16#include <algorithm>
17#include <stack>
18#include <vector>
19
29template <MInt nDim, MInt nDist, class SysEqn>
31 : Coupling(couplingId), CouplingLb(couplingId, lb), CouplingRb(couplingId, rb) {
32 TRACE();
33
34 // Init timers as the first action
35 initTimers();
36
37 initData();
41
42 RECORD_TIMER_STOP(m_timers[Timers::Constructor]);
43}
44
50template <MInt nDim, MInt nDist, class SysEqn>
52 TRACE();
53
54 RECORD_TIMER_STOP(m_timers[Timers::Class]);
55
56 averageTimer();
57}
58
64template <MInt nDim, MInt nDist, class SysEqn>
66 TRACE();
67
68 // Create timer group and coupler timer, and start the timer
69 NEW_TIMER_GROUP_NOCREATE(m_timers[Timers::TimerGroup], "LbRb");
70 NEW_TIMER_NOCREATE(m_timers[Timers::Class], "Total object lifetime", m_timers[Timers::TimerGroup]);
71 RECORD_TIMER_START(m_timers[Timers::Class]);
72
73 // Create and start constructor timer
74 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Constructor], "Constructor", m_timers[Timers::Class]);
75 RECORD_TIMER_START(m_timers[Timers::Constructor]);
76
77 // Create Couple timers
78 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CouplePostRb], "Couple post RB", m_timers[Timers::Class]);
79 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ConstructGField], "ConstructGField", m_timers[Timers::CouplePostRb]);
80 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Preparation], "Prepare construct", m_timers[Timers::ConstructGField]);
81
82 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::FindBoundaryCells], "FindBoundaryCells", m_timers[Timers::CouplePostRb]);
83
84 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::PreCouple], "Pre Couple", m_timers[Timers::FindBoundaryCells]);
85 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::FindBoundaryMapping], "Find Boundary Mapping",
86 m_timers[Timers::FindBoundaryCells]);
87
88 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitSolidDomain], "InitSolidDomain", m_timers[Timers::CouplePostRb]);
89 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SetBoundaryVelocity], "SetBoundaryVelocity", m_timers[Timers::CouplePostRb]);
90
91 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CouplePostLb], "Couple post LB", m_timers[Timers::Class]);
92
93 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CreateComm], "CreateComm", m_timers[Timers::CouplePostLb]);
94 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ApplyBC], "ApplyBC", m_timers[Timers::CouplePostLb]);
95 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ComputeBodyForces], "ComputeBodyForces", m_timers[Timers::CouplePostLb]);
96}
97
98
104template <MInt nDim, MInt nDist, class SysEqn>
106 TRACE();
107
108 // update RB grid meta data
109 bodies().updateMaxLevel(lbSolver().maxLevel());
110
111 // Conversion factors
112 const MFloat dx = a_cellLengthAtLevel(lbSolver().maxLevel());
113
114 conversionLbRb.length = dx;
115 conversionRbLb.length = 1 / conversionLbRb.length;
116
117 conversionLbRb.velocity = sqrt(3) / a_Ma();
118 conversionRbLb.velocity = 1 / conversionLbRb.velocity;
119
120 conversionLbRb.time = conversionLbRb.length / conversionLbRb.velocity;
121 conversionRbLb.time = 1 / conversionLbRb.time;
122
123 conversionLbRb.force = POW2(conversionLbRb.velocity) * POW2(conversionLbRb.length);
124 conversionRbLb.force = 1 / conversionLbRb.force;
125
126 conversionLbRb.torque = conversionLbRb.force * conversionLbRb.length;
127 conversionRbLb.torque = 1 / conversionLbRb.torque;
128
129 bodies().setTimestep(conversionLbRb.time);
130
131#ifndef NDEBUG
132 if(!lbSolver().domainId()) {
133 std::cout << "CONVERSION" << std::endl
134 << "LENGTH LB RB " << conversionLbRb.length << std::endl
135 << "LENGTH RB LB " << conversionRbLb.length << std::endl
136 << "VEL LB RB " << conversionLbRb.velocity << std::endl
137 << "VEL RB LB " << conversionRbLb.velocity << std::endl
138 << "TIME LB RB " << conversionLbRb.time << std::endl
139 << "TIME RB LB " << conversionRbLb.time << std::endl
140 << "FORCE LB RB " << conversionLbRb.force << std::endl
141 << "FORCE RB LB " << conversionRbLb.force << std::endl;
142 }
143#endif
144}
145
151template <MInt nDim, MInt nDist, class SysEqn>
153 TRACE();
154
155 lbSolver().m_noLevelSetsUsedForMb = 1;
156 lbSolver().m_maxNoSets = 1;
157}
158
164template <MInt nDim, MInt nDist, class SysEqn>
166
172template <MInt nDim, MInt nDist, class SysEqn>
174 TRACE();
175
176 // LB solver
177 lbSolver().initializeMovingBoundaries();
178 lbBndCnd().initializeBndMovingBoundaries();
179
180 // RB solver
181 bodies().setTimestep(conversionLbRb.time);
182
183 // Construct level set for initial adaptation
184 RECORD_TIMER_START(m_timers[Timers::CouplePostRb]);
185 RECORD_TIMER_START(m_timers[Timers::ConstructGField]);
186 constructGField();
187 RECORD_TIMER_STOP(m_timers[Timers::ConstructGField]);
188 RECORD_TIMER_STOP(m_timers[Timers::CouplePostRb]);
189}
190
191template <MInt nDim, MInt nDist, class SysEqn>
193 // Update conversion factors
194 initData();
195 // Construct level set to initialize newly refined cells
196 RECORD_TIMER_START(m_timers[Timers::CouplePostRb]);
197 RECORD_TIMER_START(m_timers[Timers::ConstructGField]);
198 constructGField();
199 RECORD_TIMER_STOP(m_timers[Timers::ConstructGField]);
200 RECORD_TIMER_STOP(m_timers[Timers::CouplePostRb]);
201}
202
212template <MInt nDim, MInt nDist, class SysEqn>
214 // LB bnd cnd is restarted after adaptation and needs to be initialized again
215 if(solverId == lbSolver().solverId()) {
216 lbSolver().initializeMovingBoundaries();
217 lbBndCnd().initializeBndMovingBoundaries();
218 }
219}
220
221template <MInt nDim, MInt nDist, class SysEqn>
222void LbRb<nDim, nDist, SysEqn>::subCouple(MInt /*rs*/, MInt sid, std::vector<MBool>& solverCompleted) {
223 // Do nothing if both solver already finished
224 if(solverCompleted[lbSolver().solverId()] && solverCompleted[bodies().solverId()]) {
225 return;
226 }
227
228 if(sid == bodies().solverId()) {
229 // POST RB
230 RECORD_TIMER_START(m_timers[Timers::CouplePostRb]);
231 RECORD_TIMER_START(m_timers[Timers::ConstructGField]);
232 constructGField();
233 RECORD_TIMER_STOP(m_timers[Timers::ConstructGField]);
234
235 std::vector<MInt> maxGCellLevels(lbSolver().m_maxNoSets);
236 for(MInt set = 0; set < lbSolver().m_maxNoSets; set++) {
237 maxGCellLevels[set] = lbSolver().maxLevel();
238 }
239
240 RECORD_TIMER_START(m_timers[Timers::FindBoundaryCells]);
241 RECORD_TIMER_START(m_timers[Timers::PreCouple]);
242 lbSolver().preCoupleLs(maxGCellLevels);
243 RECORD_TIMER_STOP(m_timers[Timers::PreCouple]);
244
245 RECORD_TIMER_START(m_timers[Timers::FindBoundaryMapping]);
246 lbSolver().createBndryToBodyMapping(bndryToBodyMapping, bodyToBndryMapping);
247 RECORD_TIMER_STOP(m_timers[Timers::FindBoundaryMapping]);
248 RECORD_TIMER_STOP(m_timers[Timers::FindBoundaryCells]);
249
250 RECORD_TIMER_START(m_timers[Timers::InitSolidDomain]);
251 initializeSolidDomain();
252 RECORD_TIMER_STOP(m_timers[Timers::InitSolidDomain]);
253
254 RECORD_TIMER_START(m_timers[Timers::SetBoundaryVelocity]);
255
256 struct {
257 MFloat velocity;
258 MFloat angularVelocity;
259 MFloat length;
260 MFloat temperature;
261 } conversion{conversionRbLb.velocity, conversionLbRb.time, 1.0 / a_cellLengthAtLevel(lbSolver().maxLevel()), 1.0};
262
263 maia::coupling::setBoundaryVelocity<nDim>(bodies(), a_mbCell(), bodyToBndryMapping, conversion);
264
265 RECORD_TIMER_STOP(m_timers[Timers::SetBoundaryVelocity]);
266 RECORD_TIMER_STOP(m_timers[Timers::CouplePostRb]);
267
268 } else if(sid == lbSolver().solverId()) {
269 // POST LB
270 RECORD_TIMER_START(m_timers[Timers::CouplePostLb]);
271 RECORD_TIMER_START(m_timers[Timers::CreateComm]);
272 lbBndCnd().createMBComm();
273 RECORD_TIMER_STOP(m_timers[Timers::CreateComm]);
274
275 RECORD_TIMER_START(m_timers[Timers::ApplyBC]);
276 lbBndCnd().postCouple();
277 RECORD_TIMER_STOP(m_timers[Timers::ApplyBC]);
278
279 RECORD_TIMER_START(m_timers[Timers::ComputeBodyForces]);
280
281 struct {
282 MFloat force;
283 MFloat length;
284 } const conversion{conversionLbRb.force, 1.0};
285
286 if(a_noCollectorBodies() > 0) {
287 maia::coupling::setBoundaryForceAndTorque<nDim>(a_mbCell(), bodies(), bndryToBodyMapping, conversion);
288 }
289
290#ifndef NDEBUG
291 for(MInt b = 0; b < a_noCollectorBodies(); b++) {
292 for(MInt n = 0; n < nDim; n++) {
293 if(std::isnan(bodies().a_bodyForce(b, n))) {
294 std::cout << "SUM FORCE IS NAN AFTER SETBOUNDANDFORCE AT TIMESETEP: " << lbSolver().getCurrentTimeStep()
295 << std::endl;
296 // TERMM(1, "SUM FORCE AFTER IS NAN");
297 }
298 }
299 }
300#endif
301
302 RECORD_TIMER_STOP(m_timers[Timers::ComputeBodyForces]);
303 RECORD_TIMER_STOP(m_timers[Timers::CouplePostLb]);
304 }
305}
306
315template <MInt nDim, MInt nDist, class SysEqn>
316void LbRb<nDim, nDist, SysEqn>::getBodyVelocity(const MInt body, MFloat* const bodyVelocity) {
317 for(MInt n = 0; n < nDim; n++) {
318 bodyVelocity[n] = bodies().a_bodyVelocity(body, n) * conversionRbLb.velocity;
319 }
320}
321
330template <MInt nDim, MInt nDist, class SysEqn>
331void LbRb<nDim, nDist, SysEqn>::getBodyAngularVelocity(const MInt body, MFloat* const angularVelocity) {
332 for(MInt n = 0; n < nRot; n++) {
333 angularVelocity[n] = bodies().a_angularVelocity(body, n) / conversionRbLb.time;
334 }
335}
336
342template <MInt nDim, MInt nDist, class SysEqn>
344 TRACE();
345
346 lbSolver().m_noEmbeddedBodies = 1;
347 lbSolver().m_geometryIntersection->m_noLevelSetsUsedForMb = 1;
348 lbSolver().m_geometryIntersection->m_noEmbeddedBodies = bodies().size();
349}
350
356template <MInt nDim, MInt nDist, class SysEqn>
358 TRACE();
359
360 if(lbSolver().noNeighborDomains() > 0) {
361 lbSolver().exchangeOldDistributions();
362 }
363
364 MFloatScratchSpace bodyVelocities(a_noCollectorBodies(), nDim, AT_, "bodyVelocities");
365
366 // Get the body Velocity for each embedded body
367 for(MInt body = 0; body < a_noCollectorBodies(); body++) {
368 getBodyVelocity(body, &bodyVelocities(body, 0));
369 }
370
371 for(MInt i = 0; i < a_noCells(); i++) {
372 // Regular fluid cell
373 if(a_isActive(i) && a_wasActive(i)) {
374 continue;
375 }
376
377 // Regular Solid cell
378 if(!a_isActive(i)) {
379 if(!lbSolver().c_isLeafCell(i)) {
380 continue;
381 }
382
383 // determine the body to which the cell belongs, to set the right body velocity
384 MInt bodyId = -1;
385 MInt setOfBody = 0;
386 for(MInt set = lbSolver().m_levelSetId; set < lbSolver().m_maxNoSets; set++) {
387 if(a_associatedBodyIdsMb(i, set) >= 0) {
388 bodyId = a_associatedBodyIdsMb(i, set);
389 setOfBody = set;
390 break;
391 }
392 }
393
394 // if body was deleted, the halo cells that were occupied by the body in the previous timeStep, must be refilled
395 // now
396 if(bodyId == -1 && lbSolver().a_isHalo(i) && bodies().m_bodyWasDeleted) {
397 lbBndCnd().refillEmergedCell(i);
398 lbSolver().a_isActive(i) = 1;
399 continue;
400 }
401
402 ASSERT(bodyId > -1, "No valid bodyId for solid cell! (bodyId=" << bodyId << ") (" << lbSolver().a_coordinate(i, 0)
403 << " " << lbSolver().a_coordinate(i, 1) << ") ("
404 << i << " " << lbSolver().c_globalId(i) << ")"
405 << " isHalo " << lbSolver().a_isHalo(i));
406
407 // the Velocity of the deactivated cell is set to the body velocity
408 // the Density is set to 1.0
409 if((bodyId >= 0) && (bodyId < a_noCollectorBodies()) && (a_levelSetFunctionMb(i, setOfBody) < 0)) {
410 for(MInt j = 0; j < nDim; j++) {
411 a_variable(i, j) = bodyVelocities(bodyId, j);
412 a_oldVariable(i, j) = bodyVelocities(bodyId, j);
413 }
414 } else {
415 for(MInt j = 0; j < a_noVariables(); j++) {
416 a_variable(i, j) = F0;
417 a_oldVariable(i, j) = F0;
418 }
419 }
420 a_variable(i, a_pvrho()) = 1.0;
421 a_oldVariable(i, a_pvrho()) = 1.0;
422
423 if(a_isThermal()) {
424 a_variable(i, a_pvt()) = a_initTemperatureKelvin();
425 }
426
427 // Distributions are not set since they are not used for solid nodes
428 } else {
429 // New fluid cell
430 lbBndCnd().refillEmergedCell(i);
431 }
432 }
433 bodies().m_bodyWasDeleted = false;
434}
435
441template <MInt nDim, MInt nDist, class SysEqn>
443 if(bodies().a_bodyType() == 1)
444 constructGField_<1>();
445 else if(bodies().a_bodyType() == 2)
446 constructGField_<2>();
447 else if(bodies().a_bodyType() == 3)
448 constructGField_<3>();
449 else if(bodies().a_bodyType() == 4)
450 constructGField_<4>();
451 else if(bodies().a_bodyType() == 7)
452 constructGField_<7>();
453 else
454 mTerm(1, AT_, "Body type not implemented!");
455}
456
464template <MInt nDim, MInt nDist, class SysEqn>
465template <MInt bodyType>
467 TRACE();
468
469 RECORD_TIMER_START(m_timers[Timers::Preparation]);
470
471 /* bandwidth at "level" has the no. of cells at "level",
472 whose total width equates to all summed up bands up to "level" */
473 MInt level = lbSolver().maxUniformRefinementLevel() - 1;
474 MFloat m_bodyDistThreshold = 0.0;
475 if(lbSolver().m_adaptation) {
476 m_bodyDistThreshold = lbSolver().m_bandWidth[level] * a_cellLengthAtLevel(level);
477 // m_bodyDistThreshold = 4 * a_cellLengthAtLevel(lbSolver().maxLevel());
478 } else {
479 m_bodyDistThreshold = 2 * a_cellLengthAtLevel(lbSolver().maxLevel());
480 }
481
482 // To be changed later ~jv
483 const MInt m_noLevelSetsUsedForMb = 1;
484
485 // Reset all sets
486 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
487 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
488 a_associatedBodyIdsMb(cellId, set) = -1;
489 a_levelSetFunctionMb(cellId, set) = m_bodyDistThreshold + 1e-14;
490 }
491 }
492
493 const MInt noRelevantBodies = a_noCollectorBodies();
494
495 if(noRelevantBodies == 0) {
496 RECORD_TIMER_STOP(m_timers[Timers::Preparation]);
497 return;
498 }
499
500 RECORD_TIMER_STOP(m_timers[Timers::Preparation]);
501
502 // construct vector with connecting Bodies
503 std::vector<MInt> collectorBodyIds(a_noCollectorBodies());
504 for(MInt i = 0; i < a_noCollectorBodies(); i++) {
505 collectorBodyIds[i] = i;
506 }
507
508 for(MInt i = 0; i < noMinCells(); i++) {
509 const MInt cellId = minCell(i);
510 const MFloat minDist = m_bodyDistThreshold + 1e-14;
511
512 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
513 a_associatedBodyIdsMb(cellId, set) = -1;
514 a_levelSetFunctionMb(cellId, set) = minDist;
515 }
516
517 if(a_noCollectorBodies() > 0) {
518 descendLevelSetValue<bodyType>(cellId, collectorBodyIds.data(), noRelevantBodies);
519 }
520
521 MInt parentId = a_parentId(cellId);
522 while(parentId > -1) {
523 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
524 a_levelSetFunctionMb(parentId, set) = a_levelSetFunctionMb(cellId, set);
525 a_associatedBodyIdsMb(parentId, set) = a_associatedBodyIdsMb(cellId, set);
526 }
527 parentId = a_parentId(parentId);
528 }
529 }
530}
531
544template <MInt nDim, MInt nDist, class SysEqn>
545template <MInt bodyType>
546void LbRb<nDim, nDist, SysEqn>::descendLevelSetValue(const MInt cellId, const MInt* const bodyIds, const MInt bodyCnt) {
547 const MFloat minLevelThreshold = a_cellLengthAtLevel(lbSolver().a_level(cellId));
548
549 MBool skipDescend = true;
550
551 for(MInt b = 0; b < bodyCnt; b++) {
552 const MInt k = bodyIds[b];
553 const MInt set = 0;
554
555 MFloat dist = bodies().template getDistance<bodyType>(&lbSolver().a_coordinate(cellId, 0), k);
556
557 if(dist < minLevelThreshold) {
558 skipDescend = false;
559 }
560
561 if(fabs(dist) < fabs(a_levelSetFunctionMb(cellId, set)) || (dist < F0)) {
562 a_levelSetFunctionMb(cellId, set) = dist;
563 a_associatedBodyIdsMb(cellId, set) = k;
564 }
565 }
566
567 if(skipDescend || !lbSolver().grid().tree().hasChildren(cellId)) {
568 return;
569 }
570
571 // Recursively descend via children
572 constexpr MInt maxNoChildren = nDim == 3 ? 8 : 4;
573 for(MInt child = 0; child < maxNoChildren; child++) {
574 if(a_childId(cellId, child) < 0) continue;
575 descendLevelSetValue<bodyType>(a_childId(cellId, child), bodyIds, bodyCnt);
576 }
577}
578
579template <MInt nDim, MInt nDist, class SysEqn>
581 TRACE();
582 if(!lbSolver().grid().isActive()) return;
583
584 // Get timer operation
585 m_timerType = "max";
586 m_timerType = Context::getSolverProperty<MString>("timerType", lbSolver().solverId(), AT_, &m_timerType);
587
588 // 0) map timer ids for safety
589 const MInt noTimers = m_timers.size();
590
591 // 1) fill buffer with local timer values
592 std::vector<MFloat> timerValues_;
593 timerValues_.reserve(noTimers);
594 for(MInt i = 0; i < noTimers; i++) {
595 timerValues_.emplace_back(RETURN_TIMER_TIME(m_timers[i]));
596 }
597
598 // 2) collect values from all ranks
599 if(m_timerType == "average") {
600 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_SUM,
601 lbSolver().mpiComm(), AT_, "MPI_IN_PLACE", "timerValues_");
602 } else {
603 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_MAX,
604 lbSolver().mpiComm(), AT_, "MPI_IN_PLACE", "timerValues_");
605 }
606
607 // 3) perform averaging on timer and4) set new timer values
608 if(m_timerType == "average") {
609 const MInt noDomains_ = lbSolver().noDomains();
610 for(MInt i = 0; i < noTimers; i++) {
611 const MFloat meanValue = timerValues_[i] / noDomains_;
612 SET_RECORD(m_timers[i], meanValue);
613 }
614 } else {
615 for(MInt i = 0; i < noTimers; i++) {
616 SET_RECORD(m_timers[i], timerValues_[i]);
617 }
618 }
619}
Definition: lbrb.h:28
typename CouplingRb::RBodies RBodies
Definition: lbrb.h:35
void initTimers()
Creates all timers and subtimers.
Definition: lbrb.cpp:65
void init() override
Initialize solver data needed for this coupling.
Definition: lbrb.cpp:173
std::array< MInt, Timers::_count > m_timers
Definition: lbrb.h:126
void descendLevelSetValue(const MInt cellId, const MInt *bodyId, const MInt bodyCnt)
Descend the level set value to the cells children.
Definition: lbrb.cpp:546
void checkProperties()
Checks property-data which is read in by both ls-and Lb-Solver.
Definition: lbrb.cpp:152
void initializeSolidDomain()
Initialize cells which are inisde the solid domain or just entered the fluid domain.
Definition: lbrb.cpp:357
void averageTimer()
Definition: lbrb.cpp:580
void constructGField_()
Constructs the level-set field after each time step.
Definition: lbrb.cpp:466
void subCouple(MInt, MInt, std::vector< MBool > &) override
Definition: lbrb.cpp:222
void initData()
Initializes coupler specific data.
Definition: lbrb.cpp:105
~LbRb()
D'tor for the lattice Boltzmann rigid bodies coupler.
Definition: lbrb.cpp:51
void readProperties()
Read all relevant properties.
Definition: lbrb.cpp:165
void getBodyVelocity(const MInt body, MFloat *const velocity)
Get body velocity converted to LB units.
Definition: lbrb.cpp:316
LbRb(MInt couplingId, LbSolver *lb, RBodies *rb)
C'tor for the lattice Boltzmann rigid bodies coupler.
Definition: lbrb.cpp:30
void constructGField()
Dispatch function for the body specific construction of the level set.
Definition: lbrb.cpp:442
void finalizeAdaptation(const MInt solverId) override
Coupling between solver substeps.
Definition: lbrb.cpp:213
void updateGeometry()
Updates the member-variables in the geometry-intersection class.
Definition: lbrb.cpp:343
void getBodyAngularVelocity(const MInt body, MFloat *const angularVelocity)
Get angular body velocity converted to LB units.
Definition: lbrb.cpp:331
void postAdaptation() override
Definition: lbrb.cpp:192
This class represents all LB models.
Definition: lbsolverdxqy.h:29
This class is a ScratchSpace.
Definition: scratch.h:758
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
@ Constructor
Definition: lbrb.h:105